@runfusion/fusion 0.70.2 → 0.71.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.
- package/dist/bin.js +174 -7
- package/dist/child-process-worker.js +30 -6
- package/dist/client/.vite/manifest.json +246 -246
- package/dist/client/assets/{AgentDetailView-UMM9DyW-.js → AgentDetailView-BvY24zNh.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-BfNZUiDb.js → AgentPermissionPolicyEditor-CYvJw48-.js} +1 -1
- package/dist/client/assets/{AgentsView-DtC-DVyX.js → AgentsView-BWkWEfNs.js} +3 -3
- package/dist/client/assets/{ChatView-sDJXcOwT.js → ChatView-BhlVq9Re.js} +1 -1
- package/dist/client/assets/{CommandCenter-B7BECRSV.js → CommandCenter-DingokjC.js} +1 -1
- package/dist/client/assets/{DevServerView-CyW7l6rY.js → DevServerView-kfNJk83M.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-BT3OeDJ3.js → DirectoryPicker-Cluyep4u.js} +1 -1
- package/dist/client/assets/{DocumentsView-Dbn8T4ZT.js → DocumentsView-Bwc5HSg7.js} +1 -1
- package/dist/client/assets/{EvalsView-DGOBPt3P.js → EvalsView-BEr_MhJ4.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-Beno0EK8.js → ExperimentalAgentOnboardingModal-CZK-KtFP.js} +1 -1
- package/dist/client/assets/{GoalsView-BLxtocMB.js → GoalsView-B_Qrm8po.js} +1 -1
- package/dist/client/assets/{InsightsView-DjTpiw1S.js → InsightsView-BfbclBHM.js} +1 -1
- package/dist/client/assets/{MemoryView-BvAhPVCo.js → MemoryView-V9Y08BtR.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-Di3Q9J6V.js → PiExtensionsManager-B7fl5l3O.js} +1 -1
- package/dist/client/assets/{PluginManager-reQpowmU.js → PluginManager-H32X557C.js} +1 -1
- package/dist/client/assets/{PullRequestView-DLDz9RXL.js → PullRequestView-Dhz86tnJ.js} +1 -1
- package/dist/client/assets/{ResearchView-BpdpPwyr.js → ResearchView-DEObk9J2.js} +1 -1
- package/dist/client/assets/{SecretsView-BHu1JHnH.js → SecretsView-DFEWUbXI.js} +1 -1
- package/dist/client/assets/{SessionTerminal-rtlAx2uQ.js → SessionTerminal-CwfTrmor.js} +1 -1
- package/dist/client/assets/{SettingsModal-B7m-bZlG.js → SettingsModal-2mlwjfVZ.js} +1 -1
- package/dist/client/assets/{SettingsModal-Dxz7-SNa.js → SettingsModal-H1TNebmF.js} +3 -3
- package/dist/client/assets/{SettingsTextareaRow-5Vb6XYSC.js → SettingsTextareaRow-ByeSU4Pi.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-BixsaVgv.js → SetupWizardModal-BFZnVJX1.js} +2 -2
- package/dist/client/assets/{SkillsView-CNQaKfLx.js → SkillsView-DScNdDRz.js} +1 -1
- package/dist/client/assets/{ThemeDropdown-Bhz3TH1Z.js → ThemeDropdown-BKl0kouU.js} +1 -1
- package/dist/client/assets/{TodoView-Ccr5rxPw.js → TodoView-_HojIE_Y.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-BeY_3iQR.js → WorkflowNodeEditor-CoQYdUYX.js} +1 -1
- package/dist/client/assets/{app-bX7Aarj6.js → app-0sCAWTFb.js} +1 -1
- package/dist/client/assets/{app-BFkCDjfl.js → app-Cndq8AGV.js} +1 -1
- package/dist/client/assets/{app-Bx4Tg9WL.js → app-CqpqmC8O.js} +1 -1
- package/dist/client/assets/{app-BwKqEIVs.js → app-DjxXVWX9.js} +1 -1
- package/dist/client/assets/{app-gasJpw6T.js → app-DrnsOtt9.js} +1 -1
- package/dist/client/assets/{app-BLTqCjPk.js → app-Kb21Gl_h.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-DbmZMyHk.js → architectureDiagram-3BPJPVTR-vIoH_tGm.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-BkspaqvN.js → blockDiagram-GPEHLZMM-BqjSE9AM.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-BfOk6DAf.js → c4Diagram-AAUBKEIU-TWEWVE4T.js} +1 -1
- package/dist/client/assets/channel-hhQEu5zM.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-DbL54v_S.js → chunk-2J33WTMH-CJM3p9Fh.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-VAUWnfVr.js → chunk-4BX2VUAB-Bf_1wJ7O.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-C5h7MxPM.js → chunk-55IACEB6-CI4ThikJ.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-CCc56jyj.js → chunk-727SXJPM-C2TasaKk.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-CUK6s79q.js → chunk-AQP2D5EJ-BqKUxt3g.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-COFczZ8r.js → chunk-FMBD7UC4-CdK77AxG.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-BXTcFeIM.js → chunk-ND2GUHAM-TE8zbIZ3.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-BEYAo7eA.js → chunk-QZHKN3VN-7lgttGIx.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-C2Thhy7D.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C2Thhy7D.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-DqQ74MrB.js → cose-bilkent-S5V4N54A-DsK8EBeo.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-D1DsLIdG.js → dagre-BM42HDAG-COza1ss6.js} +1 -1
- package/dist/client/assets/{dashboard-view-DFy7Ta-E.js → dashboard-view-D_etacMS.js} +1 -1
- package/dist/client/assets/{dashboard-view-D5F_ho0i.js → dashboard-view-ILJ_vnYK.js} +1 -1
- package/dist/client/assets/{dashboard-view-CgBE7XiJ.js → dashboard-view-JEFD-Zgw.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-p-547bXh.js → diagram-2AECGRRQ-Co_F0-vp.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-BE9UnZuh.js → diagram-5GNKFQAL-BD_n7vU0.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BHTLL-vQ.js → diagram-KO2AKTUF-SFnuzet_.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CWLbQcuj.js → diagram-LMA3HP47-CFYeR0mH.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-CXUiMHIE.js → diagram-OG6HWLK6-DOVfqKgw.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Dre62Vsd.js → erDiagram-TEJ5UH35-DkeW3bDN.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BFeMnep3.js → flowDiagram-I6XJVG4X-CVaNMQl_.js} +1 -1
- package/dist/client/assets/{folder-open-s7aQO2Ib.js → folder-open-BY1Gp9Wf.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-CfrUWiHI.js → ganttDiagram-6RSMTGT7-BQJ0x5Hq.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-KjKsgpva.js → gitGraphDiagram-PVQCEYII-CIt0P2Lg.js} +1 -1
- package/dist/client/assets/{index-DF2cd-e3.js → index-ClPjlOHJ.js} +168 -168
- package/dist/client/assets/index-GJLKrqhe.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-Cb_8B_3K.js → infoDiagram-5YYISTIA-B1KKCn80.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-8jtlcCaf.js → ishikawaDiagram-YF4QCWOH-CzG1cEeg.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-O6X0tJvH.js → journeyDiagram-JHISSGLW-CNB7oM4Q.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BetEnps7.js → kanban-definition-UN3LZRKU-D8vXTzfs.js} +1 -1
- package/dist/client/assets/{mermaid.core-CZbT2qhF.js → mermaid.core-BUhJJv1M.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-BRjDmxQK.js → mindmap-definition-RKZ34NQL-y_XyU0Us.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-CJHx1ZvR.js → pieDiagram-4H26LBE5-MB9aZtTc.js} +1 -1
- package/dist/client/assets/{puzzle-BJEQBgfR.js → puzzle-CE00Ce2g.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-D49nAI3y.js → quadrantDiagram-W4KKPZXB-hF7q33gK.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-BM4Uv6Jr.js → requirementDiagram-4Y6WPE33-BIOIzbEd.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-RSKSlyjr.js → sankeyDiagram-5OEKKPKP-BpLzUxJ8.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BXpcHAnr.js → sequenceDiagram-3UESZ5HK-CLXamQhZ.js} +1 -1
- package/dist/client/assets/{shield-alert-DcsqJWMG.js → shield-alert-BhLVV0rp.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-CUYzx5D8.js → standing-instructions-template-96KSNan7.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-CavU8Ef4.js → stateDiagram-AJRCARHV-CPRWhQtZ.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-Cq-9bJPI.js → stateDiagram-v2-BHNVJYJU-8GvpOVMc.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-7fHh3hS9.js → timeline-definition-PNZ67QCA-BAAldJMW.js} +1 -1
- package/dist/client/assets/{upload-DNwFaPfV.js → upload-DbKZcYCW.js} +1 -1
- package/dist/client/assets/{users-D-kPhpXu.js → users-ccVe3aKQ.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-mCh9G6D5.js → vennDiagram-CIIHVFJN-DGSAcrfx.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-DEu4AYE9.js → wardley-L42UT6IY-CLGvNiAx.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DRL0ZyeQ.js → wardleyDiagram-YWT4CUSO-BhU8FLGx.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-DUpC-GBX.js → xychartDiagram-2RQKCTM6-BQ6AzTfE.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +30 -6
- package/dist/plugins/fusion-plugin-dependency-graph/.bundled.reload-1.js +8084 -0
- package/dist/plugins/fusion-plugin-grok-runtime/.bundled.reload-2.js +26479 -0
- package/package.json +1 -1
- package/dist/client/assets/channel-CABKCAbA.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DgshwmmF.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DgshwmmF.js +0 -1
- package/dist/client/assets/index-Co20nJU4.css +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/PluginManager-
|
|
2
|
-
import{r as o,j as e}from"./vendor-react-SZ_qB27O.js";import{c as Xo,fG as Ot,Y as Ee,aS as He,fH as Zo,fI as ec,fJ as tc,fK as rn,fL as sc,fM as Ft,fN as _s,bt as Dt,fO as br,fP as ac,fQ as yl,fR as hn,fS as on,fT as fr,fU as nc,fV as lc,fW as kl,dx as Us,az as rc,aN as ic,P as $s,R as rs,b$ as oc,q as zs,s as qs,cQ as cc,X as yr,a8 as kt,bw as Qe,e9 as dc,fX as vl,fY as uc,fZ as gc,L as Ze,dv as it,f_ as xl,f$ as pc,g0 as hc,g1 as mc,g2 as bc,g3 as fc,g4 as yc,g5 as kc,g6 as vc,g as jl,bL as cn,g7 as xc,g8 as dn,g9 as jc,ga as wc,gb as Cc,u as mn,a0 as kr,gc as Sc,gd as Nc,ge as Pc,a2 as bn,aj as fn,gf as Tc,gg as Ac,ad as Kt,gh as Mc,gi as Ic,gj as Rc,gk as Ec,gl as Fc,gm as Dc,gn as wl,go as Cl,gp as Lc,de as Is,dd as Ha,ap as Oc,C as Kc,fb as Sl,gq as Bc,gr as Gc,fy as Hc,gs as Nl,gt as _c,gu as Pl,gv as Wc,gw as Uc,gx as $c,dN as zc,gy as qc,e_ as Vc,bm as Tl,e$ as Yc,gz as Qc,gA as Jc,gB as Xc,gC as Zc,gD as ed,gE as td,aT as sd,aL as ad,_ as vr,a5 as nd,c4 as Al,a1 as xr,dy as ld,bI as rd,D as id,bU as od,gF as cd,gG as _a,as as dd,aI as Ml,cs as ud,ba as xe,gH as gd,gI as pd,gJ as hd,gK as md,gL as bd,gM as fd,gN as yd,bK as Il,gO as Rl,bs as kd,gP as El,gQ as Fl,gR as vd,gS as Dl,gT as xd,gU as jd,gV as wd,gW as Cd,gX as Sd,gY as Nd,gZ as Pd,g_ as Td,g$ as Ad,h0 as Md,h1 as Id,h2 as Rd,dg as Ed,aJ as Wa,h3 as Fd,h4 as Dd,N as Ld,bQ as Od,ao as Kd,h5 as Ua,fD as Bd,h6 as Gd,h7 as Hd}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/PluginManager-H32X557C.js","assets/vendor-react-SZ_qB27O.js","assets/index-ClPjlOHJ.js","assets/vendor-i18n-GF3RlKbq.js","assets/vendor-reactflow-9C3XTE7_.js","assets/vendor-reactflow-C5ap-Sga.css","assets/vendor-codemirror-jBKmHyH0.js","assets/vendor-xterm-BNq00GSj.js","assets/vendor-xterm-LZoznX6r.css","assets/index-GJLKrqhe.css","assets/DirectoryPicker-Cluyep4u.js","assets/folder-open-BY1Gp9Wf.js","assets/DirectoryPicker-0rspvcMz.css","assets/PluginManager-Bm9FXhxQ.css","assets/PiExtensionsManager-B7fl5l3O.js","assets/puzzle-CE00Ce2g.js","assets/AgentPermissionPolicyEditor-CYvJw48-.js","assets/AgentPermissionPolicyEditor-TpdlOWZW.css","assets/PiExtensionsManager-kgTOHPE9.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{r as o,j as e}from"./vendor-react-SZ_qB27O.js";import{c as Xo,fG as Ot,Y as Ee,aS as He,fH as Zo,fI as ec,fJ as tc,fK as rn,fL as sc,fM as Ft,fN as _s,bt as Dt,fO as br,fP as ac,fQ as yl,fR as hn,fS as on,fT as fr,fU as nc,fV as lc,fW as kl,dx as Us,az as rc,aN as ic,P as $s,R as rs,b$ as oc,q as zs,s as qs,cQ as cc,X as yr,a8 as kt,bw as Qe,e9 as dc,fX as vl,fY as uc,fZ as gc,L as Ze,dv as it,f_ as xl,f$ as pc,g0 as hc,g1 as mc,g2 as bc,g3 as fc,g4 as yc,g5 as kc,g6 as vc,g as jl,bL as cn,g7 as xc,g8 as dn,g9 as jc,ga as wc,gb as Cc,u as mn,a0 as kr,gc as Sc,gd as Nc,ge as Pc,a2 as bn,aj as fn,gf as Tc,gg as Ac,ad as Kt,gh as Mc,gi as Ic,gj as Rc,gk as Ec,gl as Fc,gm as Dc,gn as wl,go as Cl,gp as Lc,de as Is,dd as Ha,ap as Oc,C as Kc,fb as Sl,gq as Bc,gr as Gc,fy as Hc,gs as Nl,gt as _c,gu as Pl,gv as Wc,gw as Uc,gx as $c,dN as zc,gy as qc,e_ as Vc,bm as Tl,e$ as Yc,gz as Qc,gA as Jc,gB as Xc,gC as Zc,gD as ed,gE as td,aT as sd,aL as ad,_ as vr,a5 as nd,c4 as Al,a1 as xr,dy as ld,bI as rd,D as id,bU as od,gF as cd,gG as _a,as as dd,aI as Ml,cs as ud,ba as xe,gH as gd,gI as pd,gJ as hd,gK as md,gL as bd,gM as fd,gN as yd,bK as Il,gO as Rl,bs as kd,gP as El,gQ as Fl,gR as vd,gS as Dl,gT as xd,gU as jd,gV as wd,gW as Cd,gX as Sd,gY as Nd,gZ as Pd,g_ as Td,g$ as Ad,h0 as Md,h1 as Id,h2 as Rd,dg as Ed,aJ as Wa,h3 as Fd,h4 as Dd,N as Ld,bQ as Od,ao as Kd,h5 as Ua,fD as Bd,h6 as Gd,h7 as Hd}from"./index-ClPjlOHJ.js";import{e as se,f as B,c as ke,d as ye,a as de,S as _d,b as Ll,g as Wd}from"./SettingsTextareaRow-ByeSU4Pi.js";import{T as Ud,a as $d}from"./ThemeDropdown-BKl0kouU.js";import{u as te,T as un}from"./vendor-i18n-GF3RlKbq.js";import{U as zd}from"./upload-DbKZcYCW.js";import{SecretsView as qd}from"./SecretsView-DFEWUbXI.js";import{B as Vd,A as Yd}from"./AgentPermissionPolicyEditor-CYvJw48-.js";import{U as Qd}from"./users-ccVe3aKQ.js";import{u as Jd,a as Ol,f as Xd,s as Zd,h as eu,t as tu,g as su,i as au}from"./SettingsModal-2mlwjfVZ.js";import"./vendor-reactflow-9C3XTE7_.js";import"./vendor-codemirror-jBKmHyH0.js";import"./vendor-xterm-BNq00GSj.js";/**
|
|
3
3
|
* @license lucide-react v1.7.0 - ISC
|
|
4
4
|
*
|
|
5
5
|
* This source code is licensed under the ISC license.
|
|
@@ -18,4 +18,4 @@ You operate with a high degree of autonomy, making architectural decisions and b
|
|
|
18
18
|
|
|
19
19
|
You hold all submissions to a high bar for correctness, security, and maintainability.`,builtIn:!0},{id:"concise-triage",name:"Concise Triage",description:"Shorter, more focused specification format with minimal prose.",role:"triage",prompt:`You are a task specification agent for "fn". Produce a concise, actionable PROMPT.md from the given task description.
|
|
20
20
|
|
|
21
|
-
Be brief and precise — avoid verbosity.`,builtIn:!0}],Tg={"executor-welcome":{key:"executor-welcome",name:"Executor Welcome",roles:["executor"],description:"Introductory section for the executor agent",defaultContent:"You are a task execution agent..."},"executor-guardrails":{key:"executor-guardrails",name:"Executor Guardrails",roles:["executor"],description:"Behavioral guardrails and constraints for the executor",defaultContent:"Treat the File Scope in PROMPT.md..."},"executor-spawning":{key:"executor-spawning",name:"Executor Spawning",roles:["executor"],description:"Instructions for spawning child agents",defaultContent:"You can spawn child agents..."},"executor-completion":{key:"executor-completion",name:"Executor Completion",roles:["executor"],description:"Completion criteria and signaling for executor",defaultContent:"After all steps are done..."},"triage-welcome":{key:"triage-welcome",name:"Triage Welcome",roles:["triage"],description:"Introductory section for the triage/specification agent",defaultContent:"You are a task specification agent..."},"triage-context":{key:"triage-context",name:"Triage Context",roles:["triage"],description:"Context-gathering instructions for triage",defaultContent:"What you receive: A raw task title..."},"reviewer-verdict":{key:"reviewer-verdict",name:"Reviewer Verdict",roles:["reviewer"],description:"Verdict criteria and format for code/review agent",defaultContent:"APPROVE — Step will achieve its stated outcomes..."},"merger-conflicts":{key:"merger-conflicts",name:"Merger Conflicts",roles:["merger"],description:"Merge conflict resolution instructions for merger",defaultContent:"If there are merge conflicts..."},"agent-generation-system":{key:"agent-generation-system",name:"Agent Generation System",roles:["executor"],description:"System prompt for generating agent specifications",defaultContent:"You are an agent specification generator..."},"workflow-step-refine":{key:"workflow-step-refine",name:"Workflow Step Refine",roles:["executor"],description:"System prompt for refining workflow step descriptions",defaultContent:"You are an expert at creating detailed agent prompts..."},"planning-system":{key:"planning-system",name:"Planning System",roles:["triage"],description:"System prompt for the AI planning assistant",defaultContent:"You are a planning assistant for the fn task board system..."},"subtask-breakdown-system":{key:"subtask-breakdown-system",name:"Subtask Breakdown System",roles:["executor"],description:"System prompt for AI subtask decomposition",defaultContent:"You are a task decomposition assistant..."},"mission-interview-system":{key:"mission-interview-system",name:"Mission Interview System",roles:["triage"],description:"System prompt for AI-assisted mission planning",defaultContent:"You are a mission planning assistant..."},"ai-refine-system":{key:"ai-refine-system",name:"AI Refine System",roles:["executor"],description:"System prompt for AI-powered text refinement",defaultContent:"You are a text refinement assistant..."},"agent-onboarding-system":{key:"agent-onboarding-system",name:"Agent Onboarding System",roles:["executor"],description:"System prompt for AI-guided agent onboarding interview",defaultContent:"You are an agent onboarding assistant for the fn task board system..."}},rr=["executor","triage","reviewer","merger"],Ag={executor:{key:"agentPrompts.roles.executor",defaultValue:"Executor Agent"},triage:{key:"agentPrompts.roles.triage",defaultValue:"Triage Agent"},reviewer:{key:"agentPrompts.roles.reviewer",defaultValue:"Reviewer Agent"},merger:{key:"agentPrompts.roles.merger",defaultValue:"Merger Agent"},scheduler:{key:"agentPrompts.roles.scheduler",defaultValue:"Scheduler Agent"},engineer:{key:"agentPrompts.roles.engineer",defaultValue:"Engineer Agent"},custom:{key:"agentPrompts.roles.custom",defaultValue:"Custom Agent"}},ns=t=>`prompt-role-tone--${t}`,Xa={name:"",description:"",role:"executor",prompt:""};function Mg(t,s){const a=t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,50),n=new Set(Et.map(i=>i.id)),c=new Set(s.map(i=>i.id));if(!n.has(a)&&!c.has(a))return a;let d=2;for(;n.has(`${a}-${d}`)||c.has(`${a}-${d}`);)d++;return`${a}-${d}`}function Ig({value:t,onChange:s,promptOverrides:a,onPromptOverridesChange:n}){const{t:c}=te("app"),d=F=>{const _=Ag[F];return c(_.key,_.defaultValue)},[i,u]=o.useState("templates"),[l,h]=o.useState(null),[p,b]=o.useState(!1),[w,x]=o.useState(Xa),[f,D]=o.useState(null),[S,C]=o.useState(null),[y,k]=o.useState(new Set),[R,P]=o.useState(null),[N,U]=o.useState(!1),[m,Y]=o.useState(null),E=o.useRef(null),L=t?.templates??[],G=t?.roleAssignments??{},K=m===null?null:m.source==="builtin"?Et.find(F=>F.id===m.id):L.find(F=>F.id===m.id),z=o.useCallback(F=>{const _=Et.filter(be=>be.role===F),ie=L.filter(be=>be.role===F);return[..._,...ie]},[L]);o.useEffect(()=>{m!==null&&E.current?.focus()},[m]);const ne=o.useCallback(()=>{b(!0),h(null),x(Xa),D(null),Y(null)},[]),re=o.useCallback(F=>{h(F.id),b(!1),x({name:F.name,description:F.description,role:F.role,prompt:F.prompt}),D(null),Y(null)},[]),ce=o.useCallback(()=>{h(null),b(!1),x(Xa),D(null),Y(null),U(!1)},[]),T=o.useCallback(()=>{const F=w.name.trim();if(!F){D(c("agentPrompts.errors.nameRequired","Template name is required"));return}let _;if(p){if(_=Mg(F,L),new Set(Et.map(V=>V.id)).has(_)){D(c("agentPrompts.errors.idConflict",'Template ID "{{templateId}}" conflicts with a built-in template. Please use a different name.',{templateId:_}));return}}else _=l;const ie={id:_,name:F,description:w.description.trim(),role:w.role,prompt:w.prompt,builtIn:!1};let be;p?be=[...L,ie]:be=L.map(le=>le.id===_?ie:le);const ve={...G};for(const[le,V]of Object.entries(ve))V===_&&w.role!==le&&delete ve[le];s({...t,templates:be,roleAssignments:Object.keys(ve).length>0?ve:void 0}),ce()},[w,p,l,L,G,t,s,ce]),$=o.useCallback(F=>{const _=L.filter(ve=>ve.id!==F),ie={...G};let be=!1;for(const[ve,le]of Object.entries(ie))le===F&&(delete ie[ve],be=!0);s({...t,templates:_.length>0?_:void 0,roleAssignments:Object.keys(ie).length>0||be?Object.keys(ie).length>0?ie:void 0:G}),C(null),l===F&&ce()},[L,G,t,s,l,ce]),ge=o.useCallback((F,_)=>{const ie={...G};_===""?delete ie[F]:ie[F]=_,s({...t,roleAssignments:Object.keys(ie).length>0?ie:void 0})},[G,t,s]),O=o.useCallback((F,_)=>{const ie={...a};ie[F]=_||null,n(ie)},[a,n]),X=o.useCallback(F=>{const _={...a};_[F]=null,n(_)},[a,n]),me=o.useCallback(F=>{k(_=>{const ie=new Set(_);return ie.has(F)?ie.delete(F):ie.add(F),ie})},[]),I=o.useCallback(F=>{P(_=>_===F?null:F)},[]),we=o.useCallback((F,_)=>{U(!1),Y({source:F,id:_})},[]),je=o.useCallback(()=>{Y(null),U(F=>!F)},[]),Ke=F=>Et.some(_=>_.id===F);return e.jsxs("div",{className:"prompt-manager",children:[e.jsxs("div",{className:"prompt-manager-tabs",children:[e.jsxs("button",{type:"button",className:`prompt-manager-tab ${i==="templates"?"active":""}`,onClick:()=>u("templates"),"data-testid":"tab-templates",children:[e.jsx(Vd,{size:14}),c("agentPrompts.tabs.templates","Templates")]}),e.jsxs("button",{type:"button",className:`prompt-manager-tab ${i==="assignments"?"active":""}`,onClick:()=>u("assignments"),"data-testid":"tab-assignments",children:[e.jsx(Qd,{size:14}),c("agentPrompts.tabs.assignments","Assignments")]}),e.jsxs("button",{type:"button",className:`prompt-manager-tab ${i==="overrides"?"active":""}`,onClick:()=>u("overrides"),"data-testid":"tab-overrides",children:[e.jsx(lu,{size:14}),c("agentPrompts.tabs.overrides","Overrides")]})]}),e.jsxs("div",{className:"prompt-manager-content",children:[i==="templates"&&e.jsxs("div",{className:"prompt-manager-templates-tab","data-testid":"templates-tab",children:[(p||l!==null)&&e.jsxs("div",{className:"prompt-template-editor","data-testid":"template-editor",children:[e.jsx("h4",{className:"prompt-template-editor-title",children:p?c("agentPrompts.editor.newTemplate","New Custom Template"):c("agentPrompts.editor.editTemplate","Edit Custom Template")}),e.jsxs("div",{className:"prompt-template-editor-fields",children:[e.jsxs("div",{className:"prompt-template-field",children:[e.jsx("label",{htmlFor:"template-name",children:c("agentPrompts.labels.name","Name")}),e.jsx("input",{id:"template-name",type:"text",value:w.name,onChange:F=>x(_=>({..._,name:F.target.value})),placeholder:c("agentPrompts.placeholders.templateName","e.g. My Custom Executor"),"data-testid":"template-name-input"})]}),e.jsxs("div",{className:"prompt-template-field",children:[e.jsx("label",{htmlFor:"template-description",children:c("agentPrompts.labels.description","Description")}),e.jsx("input",{id:"template-description",type:"text",value:w.description,onChange:F=>x(_=>({..._,description:F.target.value})),placeholder:c("agentPrompts.placeholders.description","Brief description of this template"),"data-testid":"template-description-input"})]}),e.jsxs("div",{className:"prompt-template-field",children:[e.jsx("label",{htmlFor:"template-role",children:c("agentPrompts.labels.role","Role")}),e.jsx("select",{id:"template-role",value:w.role,onChange:F=>x(_=>({..._,role:F.target.value})),"data-testid":"template-role-select",children:rr.map(F=>e.jsx("option",{value:F,children:d(F)},F))})]}),e.jsxs("div",{className:"prompt-template-field",children:[e.jsxs("div",{className:"prompt-template-prompt-label-row",children:[e.jsx("label",{htmlFor:"template-prompt",children:c("agentPrompts.labels.prompt","Prompt")}),e.jsx("button",{type:"button",className:"btn-icon prompt-template-fullscreen-btn",onClick:je,"aria-label":c("agentPrompts.ariaLabels.expandPrompt","Expand prompt to fullscreen"),"data-testid":"template-prompt-fullscreen",children:e.jsx(Is,{size:14})})]}),N?e.jsxs("div",{className:"prompt-override-fullscreen",onKeyDown:F=>{F.key==="Escape"&&(F.preventDefault(),U(!1))},children:[e.jsxs("div",{className:"prompt-override-fullscreen-header",children:[e.jsx("div",{className:"prompt-override-fullscreen-title",children:c("agentPrompts.titles.editPrompt","Edit Prompt")}),e.jsxs("button",{type:"button",className:"prompt-override-fullscreen-close",onClick:()=>U(!1),"data-testid":"template-prompt-collapse",children:[e.jsx(Ha,{size:14}),c("agentPrompts.actions.collapse","Collapse")]})]}),e.jsx("textarea",{id:"template-prompt-fullscreen","aria-label":c("agentPrompts.ariaLabels.templatePromptFullscreen","Template prompt - fullscreen"),className:"prompt-template-prompt-textarea",value:w.prompt,onChange:F=>x(_=>({..._,prompt:F.target.value})),placeholder:c("agentPrompts.placeholders.prompt","Enter the system prompt for this template..."),rows:30,autoFocus:!0,"data-testid":"template-prompt-input-fullscreen"}),e.jsx("div",{className:"prompt-override-footer",children:e.jsx("small",{className:"prompt-override-hint",children:c("agents.charactersCount","{{count}} characters",{count:w.prompt.length})})})]}):e.jsx("textarea",{id:"template-prompt",value:w.prompt,onChange:F=>x(_=>({..._,prompt:F.target.value})),placeholder:c("agentPrompts.placeholders.prompt","Enter the system prompt for this template..."),rows:8,className:"prompt-template-prompt-textarea","data-testid":"template-prompt-input"})]}),f&&e.jsx("div",{className:"prompt-template-error","data-testid":"template-error",children:f}),e.jsxs("div",{className:"prompt-template-editor-actions",children:[e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:ce,"data-testid":"cancel-template-btn",children:c("agentPrompts.actions.cancel","Cancel")}),e.jsx("button",{type:"button",className:"btn btn-primary",onClick:T,"data-testid":"save-template-btn",children:p?c("agentPrompts.actions.create","Create"):c("agentPrompts.actions.save","Save")})]})]})]}),e.jsxs("div",{className:"prompt-template-section","data-testid":"builtin-templates",children:[e.jsx("h4",{className:"prompt-template-section-title",children:c("agentPrompts.sections.builtinTemplates","Built-in Templates")}),e.jsx("p",{className:"prompt-template-section-desc",children:c("agentPrompts.descriptions.builtinTemplates","These templates are provided by Fusion and cannot be modified.")}),e.jsx("div",{className:"prompt-template-list",children:Et.map(F=>e.jsxs("div",{className:"prompt-template-card","data-testid":`builtin-template-${F.id}`,children:[e.jsxs("div",{className:"prompt-template-card-header",children:[e.jsxs("div",{className:"prompt-template-card-info",children:[e.jsx("span",{className:"prompt-template-card-name",children:F.name}),e.jsx("span",{className:`prompt-template-badge-built-in ${ns(F.role)}`,children:c("agentPrompts.badges.builtin","Built-in")}),e.jsx("span",{className:`prompt-template-badge-role ${ns(F.role)}`,children:d(F.role)})]}),e.jsx("div",{className:"prompt-template-card-actions",children:e.jsx("button",{type:"button",className:"btn-icon prompt-template-fullscreen-btn",onClick:()=>we("builtin",F.id),title:c("agentPrompts.titles.viewFullPrompt","View full prompt"),"aria-label":c("agentPrompts.ariaLabels.viewFullPromptFor","View full prompt for {{name}}",{name:F.name}),"data-testid":`expand-view-${F.id}`,children:e.jsx(Is,{size:14})})})]}),e.jsx("p",{className:"prompt-template-card-description",children:F.description}),e.jsx("div",{className:"prompt-template-card-preview",children:e.jsx("code",{children:F.prompt})})]},F.id))})]}),e.jsxs("div",{className:"prompt-template-section","data-testid":"custom-templates",children:[e.jsx("h4",{className:"prompt-template-section-title",children:c("agentPrompts.sections.customTemplates","Custom Templates")}),e.jsx("p",{className:"prompt-template-section-desc",children:c("agentPrompts.descriptions.customTemplates","Create custom templates to override built-in prompts for specific roles.")}),L.length===0&&!p&&e.jsx("div",{className:"prompt-template-empty",children:c("agentPrompts.emptyStates.noCustomTemplates","No custom templates yet. Create one to get started.")}),L.length>0&&e.jsx("div",{className:"prompt-template-list",children:L.map(F=>e.jsx("div",{className:"prompt-template-card","data-testid":`custom-template-${F.id}`,children:S===F.id?e.jsxs("div",{className:"prompt-template-delete-confirm",children:[e.jsx("p",{children:c("agentPrompts.confirmations.deleteTemplate",'Delete "{{name}}"?',{name:F.name})}),e.jsxs("div",{className:"prompt-template-delete-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>$(F.id),"data-testid":`confirm-delete-${F.id}`,children:c("agentPrompts.actions.delete","Delete")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>C(null),"data-testid":`cancel-delete-${F.id}`,children:c("agentPrompts.actions.cancel","Cancel")})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"prompt-template-card-header",children:[e.jsxs("div",{className:"prompt-template-card-info",children:[e.jsx("span",{className:"prompt-template-card-name",children:F.name}),e.jsx("span",{className:"prompt-template-badge-custom",children:c("agentPrompts.badges.custom","Custom")}),e.jsx("span",{className:`prompt-template-badge-role ${ns(F.role)}`,children:d(F.role)}),Ke(F.id)&&e.jsx("span",{className:"prompt-template-badge-override",children:c("agentPrompts.badges.overridesBuiltin","Overrides built-in")})]}),e.jsxs("div",{className:"prompt-template-card-actions",children:[e.jsx("button",{type:"button",className:"btn-icon prompt-template-fullscreen-btn",onClick:()=>we("custom",F.id),title:c("agentPrompts.titles.viewFullPrompt","View full prompt"),"aria-label":c("agentPrompts.ariaLabels.viewFullPromptFor","View full prompt for {{name}}",{name:F.name}),"data-testid":`expand-view-${F.id}`,children:e.jsx(Is,{size:14})}),e.jsx("button",{type:"button",className:"btn-icon",onClick:()=>re(F),title:c("agentPrompts.titles.edit","Edit"),"aria-label":c("agentPrompts.ariaLabels.editTemplate","Edit {{name}}",{name:F.name}),"data-testid":`edit-${F.id}`,children:e.jsx(zs,{size:14})}),e.jsx("button",{type:"button",className:"btn-icon",onClick:()=>C(F.id),title:c("agentPrompts.titles.delete","Delete"),"aria-label":c("agentPrompts.ariaLabels.deleteTemplate","Delete {{name}}",{name:F.name}),"data-testid":`delete-${F.id}`,children:e.jsx(qs,{size:14})})]})]}),e.jsx("p",{className:"prompt-template-card-description",children:F.description}),e.jsx("div",{className:"prompt-template-card-preview",children:e.jsx("code",{children:F.prompt})})]})},F.id))}),!p&&l===null&&e.jsxs("button",{type:"button",className:"btn btn-primary prompt-template-add-btn",onClick:ne,"data-testid":"add-template-btn",children:[e.jsx($s,{size:14}),c("agentPrompts.actions.addCustomTemplate","Add Custom Template")]})]}),K&&e.jsxs("div",{ref:E,className:"prompt-override-fullscreen",role:"dialog","aria-modal":"true",tabIndex:-1,onKeyDown:F=>{F.key==="Escape"&&(F.preventDefault(),Y(null))},children:[e.jsxs("div",{className:"prompt-override-fullscreen-header",children:[e.jsxs("div",{className:"prompt-override-fullscreen-title",children:[K.name,e.jsx("span",{className:`prompt-template-badge-role ${ns(K.role)}`,children:d(K.role)})]}),e.jsxs("button",{type:"button",className:"prompt-override-fullscreen-close",onClick:()=>Y(null),"data-testid":`collapse-view-${K.id}`,children:[e.jsx(Ha,{size:14}),c("agentPrompts.actions.collapse","Collapse")]})]}),e.jsx("pre",{className:"prompt-template-fullscreen-pre",children:K.prompt})]})]}),i==="assignments"&&e.jsxs("div",{className:"prompt-manager-assignments-tab","data-testid":"assignments-tab",children:[e.jsx("p",{className:"prompt-assignments-desc",children:c("agentPrompts.descriptions.assignments","Assign specific templates to agent roles. When a role has an assignment, that template will be used instead of the default built-in.")}),e.jsx("div",{className:"prompt-role-assignment-list",children:rr.map(F=>{const _=z(F),ie=G[F]??"",be=_.find(le=>le.id===ie),ve=!!ie;return e.jsxs("div",{className:"prompt-role-assignment-row","data-testid":`assignment-${F}`,children:[e.jsxs("div",{className:"prompt-role-assignment-label",children:[e.jsx("span",{className:`prompt-role-badge ${ns(F)}`,children:d(F)}),ve&&e.jsxs("span",{className:"prompt-role-assignment-status",children:[be?.name??c("agentPrompts.labels.custom","Custom")," (",c("agentPrompts.labels.overridesDefault","overrides default"),")"]})]}),e.jsxs("select",{className:"prompt-role-select",value:ie,onChange:le=>ge(F,le.target.value),"data-testid":`select-${F}`,children:[e.jsx("option",{value:"",children:c("agentPrompts.options.useDefault","Use default")}),_.map(le=>e.jsxs("option",{value:le.id,children:[le.name,Ke(le.id)?` (${c("agentPrompts.labels.builtIn","built-in")})`:` (${c("agentPrompts.labels.custom","custom")})`]},le.id))]})]},F)})}),Object.keys(G).length>0&&e.jsxs("div",{className:"prompt-assignments-note",children:[e.jsxs("strong",{children:[c("agentPrompts.labels.note","Note"),":"]})," ",c("agentPrompts.descriptions.assignmentNote","Role assignments are stored in the agentPrompts configuration. Custom templates override built-ins by ID.")]})]}),i==="overrides"&&e.jsxs("div",{className:"prompt-manager-overrides-tab","data-testid":"overrides-tab",children:[e.jsx("p",{className:"prompt-overrides-desc",children:c("agentPrompts.descriptions.overrides","Customize specific segments of AI agent prompts. Edits override built-in defaults. Use the Reset button to restore the original default for any prompt.")}),e.jsx("div",{className:"prompt-overrides-list",children:Object.values(Tg).map(F=>{const _=F.key,ie=a?.[_]??"",be=ie!=="",ve=y.has(_);return e.jsxs("div",{className:"prompt-override-item","data-testid":`override-${_}`,children:[e.jsxs("div",{className:"prompt-override-header",children:[e.jsxs("button",{type:"button",className:"prompt-override-info",onClick:()=>me(_),children:[e.jsx("span",{className:"prompt-override-name",children:F.name}),e.jsx("code",{className:"prompt-override-key",children:_}),be&&e.jsx("span",{className:"prompt-override-badge",children:c("agentPrompts.badges.customized","customized")})]}),e.jsxs("div",{className:"prompt-override-header-actions",children:[ve&&e.jsx("button",{type:"button",className:"prompt-override-fullscreen-btn",onClick:le=>{le.stopPropagation(),I(_)},"aria-label":c("agentPrompts.ariaLabels.expandToFullscreen","Expand to fullscreen"),"data-testid":`fullscreen-${_}`,children:e.jsx(Is,{size:14})}),e.jsx("button",{type:"button",className:"prompt-override-expand-btn","aria-label":ve?c("agentPrompts.ariaLabels.collapse","Collapse"):c("agentPrompts.ariaLabels.expand","Expand"),"data-testid":`expand-${_}`,onClick:le=>{le.stopPropagation(),me(_)},children:ve?e.jsx(Oc,{size:16}):e.jsx(Kc,{size:16})})]})]}),e.jsx("p",{className:"prompt-override-description",children:F.description}),ve&&(R===_?e.jsxs("div",{className:"prompt-override-fullscreen",onKeyDown:le=>{le.key==="Escape"&&(le.preventDefault(),P(null))},children:[e.jsxs("div",{className:"prompt-override-fullscreen-header",children:[e.jsxs("div",{className:"prompt-override-fullscreen-title",children:[F.name,e.jsx("code",{className:"prompt-override-key",children:_})]}),e.jsxs("button",{type:"button",className:"prompt-override-fullscreen-close",onClick:()=>P(null),"data-testid":`collapse-fullscreen-${_}`,children:[e.jsx(Ha,{size:14}),c("agentPrompts.actions.collapse","Collapse")]})]}),e.jsx("textarea",{id:`prompt-${_}-fullscreen`,"aria-label":c("agentPrompts.ariaLabels.promptOverrideFullscreen","{{name}} prompt override ({{key}}) - fullscreen",{name:F.name,key:_}),className:"prompt-override-textarea",value:ie,onChange:le=>{O(_,le.target.value)},placeholder:`Default: ${F.defaultContent.slice(0,100)}${F.defaultContent.length>100?"...":""}`,rows:30,autoFocus:!0,"data-testid":`override-input-fullscreen-${_}`}),e.jsxs("div",{className:"prompt-override-footer",children:[be&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",onClick:()=>X(_),"data-testid":`reset-fullscreen-${_}`,children:c("agentPrompts.actions.reset","Reset")}),e.jsx("small",{className:"prompt-override-hint",children:be?c("agentPrompts.hints.customOverrideActive","Custom override active. Click Reset to restore default."):c("agentPrompts.hints.noOverrideSet","No override set. Using built-in default ({{chars}} chars).",{chars:F.defaultContent.length})})]})]}):e.jsxs("div",{className:"prompt-override-editor",children:[e.jsx("textarea",{id:`prompt-${_}`,"aria-label":c("agentPrompts.ariaLabels.promptOverride","{{name}} prompt override ({{key}})",{name:F.name,key:_}),className:"prompt-override-textarea",value:ie,onChange:le=>{O(_,le.target.value)},placeholder:c("agentPrompts.placeholders.promptDefault","Default: {{preview}}",{preview:F.defaultContent.slice(0,100)+(F.defaultContent.length>100?"...":"")}),rows:4,"data-testid":`override-input-${_}`}),e.jsxs("div",{className:"prompt-override-footer",children:[be&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",onClick:le=>{le.stopPropagation(),X(_)},"data-testid":`reset-${_}`,children:c("agentPrompts.actions.reset","Reset")}),e.jsx("small",{className:"prompt-override-hint",children:be?c("agentPrompts.hints.customOverrideActive","Custom override active. Click Reset to restore default."):c("agentPrompts.hints.noOverrideSet","No override set. Using built-in default ({{chars}} chars).",{chars:F.defaultContent.length})})]})]}))]},_)})})]})]})]})}function xn({message:t,onOpenWorkflowSettings:s}){const{t:a}=te("app");return e.jsxs("div",{className:"settings-moved-stub",role:"note",children:[e.jsx("p",{className:"settings-moved-stub__message",children:t}),e.jsx("button",{type:"button",className:"settings-moved-stub__action",onClick:s,disabled:!s,children:a("settings.movedStub.openWorkflowSettings","Open workflow settings")})]})}function Rg({form:t,setForm:s,onOpenWorkflowSettings:a}){const{t:n}=te("app");return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.nav.prompts","Prompts")}),e.jsx(B,{settingKey:"prompts-section",children:n("settings.prompts.surfaceExplanation","Use this section for agent role system prompt templates, role assignments, and global PromptKey segment overrides. Per-workflow step prompts for prompt and gate nodes are edited in the Workflow Editor. No default — unset (built-in role prompts apply until overridden).")})]}),e.jsx(xn,{message:n("settings.prompts.workflowPromptsRedirect","Per-workflow step prompts for prompt and gate nodes live in the Workflow Editor."),onOpenWorkflowSettings:a}),e.jsx(Ig,{value:t.agentPrompts,onChange:c=>{s(d=>({...d,agentPrompts:c}))},promptOverrides:t.promptOverrides,onPromptOverridesChange:c=>{s(d=>({...d,promptOverrides:c}))}})]})}function Eg({form:t,setForm:s,projectId:a,addToast:n,prefixError:c,setPrefixError:d,onQuickChatButtonModeChange:i,onMobileNavPrimaryItemsChange:u}){const{t:l}=te("app"),[h,p]=o.useState([]);o.useEffect(()=>{let y=!1;return Sl(a,{includeDisabledBuiltins:!0}).then(k=>{y||p(k.filter(R=>R.id.startsWith("builtin:")&&R.kind!=="fragment"&&!Bc.has(R.id)))}).catch(()=>{y||p([])}),()=>{y=!0}},[a]);const[b,w]=o.useState([]);o.useEffect(()=>{let y=!1;return Sl(a).then(k=>{y||w(k.filter(R=>R.kind!=="fragment"))}).catch(()=>{y||w([])}),()=>{y=!0}},[a]);const x=t.aiUndoTaskWorkflowId??"builtin:review-heavy",f=x===""||b.some(y=>y.id===x),D=o.useMemo(()=>{const y=Array.isArray(t.enabledBuiltinWorkflowIds)?t.enabledBuiltinWorkflowIds:void 0;return new Set(y??h.map(k=>k.id))},[h,t.enabledBuiltinWorkflowIds]),S=(y,k)=>{s(R=>{const P=h.map(m=>m.id),N=new Set(Array.isArray(R.enabledBuiltinWorkflowIds)?R.enabledBuiltinWorkflowIds:P);k?N.add(y):N.delete(y);const U=P.filter(m=>N.has(m));return{...R,enabledBuiltinWorkflowIds:U.length===P.length?void 0:U}})},C=()=>{window.confirm(l("settings.general.clearLocalDataConfirm","Clear all cached data and UI preferences stored in this browser? This frees space used by stale chat, task, and board caches. Your tasks and project settings are safe (stored server-side). The dashboard will reload."))&&($c(),window.location.reload())};return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:l("settings.general.general","General")}),e.jsx(de,{descriptor:{key:"taskPrefix",label:l("settings.general.taskPrefix","Task Prefix"),help:l("settings.general.prefixForNewTaskIDsEGKB","Prefix for new task IDs (e.g. KB, PROJ). No default — unset."),scope:"project",placeholder:l("settings.general.fN","FN")},value:t.taskPrefix||"",onChange:y=>{const k=y??"";s(R=>({...R,taskPrefix:k||void 0})),k&&!/^[A-Z]{1,5}$/.test(k)?d(l("settings.general.prefixMustBe15UppercaseLetters","Prefix must be 1–5 uppercase letters")):d(null)},error:c??void 0}),e.jsxs("div",{className:"form-group",children:[e.jsx(Gc,{projectId:a,addToast:n}),e.jsx(B,{settingKey:"projectDefaultWorkflow",children:l("settings.general.newTasksInheritThisCustomWorkflowsStepsOverridable","New tasks inherit this custom workflow's steps (overridable per task). No default — unset (built-in default workflow).")})]}),h.length>0&&e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:l("settings.general.fusionWorkflows","Fusion workflows")}),e.jsx(B,{settingKey:"enabledBuiltinWorkflowIds",children:l("settings.general.disabledFusionWorkflowsAreHiddenFromWorkflow","Disabled Fusion workflows are hidden from workflow pickers. Existing tasks that already use one continue to resolve. Default: all built-in workflows enabled (unset).")})]}),e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:"var(--space-sm)"},children:h.map(y=>e.jsxs("label",{htmlFor:`builtin-workflow-${y.id}`,className:"checkbox-label",children:[e.jsx("input",{id:`builtin-workflow-${y.id}`,type:"checkbox",checked:D.has(y.id),onChange:k=>S(y.id,k.target.checked)}),e.jsx(Hc,{workflowId:y.id,decorative:!0}),e.jsx("span",{children:y.name})]},y.id))})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"aiUndoTaskWorkflowId",children:l("settings.general.aiUndoTaskWorkflow","AI-undo task workflow")}),e.jsx(B,{settingKey:"aiUndoTaskWorkflowId",children:l("settings.general.aiUndoTaskWorkflowHelp",'Workflow assigned to AI-undo (revert) tasks, which reverse already-shipped code and warrant stricter review. Choose "Inherit project default workflow" to leave them on the project default. Default: review-heavy.')})]}),e.jsxs("select",{id:"aiUndoTaskWorkflowId",className:"select","data-testid":"ai-undo-workflow-select",value:x,onChange:y=>s(k=>({...k,aiUndoTaskWorkflowId:y.target.value})),children:[e.jsx("option",{value:"",children:l("settings.general.aiUndoTaskWorkflowInherit","Inherit project default workflow")}),b.map(y=>e.jsx("option",{value:y.id,children:y.name},y.id)),!f&&e.jsx("option",{value:x,children:x})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"ephemeralAgentsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"ephemeralAgentsEnabled",type:"checkbox",checked:t.ephemeralAgentsEnabled!==!1,onChange:y=>s(k=>({...k,ephemeralAgentsEnabled:y.target.checked}))}),l("settings.general.useEphemeralTaskWorkerAgents"," Use ephemeral task-worker agents ")]}),e.jsxs(B,{settingKey:"ephemeralAgentsEnabled",children:[l("settings.general.whenEnabledDefaultFusionSpawnsShortLived"," When enabled (default), Fusion spawns short-lived "),e.jsx("code",{children:"executor-FN-XXXX"}),l("settings.general.agentsToRunEachTaskWhenDisabledOnly"," agents to run each task. When disabled, only permanent agents execute tasks and the scheduler auto-assigns work using the agent reporting chain. Tasks with no eligible permanent agent stay queued. ")]})]})}),e.jsx(se,{descriptor:{key:"ephemeralAgentsCanCreateTasks",label:l("settings.general.allowEphemeralAgentsToCreateTasks"," Allow ephemeral agents to create tasks "),help:l("settings.general.allowEphemeralAgentsToCreateTasksHint","When enabled (default), ephemeral task-worker agents can open follow-up tasks via fn_task_create. When disabled, only humans and permanent agents can create tasks; ephemeral callers are rejected."),scope:"project"},value:t.ephemeralAgentsCanCreateTasks!==!1,onChange:y=>s(k=>({...k,ephemeralAgentsCanCreateTasks:y===!0}))}),e.jsx(se,{descriptor:{key:"workspaceMode",label:l("settings.general.workspaceMode"," Workspace mode (multi-repo) "),help:l("settings.general.workspaceModeHint","When enabled, the project root is treated as a workspace containing multiple git sub-repos. Tasks run per-sub-repo and no git repo is created at the root. Disable for single-repo projects. No default — unset (disabled)."),scope:"project"},value:t.workspaceMode===!0,onChange:y=>s(k=>({...k,workspaceMode:y===!0}))}),e.jsx(se,{descriptor:{key:"allowAbsoluteFileBrowserPaths",label:l("settings.general.allowAbsoluteFileBrowserPaths"," Allow absolute file-browser paths "),help:l("settings.general.allowAbsoluteFileBrowserPathsHint","When enabled, slash-prefixed paths such as /tmp can be opened in the workspace file browser. Windows drive-letter paths remain blocked, and other path validators are unchanged. Default: disabled."),scope:"project"},value:t.allowAbsoluteFileBrowserPaths===!0,onChange:y=>s(k=>({...k,allowAbsoluteFileBrowserPaths:y===!0}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"completionDocumentationMode",children:l("settings.general.completionDocumentationAutomation","Completion Documentation Automation")}),e.jsxs(B,{settingKey:"completionDocumentationMode",children:[l("settings.general.controlsHowFutureTaskSpecsHandleReleaseNote"," Controls how future task specs handle release-note artifacts at completion. Use changeset mode for repositories that follow "),e.jsx("code",{children:".changeset"}),l("settings.general.workflowsOrChangelogModeWhenContributorsShouldUpdate"," workflows, or changelog mode when contributors should update an existing changelog file. Default: off. ")]})]}),e.jsxs("select",{id:"completionDocumentationMode",value:t.completionDocumentationMode||"off",onChange:y=>s(k=>({...k,completionDocumentationMode:y.target.value})),children:[e.jsx("option",{value:"off",children:l("settings.general.off","Off")}),e.jsx("option",{value:"changeset",children:l("settings.general.requireChangesetChangesetMd","Require changeset (.changeset/*.md)")}),e.jsx("option",{value:"changelog",children:l("settings.general.requireChangelogUpdateExistingChangelog","Require changelog update (existing changelog)")})]})]}),e.jsx(ke,{descriptor:{key:"quickChatButtonMode",label:l("settings.general.quickChatLauncher","Quick Chat launcher"),help:l("settings.general.quickChatLauncherHint","Choose whether Quick Chat opens from the draggable floating button, a footer button beside Terminal, or stays hidden. Default: off (hidden)."),scope:"project",options:[{value:"floating",label:l("settings.general.quickChatLauncherFloating","Floating button")},{value:"footer",label:l("settings.general.quickChatLauncherFooter","Footer button")},{value:"off",label:l("settings.general.off","Off")}]},value:t.quickChatButtonMode??(t.showQuickChatFAB?"floating":"off"),onChange:y=>s(k=>{const R=y??"off";return i?.(R),{...k,quickChatButtonMode:R,showQuickChatFAB:R==="floating"}})}),e.jsx(_d,{htmlFor:"mobileNavPrimaryItems",label:l("settings.general.mobileNavPrimaryItems","Mobile footer quick actions"),help:l("settings.general.mobileNavPrimaryItemsHint","Default: Dashboard, Tasks, Agents, Missions, Chat, Mailbox. Add eligible destinations; unselected destinations remain in More."),scope:"project",children:e.jsx("div",{role:"group","aria-label":l("settings.general.mobileNavPrimaryItems","Mobile footer quick actions"),children:(()=>{const y=Array.isArray(t.mobileNavPrimaryItems)&&t.mobileNavPrimaryItems.length>0?t.mobileNavPrimaryItems.filter(P=>Nl.includes(P)):[..._c],k=P=>{s(N=>({...N,mobileNavPrimaryItems:P})),u?.(P)},R=Nl.filter(P=>!y.includes(P));return e.jsxs(e.Fragment,{children:[y.map((P,N)=>{const U=l(Pl[P],P),m=Y=>{const E=[...y];[E[N],E[N+Y]]=[E[N+Y],E[N]],k(E)};return e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("span",{children:U}),e.jsxs("span",{children:[e.jsx("button",{type:"button",className:"btn btn-icon",disabled:N===0,"aria-label":l("settings.general.moveNavItemEarlier","Move {{item}} earlier",{item:U}),onClick:()=>m(-1),children:"↑"}),e.jsx("button",{type:"button",className:"btn btn-icon",disabled:N===y.length-1,"aria-label":l("settings.general.moveNavItemLater","Move {{item}} later",{item:U}),onClick:()=>m(1),children:"↓"}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":l("settings.general.removeNavItem","Remove {{item}}",{item:U}),onClick:()=>k(y.filter(Y=>Y!==P)),children:"×"})]})]},P)}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("span",{children:l("settings.general.addNavItem","Add quick action")}),e.jsxs("select",{id:"mobileNavPrimaryItems",value:"",disabled:y.length>=Wc,onChange:P=>{P.target.value&&k([...y,P.target.value])},children:[e.jsx("option",{value:"",children:l("settings.general.selectNavItem","Choose a destination")}),R.map(P=>e.jsx("option",{value:P,children:l(Pl[P],P)},P))]})]})]})})()})}),e.jsx(se,{descriptor:{key:"quickChatCloseOnOutsideClick",label:l("settings.general.quickChatCloseOnOutsideClick","Close Quick Chat on outside click"),help:l("settings.general.quickChatCloseOnOutsideClickHint","When enabled, clicking outside the Quick Chat window closes it. Disable to keep it open until you close it explicitly. Default: enabled."),scope:"project"},value:t.quickChatCloseOnOutsideClick!==!1,onChange:y=>s(k=>({...k,quickChatCloseOnOutsideClick:y===!0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.chatHistory","Chat history")}),e.jsx(se,{descriptor:{key:"showTaskChatsInCommonFeed",label:l("settings.general.showTaskChatsInCommonFeed","Show task chats in common Chat feed"),help:l("settings.general.showTaskChatsInCommonFeedHint","When enabled, populated task-detail Chat conversations appear in the common Direct feed. Empty task chats stay hidden. Default: disabled."),scope:"project"},value:t.showTaskChatsInCommonFeed===!0,onChange:y=>s(k=>({...k,showTaskChatsInCommonFeed:y===!0}))}),e.jsx(ke,{descriptor:{key:"chatAutoCleanupDays",label:l("settings.general.autoCleanupOldChats","Auto-cleanup old chats"),help:l("settings.general.deleteChatSessionsAndRoomsThatHaveBeen","Delete chat sessions and rooms that have been idle for this many days. Default: Off."),scope:"project",options:[{value:"0",label:l("settings.general.off","Off")},{value:"7",label:l("settings.general.7Days","7 days")},{value:"14",label:l("settings.general.14Days","14 days")},{value:"30",label:l("settings.general.30Days","30 days")},{value:"60",label:l("settings.general.60Days","60 days")},{value:"90",label:l("settings.general.90Days","90 days")}]},value:String(t.chatAutoCleanupDays??0),onChange:y=>s(k=>({...k,chatAutoCleanupDays:Number(y)||0}))}),e.jsx(ke,{descriptor:{key:"mailAutoCleanupDays",label:l("settings.general.autoPruneOldMail","Auto-prune old mail"),help:l("settings.general.deleteInboxOutboxMessagesOlderThanThisMany","Delete inbox/outbox messages older than this many days. Default: Off. 7 days is the suggested setting."),scope:"project",options:[{value:"0",label:l("settings.general.off","Off")},{value:"7",label:l("settings.general.7Days","7 days")},{value:"14",label:l("settings.general.14Days","14 days")},{value:"30",label:l("settings.general.30Days","30 days")},{value:"60",label:l("settings.general.60Days","60 days")},{value:"90",label:l("settings.general.90Days","90 days")}]},value:String(t.mailAutoCleanupDays??0),onChange:y=>s(k=>({...k,mailAutoCleanupDays:Number(y)||0}))}),e.jsx(ke,{descriptor:{key:"operationalLogRetentionDays",label:l("settings.general.operationalLogRetention","Operational log retention"),help:l("settings.general.loweringThisWindowMeansReliabilityMetricsChartsAnd"," Lowering this window means Reliability metrics/charts and the Activity feed will not show history older than the selected range. Per-task task detail history is unaffected. Default: 30 days. "),scope:"project",options:[{value:"0",label:l("settings.general.off","Off")},{value:"7",label:l("settings.general.7Days","7 days")},{value:"14",label:l("settings.general.14Days","14 days")},{value:"30",label:l("settings.general.30Days","30 days")},{value:"60",label:l("settings.general.60Days","60 days")},{value:"90",label:l("settings.general.90Days","90 days")}]},value:String(t.operationalLogRetentionDays??30),onChange:y=>s(k=>({...k,operationalLogRetentionDays:Number(y)||0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.chatRooms","Chat Rooms")}),e.jsx(ye,{descriptor:{key:"chatRoomRecentVerbatimMessages",label:l("settings.general.recentVerbatimRoomMessages","Recent verbatim room messages"),help:l("settings.general.numberOfMostRecentChatRoomMessagesKept","Number of most-recent chat-room messages kept verbatim in the responder transcript. Older messages are compacted into a summary block. Default: 25."),scope:"project",min:1,placeholder:l("settings.general.25","25")},value:t.chatRoomRecentVerbatimMessages??null,onChange:y=>s(k=>({...k,chatRoomRecentVerbatimMessages:y||void 0}))}),e.jsx(ye,{descriptor:{key:"chatRoomCompactionFetchLimit",label:l("settings.general.roomCompactionFetchLimit","Room compaction fetch limit"),help:l("settings.general.upperBoundOnMessagesFetchedFromTheRoom","Upper bound on messages fetched from the room store for compaction consideration. Default: 200."),scope:"project",min:1,placeholder:l("settings.general.200","200")},value:t.chatRoomCompactionFetchLimit??null,onChange:y=>s(k=>({...k,chatRoomCompactionFetchLimit:y||void 0}))}),e.jsx(ye,{descriptor:{key:"chatRoomSummaryMaxChars",label:l("settings.general.roomSummaryMaxCharacters","Room summary max characters"),help:l("settings.general.hardCapOnTheSynthesizedEarlierRoomContext",'Hard cap on the synthesized "Earlier room context" summary block. Default: 3000.'),scope:"project",min:200,placeholder:l("settings.general.3000","3000")},value:t.chatRoomSummaryMaxChars??null,onChange:y=>s(k=>({...k,chatRoomSummaryMaxChars:y||void 0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.capacityRiskBanner","Capacity Risk Banner")}),e.jsx(se,{descriptor:{key:"capacityRiskBannerEnabled",label:l("settings.general.showCapacityRiskBanner"," Show capacity risk banner "),help:l("settings.general.warnOnTheBoardWhenTodoWorkExceeds","Warn on the board when todo work exceeds the threshold and no idle agents are available. Default: disabled."),scope:"project"},value:t.capacityRiskBannerEnabled===!0,onChange:y=>s(k=>({...k,capacityRiskBannerEnabled:y===!0}))}),e.jsx(ye,{descriptor:{key:"capacityRiskTodoThreshold",label:l("settings.general.todoThreshold","Todo threshold"),help:l("settings.general.bannerFiresWhenTodoCountIsStrictlyGreater","Banner fires when todo count is strictly greater than this value (default 20). Applies when the banner is enabled."),scope:"project",min:0},value:t.capacityRiskTodoThreshold??20,onChange:y=>s(k=>({...k,capacityRiskTodoThreshold:y===null?0:Math.max(0,Math.trunc(y)||0)}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.sessionAdvisor","Session advisor (overseer agent)")}),e.jsx(ke,{descriptor:{key:"sessionAdvisorEnabledByDefault",label:l("settings.general.defaultSessionAdvisorForNewTasks","Default for new tasks"),help:l("settings.general.sessionAdvisorHelp","Controls whether newly created tasks enable the session advisor (live LLM overseer of the executor). Individual tasks can override this from Quick Add or task detail. Also set Session advisor model provider and model id under workflow settings before the advisor can run."),scope:"project",options:[{value:"off",label:l("settings.general.offDefault","Off (default)")},{value:"new-tasks",label:l("settings.general.onForNewTasks","On for new tasks")}]},value:t.sessionAdvisorEnabledByDefault?"new-tasks":"off",onChange:y=>s(k=>({...k,sessionAdvisorEnabledByDefault:y==="new-tasks"}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.gitHubTracking","GitHub Tracking")}),e.jsx(se,{descriptor:{key:"githubImportAutoTranslate",label:l("settings.general.autoTranslateImportedIssues","Auto-translate imported issues"),help:l("settings.general.autoTranslateImportedIssuesHelp","When enabled, the Import Tasks panel automatically translates foreign-language issue titles and bodies into the target language below and shows the translation by default. You can always switch back to the original text, and imported tasks carry the translated text. Default: disabled."),scope:"project"},value:t.githubImportAutoTranslate===!0,onChange:y=>s(k=>({...k,githubImportAutoTranslate:y===!0?!0:void 0}))}),e.jsx(ke,{descriptor:{key:"importTranslateTargetLocale",label:l("settings.general.translationTargetLanguage","Translation target language"),help:l("settings.general.translationTargetLanguageHelp","Language imported issues are translated into when auto-translation is enabled. No default — unset inherits the dashboard language."),scope:"project",options:[{value:"",label:l("settings.general.followDashboardLanguage","Follow dashboard language")},...br.map(y=>({value:y,label:Uc(y)}))]},value:t.importTranslateTargetLocale??"",onChange:y=>s(k=>({...k,importTranslateTargetLocale:y&&Ft(y)?y:void 0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.browserData","Browser Data")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:l("settings.general.clearLocalData","Clear local data")}),e.jsx(B,{settingKey:"clearLocalData",children:l("settings.general.clearLocalDataHint","Remove cached board snapshots, chat threads, and UI preferences stored in this browser. Frees space when the dashboard runs low on browser storage. Your tasks and project settings are stored server-side and are not affected.")})]}),e.jsx("div",{style:{marginTop:"var(--space-sm)"},children:e.jsx("button",{type:"button",className:"btn btn-sm",onClick:C,children:l("settings.general.clearLocalDataButton","Clear local data")})})]})]})}const Za="builtin:coding",Fg=[{id:"planning",providerId:"planningProvider",modelId:"planningModelId",thinkingId:"planningThinkingLevel",label:"Plan/Triage Model",help:"Provider and model used when planning or triaging tasks. Leave unset to inherit from the workflow default."},{id:"planning-fallback",providerId:"planningFallbackProvider",modelId:"planningFallbackModelId",thinkingId:"planningFallbackThinkingLevel",label:"Planning Fallback Model",help:"Fallback provider and model used when the primary Plan/Triage model cannot be used."},{id:"execution",providerId:"executionProvider",modelId:"executionModelId",thinkingId:"executionThinkingLevel",label:"Executor Model",help:"Provider and model used while executing workflow steps. Leave unset to inherit from the workflow default."},{id:"execution-fallback",providerId:"executionFallbackProvider",modelId:"executionFallbackModelId",thinkingId:"executionFallbackThinkingLevel",label:"Executor Fallback Model",help:"Fallback provider and model used when the primary Executor model cannot be used."},{id:"validator",providerId:"validatorProvider",modelId:"validatorModelId",thinkingId:"validatorThinkingLevel",label:"Reviewer Model",help:"Provider and model used for workflow review or validation lanes. Leave unset to inherit from the workflow default."},{id:"validator-fallback",providerId:"validatorFallbackProvider",modelId:"validatorFallbackModelId",thinkingId:"validatorFallbackThinkingLevel",label:"Reviewer Fallback Model",help:"Fallback provider and model used when the primary Reviewer model cannot be used."}];function Dg(t){const s=new Map((t??[]).map(a=>[a.id,a]));return Fg.filter(a=>{const n=s.get(a.providerId),c=s.get(a.modelId),d=a.thinkingId?s.get(a.thinkingId):void 0;return n?.type==="string"&&c?.type==="string"&&(!a.thinkingId||d?.type==="enum"||d?.type==="string")})}function Lg(t,s){const a=t[s.providerId],n=t[s.modelId];return typeof a=="string"&&typeof n=="string"&&a&&n?`${a}/${n}`:""}function Og(t,s){return Object.is(t,s)?!0:Array.isArray(t)&&Array.isArray(s)?t.length===s.length&&t.every((a,n)=>Object.is(a,s[n])):!1}class Mr extends Error{rejections;constructor(s){super("Workflow model lane settings were rejected"),this.name="WorkflowLaneFlushRejection",this.rejections=s}}function Kg({form:t,setForm:s,models:a,projectId:n,onOpenWorkflowSettings:c,registerWorkflowLaneSaver:d}){const{t:i}=te("app"),{agents:u,loading:l}=zc(n),{modelLanes:h,getLaneStatus:p,getLaneValue:b,updateLaneValue:w,resetLaneValue:x,getLaneThinkingValue:f,updateLaneThinkingValue:D,resetLaneThinkingValue:S,availableModels:C,modelsLoading:y,favoriteProviders:k,favoriteModels:R,onToggleFavorite:P,onToggleModelFavorite:N,editingPresetId:U,setEditingPresetId:m,presetDraft:Y,setPresetDraft:E,onSavePresetDraft:L,confirmDelete:G}=a,K=t.modelPresets||[],z=K.map(v=>({id:v.id,name:v.name})),ne=new Set(Object.values(t.defaultPresetBySize||{}).filter(Boolean)),re=typeof t.defaultWorkflowId=="string"&&t.defaultWorkflowId.trim()?t.defaultWorkflowId:Za,[ce,T]=o.useState(re),[$,ge]=o.useState(null),[O,X]=o.useState(!1),[me,I]=o.useState({}),[we,je]=o.useState({}),[Ke,F]=o.useState([]),_=o.useRef(0),ie=Object.keys(me).length>0;o.useEffect(()=>{T(re)},[re]),o.useEffect(()=>{if(!n){ge(null),I({}),je({}),F([]);return}const v=++_.current;X(!0),Promise.all([qc(ce,n),Vc(ce,n)]).then(([q,J])=>{if(_.current!==v)return;ge(J),I({}),je({});const ae="settings"in q.ir?q.ir.settings:void 0;F(Dg(ae))}).catch(q=>{if(_.current===v){if(q instanceof Tl&&q.status===404&&ce!==Za){T(Za);return}ge({stored:{},effective:{},orphaned:[]}),F([])}}).finally(()=>{_.current===v&&X(!1)})},[n,ce]);const be=o.useMemo(()=>({...$?.effective??{},...Object.fromEntries(Object.entries(me).filter(([,v])=>v!==null))}),[$,me]),ve=o.useCallback((v,q)=>{je(J=>{const ae={...J};return delete ae[v.providerId],delete ae[v.modelId],ae}),I(J=>{if(!q)return{...J,[v.providerId]:null,[v.modelId]:null};const ae=q.indexOf("/");return ae<=0?J:{...J,[v.providerId]:q.slice(0,ae),[v.modelId]:q.slice(ae+1)}})},[]),le=o.useCallback((v,q)=>{v.thinkingId&&(je(J=>{if(!v.thinkingId||!J[v.thinkingId])return J;const ae={...J};return delete ae[v.thinkingId],ae}),I(J=>({...J,[v.thinkingId]:q||null})))},[]),V=o.useCallback(v=>{ve(v,""),le(v,"")},[ve,le]),pe=o.useCallback(async()=>{if(!n||!ie)return;const v={...me},q=Object.keys(v);try{const J=await Yc(ce,v,n);ge(J),I(ae=>{const Ne={...ae};for(const De of q)Og(ae[De],v[De])&&delete Ne[De];return Ne}),je({})}catch(J){if(J instanceof Tl&&J.status===400&&J.details){const ae=J.details.rejections??[];if(ae.length>0)throw je(Object.fromEntries(ae.map(Ne=>[Ne.settingId,Ne]))),new Mr(ae)}throw J}},[n,ie,ce,me]);o.useEffect(()=>(d?.(pe),()=>d?.(null)),[d,pe]);const Ce=h.filter(v=>["default","merger","import-translate"].includes(v.laneId)),A=h.find(v=>v.laneId==="summarization"),M=v=>v.laneId==="default"?"Project Default Model":v.laneId==="merger"?"Project Merger Model":v.laneId==="summarization"?"Project Summarization Model":v.laneId==="import-translate"?"Project Import Auto-Translation Model":v.label,W=v=>v.laneId==="default"?"Project-wide default AI model used when no more specific task or project lane override is set.":v.laneId==="merger"?"Model used for merge conflict resolution, clean-room merge, stash-conflict recovery, and related merger agent sessions.":v.laneId==="summarization"?"Model used for title auto-summarization, merge commit summaries, GitHub tracking issue titles, and PR title/body generation.":v.laneId==="import-translate"?"Model used to translate foreign-language GitHub/GitLab issue titles and bodies in the Import Tasks panel. One short readonly call per issue — a cheap, fast model is usually the right pick.":v.helperText,Z=t.mergerFallbackProvider&&t.mergerFallbackModelId?`${t.mergerFallbackProvider}/${t.mergerFallbackModelId}`:"",oe=typeof t.mergerFallbackThinkingLevel=="string"?t.mergerFallbackThinkingLevel:"",fe=!!(Z||oe),he=v=>{if(!v){s(J=>({...J,mergerFallbackProvider:void 0,mergerFallbackModelId:void 0,mergerFallbackThinkingLevel:void 0}));return}const q=v.indexOf("/");s(J=>({...J,mergerFallbackProvider:v.slice(0,q),mergerFallbackModelId:v.slice(q+1)}))},Pe=v=>{s(q=>({...q,mergerFallbackThinkingLevel:v||void 0}))},et=()=>{s(v=>({...v,mergerFallbackProvider:void 0,mergerFallbackModelId:void 0,mergerFallbackThinkingLevel:void 0}))},Fe=()=>e.jsxs("div",{className:"form-group","data-testid":"project-model-lane-merger-fallback",children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:"mergerFallbackModel",children:i("settings.projectModels.mergerFallbackModel","Merger Fallback Model")}),e.jsx("span",{className:`settings-lane-badge ${fe?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:fe?"Explicitly set for this project":"Inherited from global settings",children:fe?"Override (Project)":"Inherited (Global)"}),e.jsx(B,{settingKey:"mergerFallbackModel",children:i("settings.projectModels.mergerFallbackHelp","Fallback provider and model used when a merger session retries. Leave unset to use the shared global fallback model pair.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:"mergerFallbackModel",label:"Merger Fallback Model",models:C,value:Z,onChange:he,placeholder:i("settings.projectModels.useGlobal","Use global"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!0,thinkingLevel:oe,onThinkingLevelChange:Pe,defaultThinkingLevel:t.defaultThinkingLevel})}),fe&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromGlobal","Reset to inherit from global"),onClick:et,children:i("settings.projectModels.reset"," Reset ")})]})]}),_e=t.titleSummarizerFallbackProvider&&t.titleSummarizerFallbackModelId?`${t.titleSummarizerFallbackProvider}/${t.titleSummarizerFallbackModelId}`:"",is=typeof t.titleSummarizerFallbackThinkingLevel=="string"?t.titleSummarizerFallbackThinkingLevel:"",Be=!!(_e||is),Js=v=>{if(!v){s(J=>({...J,titleSummarizerFallbackProvider:void 0,titleSummarizerFallbackModelId:void 0,titleSummarizerFallbackThinkingLevel:void 0}));return}const q=v.indexOf("/");s(J=>({...J,titleSummarizerFallbackProvider:v.slice(0,q),titleSummarizerFallbackModelId:v.slice(q+1)}))},St=v=>{s(q=>({...q,titleSummarizerFallbackThinkingLevel:v||void 0}))},Nt=()=>{s(v=>({...v,titleSummarizerFallbackProvider:void 0,titleSummarizerFallbackModelId:void 0,titleSummarizerFallbackThinkingLevel:void 0}))},tt=v=>{const q=p(v),J=b(v),ae=f(v),Ne=q==="overridden"||!!ae,De=M(v);return e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:`${v.laneId}Model`,children:De}),e.jsx("span",{className:`settings-lane-badge ${Ne?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:Ne?"Explicitly set for this project":"Inherited from global settings",children:Ne?"Override (Project)":"Inherited (Global)"}),e.jsxs(B,{settingKey:`${v.laneId}Model`,children:[W(v),i("settings.projectModels.fallsBackTo"," Falls back to: "),v.fallbackOrder,"."]})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:`${v.laneId}Model`,label:De,models:C,value:J,onChange:Ge=>w(v,Ge),placeholder:v.laneId==="default"?"Use global default":"Use global",favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!!v.projectThinkingKey,thinkingLevel:ae,onThinkingLevelChange:Ge=>D(v,Ge),defaultThinkingLevel:t.defaultThinkingLevel})}),Ne&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromGlobal","Reset to inherit from global"),onClick:()=>{x(v),S(v)},style:{whiteSpace:"nowrap"},children:i("settings.projectModels.reset"," Reset ")})]})]},v.laneId)},ct=t.chatDefaultKind??"model",os=t.chatDefaultModelProvider&&t.chatDefaultModelId?`${t.chatDefaultModelProvider}/${t.chatDefaultModelId}`:"",cs=typeof t.chatDefaultThinkingLevel=="string"?t.chatDefaultThinkingLevel:"",vt=!!(t.chatNewSessionMode||t.chatDefaultKind||t.chatDefaultAgentId||os||cs),Xs=v=>{if(!v){s(J=>({...J,chatDefaultKind:"model",chatDefaultAgentId:void 0,chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0}));return}const q=v.indexOf("/");q<=0||s(J=>({...J,chatDefaultKind:"model",chatDefaultAgentId:void 0,chatDefaultModelProvider:v.slice(0,q),chatDefaultModelId:v.slice(q+1)}))},Zs=v=>{s(q=>({...q,chatDefaultThinkingLevel:v||void 0}))},We=()=>{s(v=>({...v,chatNewSessionMode:void 0,chatDefaultKind:void 0,chatDefaultAgentId:void 0,chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0}))};return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:i("settings.projectModels.tokenCap","Token Cap")}),e.jsx(ye,{descriptor:{key:"tokenCap",label:i("settings.projectModels.tokenCap","Token Cap"),help:i("settings.projectModels.automaticallyCompactContextWhenApproachingThisTokenCount","Automatically compact context when approaching this token count. Leave empty for no cap (compact only on overflow errors). Set a number to proactively compact when reaching this token count. No default — unset (no cap)."),scope:"project",placeholder:i("settings.projectModels.noCap","No cap")},value:t.tokenCap??null,onChange:v=>s(q=>({...q,tokenCap:v?Math.trunc(v):null})),clearable:t.tokenCap!=null}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.modelLanes","Model Lanes")}),e.jsx(B,{settingKey:"project-model-lanes",children:i("settings.projectModels.overrideGlobalModelSettingsAtTheProjectLevel"," Override global model settings at the project level. Each lane controls a specific AI usage context. Unset lanes inherit from the corresponding global lane. The Project Default Model is the fallback for this project when a more specific lane is unset. ")})]}),y?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:i("settings.projectModels.loadingAvailableModels","Loading available models…")})}):C.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationFirst"," No models available. Configure authentication first. ")}):e.jsxs(e.Fragment,{children:[Ce.filter(v=>v.laneId==="default"||v.laneId==="merger").map(tt),Fe(),Ce.filter(v=>v.laneId==="import-translate").map(tt)]}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.chatHeading","Chat")}),e.jsx(B,{settingKey:"project-chat-defaults",children:i("settings.projectModels.chatDescription","Choose the default target for new Direct chats and whether New Chat should prompt or immediately use that default.")})]}),e.jsx(ke,{descriptor:{key:"chatNewSessionMode",label:i("settings.projectModels.chatNewSessionMode","New Chat behavior"),help:i("settings.projectModels.chatNewSessionModeHelp","Prompt mode opens New Chat with this default preselected. Always-default mode skips the dialog when the configured default is complete."),scope:"project",options:[{value:"prompt",label:i("settings.projectModels.chatNewSessionModePrompt","Prompt for model each time")},{value:"always-default",label:i("settings.projectModels.chatNewSessionModeAlwaysDefault","Always use configured default")}]},value:t.chatNewSessionMode??"prompt",onChange:v=>s(q=>({...q,chatNewSessionMode:v==="always-default"?"always-default":void 0}))}),e.jsxs("div",{className:"form-group","data-testid":"project-models-chat-kind",children:[e.jsx("label",{children:i("settings.projectModels.chatDefaultKind","Chat default target")}),e.jsxs("div",{className:"chat-new-dialog-mode-toggle","data-testid":"project-models-chat-kind-toggle",children:[e.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${ct==="model"?" chat-new-dialog-mode-btn--active":""}`,onClick:()=>s(v=>({...v,chatDefaultKind:"model",chatDefaultAgentId:void 0})),children:i("settings.projectModels.chatDefaultKindModel","Model")}),e.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${ct==="agent"?" chat-new-dialog-mode-btn--active":""}`,onClick:()=>s(v=>({...v,chatDefaultKind:"agent",chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0})),children:i("settings.projectModels.chatDefaultKindAgent","Agent")})]})]}),ct==="model"?e.jsxs("div",{className:"form-group","data-testid":"project-models-chat-model",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"chatDefaultModel",children:i("settings.projectModels.chatDefaultModel","Chat Default Model")}),e.jsx(B,{settingKey:"chatDefaultModel",children:i("settings.projectModels.chatDefaultModelHelp","Model-mode New Chat uses the built-in Fusion chat agent with this provider/model pair. Leave empty to fall back to prompting.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:"chatDefaultModel",label:i("settings.projectModels.chatDefaultModel","Chat Default Model"),models:C,value:os,onChange:Xs,placeholder:i("settings.projectModels.selectChatDefaultModel","Select a chat default model"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!0,thinkingLevel:cs,onThinkingLevelChange:Zs,defaultThinkingLevel:t.defaultThinkingLevel})}),vt&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.chatDefaultReset","Reset Chat default"),onClick:We,children:i("settings.projectModels.reset"," Reset ")})]})]}):e.jsxs("div",{className:"form-group","data-testid":"project-models-chat-agent",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"chatDefaultAgentId",children:i("settings.projectModels.chatDefaultAgent","Chat Default Agent")}),e.jsx(B,{settingKey:"chatDefaultAgentId",children:i("settings.projectModels.chatDefaultAgentHelp","Agent-mode New Chat starts a Direct chat with the selected durable agent.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsxs("select",{id:"chatDefaultAgentId",value:t.chatDefaultAgentId??"",disabled:l||u.length===0,onChange:v=>s(q=>({...q,chatDefaultKind:"agent",chatDefaultAgentId:v.target.value||void 0,chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0})),children:[e.jsx("option",{value:"",children:l?i("settings.projectModels.loadingAgents","Loading agents…"):i("settings.projectModels.selectChatDefaultAgent","Select a chat default agent")}),u.map(v=>e.jsxs("option",{value:v.id,children:[v.name," (",v.role,")"]},v.id))]})}),vt&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.chatDefaultReset","Reset Chat default"),onClick:We,children:i("settings.projectModels.reset"," Reset ")})]}),u.length===0&&!l?e.jsx("small",{children:i("settings.projectModels.chatDefaultAgentEmpty","No agents are available for this project yet.")}):null]}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.defaultWorkflowModelLanes","Default workflow model lanes")}),e.jsxs(B,{settingKey:"default-workflow-model-lanes",children:[i("settings.movedStub.modelLanes","Per-phase model lanes (execution, planning, reviewer, and their fallbacks) now live on the workflow."),i("settings.projectModels.theseProjectOverridesApplyToTheActiveDefault"," These project overrides apply to the active default workflow. ")]})]}),n?O?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:i("settings.projectModels.loadingWorkflowModelLanes","Loading workflow model lanes…")})}):C.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationBeforeSelectingWorkflow"," No models available. Configure authentication before selecting workflow model lanes. ")}):e.jsxs(e.Fragment,{children:[Ke.map(v=>{const q=Lg(be,v),J=v.thinkingId?be[v.thinkingId]:void 0,ae=typeof J=="string"?J:"",Ne=Object.prototype.hasOwnProperty.call(me,v.providerId)?me[v.providerId]!==null:!!($?.stored&&(Object.prototype.hasOwnProperty.call($.stored,v.providerId)||Object.prototype.hasOwnProperty.call($.stored,v.modelId))),De=v.thinkingId?Object.prototype.hasOwnProperty.call(me,v.thinkingId)?me[v.thinkingId]!==null:!!($?.stored&&Object.prototype.hasOwnProperty.call($.stored,v.thinkingId)):!1,Ge=Ne||De,st=we[v.providerId]?.message??we[v.modelId]?.message??(v.thinkingId?we[v.thinkingId]?.message:void 0);return e.jsxs("div",{className:"form-group","data-testid":`workflow-model-lane-${v.id}`,children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:`workflow-${v.id}-model`,children:v.label}),e.jsx("span",{className:`settings-lane-badge ${Ge?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:Ge?"Explicitly set for this project workflow":"Inherited from workflow defaults",children:Ge?"Override (Project)":"Inherited (Workflow)"}),v.help?e.jsx(B,{settingKey:`workflow-${v.id}-model`,children:v.help}):null]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:`workflow-${v.id}-model`,label:v.label,models:C,value:q,onChange:dt=>ve(v,dt),placeholder:i("settings.projectModels.useWorkflowDefault","Use workflow default"),defaultOptionLabel:"Use workflow default",favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!!v.thinkingId,thinkingLevel:ae,onThinkingLevelChange:v.thinkingId?dt=>le(v,dt):void 0,defaultThinkingLevel:typeof t.defaultThinkingLevel=="string"?t.defaultThinkingLevel:"off"})}),Ge&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromWorkflow","Reset to inherit from workflow"),onClick:()=>V(v),style:{whiteSpace:"nowrap"},children:i("settings.projectModels.reset"," Reset ")})]}),st?e.jsx("small",{className:"settings-error","data-testid":`workflow-model-lane-error-${v.id}`,children:st}):null]},v.id)}),c?e.jsx("div",{className:"settings-model-lane-actions","aria-label":i("settings.projectModels.defaultWorkflowModelLaneActions","Default workflow model lane actions"),children:e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",onClick:c,children:i("settings.projectModels.advancedWorkflowPolicy"," Advanced workflow policy ")})}):null]}):e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.openAProjectToEditWorkflowModelLanes","Open a project to edit workflow model lanes.")}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.modelPresets","Model Presets")}),e.jsxs("div",{className:"form-group settings-model-presets",children:[e.jsx("label",{children:i("settings.projectModels.configuredPresets","Configured presets")}),K.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noPresetsConfiguredYet","No presets configured yet.")}):e.jsx("div",{className:"settings-preset-list",children:K.map(v=>{const q=Qc(v),J=`${q.executorValue||"default"} / ${q.validatorValue||"default"}`;return e.jsxs("div",{className:"settings-preset-item",children:[e.jsxs("div",{className:"settings-preset-item-meta",children:[e.jsx("strong",{children:v.name}),e.jsx("span",{className:"settings-muted settings-preset-summary",children:J})]}),e.jsxs("div",{className:"settings-preset-item-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>{m(v.id),E({...v})},children:i("settings.projectModels.edit"," Edit ")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:async()=>{ne.has(v.id)&&!await G({title:i("settings.models.deletePresetTitle","Delete Preset"),message:i("settings.models.deletePresetMessage",'Preset "{{name}}" is used in auto-selection. Delete it anyway?',{name:v.name}),danger:!0})||(s(ae=>({...ae,modelPresets:(ae.modelPresets||[]).filter(Ne=>Ne.id!==v.id),defaultPresetBySize:Object.fromEntries(Object.entries(ae.defaultPresetBySize||{}).filter(([,Ne])=>Ne!==v.id))})),U===v.id&&(m(null),E(null)))},children:i("settings.projectModels.delete"," Delete ")})]})]},v.id)})}),Y?null:e.jsx("div",{className:"settings-preset-actions",children:e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>{m(null),E({id:"",name:"",executorProvider:void 0,executorModelId:void 0,validatorProvider:void 0,validatorModelId:void 0})},children:i("settings.projectModels.addPreset"," Add Preset ")})})]}),Y?e.jsxs("div",{className:"form-group settings-preset-editor",children:[e.jsx("label",{children:i("settings.projectModels.presetEditor","Preset editor")}),e.jsxs("div",{className:"settings-preset-editor-fields",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"preset-name",children:i("settings.projectModels.name","Name")}),e.jsx("input",{id:"preset-name",type:"text",value:Y.name,onChange:v=>{const q=v.target.value;E(J=>J&&{...J,name:q})}})]}),C.length===0?e.jsx("small",{children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationFirst2","No models available. Configure authentication first.")}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"preset-executor-model",children:i("settings.projectModels.executorModel","Executor model")}),e.jsx(Qe,{id:"preset-executor-model",label:"Preset executor model",models:C,value:Y.executorProvider&&Y.executorModelId?`${Y.executorProvider}/${Y.executorModelId}`:"",onChange:v=>{if(!v){E(J=>J&&{...J,executorProvider:void 0,executorModelId:void 0});return}const q=v.indexOf("/");E(J=>J&&{...J,executorProvider:v.slice(0,q),executorModelId:v.slice(q+1)})},placeholder:i("settings.projectModels.useDefault","Use default"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"preset-validator-model",children:i("settings.projectModels.reviewerModel","Reviewer model")}),e.jsx(Qe,{id:"preset-validator-model",label:"Preset reviewer model",models:C,value:Y.validatorProvider&&Y.validatorModelId?`${Y.validatorProvider}/${Y.validatorModelId}`:"",onChange:v=>{if(!v){E(J=>J&&{...J,validatorProvider:void 0,validatorModelId:void 0});return}const q=v.indexOf("/");E(J=>J&&{...J,validatorProvider:v.slice(0,q),validatorModelId:v.slice(q+1)})},placeholder:i("settings.projectModels.useDefault","Use default"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable"})]})]})]}),e.jsxs("div",{className:"modal-actions settings-preset-editor-actions",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:L,children:i("settings.models.savePreset","Save preset")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>{m(null),E(null)},children:i("settings.actions.cancel","Cancel")})]})]}):null,e.jsx(se,{descriptor:{key:"autoSelectModelPreset",label:i("settings.projectModels.autoSelectPresetBasedOnTaskSize"," Auto-select preset based on task size "),help:i("settings.projectModels.autoSelectModelPresetHint","Default: disabled."),scope:"project"},value:t.autoSelectModelPreset||!1,onChange:v=>s(q=>({...q,autoSelectModelPreset:v===!0}))}),t.autoSelectModelPreset?e.jsx("div",{className:"settings-preset-size-grid",children:["S","M","L"].map(v=>e.jsxs("div",{className:"form-group settings-preset-size-row",children:[e.jsx("label",{htmlFor:`preset-size-${v}`,children:v==="S"?"Small tasks (S):":v==="M"?"Medium tasks (M):":"Large tasks (L):"}),e.jsxs("select",{id:`preset-size-${v}`,value:t.defaultPresetBySize?.[v]||"",onChange:q=>{const J=q.target.value||void 0;s(ae=>({...ae,defaultPresetBySize:{...ae.defaultPresetBySize||{},[v]:J}}))},children:[e.jsx("option",{value:"",children:i("settings.projectModels.noPreset","No preset")}),z.map(q=>e.jsx("option",{value:q.id,children:q.name},q.id))]})]},v))}):null,e.jsx(se,{descriptor:{key:"taskDefinitionInInputLanguage",label:i("settings.projectModels.taskDefinitionInInputLanguage","Write task definitions in the operator's input language"),help:i("settings.projectModels.taskDefinitionInInputLanguageHelp","When enabled, generated task-definition prose uses supported detectable input languages (Spanish, French, Korean, or Chinese as zh-CN). Headings, markers, and code stay English. Unsupported or undetectable input stays English. Default: disabled."),scope:"project"},value:t.taskDefinitionInInputLanguage||!1,onChange:v=>s(q=>({...q,taskDefinitionInInputLanguage:v===!0}))}),e.jsxs("section",{"data-testid":"project-models-ai-summarization",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.aITitleAndGitCommitMessageSummarization"," AI Title and Git Commit Message Summarization ")}),e.jsxs(B,{settingKey:"project-ai-summarization",children:[i("settings.projectModels.configuresTheModelUsedForTwoShortSummary"," Configures the model used for two short-summary jobs: auto-generating task titles from long descriptions, and generating merge commit summaries from step commits and diff stats. "),t.autoSummarizeTitles||t.useAiMergeCommitSummary||t.githubTrackingEnabledByDefault?i("settings.movedStub.summarizerModelInline","These summarization model controls govern title auto-summarization, merge commit summaries, GitHub tracking titles, and PR metadata generation."):""]})]}),y?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:i("settings.projectModels.loadingAvailableModels","Loading available models…")})}):C.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationFirst"," No models available. Configure authentication first. ")}):e.jsxs(e.Fragment,{children:[A?tt(A):null,e.jsxs("div",{className:"form-group","data-testid":"project-model-lane-title-summarizer-fallback",children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:"titleSummarizerFallbackModel",children:i("settings.projectModels.titleSummarizerFallbackModel","Title Summarizer Fallback Model")}),e.jsx("span",{className:`settings-lane-badge ${Be?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:Be?"Explicitly set for this project":"Inherited from global settings",children:Be?"Override (Project)":"Inherited (Global)"}),e.jsx(B,{settingKey:"titleSummarizerFallbackModel",children:i("settings.projectModels.titleSummarizerFallbackHelp","Fallback provider and model used when the primary Title Summarizer model cannot be used. Falls back to the global summarization lane and then the default model chain.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:"titleSummarizerFallbackModel",label:"Title Summarizer Fallback Model",models:C,value:_e,onChange:Js,placeholder:i("settings.projectModels.useGlobal","Use global"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!0,thinkingLevel:is,onThinkingLevelChange:St,defaultThinkingLevel:t.defaultThinkingLevel})}),Be&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromGlobal","Reset to inherit from global"),onClick:Nt,style:{whiteSpace:"nowrap"},children:i("settings.projectModels.reset"," Reset ")})]})]})]}),e.jsx(se,{descriptor:{key:"autoSummarizeTitles",label:i("settings.projectModels.autoSummarizeLongDescriptionsAsTitles"," Auto-summarize long descriptions as titles "),help:i("settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut"," When enabled, tasks created without a title but with descriptions over 200 characters will automatically get an AI-generated title (max 60 characters). The same model is also used to generate fallback merge commit message bodies when the branch's commit log is empty (e.g. squash merges with no unique commits), and GitHub tracking issue titles when a tracked task has no title yet. Default: disabled. "),scope:"project"},value:t.autoSummarizeTitles||!1,onChange:v=>s(q=>({...q,autoSummarizeTitles:v===!0}))}),e.jsx(se,{descriptor:{key:"useAiMergeCommitSummary",label:i("settings.projectModels.aIMergeCommitSummaries"," AI merge commit summaries "),help:i("settings.projectModels.whenEnabledMergeCommitMessagesIncludeAnAI"," When enabled, merge commit messages include an AI-generated subject plus body summary (narrative + bullets + diff-stat) instead of just listing step commit subjects. Uses the title summarization model. Default: enabled. "),scope:"project"},value:t.useAiMergeCommitSummary||!1,onChange:v=>s(q=>({...q,useAiMergeCommitSummary:v===!0}))}),e.jsx(Ll,{descriptor:{key:"prTitlePromptInstructions",label:i("settings.projectModels.prTitlePromptInstructions","PR title prompt guidance"),help:i("settings.projectModels.prTitlePromptInstructionsHelp","Guides the AI-generated Create PR title. Leave blank to use the default PR metadata prompt. No default — unset."),scope:"project",placeholder:i("settings.projectModels.prTitlePromptInstructionsPlaceholder","Example: Use conventional-commit style and keep titles under 72 characters.")},value:t.prTitlePromptInstructions||"",onChange:v=>s(q=>({...q,prTitlePromptInstructions:v??""}))}),e.jsx(Ll,{descriptor:{key:"prDescriptionPromptInstructions",label:i("settings.projectModels.prDescriptionPromptInstructions","PR description prompt guidance"),help:i("settings.projectModels.prDescriptionPromptInstructionsHelp","Guides the AI-generated Create PR summary, changes, and testing sections. Leave blank to use the default PR metadata prompt. No default — unset."),scope:"project",placeholder:i("settings.projectModels.prDescriptionPromptInstructionsPlaceholder","Example: Emphasize operator-facing behavior and list verification commands exactly.")},value:t.prDescriptionPromptInstructions||"",onChange:v=>s(q=>({...q,prDescriptionPromptInstructions:v??""}))})]})]})}const ir=1440*60*1e3,Bg=2;function Gg({form:t,setForm:s,concurrencyLoading:a=!1,onOverlapIgnorePathChange:n,onOpenOverlapPathPicker:c,onRemoveOverlapIgnorePath:d,onAddOverlapIgnorePath:i,onOpenWorkflowSettings:u}){const{t:l}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:l("settings.scheduling.scheduling","Scheduling")}),e.jsx(ye,{descriptor:{key:"executorToolFailureRetryCount",label:l("settings.scheduling.executorToolFailureRetryCount","Executor tool-failure retries"),help:l("settings.scheduling.executorToolFailureRetryCountHelp","Same-model retries after consecutive tool-call failures. Set 0 to disable. Default: 2."),scope:"project",min:0,step:1},value:t.executorToolFailureRetryCount??2,onChange:h=>s(p=>({...p,executorToolFailureRetryCount:Math.max(0,Math.floor(h??2))}))}),e.jsx(ye,{descriptor:{key:"executorToolFailureRetryBackoffMs",label:l("settings.scheduling.executorToolFailureRetryBackoffMs","Tool-failure retry backoff (ms)"),help:l("settings.scheduling.executorToolFailureRetryBackoffMsHelp","Unref'd wait before retrying. Default: 2000."),scope:"project",min:0,step:1},value:t.executorToolFailureRetryBackoffMs??2e3,onChange:h=>s(p=>({...p,executorToolFailureRetryBackoffMs:Math.max(0,Math.floor(h??2e3))}))}),e.jsx(ye,{descriptor:{key:"executorToolFailureThreshold",label:l("settings.scheduling.executorToolFailureThreshold","Consecutive tool failures"),help:l("settings.scheduling.executorToolFailureThresholdHelp","Terminal tool errors required before retrying. Default: 3."),scope:"project",min:1,step:1},value:t.executorToolFailureThreshold??3,onChange:h=>s(p=>({...p,executorToolFailureThreshold:Math.max(1,Math.floor(h??3))}))}),e.jsx(se,{descriptor:{key:"executorModelEscalationEnabled",label:l("settings.scheduling.executorModelEscalationEnabled","Escalate after tool-failure retries"),help:l("settings.scheduling.executorModelEscalationEnabledHelp","After same-model retries are exhausted, try one configured alternate model or node. Disabled by default."),scope:"project"},value:t.executorModelEscalationEnabled===!0,onChange:h=>s(p=>({...p,executorModelEscalationEnabled:h===!0}))}),e.jsx(de,{descriptor:{key:"executorEscalationProvider",label:l("settings.scheduling.executorEscalationProvider","Escalation provider"),help:l("settings.scheduling.executorEscalationProviderHelp","Provider for the alternate model. Requires an alternate model ID."),scope:"project"},value:t.executorEscalationProvider??"",onChange:h=>s(p=>({...p,executorEscalationProvider:h??""}))}),e.jsx(de,{descriptor:{key:"executorEscalationModelId",label:l("settings.scheduling.executorEscalationModelId","Escalation model ID"),help:l("settings.scheduling.executorEscalationModelIdHelp","Alternate model ID. Requires an escalation provider."),scope:"project"},value:t.executorEscalationModelId??"",onChange:h=>s(p=>({...p,executorEscalationModelId:h??""}))}),e.jsx(de,{descriptor:{key:"executorEscalationNodeId",label:l("settings.scheduling.executorEscalationNodeId","Escalation node ID"),help:l("settings.scheduling.executorEscalationNodeIdHelp","Optional configured node; a node target re-enters scheduler routing."),scope:"project"},value:t.executorEscalationNodeId??"",onChange:h=>s(p=>({...p,executorEscalationNodeId:h??""}))}),e.jsx(ye,{descriptor:{key:"maxConcurrent",label:l("settings.scheduling.maxConcurrentTasks","Max Concurrent Tasks"),help:l("settings.scheduling.maxConcurrentTasksHint","Default: 2."),scope:"project",min:1,max:10,disabled:a},value:t.maxConcurrent??null,onChange:h=>s(p=>({...p,maxConcurrent:h??void 0}))}),e.jsx(ye,{descriptor:{key:"maxConcurrentVerifications",label:l("settings.scheduling.maxConcurrentVerifications","Max Concurrent Verifications"),help:l("settings.scheduling.maxConcurrentVerificationsHint","Caps stacked typecheck/build verification across tasks. Default: 1. Range: 1–8."),scope:"project",min:1,max:8,disabled:a},value:t.maxConcurrentVerifications??null,onChange:h=>{if(h===null){s(b=>({...b,maxConcurrentVerifications:void 0}));return}const p=Math.min(8,Math.max(1,Math.floor(h)||1));s(b=>({...b,maxConcurrentVerifications:p}))}}),e.jsx(ye,{descriptor:{key:"maxTriageConcurrent",label:l("settings.scheduling.maxTriageConcurrent","Max Triage Concurrent"),help:l("settings.scheduling.maximumConcurrentPlanningAgents","Maximum concurrent planning agents. Default: 2."),scope:"project",min:1,max:10,disabled:a},value:t.maxTriageConcurrent??null,onChange:h=>s(p=>({...p,maxTriageConcurrent:h??void 0}))}),e.jsx(ye,{descriptor:{key:"pollIntervalMs",label:l("settings.scheduling.pollIntervalMs","Poll Interval (ms)"),help:l("settings.scheduling.pollIntervalMsHint","Default: 15000 (15 seconds)."),scope:"project",min:5e3,step:1e3},value:t.pollIntervalMs??null,onChange:h=>s(p=>({...p,pollIntervalMs:h??void 0}))}),e.jsx(ke,{descriptor:{key:"heartbeatScopeDiscipline",label:l("settings.scheduling.heartbeatScopeDiscipline","Heartbeat Scope Discipline"),help:l("settings.scheduling.strictCoordinationFocusedHigherPerTickTokensLite","Strict — coordination-focused; higher per-tick tokens. Lite — pre-2026-05-11 behavior. Off — minimal procedure."),scope:"project",options:[{value:"strict",label:l("settings.scheduling.strictDefault","Strict (default)")},{value:"lite",label:l("settings.scheduling.lite","Lite")},{value:"off",label:l("settings.scheduling.off","Off")}]},value:t.heartbeatScopeDiscipline??"strict",onChange:h=>s(p=>({...p,heartbeatScopeDiscipline:h}))}),e.jsx(se,{descriptor:{key:"engineerBacklogAutoClaim",label:l("settings.scheduling.letEngineerAgentsAutoClaimBacklogTasks"," Let engineer agents auto-claim backlog tasks "),help:l("settings.scheduling.backlogNoTaskAutoClaimIsExecutorOnly","Backlog/no-task auto-claim is executor-only by default. Enable to let engineer-role agents auto-claim unowned backlog tasks; explicit routing and delegation are unchanged. Default: off."),scope:"project"},value:t.engineerBacklogAutoClaim===!0,onChange:h=>s(p=>({...p,engineerBacklogAutoClaim:h===!0}))}),e.jsx(ye,{descriptor:{key:"taskStuckTimeoutMs",label:l("settings.scheduling.stuckTaskTimeoutMinutes","Stuck Task Timeout (minutes)"),help:l("settings.scheduling.timeoutInMinutesForDetectingStuckTasksWhen","Timeout in minutes for detecting stuck tasks. When a task's agent session shows no activity for longer than this duration, the task is terminated and retried. Leave empty to disable. Suggested: 10. Default: 10 minutes (600000ms)."),scope:"project",min:1,step:1},value:t.taskStuckTimeoutMs?Math.round(t.taskStuckTimeoutMs/6e4):null,onChange:h=>s(p=>({...p,taskStuckTimeoutMs:h!==null&&h>0?h*6e4:void 0}))}),e.jsx(ye,{descriptor:{key:"buildTimeoutMs",label:l("settings.scheduling.buildTimeoutMinutes","Build/Verification Timeout (minutes)"),help:l("settings.scheduling.maximumTimeInMinutesForBuildVerificationCommands","Maximum time in minutes for build/verification commands before they are killed. Raise for large monorepo or Docker builds. Default: 5."),scope:"project",min:1,step:1},value:t.buildTimeoutMs?Math.round(t.buildTimeoutMs/6e4):null,onChange:h=>s(p=>({...p,buildTimeoutMs:h!==null&&h>0?h*6e4:void 0}))}),e.jsx(ye,{descriptor:{key:"staleHighFanoutBlockerAgeThresholdMs",label:l("settings.scheduling.staleHighFanOutEscalationHours","Stale High Fan-out Escalation (hours)"),help:l("settings.scheduling.escalateHighFanOutBlockersOnlyAfterThey","Escalate high fan-out blockers only after they remain in in-progress or in-review for this many hours (age source: columnMovedAt, fallback updatedAt). Default: 2 hours."),scope:"project",min:1,step:1},value:t.staleHighFanoutBlockerAgeThresholdMs?Math.round(t.staleHighFanoutBlockerAgeThresholdMs/36e5):null,onChange:h=>s(p=>({...p,staleHighFanoutBlockerAgeThresholdMs:h!==null&&h>0?h*36e5:void 0}))}),e.jsx(se,{descriptor:{key:"preserveProgressOnStuckRequeue",label:l("settings.scheduling.preserveStepProgressOnStuckTaskRequeue"," Preserve step progress on stuck-task requeue "),help:l("settings.scheduling.whenTheStuckDetectorKillsAndReQueues","When the stuck detector kills and re-queues a task, keep completed step statuses so the agent can resume from where it left off. Disable to reset every step to pending on each stuck retry. Default: enabled."),scope:"project"},value:t.preserveProgressOnStuckRequeue!==!1,onChange:h=>s(p=>({...p,preserveProgressOnStuckRequeue:h===!0}))}),e.jsx(se,{descriptor:{key:"specStalenessEnabled",label:l("settings.scheduling.enablePlanStalenessEnforcement"," Enable plan staleness enforcement "),help:l("settings.scheduling.whenEnabledTasksWithStalePlansPROMPTMd","When enabled, tasks with stale plans (PROMPT.md older than the threshold) are automatically sent back to planning for replanning. Default: disabled."),scope:"project"},value:t.specStalenessEnabled||!1,onChange:h=>s(p=>({...p,specStalenessEnabled:h===!0}))}),e.jsx(ye,{descriptor:{key:"specStalenessMaxAgeMs",label:l("settings.scheduling.staleSpecThresholdHours","Stale Spec Threshold (hours)"),help:l("settings.scheduling.maximumAgeInHoursBeforeAPlanIs","Maximum age in hours before a plan is considered stale. Default: 6 hours."),scope:"project",min:0,step:1,disabled:!t.specStalenessEnabled},value:t.specStalenessMaxAgeMs!==void 0?Math.round(t.specStalenessMaxAgeMs/36e5):null,onChange:h=>s(p=>({...p,specStalenessMaxAgeMs:h!==null?h*36e5:void 0}))}),e.jsx(se,{descriptor:{key:"autoArchiveDoneTasksEnabled",label:l("settings.scheduling.enableAutomaticTaskArchiving"," Enable automatic task archiving "),help:l("settings.scheduling.completedTasksOlderThanTheThresholdAreMoved","Completed tasks older than the threshold are moved out of the active task database. Default: enabled."),scope:"project"},value:t.autoArchiveDoneTasksEnabled??!0,onChange:h=>s(p=>({...p,autoArchiveDoneTasksEnabled:h===!0}))}),e.jsx(ye,{descriptor:{key:"autoArchiveDoneAfterMs",label:l("settings.scheduling.archiveCompletedTasksAfterDays","Archive Completed Tasks After (days)"),help:l("settings.scheduling.numberOfDaysATaskCanStayIn","Number of days a task can stay in Done before it is archived. Default: 2 days (48 hours)."),scope:"project",min:1,step:1,disabled:t.autoArchiveDoneTasksEnabled===!1},value:t.autoArchiveDoneAfterMs!==void 0?Math.round(t.autoArchiveDoneAfterMs/ir):Bg,onChange:h=>s(p=>({...p,autoArchiveDoneAfterMs:h===null?void 0:h*ir}))}),e.jsx(ke,{descriptor:{key:"archiveAgentLogMode",label:l("settings.scheduling.archiveAgentLog","Archive Agent Log"),help:l("settings.scheduling.compactModeKeepsArchiveSizeLowWhilePreserving","Compact mode keeps archive size low while preserving recent agent activity for context. Default: compact."),scope:"project",disabled:t.autoArchiveDoneTasksEnabled===!1,options:[{value:"compact",label:l("settings.scheduling.compactSummaryAndRecentEntries","Compact summary and recent entries")},{value:"none",label:l("settings.scheduling.doNotArchiveAgentLogs","Do not archive agent logs")},{value:"full",label:l("settings.scheduling.fullAgentLog","Full agent log")}]},value:t.archiveAgentLogMode??"compact",onChange:h=>s(p=>({...p,archiveAgentLogMode:h}))}),e.jsx(se,{descriptor:{key:"autoArchiveDuplicateTasksEnabled",label:l("settings.scheduling.autoArchiveDuplicateTasks"," Automatically archive duplicate tasks "),help:l("settings.scheduling.autoArchiveDuplicateTasksHelp","Automatically archive tasks detected as same-agent duplicates on creation (off by default). When disabled, duplicates are flagged in place with the yellow Duplicate chip and Keep/Archive actions instead of being archived automatically."),scope:"project"},value:t.autoArchiveDuplicateTasksEnabled??!1,onChange:h=>s(p=>({...p,autoArchiveDuplicateTasksEnabled:h===!0}))}),e.jsx(ke,{descriptor:{key:"triageDuplicateResolution",label:l("settings.scheduling.triageDuplicateResolution","Triage duplicate resolution"),help:l("settings.scheduling.triageDuplicateResolutionHelp","Block triage duplicates for a linked Keep/Delete decision (default), keep automatically, or delete automatically."),scope:"project",options:[{value:"prompt",label:l("settings.scheduling.triageDuplicateResolutionPrompt","Block for decision (default)")},{value:"keep",label:l("settings.scheduling.triageDuplicateResolutionKeep","Keep automatically")},{value:"delete",label:l("settings.scheduling.triageDuplicateResolutionDelete","Delete automatically")}]},value:t.triageDuplicateResolution??"prompt",onChange:h=>s(p=>({...p,triageDuplicateResolution:h}))}),e.jsx(ye,{descriptor:{key:"maxStuckKills",label:l("settings.scheduling.maxStuckRetries","Max Stuck Retries"),help:l("settings.scheduling.maximumStuckDetectorRetriesBeforeATaskIs","Maximum stuck-detector retries before a task is marked failed. Default: 6."),scope:"project",min:1,step:1},value:t.maxStuckKills??null,onChange:h=>s(p=>({...p,maxStuckKills:h!==null&&h>0?h:void 0}))}),e.jsx(se,{descriptor:{key:"groupOverlappingFiles",label:l("settings.scheduling.serializeTasksWithOverlappingFiles"," Serialize tasks with overlapping files "),help:l("settings.scheduling.whenEnabledTasksThatModifyTheSameFiles","When enabled, tasks that modify the same files are queued serially to avoid merge conflicts. Default: enabled."),scope:"project"},value:t.groupOverlappingFiles,onChange:h=>s(p=>({...p,groupOverlappingFiles:h===!0}))}),e.jsx(se,{descriptor:{key:"ignoreHiddenOverlapPaths",label:l("settings.scheduling.ignoreHiddenDotPathsInOverlapChecks"," Ignore hidden dot paths in overlap checks "),help:l("settings.scheduling.ignoreHiddenDotPathsHelp","When enabled, overlap checks ignore hidden path segments such as .fusion/, .changeset/, .github/, .env, and nested .cache/ directories. Uncheck to restore legacy counting for stricter serialization. Default: enabled."),scope:"project"},value:t.ignoreHiddenOverlapPaths!==!1,onChange:h=>s(p=>({...p,ignoreHiddenOverlapPaths:h===!0}))}),e.jsxs("div",{className:"form-group settings-overlap-ignore-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:l("settings.scheduling.ignoredOverlapPaths","Ignored overlap paths")}),e.jsxs(B,{settingKey:"overlapIgnorePaths",children:[l("settings.scheduling.optionalFileOrDirectoryPathsToIgnoreWhen"," No default — unset (empty). Optional file or directory paths to ignore when overlap serialization is enabled. Paths are project-relative (for example "),e.jsx("code",{children:"docs/"}),l("settings.scheduling.or"," or "),e.jsx("code",{children:"generated/*"}),l("settings.scheduling.closeParenPeriod",").")]})]}),e.jsx("div",{className:"settings-overlap-ignore-list",children:(t.overlapIgnorePaths&&t.overlapIgnorePaths.length>0?t.overlapIgnorePaths:[""]).map((h,p)=>e.jsxs("div",{className:"settings-overlap-ignore-row",children:[e.jsxs("div",{className:"settings-overlap-ignore-path-controls",children:[e.jsx("input",{className:"input",type:"text",value:h,placeholder:l("settings.scheduling.docs","docs/"),onChange:b=>n(p,b.target.value)}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>c(p),"aria-label":`Browse path for ignored overlap entry ${p+1}`,children:l("settings.scheduling.browse"," Browse ")})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>d(p),disabled:(t.overlapIgnorePaths??[]).length===0&&p===0,children:l("settings.scheduling.remove"," Remove ")})]},`overlap-ignore-${p}`))}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:i,children:l("settings.scheduling.addIgnoredPath"," Add ignored path ")})]}),e.jsx("div",{className:"settings-section-divider"}),e.jsx("h5",{className:"settings-section-heading",children:l("settings.scheduling.stepExecution","Step Execution")}),e.jsx(xn,{message:l("settings.movedStub.stepExecution","Step execution settings (run steps in new sessions, max parallel steps) now live on the workflow."),onOpenWorkflowSettings:u})]})}function Hg({globalMaxConcurrent:t,concurrencyLoading:s=!1,onGlobalMaxConcurrentChange:a}){const{t:n}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.scheduling.scopeGlobalTitle","Global — applies to all projects")}),e.jsx("p",{className:"settings-section-description",children:n("settings.scheduling.scopeGlobalCaption","Shared by every project on this machine.")}),e.jsx(ye,{descriptor:{key:"globalMaxConcurrent",label:n("settings.scheduling.globalMaxConcurrent","Global Max Concurrent"),help:n("settings.scheduling.maximumConcurrentAgentsAcrossAllProjects","Maximum concurrent agents across all projects. Default: 4."),min:0,max:1e4,disabled:s},value:t??null,onChange:c=>a(c??void 0)})]})}function _g({defer:t=!1}){const{t:s}=te("app"),[a,n]=o.useState(null),[c,d]=o.useState(!1),[i,u]=o.useState(!1),[l,h]=o.useState(null),[p,b]=o.useState(null),[w,x]=o.useState(null),f=k=>{switch(k){case"installed":return{text:s("cliBinary.stateInstalled","Installed"),tone:"ok"};case"missing":return{text:s("cliBinary.stateMissing","Not installed"),tone:"err"};case"version-mismatch":return{text:s("cliBinary.stateVersionMismatch","Version mismatch"),tone:"warn"};case"skipped":return{text:s("cliBinary.stateCheckDisabled","Check disabled"),tone:"warn"}}},D=o.useCallback(async()=>{d(!0),b(null);try{const k=await Jc();n(k)}catch(k){b(k instanceof Error?k.message:String(k))}finally{d(!1)}},[]);o.useEffect(()=>{t||D()},[t,D]);const S=o.useCallback(async()=>{u(!0),h(null),b(null);try{const k=await Xc();n({binary:k.binary,expectedVersion:k.expectedVersion,state:k.state,install:k.install}),h(k.installResult)}catch(k){b(k instanceof Error?k.message:String(k))}finally{u(!1)}},[]),C=o.useCallback(async(k,R)=>{await mn(R)&&(x(k),setTimeout(()=>x(N=>N===k?null:N),1500))},[]),y=a?f(a.state):null;return e.jsxs("div",{className:"cli-binary-panel",children:[e.jsxs("div",{className:"cli-binary-header",children:[e.jsx("h4",{className:"settings-section-heading",children:s("cliBinary.heading","CLI Binary")}),y&&e.jsx("span",{className:`cli-binary-pill cli-binary-pill--${y.tone}`,children:y.text})]}),e.jsx("small",{className:"cli-binary-help",children:s("cliBinary.help","Installing the global CLI lets you run fn and fusion from any terminal. Automations and scripts work without it via npx, but a global install is faster and more convenient.")}),c&&!a&&e.jsx("p",{className:"cli-binary-status-line",children:s("cliBinary.checking","Checking…")}),a&&e.jsxs("div",{className:"cli-binary-detail",children:[a.binary.installed?e.jsxs("ul",{className:"cli-binary-info-list",children:[e.jsxs("li",{children:[e.jsx("span",{children:s("cliBinary.binaryLabel","Binary:")}),e.jsx("code",{children:a.binary.binary})]}),a.binary.path&&e.jsxs("li",{children:[e.jsx("span",{children:s("cliBinary.pathLabel","Path:")}),e.jsx("code",{children:a.binary.path})]}),e.jsxs("li",{children:[e.jsx("span",{children:s("cliBinary.versionLabel","Version:")}),e.jsx("code",{children:a.binary.version??"unknown"}),e.jsx("span",{className:"cli-binary-expected",children:s("cliBinary.expectedVersion","(expected {{version}})",{version:a.expectedVersion})})]})]}):e.jsx("p",{className:"cli-binary-status-line",children:s("cliBinary.notOnPath","Neither fn nor fusion was found on PATH.")}),e.jsxs("div",{className:"cli-binary-actions",children:[e.jsx("button",{type:"button",className:"cli-binary-install-btn",onClick:S,disabled:i,children:i?s("cliBinary.installing","Installing…"):a.binary.installed?s("cliBinary.reinstall","Reinstall"):s("cliBinary.installWithNpm","Install with npm")}),e.jsx("button",{type:"button",className:"cli-binary-refresh-btn",onClick:()=>void D(),disabled:c||i,children:s("cliBinary.refresh","Refresh")})]}),e.jsxs("div",{className:"cli-binary-commands",children:[e.jsx("label",{children:s("cliBinary.orCopyLabel","Or copy and run yourself:")}),[{label:"npm",command:a.install.npm},{label:"curl",command:a.install.curl}].map(({label:k,command:R})=>e.jsxs("div",{className:"cli-binary-command-row",children:[e.jsx("code",{children:R}),e.jsx("button",{type:"button",onClick:()=>void C(k,R),className:"cli-binary-copy-btn",children:w===k?s("cliBinary.copied","Copied"):s("cliBinary.copy","Copy")})]},k))]})]}),l&&e.jsxs("details",{className:"cli-binary-install-log",open:!l.success,children:[e.jsx("summary",{children:l.success?s("cliBinary.succeededDuration","Install succeeded in {{duration}}s",{duration:(l.durationMs/1e3).toFixed(1)}):s("cliBinary.failedExit","Install failed (exit {{code}})",{code:l.exitCode??"n/a"})}),l.permissionsHint&&e.jsx("p",{className:"cli-binary-permissions-hint",children:l.permissionsHint}),l.stdout&&e.jsx("pre",{className:"cli-binary-install-output",children:l.stdout}),l.stderr&&e.jsx("pre",{className:"cli-binary-install-output cli-binary-install-output--err",children:l.stderr})]}),p&&e.jsx("p",{className:"field-error",children:p})]})}function Wg(){const{t}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:t("settings.nav.cliBinary","CLI Binary")}),e.jsx(_g,{})]})}function Ug({form:t,setForm:s}){const{t:a}=te("app"),n=t.evalSettings??{},c=n.enabled??!1;return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.scheduledEvals.scheduledEvals","Scheduled Evals")}),e.jsx(se,{descriptor:{key:"evalSettings.enabled",label:a("settings.scheduledEvals.enableScheduledEvalRunsForThisProject"," Enable scheduled eval runs for this project "),help:a("settings.scheduledEvals.enabledHint","Default: disabled."),scope:"project"},value:c,onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},enabled:d===!0}}))}),e.jsx(ye,{descriptor:{key:"evalSettings.intervalMs",label:a("settings.scheduledEvals.intervalMs","Interval (ms)"),help:a("settings.scheduledEvals.intervalMsHint","Default: 86400000 (24 hours)."),scope:"project",disabled:!c,min:6e4,max:6048e5,step:1e3},value:n.intervalMs??864e5,onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},intervalMs:d===null?void 0:d}}))}),e.jsx(de,{descriptor:{key:"evalSettings.evaluatorProvider",label:a("settings.scheduledEvals.evaluatorProvider","Evaluator Provider"),help:a("settings.scheduledEvals.evaluatorProviderHint","No default — unset (inherits the project validator lane provider)."),scope:"project",placeholder:a("settings.scheduledEvals.openai","openai")},value:n.evaluatorProvider??"",onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},evaluatorProvider:(d??"").trim()===""?void 0:d??void 0}}))}),e.jsx(de,{descriptor:{key:"evalSettings.evaluatorModelId",label:a("settings.scheduledEvals.evaluatorModel","Evaluator Model"),help:a("settings.scheduledEvals.leaveProviderAndModelBlankToInheritThe"," Leave provider and model blank to inherit the project validator lane model settings. No default — unset. "),scope:"project",placeholder:a("settings.scheduledEvals.gpt5","gpt-5")},value:n.evaluatorModelId??"",onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},evaluatorModelId:(d??"").trim()===""?void 0:d??void 0}}))}),e.jsx(ke,{descriptor:{key:"evalSettings.followUpPolicy",label:a("settings.scheduledEvals.followUpPolicy","Follow-up Policy"),help:a("settings.scheduledEvals.followUpPolicyHint","Default: suggest only."),scope:"project",disabled:!c,options:[{value:"disabled",label:a("settings.scheduledEvals.disabled","Disabled")},{value:"suggest-only",label:a("settings.scheduledEvals.suggestOnly","Suggest only")},{value:"auto-create",label:a("settings.scheduledEvals.autoCreateTasks","Auto-create tasks")}]},value:n.followUpPolicy??"suggest-only",onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},followUpPolicy:d}}))}),e.jsx(ye,{descriptor:{key:"evalSettings.retentionDays",label:a("settings.scheduledEvals.retentionDays","Retention (days)"),help:a("settings.scheduledEvals.retentionDaysHint","Default: 30."),scope:"project",disabled:!c,min:1,max:365,step:1},value:n.retentionDays??30,onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},retentionDays:d===null?void 0:d}}))})]})}function $g(t,s){return t==="online"?s("settings.nodeRouting.statusOnline","Online"):t==="connecting"?s("settings.nodeRouting.statusConnecting","Connecting"):t==="error"?s("settings.nodeRouting.statusError","Error"):s("settings.nodeRouting.statusOffline","Offline")}function zg({form:t,setForm:s,nodes:a}){const{t:n}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.nodeRouting.nodeRouting","Node Routing")}),e.jsx("p",{className:"settings-section-description",children:n("settings.nodeRouting.configureHowTasksAreRoutedToExecutionNodes","Configure how tasks are routed to execution nodes.")}),e.jsx("p",{className:"settings-node-routing-note",children:n("settings.nodeRouting.theseSettingsApplyAtTheProjectLevel","These settings apply at the project level.")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"defaultNodeId",children:n("settings.nodeRouting.defaultExecutionNode","Default Execution Node")}),e.jsx(B,{settingKey:"defaultNodeId",children:n("settings.nodeRouting.usedWhenATaskHasNoNodeOverride","Used when a task has no node override. Node status is shown for safer routing selection. No default — unset (local execution).")})]}),e.jsxs("select",{id:"defaultNodeId",className:"select",value:typeof t.defaultNodeId=="string"?t.defaultNodeId:"",onChange:c=>{const d=c.target.value;s(i=>({...i,defaultNodeId:d||void 0}))},children:[e.jsx("option",{value:"",children:n("settings.nodeRouting.localExecutionNoDefaultNode","Local execution (no default node)")}),a.map(c=>e.jsxs("option",{value:c.id,children:[c.name," (",$g(c.status,n),")"]},c.id))]}),(()=>{const c=a.find(d=>d.id===t.defaultNodeId);return c?e.jsxs("div",{className:"settings-node-status",children:[e.jsx("span",{children:n("settings.nodeRouting.selectedNode","Selected node:")}),e.jsx(Zc,{status:c.status,showLabel:!0})]}):null})()]}),e.jsx(ke,{descriptor:{key:"unavailableNodePolicy",label:n("settings.nodeRouting.unavailableNodePolicy","Unavailable Node Policy"),help:n("settings.nodeRouting.unavailableNodePolicyHint","Default: block execution."),scope:"project",options:[{value:"block",label:n("settings.nodeRouting.blockExecution","Block execution")},{value:"fallback-local",label:n("settings.nodeRouting.fallBackToLocal","Fall back to local")}]},value:t.unavailableNodePolicy==="fallback-local"?"fallback-local":"block",onChange:c=>s(d=>({...d,unavailableNodePolicy:c}))})]})}function qg({form:t,setForm:s,gitRemotes:a,worktrunkInstall:n,worktrunkInstallVerified:c,onOpenWorktreesDirPicker:d,onWorktreeCopyFileChange:i,onRemoveWorktreeCopyFile:u,onAddWorktreeCopyFile:l,onOpenWorktreeCopyFilePicker:h,onOpenApprovals:p}){const{t:b}=te("app"),w=(t.worktreeCopyFiles?.length??0)>0?t.worktreeCopyFiles??[]:[""];return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:b("settings.worktrees.worktrees","Worktrees")}),e.jsx(ye,{descriptor:{key:"maxWorktrees",label:b("settings.worktrees.maxWorktrees","Max Worktrees"),help:b("settings.worktrees.limitsTotalGitWorktreesIncludingInReviewTasks","Limits total git worktrees including in-review tasks. Default: 4."),scope:"project",min:1,max:20},value:t.maxWorktrees??null,onChange:x=>s(f=>({...f,maxWorktrees:x??void 0}))}),e.jsx(de,{descriptor:{key:"worktreeInitCommand",label:b("settings.worktrees.worktreeInitCommand","Worktree Init Command"),help:b("settings.worktrees.shellCommandToRunInEachNewWorktree","Shell command to run in each new worktree after creation. No default — unset."),scope:"project",placeholder:b("settings.worktrees.pnpmInstallFrozenLockfile","pnpm install --frozen-lockfile")},value:t.worktreeInitCommand??null,onChange:x=>s(f=>({...f,worktreeInitCommand:x??""}))}),e.jsx(se,{descriptor:{key:"recycleWorktrees",label:b("settings.worktrees.recycleWorktrees"," Recycle worktrees "),help:t.worktreeNaming==="task-id"&&t.recycleWorktrees!==!0?b("settings.worktrees.recycleNotApplicableWithTaskIdNaming","Not available with Task ID worktree naming — that mode pins each task to its own worktree directory, which is mutually exclusive with the recycle pool. Switch naming to Random or Task title to enable recycling."):b("settings.worktrees.offByDefaultOptInWhenEnabledCompleted","Off by default (opt-in). When enabled, completed task worktrees are returned to an idle pool instead of being deleted, preserving build caches for faster startup. Mutually exclusive with Task ID worktree naming."),scope:"project",disabled:t.worktreeNaming==="task-id"&&t.recycleWorktrees!==!0},value:t.recycleWorktrees===!0,onChange:x=>s(f=>({...f,recycleWorktrees:x===!0}))}),e.jsx(se,{descriptor:{key:"showWorktreeGrouping",label:b("settings.worktrees.showWorktreeGrouping"," Show worktree grouping on the board "),help:b("settings.worktrees.showWorktreeGroupingHelp","Off by default. When enabled, WIP and processing columns always group tasks by worktree and show worktree names, including workflow-mode processing columns."),scope:"project"},value:t.showWorktreeGrouping===!0,onChange:x=>s(f=>({...f,showWorktreeGrouping:x===!0}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:b("settings.worktrees.filesToCopyIntoNewWorktrees","Files to copy into new worktrees")}),e.jsx(B,{settingKey:"worktreeCopyFiles",children:b("settings.worktrees.copyFilesHelp","Optional. Repository-root-relative regular files are copied into fresh or pooled task worktrees before init commands run. Missing files or directories are skipped without exposing contents. Default: empty (no files copied).")})]}),e.jsx("div",{className:"settings-overlap-ignore-list","data-testid":"worktree-copy-files-list",children:w.map((x,f)=>e.jsxs("div",{className:"settings-overlap-ignore-row",children:[e.jsxs("div",{className:"settings-overlap-ignore-path-controls",children:[e.jsx("input",{id:`worktreeCopyFile-${f}`,type:"text",className:"input",placeholder:b("settings.worktrees.copyFilePlaceholder",".env"),value:x,onChange:D=>i(f,D.target.value),"aria-label":b("settings.worktrees.copyFilePathLabel","File to copy into new worktrees")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>h(f),"aria-label":b("settings.worktrees.browseCopyFile","Browse file to copy into new worktrees"),children:b("settings.worktrees.browse"," Browse ")})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>u(f),"aria-label":b("settings.worktrees.removeCopyFile","Remove copied worktree file"),children:b("settings.worktrees.remove","Remove")})]},f))}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:l,children:b("settings.worktrees.addCopyFile","Add file")})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"executorAllowSiblingBranchRename",className:"checkbox-label",children:[e.jsx("input",{id:"executorAllowSiblingBranchRename",type:"checkbox",checked:t.executorAllowSiblingBranchRename===!0,onChange:x=>s(f=>({...f,executorAllowSiblingBranchRename:x.target.checked}))}),b("settings.worktrees.allowSilentSiblingBranchRenameDuringExecutorConflicts"," Allow silent sibling branch rename during executor conflicts ")]}),e.jsxs(B,{settingKey:"executorAllowSiblingBranchRename",children:[b("settings.worktrees.discouragedThisRestoresTheLegacyBehaviorWhereA"," Discouraged. This restores the legacy behavior where a live "),e.jsx("code",{children:"fusion/<task-id>"}),b("settings.worktrees.branchCollisionSilentlyForksWorkOntoSiblingBranches"," branch collision silently forks work onto sibling branches like "),e.jsx("code",{children:"-2"}),b("settings.worktrees.andCanHidePriorCommitsFromTheDefault"," and can hide prior commits from the default recovery flow. Default: disabled. ")]})]})}),e.jsx(ke,{descriptor:{key:"worktreeNaming",label:b("settings.worktrees.worktreeNamingStyle","Worktree Naming Style"),help:t.recycleWorktrees?b("settings.worktrees.namingStyleNotApplicableWhenRecycling",'Naming style is not applicable when recycling worktrees — pooled worktrees retain their existing names. "Task ID" is unavailable here because task-pinned worktrees are mutually exclusive with recycling; turn off Recycle worktrees to use it.'):b("settings.worktrees.howToNameFreshWorktreeDirectories",'How to name fresh worktree directories. Only applies when recycling is off. "Task ID" also pins each task to its own worktree directory for its whole lifecycle (mutually exclusive with recycling). Default: random.'),scope:"project",disabled:t.recycleWorktrees,options:[{value:"random",label:b("settings.worktrees.randomNamesEGSwiftFalcon","Random names (e.g., swift-falcon)")},{value:"task-id",label:b("settings.worktrees.taskIDEGFN042","Task ID (e.g., FN-042)")},{value:"task-title",label:b("settings.worktrees.taskTitleEGFixLoginBug","Task title (e.g., fix-login-bug)")}]},value:t.worktreeNaming||"random",onChange:x=>s(f=>({...f,worktreeNaming:x}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktreesDir",children:b("settings.worktrees.worktreesDirectory","Worktrees Directory")}),e.jsx(B,{settingKey:"worktreesDir",children:t.worktrunk?.enabled===!0?"Disabled because Worktrunk integration is enabled — worktrunk manages the worktree directory layout. Disable worktrunk integration to use a custom directory.":e.jsxs(e.Fragment,{children:[b("settings.worktrees.optionalSupports"," Optional. Supports "),e.jsx("code",{children:"~"}),b("settings.worktrees.and"," and "),e.jsx("code",{children:"{repo}"}),b("settings.worktrees.defaultsTo",". Defaults to "),e.jsx("code",{children:"<projectRoot>/.worktrees"}),b("settings.worktrees.whenUnsetOnlyAffectsNewlyCreatedWorktrees"," when unset. Only affects newly-created worktrees. ")]})})]}),e.jsxs("div",{className:"settings-overlap-ignore-path-controls",children:[e.jsx("input",{id:"worktreesDir",type:"text",placeholder:b("settings.worktrees.defaultsToWorktreesLeaveEmptyUnlessOverriding","Defaults to .worktrees — leave empty unless overriding"),value:t.worktreesDir||"",disabled:t.worktrunk?.enabled===!0,onChange:x=>s(f=>({...f,worktreesDir:x.target.value}))}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:d,"aria-label":b("settings.worktrees.browseWorktreesDirectory","Browse worktrees directory"),disabled:t.worktrunk?.enabled===!0,children:b("settings.worktrees.browse"," Browse ")})]})]}),e.jsx(se,{descriptor:{key:"worktreeRebaseBeforeMerge",label:b("settings.worktrees.rebaseFromRemoteBeforeMerge"," Rebase from remote before merge "),help:b("settings.worktrees.whenEnabledTheMergerFetchesFromTheConfigured","When enabled, the merger fetches from the configured remote and rebases the task branch onto the latest default-branch tip before merging — catching concurrent pushes from other collaborators or fusion workers. Any conflicts the rebase surfaces flow into the existing smart/AI resolve pipeline. Default: enabled."),scope:"project"},value:t.worktreeRebaseBeforeMerge!==!1,onChange:x=>s(f=>({...f,worktreeRebaseBeforeMerge:x===!0}))}),t.worktreeRebaseBeforeMerge!==!1&&e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktreeRebaseRemote",children:b("settings.worktrees.rebaseRemote","Rebase Remote")}),e.jsxs(B,{settingKey:"worktreeRebaseRemote",children:[b("settings.worktrees.whichRemoteToFetchForThePreMerge",' Which remote to fetch for the pre-merge rebase. "Use git default" falls back to the remote configured for the default branch (typically '),e.jsx("code",{children:"origin"}),b("settings.worktrees.closeParenPeriod",").")]})]}),e.jsxs("select",{id:"worktreeRebaseRemote",value:t.worktreeRebaseRemote??"",onChange:x=>s(f=>({...f,worktreeRebaseRemote:x.target.value||void 0})),children:[e.jsx("option",{value:"",children:b("settings.worktrees.useGitDefault","Use git default")}),a.map(x=>e.jsxs("option",{value:x.name,children:[x.name," (",x.fetchUrl,")"]},x.name))]})]}),e.jsx(se,{descriptor:{key:"worktreeRebaseLocalBase",label:b("settings.worktrees.alsoRebaseOntoLocalDefaultBranchHEAD"," Also rebase onto local default-branch HEAD "),help:b("settings.worktrees.inAdditionToTheRemoteRebaseAboveAlso"," In addition to the remote rebase above, also rebase the task branch onto the local default-branch HEAD (rootDir). This catches sibling tasks that merged locally but haven't been pushed yet — without it, two concurrent tasks where one deletes code can have the other silently re-introduce it via the fallback strategy. Enabled by default; only disable if it causes issues with your workflow. "),scope:"project"},value:t.worktreeRebaseLocalBase!==!1,onChange:x=>s(f=>({...f,worktreeRebaseLocalBase:x===!0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:b("settings.worktrees.worktrunkIntegration","Worktrunk integration")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"worktrunkEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"worktrunkEnabled",type:"checkbox",checked:t.worktrunk?.enabled===!0,disabled:!c&&t.worktrunk?.enabled!==!0,onChange:x=>s(f=>({...f,worktrunk:{enabled:x.target.checked,binaryPath:f.worktrunk?.binaryPath??"",onFailure:f.worktrunk?.onFailure??"fail"}}))}),b("settings.worktrees.enableWorktrunkIntegration"," Enable worktrunk integration ")]}),e.jsxs(B,{settingKey:"worktrunkEnabled",children:[b("settings.worktrees.disabledByDefaultOptInWhenEnabledFusion"," Disabled by default (opt-in). When enabled, Fusion shells out to "),e.jsx("code",{children:"worktrunk"}),b("settings.worktrees.forWorktreeCreateSyncPruneAndRemoveOperations"," for worktree create, sync, prune, and remove operations and follows worktrunk's directory layout. ")]})]}),!c&&t.worktrunk?.enabled!==!0&&e.jsx("small",{className:"settings-muted",children:b("settings.worktrees.installTheWorktrunkBinaryBelowToEnableThis","Install the worktrunk binary below to enable this integration.")})]}),e.jsxs("div",{className:"form-group","data-testid":"worktrunk-install-affordance",children:[n.status==="installed"&&e.jsxs("small",{className:"settings-muted",children:[b("settings.worktrees.worktrunk"," worktrunk "),n.version??"",b("settings.worktrees.installedAt"," installed at "),n.installPath??"~/.fusion/bin/worktrunk"]}),(n.status==="missing"||n.status==="installing")&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"btn btn-primary",onClick:()=>void n.requestInstall(),disabled:n.requesting||n.status==="installing",children:b("settings.worktrees.installWorktrunk","Install worktrunk binary")}),e.jsx("small",{className:"settings-muted",children:b("settings.worktrees.enableWorktrunkAndRequestApprovalToInstallThe","Enable worktrunk and request approval to install the pinned release.")})]}),n.status==="pending-approval"&&e.jsxs(e.Fragment,{children:[e.jsx("small",{className:"settings-muted",children:b("settings.worktrees.awaitingApproval","Awaiting approval — open Approvals to continue.")}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:()=>p?.(n.pendingApprovalId),children:b("settings.worktrees.openApprovals","Open Approvals")})]}),(n.status==="denied"||n.status==="failed")&&e.jsxs(e.Fragment,{children:[e.jsx("small",{style:{color:"var(--color-error)"},children:n.error??"Worktrunk install failed."}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:()=>void n.requestInstall(),children:b("settings.worktrees.tryAgain","Try again")})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktrunkBinaryPath",children:b("settings.worktrees.worktrunkBinaryPath","Worktrunk binary path")}),e.jsx(B,{settingKey:"worktrunkBinaryPath",children:b("settings.worktrees.optionalLeaveBlankToAutoResolveFusionWill","Optional. Leave blank to auto-resolve; Fusion will offer to install on first use.")})]}),e.jsx("input",{id:"worktrunkBinaryPath",type:"text",className:"input",placeholder:b("settings.worktrees.autoDetectFusionBinWorktrunkOrPATH","auto-detect (~/.fusion/bin/worktrunk or $PATH)"),value:t.worktrunk?.binaryPath??"",disabled:t.worktrunk?.enabled!==!0,onChange:x=>s(f=>({...f,worktrunk:{enabled:f.worktrunk?.enabled===!0,binaryPath:x.target.value,onFailure:f.worktrunk?.onFailure??"fail"}}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktrunkOnFailure",children:b("settings.worktrees.worktrunkFailureBehavior","Worktrunk failure behavior")}),e.jsxs(B,{settingKey:"worktrunkOnFailure",children:[e.jsx("code",{children:"fail"}),b("settings.worktrees.stopsOnWorktrunkErrorsForExplicitOperatorRecovery"," stops on worktrunk errors for explicit operator recovery; "),e.jsx("code",{children:"fallback-native"}),b("settings.worktrees.keepsProgressMovingBySwitchingToFusionApos"," keeps progress moving by switching to Fusion's built-in worktree backend. ")]})]}),e.jsxs("select",{id:"worktrunkOnFailure",className:"select",value:t.worktrunk?.onFailure??"fail",disabled:t.worktrunk?.enabled!==!0,onChange:x=>s(f=>({...f,worktrunk:{enabled:f.worktrunk?.enabled===!0,binaryPath:f.worktrunk?.binaryPath??"",onFailure:x.target.value}})),children:[e.jsx("option",{value:"fail",children:b("settings.worktrees.failAndPauseTheTaskDefault","Fail and pause the task (default)")}),e.jsx("option",{value:"fallback-native",children:b("settings.worktrees.fallBackToFusionsNativeWorktreeBackend","Fall back to Fusion's native worktree backend")})]})]})]})}function Vg({form:t,setForm:s}){const{t:a}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.commands.commands","Commands")}),e.jsx(de,{descriptor:{key:"testCommand",label:a("settings.commands.testCommand","Test Command"),help:a("settings.commands.commandUsedToRunTestsInjectedIntoGenerated","Command used to run tests — injected into generated task specs. No default — unset."),scope:"project",placeholder:a("settings.commands.eGPnpmTest","e.g. pnpm test")},value:t.testCommand??null,onChange:n=>s(c=>({...c,testCommand:n||void 0}))}),e.jsx(de,{descriptor:{key:"buildCommand",label:a("settings.commands.buildCommand","Build Command"),help:a("settings.commands.commandUsedToBuildTheProjectInjectedInto","Command used to build the project — injected into generated task specs. No default — unset."),scope:"project",placeholder:a("settings.commands.eGPnpmBuild","e.g. pnpm build")},value:t.buildCommand??null,onChange:n=>s(c=>({...c,buildCommand:n||void 0}))})]})}function Yg(t){const s=(t??"").trim().split(/\s+/).filter(Boolean);return{remote:s[0]??"origin",branch:s.slice(1).join(" ")}}function Ks(t,s){const a=t.trim()||"origin",n=s.trim();return n?`${a} ${n}`:a==="origin"?void 0:a}function Qg(t){const s=Number(t);return Number.isFinite(s)&&s>0?Math.floor(s):3}async function Jg(t){if(!t.ok)throw new Error(await t.text()||"Failed to load legacy auto-merge stamps");return t.json()}function Xg({form:t,setForm:s,integrationBranchOptions:a,integrationBranchCustomMode:n,setIntegrationBranchCustomMode:c,onOpenWorkflowSettings:d,gitRemoteOptions:i=[],projectId:u}){const{t:l}=te("app"),h=Yg(t.pushRemote),[p,b]=o.useState([]),[w,x]=o.useState(!1);o.useEffect(()=>{if(!t.pushAfterMerge||i.length===0)return;let E=!1;return ed(h.remote,u).then(L=>{E||b(L)}).catch(()=>{E||b([])}),()=>{E=!0}},[t.pushAfterMerge,h.remote,u,i.length]);const[f,D]=o.useState([]),[S,C]=o.useState(!0),[y,k]=o.useState(!1),[R,P]=o.useState(null),[N,U]=o.useState(null),m=o.useCallback(async()=>{C(!0),P(null);try{const E=await Jg(await fetch("/api/maintenance/legacy-automerge-stamps"));D(Array.isArray(E.candidates)?E.candidates:[])}catch(E){P(E instanceof Error?E.message:"Failed to load legacy auto-merge stamps")}finally{C(!1)}},[]);o.useEffect(()=>{m()},[m]);const Y=async()=>{if(window.confirm("Apply cleanup for legacy auto-merge stamps? This clears only legacy non-override in-review stamps returned by the store and never touches genuine per-task overrides.")){k(!0),P(null),U(null);try{const L=await fetch("/api/maintenance/legacy-automerge-stamps/apply",{method:"POST"});if(!L.ok)throw new Error(await L.text()||"Failed to apply legacy auto-merge stamp cleanup");const G=await L.json();U(`Cleared ${G.count} legacy auto-merge stamp${G.count===1?"":"s"}.`),await m()}catch(L){P(L instanceof Error?L.message:"Failed to apply legacy auto-merge stamp cleanup")}finally{k(!1)}}};return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:l("settings.merge.merge","Merge")}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"autoMerge",className:"checkbox-label",children:[e.jsx("input",{id:"autoMerge",type:"checkbox",checked:t.autoMerge,onChange:E=>s(L=>({...L,autoMerge:E.target.checked}))}),l("settings.merge.autoMergeCompletedTasks"," Auto-merge completed tasks ")]}),e.jsx(B,{settingKey:"autoMerge",children:l("settings.merge.whenEnabledTasksThatPassReviewAreAutomatically","When enabled, tasks that pass review are automatically merged into the main branch. Default: enabled.")})]})}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"planApprovalMode",children:l("settings.merge.planApprovalMode","Plan approval mode")}),e.jsx(B,{settingKey:"planApprovalMode",children:l("settings.merge.planApprovalModeHelp","Project-wide override for the planning approval gate. Leave on workflow to use each workflow's Require plan approval setting, or force all approved specs to bypass or wait for manual approval.")})]}),e.jsxs("select",{id:"planApprovalMode",className:"select",value:t.planApprovalMode??"auto-approve-all",onChange:E=>{const L=E.target.value;s(G=>({...G,planApprovalMode:L}))},"data-testid":"plan-approval-mode-select",children:[e.jsx("option",{value:"workflow",children:l("settings.merge.planApprovalModeWorkflow","Use workflow setting")}),e.jsx("option",{value:"auto-approve-all",children:l("settings.merge.planApprovalModeAutoApproveAll","Auto-approve all tasks (default)")}),e.jsx("option",{value:"require-all",children:l("settings.merge.planApprovalModeRequireAll","Require approval for all tasks")})]})]}),e.jsx(ye,{descriptor:{key:"maxAutoMergeRetries",label:l("settings.merge.autoMergeConflictRetries","Auto-merge conflict retries"),help:l("settings.merge.positiveIntegerRetryCapForAutoMergeConflict","Positive integer retry cap for auto-merge conflict resolution before a task parks for human recovery. Default 3."),scope:"project",min:1,step:1},value:t.maxAutoMergeRetries??3,onChange:E=>s(L=>({...L,maxAutoMergeRetries:E===null?void 0:Qg(E)}))}),e.jsxs("div",{className:"form-group","data-testid":"legacy-automerge-stamp-cleanup-panel",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h5",{className:"settings-section-heading",children:l("settings.merge.legacyAutoMergeStampCleanup","Legacy auto-merge stamp cleanup")}),e.jsx(B,{settingKey:"legacy-automerge-stamp-cleanup",children:l("settings.merge.findsInReviewTasksWhoseAutoMergeValue"," Finds in-review tasks whose auto-merge value came from the legacy review-entry stamp. Dry-run is automatic; applying delegates to the store cleanup and preserves genuine per-task overrides. ")})]}),S?e.jsx("small",{"aria-live":"polite",children:l("settings.merge.checkingForLegacyAutoMergeStamps","Checking for legacy auto-merge stamps…")}):f.length===0?e.jsx("small",{"data-testid":"legacy-automerge-stamp-empty-state",children:l("settings.merge.noLegacyAutoMergeStampsToCleanUp"," No legacy auto-merge stamps to clean up. ")}):e.jsxs(e.Fragment,{children:[e.jsxs("small",{children:[f.length,l("settings.merge.legacyAutoMergeStamp"," legacy auto-merge stamp"),f.length===1?"":"s",l("settings.merge.readyToCleanUp"," ready to clean up.")]}),e.jsx("ul",{children:f.map(E=>e.jsxs("li",{"data-testid":"legacy-automerge-stamp-candidate-row",children:[e.jsx("strong",{children:E.taskId})," — ",E.column]},E.taskId))}),e.jsx("button",{type:"button",className:"btn",onClick:Y,disabled:y,"data-testid":"legacy-automerge-stamp-apply-button",children:y?"Applying cleanup…":"Apply cleanup"})]}),N?e.jsx("small",{className:"settings-success","aria-live":"polite",children:N}):null,R?e.jsx("small",{className:"settings-error",role:"alert",children:R}):null]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergerMode",children:l("settings.merge.aIMerge","AI merge")}),e.jsxs(B,{settingKey:"mergerMode",children:[l("settings.merge.aIModeMergesTheTaskBranchIntoAn"," AI mode merges the task branch into an isolated clean-room checkout at the target branch's tip, has an AI reviewer audit the squash (with corrective retries — advisory concerns land with a logged warning, an unfixable correctness concern hard-fails), then fast-forwards the target branch and syncs your local checkout (AI reconciles a conflicting restore). Each task merges to its own target branch, or the default integration branch. "),e.jsx("strong",{children:l("settings.merge.theLegacyMergeSettingsBelowDoNotApply","The legacy merge settings below do not apply while AI merge is on.")})]})]}),e.jsxs("select",{id:"mergerMode",className:"select",value:t.merger?.mode??"ai",onChange:E=>s(L=>({...L,merger:{...L.merger??{},mode:E.target.value}})),children:[e.jsx("option",{value:"ai",children:l("settings.merge.aIMergeDefaultAIMergesInAClean","AI merge (default) — AI merges in a clean room, an AI reviewer audits with retries, then lands")}),e.jsx("option",{value:"deterministic",children:l("settings.merge.deterministicLegacyRebaseConflictStrategyAuditPipeline","Deterministic (legacy) — rebase / conflict-strategy / audit pipeline")})]})]}),(t.merger?.mode??"ai")==="ai"&&e.jsxs(e.Fragment,{children:[e.jsx(ye,{descriptor:{key:"merger.maxReviewPasses",label:l("settings.merge.maxAIReviewPasses","Max AI review passes"),help:l("settings.merge.aICorrectiveRoundsBeforeLandingTheBestResult","AI corrective rounds before landing the best result (advisory concern) or hard-failing (unfixable correctness concern). Default 3. The reviewer uses your project's reviewer/validator model."),scope:"project",min:0,max:10},value:t.merger?.maxReviewPasses??3,onChange:E=>s(L=>({...L,merger:{...L.merger??{},maxReviewPasses:E??void 0}}))}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"mergerAllowDirtyLocalCheckoutSync",className:"checkbox-label",children:[e.jsx("input",{id:"mergerAllowDirtyLocalCheckoutSync",type:"checkbox",checked:t.merger?.allowDirtyLocalCheckoutSync===!0,onChange:E=>s(L=>({...L,merger:{...L.merger??{},allowDirtyLocalCheckoutSync:E.target.checked}}))}),l("settings.merge.allowAIMergeToSyncADirtyChecked"," Allow AI merge to sync a dirty checked-out integration branch ")]}),e.jsx(B,{settingKey:"merger.allowDirtyLocalCheckoutSync",children:l("settings.merge.dangerousCompatibilityEscapeHatchLeaveOffUnlessYou"," Dangerous compatibility escape hatch — restores the legacy stash → fast-forward → restore behavior when your checked-out integration branch has unrelated local edits. When off, AI merge blocks before advancing the branch so dirty project-root edits cannot contaminate a completed merge. Default: enabled (new/unconfigured projects sync a dirty checkout). ")})]})})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"testMode",className:"checkbox-label",children:[e.jsx("input",{id:"testMode",type:"checkbox",checked:t.testMode===!0,onChange:E=>s(L=>({...L,testMode:E.target.checked}))}),l("settings.merge.enableTestMode"," Enable test mode ")]}),e.jsx(B,{settingKey:"testMode",children:l("settings.merge.forcesAllAILanesToUseTheDeterministic","Forces all AI lanes to use the deterministic mock provider. No network calls, zero token cost. No default — unset (disabled).")})]})}),e.jsx(xn,{message:l("settings.movedStub.reviewVerification","Review, verification auto-fix, and scope-enforcement settings now live on the workflow."),onOpenWorkflowSettings:d}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeStrategy",children:l("settings.merge.autoCompletionMode","Auto-completion mode")}),e.jsx(B,{settingKey:"mergeStrategy",children:l("settings.merge.controlsWhatHappensAfterATaskReachesIn"," Controls what happens after a task reaches In Review. Direct mode merges into the current branch locally. Pull request mode keeps the task in In Review while Fusion waits for GitHub reviews and required checks before merging the PR. ")})]}),e.jsxs("select",{id:"mergeStrategy",value:t.mergeStrategy||"direct",onChange:E=>s(L=>({...L,mergeStrategy:E.target.value})),children:[e.jsx("option",{value:"direct",children:l("settings.merge.directMergeIntoTheCurrentBranch","Direct merge into the current branch (default)")}),e.jsx("option",{value:"pull-request",children:l("settings.merge.createMonitorAndMergeAGitHubPullRequest","Create, monitor, and merge a GitHub pull request")})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"integrationBranch",children:l("settings.merge.integrationBranch","Integration branch")}),e.jsxs(B,{settingKey:"integrationBranch",children:[l("settings.merge.theCanonicalBranchFusionMergesTasksIntoAnd"," No default — unset (auto-detect). The canonical branch Fusion merges tasks into and uses as the reference for all ahead/behind / overlap / pre-rebase computations. Leave on "),e.jsx("em",{children:l("settings.merge.autoDetect","auto-detect")}),l("settings.merge.toResolveViaTheStandardCascade"," to resolve via the standard cascade ("),e.jsx("code",{children:"integrationBranch"}),l("settings.merge.legacy"," → legacy "),e.jsx("code",{children:"baseBranch"})," →",e.jsx("code",{children:"origin/HEAD"}),l("settings.merge.symbolicRefFallback"," symbolic ref → fallback "),e.jsx("code",{children:"main"}),l("settings.merge.pickALocalBranchFromTheDropdownCommon","). Pick a local branch from the dropdown — common integration names like "),e.jsx("code",{children:"main"}),",",e.jsx("code",{children:"master"}),", ",e.jsx("code",{children:"trunk"}),l("settings.merge.and",", and "),e.jsx("code",{children:"develop"}),l("settings.merge.areListedFirstOrChoose"," are listed first — or choose "),e.jsx("em",{children:l("settings.merge.custom","Custom…")}),l("settings.merge.toTypeABranchThatDoesnAposT"," to type a branch that doesn't exist locally yet. Applies to both direct merges and pull-request mode; individual tasks can still override via task metadata. ")]})]}),(()=>{const E=t.integrationBranch??"",L=E.length>0&&a.includes(E);if(n||E.length>0&&!L)return e.jsxs("div",{className:"form-inline-group",children:[e.jsx("input",{id:"integrationBranch",type:"text",className:"input",placeholder:l("settings.merge.branchName","branch name"),value:E,onChange:ne=>{const re=ne.target.value.trim();s(ce=>({...ce,integrationBranch:re.length===0?void 0:re}))},"data-testid":"integration-branch-custom-input"}),e.jsx("button",{type:"button",className:"btn-link",onClick:()=>{c(!1),s(ne=>({...ne,integrationBranch:void 0}))},"data-testid":"integration-branch-use-dropdown",children:l("settings.merge.useDropdown"," Use dropdown ")})]});const K="__fusion-custom__",z="";return e.jsxs("select",{id:"integrationBranch",className:"select",value:E,onChange:ne=>{const re=ne.target.value;if(re===K){c(!0);return}s(ce=>({...ce,integrationBranch:re===z?void 0:re}))},"data-testid":"integration-branch-select",children:[e.jsx("option",{value:z,children:l("settings.merge.autoDetectOriginHEADMain","(auto-detect — origin/HEAD → main)")}),a.map(ne=>e.jsx("option",{value:ne,children:ne},ne)),e.jsx("option",{value:K,children:l("settings.merge.custom","Custom…")})]})})()]}),t.mergeStrategy!=="pull-request"&&(t.merger?.mode??"ai")!=="ai"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"directMergeCommitStrategy",children:l("settings.merge.directMergeCommitRouting","Direct merge commit routing")}),e.jsxs(B,{settingKey:"directMergeCommitStrategy",children:[l("settings.merge.autoKeepsTodayAposSSquashBehaviorFor"," Auto keeps today's squash behavior for branches with zero or one substantive commit, but switches multi-substantive branches to a history-preserving rebase-and-merge path. Individual tasks can override this in PROMPT.md with "),e.jsx("code",{children:"**Direct Merge Commit Strategy:** auto|always-squash|always-rebase"}),"."]})]}),e.jsxs("select",{id:"directMergeCommitStrategy",className:"select",value:t.directMergeCommitStrategy??"always-squash",onChange:E=>s(L=>({...L,directMergeCommitStrategy:E.target.value})),children:[e.jsx("option",{value:"auto",children:l("settings.merge.autoSquashSingleSubstantiveBranchesPreserveMultiSubstantive","Auto — squash single-substantive branches, preserve multi-substantive history")}),e.jsx("option",{value:"always-squash",children:l("settings.merge.alwaysSquashDirectMerges","Always squash direct merges (default)")}),e.jsx("option",{value:"always-rebase",children:l("settings.merge.alwaysPreserveDirectMergeCommitHistory","Always preserve direct-merge commit history")})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeIntegrationWorktree",children:l("settings.merge.integrationWorktree","Integration worktree")}),e.jsx(B,{settingKey:"mergeIntegrationWorktree",children:l("settings.merge.autoMergeRunsInTheTaskWorktreeBy"," Auto-merge runs in the task worktree by default. Switch to the legacy project-root path only if you need the pre-FN-5279 fallback; worktrunk-managed projects still defer to worktrunk. ")})]}),e.jsxs("select",{id:"mergeIntegrationWorktree",className:"select",value:t.mergeIntegrationWorktree??"reuse-task-worktree",onChange:E=>s(L=>({...L,mergeIntegrationWorktree:E.target.value})),children:[e.jsx("option",{value:"reuse-task-worktree",children:l("settings.merge.reuseTaskWorktreeDefault","Reuse task worktree (default)")}),e.jsx("option",{value:"cwd-main",children:l("settings.merge.useProjectRootLegacy","Use project root (legacy)")})]}),(t.mergeIntegrationWorktree??"reuse-task-worktree")!=="reuse-task-worktree"&&e.jsxs("div",{className:"settings-warning-banner",role:"alert","aria-live":"polite","data-testid":"merge-integration-worktree-warning",children:[e.jsx("strong",{children:l("settings.merge.legacyIntegrationBranchMode","Legacy integration-branch mode.")})," ",l("settings.merge.autoMergeWillRunRebaseConflictResolutionAnd"," Auto-merge will run rebase, conflict resolution, and squash commits inside the project root (the user's checked-out integration-branch worktree) instead of the task worktree. Fusion assumes that directory is already on the integration branch and clean; if it isn't, merges may fail or touch the user's working tree. Reuse-task-worktree is the recommended default (FN-5279). Switch back unless you have a specific reason to opt in (FN-5348). ")]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeAdvanceAutoSync",children:l("settings.merge.autoSyncProjectCheckoutAfterMerge","Auto-sync project checkout after merge")}),e.jsxs(B,{settingKey:"mergeAdvanceAutoSync",children:[l("settings.merge.afterFusionAdvancesTheIntegrationBranchRefThe"," After Fusion advances the integration branch ref, the merger can auto-sync other worktrees still checked out on that branch (typically your project-root checkout). "),e.jsx("code",{children:"Stash + fast-forward"}),l("settings.merge.snapshotsRealLocalEditsAsAPatchAgainst"," snapshots real local edits as a patch against the previous tip, snaps the worktree to the new tip, then reapplies the patch — untracked files that collide with newly-tracked paths are left in a temp dir for manual recovery. "),e.jsx("code",{children:"Fast-forward only"}),l("settings.merge.snapsCleanlyWhenTheWorktreeHasNoEdits"," snaps cleanly when the worktree has no edits and skips otherwise. "),e.jsx("code",{children:"Off"}),l("settings.merge.isTheLegacyBehavior"," is the legacy behavior: "),e.jsx("code",{children:"git status"}),l("settings.merge.inYourProjectRootWillShowTheNew"," in your project root will show the new commits inverted as "staged changes" until you pull manually. Only applies to direct merges. ")]})]}),e.jsxs("select",{id:"mergeAdvanceAutoSync",className:"select",value:t.mergeAdvanceAutoSync??"stash-and-ff",onChange:E=>s(L=>({...L,mergeAdvanceAutoSync:E.target.value})),"data-testid":"merge-advance-auto-sync-select",children:[e.jsx("option",{value:"stash-and-ff",children:l("settings.merge.stashFastForwardDefaultPreserveLocalEdits","Stash + fast-forward (default) — preserve local edits")}),e.jsx("option",{value:"ff-only",children:l("settings.merge.fastForwardOnlySkipDirtyWorktrees","Fast-forward only — skip dirty worktrees")}),e.jsx("option",{value:"off",children:l("settings.merge.offLeaveTheProjectRootStaleLegacyBehavior","Off — leave the project root stale (legacy behavior)")})]})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"includeTaskIdInCommit",className:"checkbox-label",children:[e.jsx("input",{id:"includeTaskIdInCommit",type:"checkbox",checked:t.includeTaskIdInCommit!==!1,onChange:E=>s(L=>({...L,includeTaskIdInCommit:E.target.checked}))}),l("settings.merge.includeTaskIDInCommitScope"," Include task ID in commit scope ")]}),e.jsxs(B,{settingKey:"includeTaskIdInCommit",children:[l("settings.merge.whenDisabledMergeCommitMessagesOmitTheTask","When disabled, merge commit messages omit the task ID from the scope (e.g. "),e.jsx("code",{children:"feat: ..."}),l("settings.merge.insteadOf"," instead of "),e.jsx("code",{children:"feat(KB-001): ..."}),l("settings.merge.includeTaskIdInCommitDefault","). Default: enabled.")]})]})}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"commitAuthorEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"commitAuthorEnabled",type:"checkbox",checked:t.commitAuthorEnabled!==!1,onChange:E=>s(L=>({...L,commitAuthorEnabled:E.target.checked}))}),l("settings.merge.addFusionAsCoAuthorOnCommits"," Add Fusion as co-author on commits ")]}),e.jsxs(B,{settingKey:"commitAuthorEnabled",children:[l("settings.merge.whenEnabledCommitsMadeByFusionKeepYour"," When enabled, commits made by Fusion keep your git identity as the primary author and append a "),e.jsx("code",{children:"Co-authored-by"}),l("settings.merge.trailerCreditingFusionRecognizedByGitHubForShared"," trailer crediting Fusion (recognized by GitHub for shared attribution). Default: enabled. ")]})]})}),t.commitAuthorEnabled!==!1&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"commitAuthorName",children:l("settings.merge.coAuthorName","Co-author Name")}),e.jsxs(B,{settingKey:"commitAuthorName",children:[l("settings.merge.nameUsedInThe","Name used in the "),e.jsx("code",{children:"Co-authored-by"}),l("settings.merge.trailer"," trailer. Default: Fusion.")]})]}),e.jsx("input",{id:"commitAuthorName",type:"text",value:t.commitAuthorName??"",placeholder:l("settings.merge.fusion","Fusion"),onChange:E=>s(L=>({...L,commitAuthorName:E.target.value||void 0}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"commitAuthorEmail",children:l("settings.merge.coAuthorEmail","Co-author Email")}),e.jsxs(B,{settingKey:"commitAuthorEmail",children:[l("settings.merge.emailUsedInThe","Email used in the "),e.jsx("code",{children:"Co-authored-by"}),l("settings.merge.trailerEmail"," trailer. Default: noreply@runfusion.ai.")]})]}),e.jsx("input",{id:"commitAuthorEmail",type:"email",value:t.commitAuthorEmail??"",placeholder:l("settings.merge.noreplyRunfusionAi","noreply@runfusion.ai"),onChange:E=>s(L=>({...L,commitAuthorEmail:E.target.value||void 0}))})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"autoResolveConflicts",className:"checkbox-label",children:[e.jsx("input",{id:"autoResolveConflicts",type:"checkbox",checked:t.autoResolveConflicts!==!1,onChange:E=>s(L=>({...L,autoResolveConflicts:E.target.checked}))}),l("settings.merge.autoResolveConflictsInLockFilesAndGenerated"," Auto-resolve conflicts in lock files and generated files ")]}),e.jsx(B,{settingKey:"autoResolveConflicts",children:l("settings.merge.whenEnabledLockFilesPackageLockJsonPnpm","When enabled, lock files (package-lock.json, pnpm-lock.yaml, etc.), generated files (dist/*, *.gen.ts), and trivial whitespace conflicts are resolved automatically without AI intervention. Complex code conflicts still require AI review. Default: enabled.")})]})}),(t.merger?.mode??"ai")!=="ai"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"smartConflictResolution",className:"checkbox-label",children:[e.jsx("input",{id:"smartConflictResolution",type:"checkbox",checked:t.smartConflictResolution!==!1,onChange:E=>s(L=>({...L,smartConflictResolution:E.target.checked}))}),l("settings.merge.smartConflictResolution"," Smart conflict resolution ")]}),e.jsx(B,{settingKey:"smartConflictResolution",children:l("settings.merge.whenEnabledLockFilesPackageLockJsonPnpm2","When enabled, lock files (package-lock.json, pnpm-lock.yaml, etc.) are resolved using 'ours' strategy, generated files (dist/*, *.gen.ts) using 'theirs' strategy, and trivial whitespace conflicts are auto-resolved without spawning an AI agent. Complex code conflicts still require AI review. Default: enabled.")})]})}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeConflictStrategy",children:l("settings.merge.conflictFallbackStrategy","Conflict Fallback Strategy")}),e.jsxs(B,{settingKey:"mergeConflictStrategy",children:[l("settings.merge.both"," Both "),e.jsx("strong",{children:l("settings.merge.smart","Smart")}),l("settings.merge.optionsStartWithABestEffort"," options start with a best-effort "),e.jsx("code",{children:"git fetch"}),l("settings.merge.fastForwardOfLocalMainFrom"," + fast-forward of local main from "),e.jsx("code",{children:"origin"}),l("settings.merge.soAFreshlyPushedSiblingCommitDoesntGet"," (so a freshly-pushed sibling commit doesn't get clobbered), then run an AI agent, then auto-resolve handles lock/generated/trivial files. They differ only in the "),e.jsx("em",{children:l("settings.merge.finalFallback","final fallback")}),":"," ",e.jsx("strong",{children:l("settings.merge.smartPreferMain","Smart, prefer main")}),l("settings.merge.uses"," uses "),e.jsx("code",{children:"-X ours"}),l("settings.merge.soMainWinsProtectsJustMergedSiblingWork"," so main wins — protects just-merged sibling work and is the new default. ")," ",e.jsx("strong",{children:l("settings.merge.smartPreferTask","Smart, prefer task")}),l("settings.merge.uses"," uses "),e.jsx("code",{children:"-X theirs"}),l("settings.merge.soTheTaskBranchWinsFastButCan"," so the task branch wins — fast, but can resurrect code an earlier sibling task deleted (the FN-2887 class of regression). ")," ",e.jsx("strong",{children:l("settings.merge.aIOnly","AI only")}),l("settings.merge.retriesTheAIAgentRatherThanAutoPicking"," retries the AI agent rather than auto-picking a side. ")," ",e.jsx("strong",{children:l("settings.merge.abort","Abort")}),l("settings.merge.stopsAfterTheFirstAIAttemptAndWaits"," stops after the first AI attempt and waits for a human. ")," ",e.jsxs("em",{children:[l("settings.merge.legacy2","Legacy "),e.jsx("code",{children:'"smart"'}),l("settings.merge.and2"," and "),e.jsx("code",{children:'"prefer-main"'}),l("settings.merge.valuesFromOlderSettingsAreMigratedAutomatically"," values from older settings are migrated automatically.")]})]})]}),e.jsxs("select",{id:"mergeConflictStrategy",value:t.mergeConflictStrategy??"smart-prefer-main",onChange:E=>s(L=>({...L,mergeConflictStrategy:E.target.value})),children:[e.jsx("option",{value:"smart-prefer-main",children:l("settings.merge.smartPreferMainOnFallbackFetchFfOrigin","Smart, prefer main on fallback — fetch+ff origin → AI → auto-resolve → -X ours (default; protects just-merged sibling work)")}),e.jsx("option",{value:"smart-prefer-branch",children:l("settings.merge.smartPreferTaskOnFallbackFetchFfOrigin",'Smart, prefer task on fallback — fetch+ff origin → AI → auto-resolve → -X theirs (legacy "smart" behavior; task branch wins)')}),e.jsx("option",{value:"ai-only",children:l("settings.merge.aIOnlyAIAutoResolveAIRetryNever","AI only — AI → auto-resolve → AI retry; never silently pick a side")}),e.jsx("option",{value:"abort",children:l("settings.merge.abortOneAIAttemptRequireManualResolutionIf","Abort — one AI attempt; require manual resolution if it fails")})]})]}),e.jsx(ke,{descriptor:{key:"mergeStrategyOverlapBehavior",label:l("settings.merge.smartPreferMainOverlapGuard","Smart Prefer Main Overlap Guard"),help:l("settings.merge.whenUsingSmartPreferMainAutomaticallyPreferThe"," When using smart-prefer-main, automatically prefer the branch side for files that main has recently modified to avoid silently discarding branch work. "),scope:"project",options:[{value:"flip-to-prefer-branch",label:l("settings.merge.flipOverlappingFilesToPreferTheTaskBranch","Flip overlapping files to prefer the task branch (default)")},{value:"warn-only",label:l("settings.merge.warnOnlyKeepLegacyMainWinsFallback","Warn only — keep legacy main-wins fallback")},{value:"ignore",label:l("settings.merge.ignoreOverlapDetectionPreserveLegacyBehavior","Ignore overlap detection — preserve legacy behavior")}]},value:t.mergeStrategyOverlapBehavior??"flip-to-prefer-branch",onChange:E=>s(L=>({...L,mergeStrategyOverlapBehavior:E}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"postMergeAuditMode",children:l("settings.merge.postMergeAuditMode","Post-merge audit mode")}),e.jsxs(B,{settingKey:"postMergeAuditMode",children:[l("settings.merge.controlsThePostMergeAuditGate"," Controls the post-merge audit gate. "),e.jsx("strong",{children:l("settings.merge.warn","Warn")}),l("settings.merge.defaultLogsFindingsButAutoCompletesTheMerge"," (default) logs findings but auto-completes the merge. "),e.jsx("strong",{children:l("settings.merge.block","Block")}),l("settings.merge.isTheStricterOptInModeThatRefuses"," is the stricter opt-in mode that refuses to auto-complete merges with duplicate-subject or touched-file overlap risks. "),e.jsx("strong",{children:l("settings.merge.off","Off")}),l("settings.merge.skipsTheAuditEntirelySwitchingToOffIs"," skips the audit entirely. Switching to Off is recommended only if you trust your branches don't silently drop edits. ")]})]}),e.jsxs("select",{className:"select",id:"postMergeAuditMode",value:t.postMergeAuditMode??"warn",onChange:E=>s(L=>({...L,postMergeAuditMode:E.target.value})),children:[e.jsx("option",{value:"block",children:l("settings.merge.blockStrict","Block (strict)")}),e.jsx("option",{value:"warn",children:l("settings.merge.warnDefaultLogFindingsContinue","Warn (default; log findings, continue)")}),e.jsx("option",{value:"off",children:l("settings.merge.offSkipAudit","Off (skip audit)")})]})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"pushAfterMerge",className:"checkbox-label",children:[e.jsx("input",{id:"pushAfterMerge",type:"checkbox",checked:t.pushAfterMerge===!0,onChange:E=>s(L=>({...L,pushAfterMerge:E.target.checked}))}),l("settings.merge.pushToRemoteAfterMerge"," Push to remote after merge ")]}),e.jsx(B,{settingKey:"pushAfterMerge",children:l("settings.merge.whenEnabledTheMergedResultIsAutomaticallyPushed","When enabled, the merged result is automatically pushed to the configured git remote. This includes pulling the latest from the remote first (rebase) and resolving any conflicts with AI if needed. Default: disabled.")})]})}),t.pushAfterMerge&&(i.length===0?e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"pushRemote",children:l("settings.merge.pushRemote","Push Remote")}),e.jsx(B,{settingKey:"pushRemote",children:l("settings.merge.gitRemoteToPushToEGOrigin",'Git remote to push to (e.g. "origin"). Can include branch name (e.g. "origin main"). Default: "origin".')})]}),e.jsx("input",{id:"pushRemote",type:"text",placeholder:l("settings.merge.origin","origin"),value:t.pushRemote||"",onChange:E=>s(L=>({...L,pushRemote:E.target.value||void 0}))})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"pushRemote",children:l("settings.merge.pushRemote","Push Remote")}),e.jsx(B,{settingKey:"pushRemote",children:l("settings.merge.gitRemoteThatMergedResultsArePushedTo",'Git remote that merged results are pushed to. Default: "origin".')})]}),e.jsxs("select",{id:"pushRemote",className:"select",value:h.remote,onChange:E=>{const L=E.target.value;x(!1),s(G=>({...G,pushRemote:Ks(L,"")}))},"data-testid":"push-remote-select",children:[!i.includes(h.remote)&&e.jsx("option",{value:h.remote,children:h.remote}),i.map(E=>e.jsx("option",{value:E,children:E},E))]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"pushRemoteBranch",children:l("settings.merge.pushTargetBranch","Push target branch")}),e.jsx(B,{settingKey:"pushRemoteBranch",children:l("settings.merge.pushTargetBranchHelp","Branch on the remote that merged results are pushed to. Leave on the default to push the integration branch to its same-named remote branch; pick a listed remote branch or choose Custom… to type one that doesn't exist on the remote yet (the push creates it).")})]}),(()=>{const E=h.branch,L=E.length>0&&p.includes(E);if(w||E.length>0&&!L)return e.jsxs("div",{className:"form-inline-group",children:[e.jsx("input",{id:"pushRemoteBranch",type:"text",className:"input",placeholder:l("settings.merge.branchName","branch name"),value:E,onChange:K=>{const z=K.target.value.trim();s(ne=>({...ne,pushRemote:Ks(h.remote,z)}))},"data-testid":"push-remote-branch-custom-input"}),e.jsx("button",{type:"button",className:"btn-link",onClick:()=>{x(!1),s(K=>({...K,pushRemote:Ks(h.remote,"")}))},"data-testid":"push-remote-branch-use-dropdown",children:l("settings.merge.useDropdown"," Use dropdown ")})]});const G="__fusion-custom__";return e.jsxs("select",{id:"pushRemoteBranch",className:"select",value:E,onChange:K=>{const z=K.target.value;if(z===G){x(!0);return}s(ne=>({...ne,pushRemote:Ks(h.remote,z)}))},"data-testid":"push-remote-branch-select",children:[e.jsx("option",{value:"",children:l("settings.merge.sameAsIntegrationBranchDefault","(same as integration branch — default)")}),p.map(K=>e.jsx("option",{value:K,children:K},K)),e.jsx("option",{value:G,children:l("settings.merge.custom","Custom…")})]})})()]})]}))]})}const Bs="__custom__";function Zg(t){const s=new Map;for(const a of t){const n=a.value.trim();!n||s.has(n)||s.set(n,{...a,value:n,label:a.label?.trim()||n})}return[...s.values()].sort((a,n)=>a.value.localeCompare(n.value))}function Ir({id:t,value:s,onChange:a,options:n,loading:c=!1,error:d,placeholder:i="owner/repo",ariaLabel:u}){const{t:l}=te("app"),h=o.useRef(null),p=o.useId(),[b,w]=o.useState(!1),x=o.useMemo(()=>Zg(n),[n]),f=x.find(y=>y.value===s),D=f?f.value:Bs;o.useEffect(()=>{w(D===Bs)},[D]);const S=y=>{if(y===Bs){w(!0),requestAnimationFrame(()=>{h.current?.focus()});return}w(!1),a(y)},C=d||(c?l("trackingRepoSelect.loadingHint","Loading detected GitHub remotes…"):null);return e.jsxs("div",{className:"tracking-repo-select",children:[e.jsxs("select",{id:t,className:"select",value:D,onChange:y=>S(y.target.value),"aria-label":u,"aria-describedby":C?p:void 0,children:[x.map(y=>e.jsx("option",{value:y.value,children:y.source?`${y.label} — ${y.source}`:y.label},y.value)),e.jsx("option",{value:Bs,children:l("trackingRepoSelect.customOption","Custom…")})]}),b?e.jsx("input",{ref:h,className:"input tracking-repo-select__custom-input",type:"text",value:s,placeholder:i,onChange:y=>a(y.target.value),"aria-describedby":C?p:void 0}):null,C?e.jsx("small",{id:p,className:d?"tracking-repo-select__hint tracking-repo-select__hint--error":"tracking-repo-select__hint",children:C}):null]})}function ep({form:t,setForm:s,projectTrackingRepoOptions:a,projectTrackingRepoLoading:n,projectTrackingRepoError:c}){const{t:d}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:d("settings.general.gitHubTracking","GitHub Tracking")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"githubTrackingMode",children:d("settings.general.defaultTrackingModeForNewTasks","Default tracking mode for new tasks")}),e.jsxs(B,{settingKey:"githubTrackingMode",children:[d("settings.general.controlsWhetherNewlyCreatedTasksHaveGitHubIssue"," Controls whether newly created tasks have GitHub issue tracking enabled by default. Individual tasks can still override this from the task detail modal. "),d("settings.general.trackingIssuesUseThisTaskAposSTitle"," Tracking issues use this task's title. If a task has no title yet, Fusion can summarize its description using the title summarization model in Project Models. "),!t.autoSummarizeTitles&&!t.useAiMergeCommitSummary&&!t.githubTrackingEnabledByDefault?d("settings.general.enableSummarizationInProjectModelsToConfigureThatModel"," Enable summarization in Project Models to configure that model."):""]})]}),e.jsxs("select",{id:"githubTrackingMode",className:"select",value:t.githubTrackingEnabledByDefault?"new-tasks":"off",onChange:i=>s(u=>({...u,githubTrackingEnabledByDefault:i.target.value==="new-tasks"})),children:[e.jsx("option",{value:"off",children:d("settings.general.offDefault","Off (default)")}),e.jsx("option",{value:"new-tasks",children:d("settings.general.onForNewTasks","On for new tasks")})]})]}),e.jsx(se,{descriptor:{key:"githubLinkImportedIssuesToTracking",label:d("settings.general.alwaysLinkImportedGitHubIssuesToTracking"," Always link imported GitHub issues to GitHub tracking "),help:d("settings.general.whenEnabledImportedGitHubIssuesUseTheirSource","When enabled, GitHub issue imports become tracked tasks that adopt the source issue. This does not turn GitHub tracking on for ordinary new tasks. Default: disabled."),scope:"project"},value:t.githubLinkImportedIssuesToTracking===!0,onChange:i=>s(u=>({...u,githubLinkImportedIssuesToTracking:i===!0}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"projectGithubTrackingDefaultRepoGeneral",children:d("settings.general.projectDefaultTrackingRepo","Project default tracking repo")}),e.jsx(B,{settingKey:"projectGithubTrackingDefaultRepoGeneral",children:d("settings.general.defaultRepoUsedWhenCreatingGitHubIssuesFor","Default repo used when creating GitHub issues for tracked tasks. Falls back to the global default if blank.")})]}),e.jsx(Ir,{id:"projectGithubTrackingDefaultRepoGeneral",ariaLabel:"Project default tracking repo",value:t.githubTrackingDefaultRepo??"",options:a,loading:n,error:c??void 0,placeholder:d("settings.general.ownerRepo","owner/repo"),onChange:i=>s(u=>({...u,githubTrackingDefaultRepo:i||void 0}))})]}),e.jsx(se,{descriptor:{key:"githubTrackingDedupEnabled",label:d("settings.general.searchTheTrackingRepoForLikelyDuplicatesBefore"," Search the tracking repo for likely duplicates before opening a new issue "),help:d("settings.general.whenEnabledFusionChecksOpenAndClosedIssues"," When enabled, Fusion checks open and closed issues in the target repo for likely duplicates (using File Scope paths and key symptoms) before creating a new tracking issue. Uncheck to always create a new issue. Default: enabled. "),scope:"project"},value:t.githubTrackingDedupEnabled!==!1,onChange:i=>s(u=>({...u,githubTrackingDedupEnabled:i===!0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:d("settings.merge.gitHubAuthentication","GitHub Authentication")}),e.jsx(ke,{descriptor:{key:"githubAuthMode",label:d("settings.merge.gitHubAuthMode","GitHub auth mode"),scope:"project",options:[{value:"gh-cli",label:d("settings.merge.gitHubCLIGhAuth","GitHub CLI (gh auth) (default)")},{value:"token",label:d("settings.merge.personalAccessToken","Personal access token")}]},value:t.githubAuthMode??"gh-cli",onChange:i=>s(u=>({...u,githubAuthMode:i}))}),(t.githubAuthMode??"gh-cli")==="token"&&e.jsx(de,{descriptor:{key:"githubAuthToken",label:d("settings.merge.gitHubPersonalAccessToken","GitHub personal access token"),help:d("settings.merge.githubAuthTokenHint","No default — unset."),scope:"project",type:"password"},value:t.githubAuthToken??"",onChange:i=>s(u=>({...u,githubAuthToken:i||void 0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:d("settings.general.gitLabConfiguration","GitLab Configuration")}),e.jsxs("details",{className:"settings-gitlab-disclosure","data-testid":"project-gitlab-configuration-disclosure",children:[e.jsxs("summary",{children:[e.jsx("span",{className:"settings-gitlab-disclosure__title",children:d("settings.general.gitLabConfiguration","GitLab Configuration")}),e.jsxs("label",{className:"checkbox-label settings-gitlab-disclosure__toggle",htmlFor:"gitlabEnabled",onClick:i=>i.stopPropagation(),children:[e.jsx("input",{id:"gitlabEnabled",type:"checkbox",checked:t.gitlabEnabled!==!1,onChange:i=>s(u=>({...u,gitlabEnabled:i.target.checked}))}),d("settings.general.enableGitLabIntegration","Enable GitLab integration")]}),e.jsx("span",{onClick:i=>i.stopPropagation(),children:e.jsx(B,{settingKey:"project-gitlab-configuration",children:t.gitlabEnabled===!1?d("settings.general.gitLabDisabledHint","GitLab API imports, comments, close/reopen, and refresh operations are disabled. Saved URLs and tokens remain stored for re-enable."):d("settings.general.gitLabEnabledHint","Configure GitLab.com or self-managed GitLab URLs. Blank values inherit global fallbacks and then GitLab.com. No default — unset (unset behaves as enabled until explicitly disabled).")})})]}),e.jsxs("div",{className:"settings-gitlab-disclosure__body","aria-disabled":t.gitlabEnabled===!1,children:[e.jsx(de,{descriptor:{key:"gitlabInstanceUrl",label:d("settings.general.gitLabInstanceUrl","GitLab instance URL"),help:d("settings.general.gitLabInstanceUrlHint","Blank uses GitLab.com or the global default. Set an absolute http:// or https:// URL for self-managed GitLab, such as https://gitlab.example.com/gitlab."),type:"url",placeholder:"https://gitlab.com",disabled:t.gitlabEnabled===!1},value:t.gitlabInstanceUrl??"",onChange:i=>s(u=>({...u,gitlabInstanceUrl:i||void 0}))}),e.jsx(de,{descriptor:{key:"gitlabApiBaseUrl",label:d("settings.general.gitLabApiBaseUrlOptional","GitLab API base URL (optional / advanced)"),help:d("settings.general.gitLabApiBaseUrlHint","Blank derives <instance>/api/v4. Override only when a self-managed GitLab API is served from a different absolute http:// or https:// URL."),type:"url",placeholder:"https://gitlab.com/api/v4",disabled:t.gitlabEnabled===!1},value:t.gitlabApiBaseUrl??"",onChange:i=>s(u=>({...u,gitlabApiBaseUrl:i||void 0}))}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h5",{className:"settings-section-heading",children:d("settings.merge.gitLabAuthentication","GitLab Authentication")}),e.jsx(B,{settingKey:"project-gitlab-authentication",children:t.gitlabEnabled===!1?d("settings.merge.gitLabDisabledHint","GitLab comments, close/reopen, import fetches, and refresh operations are disabled. Saved tokens remain stored for re-enable."):d("settings.merge.gitLabAuthDetails","Fusion uses GitLab REST API token authentication with the PRIVATE-TOKEN header. Leave the token blank to clear the project override and fall back to a configured global GitLab token or GITLAB_TOKEN where available. No default — unset (unset behaves as enabled until explicitly disabled).")})]}),e.jsx(ke,{descriptor:{key:"gitlabAuthTokenType",label:d("settings.merge.gitLabTokenType","GitLab token type"),disabled:t.gitlabEnabled===!1,options:[{value:"personal",label:d("settings.merge.gitLabPersonalAccessToken","Personal access token (default)")},{value:"project",label:d("settings.merge.gitLabProjectAccessToken","Project access token")},{value:"group",label:d("settings.merge.gitLabGroupAccessToken","Group access token")}]},value:t.gitlabAuthTokenType??"personal",onChange:i=>s(u=>({...u,gitlabAuthTokenType:i}))}),e.jsx(de,{descriptor:{key:"gitlabAuthToken",label:d("settings.merge.gitLabAccessToken","GitLab access token"),help:d("settings.merge.gitLabAuthTokenHint","Read-only GitLab operations need read_api or api. Future write actions such as comments and auto-close need api. Project and group tokens are limited to their associated resource and role membership. No default — unset."),type:"password",disabled:t.gitlabEnabled===!1},value:t.gitlabAuthToken??"",onChange:i=>s(u=>({...u,gitlabAuthToken:i||void 0}))})]})]})]})}function tp({form:t,setForm:s,globalSettings:a,onGlobalGitlabSettingsChange:n,globalTrackingRepoOptions:c,globalTrackingRepoLoading:d,globalTrackingRepoError:i}){const{t:u}=te("app"),l=a??t;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"globalGithubTrackingDefaultRepo",children:u("settings.globalGeneral.globalDefaultTrackingRepo","Global default tracking repo")}),e.jsx(B,{settingKey:"globalGithubTrackingDefaultRepo",children:u("settings.globalGeneral.projectsInheritThisValueWhenTheyDoNot","Projects inherit this value when they do not set a project default tracking repo. No default — unset.")})]}),e.jsx(Ir,{id:"globalGithubTrackingDefaultRepo",ariaLabel:"Global default tracking repo",value:t.githubTrackingDefaultRepo??"",options:c,loading:d,error:i??void 0,placeholder:u("settings.globalGeneral.ownerRepo","owner/repo"),onChange:h=>s(p=>({...p,githubTrackingDefaultRepo:h||void 0}))})]}),e.jsxs("details",{className:"settings-gitlab-disclosure","data-testid":"global-gitlab-configuration-disclosure",children:[e.jsxs("summary",{children:[e.jsx("span",{className:"settings-gitlab-disclosure__title",children:u("settings.globalGeneral.gitLabConfiguration","GitLab Configuration")}),e.jsxs("label",{className:"checkbox-label settings-gitlab-disclosure__toggle",htmlFor:"globalGitlabEnabled",onClick:h=>h.stopPropagation(),children:[e.jsx("input",{id:"globalGitlabEnabled",type:"checkbox",checked:l.gitlabEnabled!==!1,onChange:h=>n({gitlabEnabled:h.target.checked})}),u("settings.globalGeneral.enableGitLabIntegration","Enable GitLab integration")]}),e.jsx("span",{onClick:h=>h.stopPropagation(),children:e.jsx(B,{settingKey:"global-gitlab-configuration",children:l.gitlabEnabled===!1?u("settings.globalGeneral.gitLabDisabledHint","GitLab API operations are disabled by global default. Saved URL and token fallbacks remain stored for re-enable."):u("settings.globalGeneral.gitLabEnabledHint","Global GitLab URL and token fallbacks apply to projects that do not set their own values. No default — unset (unset behaves as enabled until explicitly disabled).")})})]}),e.jsxs("div",{className:"settings-gitlab-disclosure__body","aria-disabled":l.gitlabEnabled===!1,children:[e.jsx(de,{descriptor:{key:"gitlabInstanceUrl",label:u("settings.globalGeneral.gitLabInstanceUrl","Global GitLab instance URL"),help:u("settings.globalGeneral.gitLabInstanceUrlHint","Blank defaults to GitLab.com. Projects inherit this self-managed GitLab URL unless they set their own project value. No default — unset."),type:"url",placeholder:"https://gitlab.com",disabled:l.gitlabEnabled===!1},value:l.gitlabInstanceUrl??"",onChange:h=>n({gitlabInstanceUrl:h||void 0})}),e.jsx(de,{descriptor:{key:"gitlabApiBaseUrl",label:u("settings.globalGeneral.gitLabApiBaseUrlOptional","Global GitLab API base URL (optional / advanced)"),help:u("settings.globalGeneral.gitLabApiBaseUrlHint","Blank derives <instance>/api/v4. Override only for self-managed GitLab API gateways that use a different absolute http:// or https:// URL. No default — unset."),type:"url",placeholder:"https://gitlab.com/api/v4",disabled:l.gitlabEnabled===!1},value:l.gitlabApiBaseUrl??"",onChange:h=>n({gitlabApiBaseUrl:h||void 0})}),e.jsx(ke,{descriptor:{key:"gitlabAuthTokenType",label:u("settings.globalGeneral.gitLabTokenType","Global GitLab token type"),help:u("settings.globalGeneral.gitLabTokenTypeHint","No default — unset (the selector falls back to personal access token until you choose otherwise)."),disabled:l.gitlabEnabled===!1,options:[{value:"personal",label:u("settings.globalGeneral.gitLabPersonalAccessToken","Personal access token")},{value:"project",label:u("settings.globalGeneral.gitLabProjectAccessToken","Project access token")},{value:"group",label:u("settings.globalGeneral.gitLabGroupAccessToken","Group access token")}]},value:l.gitlabAuthTokenType??"personal",onChange:h=>n({gitlabAuthTokenType:h})}),e.jsx(de,{descriptor:{key:"gitlabAuthToken",label:u("settings.globalGeneral.gitLabAccessToken","Global GitLab access token"),help:u("settings.globalGeneral.gitLabAuthTokenHint","Projects inherit this fallback only when they do not set a project GitLab token. Read-only operations need read_api or api; write actions need api; project/group tokens remain limited by resource membership. No default — unset."),type:"password",disabled:l.gitlabEnabled===!1},value:l.gitlabAuthToken??"",onChange:h=>n({gitlabAuthToken:h||void 0})})]})]})]})}function or(t){return Array.from(new Set(t.split(/[\n,]+/).map(s=>s.trim()).filter(s=>s.length>0)))}function sp({value:t,onChange:s,disabled:a=!1}){const{t:n}=te("app"),c=t?.approvalMode??"trusted-only",d=t?.alwaysApproveDelete??!0,i={always:{label:n("agentProvisioning.always","Always require approval"),description:n("agentProvisioning.alwaysDesc","All fn_agent_create/fn_agent_delete requests require approval unless caller is trusted.")},"trusted-only":{label:n("agentProvisioning.trustedOnly","Trusted-only"),description:n("agentProvisioning.trustedOnlyDesc","Trusted roles/agent IDs bypass approval; other callers require approval.")},never:{label:n("agentProvisioning.never","Never require approval"),description:n("agentProvisioning.neverDesc","Allow provisioning without approval for non-privileged callers.")}},u=l=>{s({...t??{},...l})};return e.jsxs("div",{className:"agent-provisioning-policy-editor card",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"agent-provisioning-approval-mode",children:n("agentProvisioning.approvalMode","Approval mode")}),e.jsx("select",{id:"agent-provisioning-approval-mode",className:"select",value:c,onChange:l=>u({approvalMode:l.target.value}),disabled:a,children:td.map(l=>e.jsx("option",{value:l,children:i[l].label},l))}),e.jsx("small",{className:"agent-provisioning-policy-help",children:i[c].description})]}),e.jsx("div",{className:"form-group",children:e.jsxs("label",{className:"checkbox-label",htmlFor:"agent-provisioning-always-approve-delete",children:[e.jsx("input",{id:"agent-provisioning-always-approve-delete",type:"checkbox",checked:d,onChange:l=>u({alwaysApproveDelete:l.target.checked}),disabled:a}),n("agentProvisioning.alwaysApproveDelete","Always require approval for fn_agent_delete")]})}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"agent-provisioning-trusted-roles",children:n("agentProvisioning.trustedRoles","Trusted roles")}),e.jsx("textarea",{id:"agent-provisioning-trusted-roles",className:"input agent-provisioning-policy-textarea",value:(t?.trustedRoles??[]).join(", "),onChange:l=>u({trustedRoles:or(l.target.value)}),disabled:a,placeholder:n("agentProvisioning.trustedRolesPlaceholder","reviewer, ceo"),rows:2})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"agent-provisioning-trusted-agent-ids",children:n("agentProvisioning.trustedAgentIds","Trusted agent IDs")}),e.jsx("textarea",{id:"agent-provisioning-trusted-agent-ids",className:"input agent-provisioning-policy-textarea",value:(t?.trustedAgentIds??[]).join(", "),onChange:l=>u({trustedAgentIds:or(l.target.value)}),disabled:a,placeholder:n("agentProvisioning.trustedAgentIdsPlaceholder","agent-abc123"),rows:2})]}),e.jsx("p",{className:"agent-provisioning-policy-help",children:e.jsx(un,{i18nKey:"app:agentProvisioning.helpText",defaults:"These settings govern durable provisioning tools only: <code>fn_agent_create</code> and <code>fn_agent_delete</code>. Ephemeral <code2>fn_spawn_agent</code2> requests stay under the task/agent mutation approval gate (FN-3973).",components:{code:e.jsx("code",{}),code2:e.jsx("code",{})}})})]})}function en(t){return sd.reduce((s,a)=>(s[a]=t?.[a]??"allow",s),{})}function ap({form:t,setForm:s}){const{t:a}=te("app");return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.agentPermissions.agentPermissions","Agent Permissions")}),e.jsx(B,{settingKey:"defaultAgentPermissionPolicy",children:a("settings.agentPermissions.perAgentSettingsOverrideProjectDefaultsEachCategory","Project defaults apply to permanent agents, ephemeral task workers, and fallback executor workers unless a per-agent override is set. Exact tool rules compose with the legacy ephemeral create-task toggle. Default: unset — every action category defaults to allow until a category is explicitly restricted.")})]}),e.jsx(Yd,{mode:"project-default",value:t.defaultAgentPermissionPolicy?{presetId:"custom",rules:en(t.defaultAgentPermissionPolicy.rules),...t.defaultAgentPermissionPolicy.toolRules?{toolRules:t.defaultAgentPermissionPolicy.toolRules}:{}}:{presetId:"custom",rules:en()},onChange:n=>s(c=>({...c,defaultAgentPermissionPolicy:{rules:en(n?.rules),...n?.toolRules?{toolRules:n.toolRules}:{}}}))}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.agentPermissions.agentProvisioningApprovals","Agent Provisioning Approvals")}),e.jsx(B,{settingKey:"agentProvisioning",children:a("settings.agentPermissions.configureProjectLevelApprovalBehaviorForDurableProvisioning"," Configure project-level approval behavior for durable provisioning tools (fn_agent_create/fn_agent_delete). Default: no approval policy configured (empty). ")})]}),e.jsx(sp,{value:t.agentProvisioning,onChange:n=>s(c=>({...c,agentProvisioning:n}))})]})}const np=72;function lp(t,s){if(t.length<=s)return t;const a=Math.max(1,s-1),n=Math.ceil(a/2),c=Math.floor(a/2);return`${t.slice(0,n)}…${t.slice(t.length-c)}`}function rp(t){const s=`${t.label} — ${t.path}`;return lp(s,np)}function ip({form:t,setForm:s,memory:a}){const{t:n}=te("app"),{memoryCapabilities:c,memoryBackendStatus:d,memoryBackendLoading:i,memoryBackendError:u,memoryFiles:l,selectedMemoryPath:h,setSelectedMemoryPath:p,memoryContent:b,setMemoryContent:w,memoryLoading:x,memoryDirty:f,setMemoryDirty:D,memoryTestQuery:S,setMemoryTestQuery:C,memoryTestLoading:y,memoryTestResult:k,qmdInstallLoading:R,dreamRunning:P,memoryCompactLoading:N,onInstallQmd:U,onTestMemoryRetrieval:m,onDreamNow:Y,onCompactMemory:E,onSaveMemory:L}=a,G=t.memoryEnabled!==!1,K=!i&&d!==null,z=K?c?.writable??!0:!0,ne=G&&z,re=l.find(T=>T.path===h),ce={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.memory.memory","Memory")}),e.jsxs(B,{settingKey:"memory-section",children:[n("settings.memory.memoryLivesIn"," Memory lives in "),e.jsx("code",{children:".fusion/memory/"}),n("settings.memory.agentsSearchWithQmdFirstFallBackTo",". Agents search with qmd first, fall back to local files when qmd is missing, and open exact line windows only when needed. ")]})]}),e.jsx(se,{descriptor:{key:"memoryEnabled",label:n("settings.memory.enableMemoryTools"," Enable memory tools "),help:n("settings.memory.agentsGetMemorySearchMemoryGetAndMemory","Agents get memory_search, memory_get, and memory_append tools. Search defaults to qmd with a local file fallback. Default: enabled."),scope:"project"},value:t.memoryEnabled!==!1,onChange:T=>s($=>({...$,memoryEnabled:T===!0}))}),i?e.jsx("div",{className:"form-group",children:e.jsx("small",{className:"settings-muted",children:n("settings.memory.checkingMemoryWriteAccess","Checking memory write access...")})}):u?e.jsx("div",{className:"form-group",children:e.jsxs("small",{className:"field-error",children:[n("settings.memory.failedToLoadBackendStatus","Failed to load backend status: "),u]})}):null,K&&d.qmdAvailable===!1&&e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:[n("settings.memory.qmdIsNotInstalledSearchWillUseLocal"," qmd is not installed. Search will use local files. Install indexed retrieval: "),e.jsx("code",{children:d.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:U,disabled:R,children:R?n("settings.memory.installing","Installing…"):n("settings.memory.installQmd","Install qmd")})]}),e.jsx(se,{descriptor:{key:"memoryAutoSummarizeEnabled",label:n("settings.memory.autoSummarizeMemory"," Auto-Summarize Memory "),help:n("settings.memory.automaticallyCompactMemoryWhenItExceedsTheThreshold","Automatically compact memory when it exceeds the threshold on a schedule. Default: disabled."),scope:"project"},value:t.memoryAutoSummarizeEnabled||!1,onChange:T=>s($=>({...$,memoryAutoSummarizeEnabled:T===!0}))}),(t.memoryAutoSummarizeEnabled||!1)&&e.jsxs(e.Fragment,{children:[e.jsx(ye,{descriptor:{key:"memoryAutoSummarizeThresholdChars",label:n("settings.memory.compactionThresholdChars","Compaction Threshold (chars)"),help:n("settings.memory.memoryWillBeCompactedWhenItExceedsThis","Memory will be compacted when it exceeds this character count. Default: 50000."),scope:"project",min:1e3},value:t.memoryAutoSummarizeThresholdChars??5e4,onChange:T=>s($=>({...$,memoryAutoSummarizeThresholdChars:T||5e4}))}),e.jsx(de,{descriptor:{key:"memoryAutoSummarizeSchedule",label:n("settings.memory.scheduleCron","Schedule (cron)"),help:n("settings.memory.cronExpressionForAutoSummarizeScheduleDefaultDaily","Cron expression for auto-summarize schedule. Default: 0 3 * * * (daily at 3 AM)."),scope:"project",placeholder:n("settings.memory.03","0 3 * * *")},value:t.memoryAutoSummarizeSchedule??"0 3 * * *",onChange:T=>s($=>({...$,memoryAutoSummarizeSchedule:T??""}))})]}),e.jsx(se,{descriptor:{key:"insightExtractionEnabled",label:n("settings.memory.enableInsightExtraction"," Enable Insight Extraction "),help:n("settings.memory.periodicallyExtractDurableInsightsFromCompletedTasks","Periodically extract durable insights/learnings from completed tasks into memory"),scope:"project"},value:t.insightExtractionEnabled||!1,onChange:T=>s($=>({...$,insightExtractionEnabled:T===!0}))}),(t.insightExtractionEnabled||!1)&&e.jsx(de,{descriptor:{key:"insightExtractionSchedule",label:n("settings.memory.scheduleCron","Schedule (cron)"),help:n("settings.memory.cronExpressionForInsightExtractionScheduleDefaultDaily","Cron expression for insight extraction schedule (default: daily at 2 AM)"),scope:"project",placeholder:n("settings.memory.02","0 2 * * *")},value:t.insightExtractionSchedule??"0 2 * * *",onChange:T=>s($=>({...$,insightExtractionSchedule:T??""}))}),e.jsx("div",{style:{borderTop:"1px solid var(--border)",margin:"var(--space-lg) 0"}}),e.jsx(se,{descriptor:{key:"memoryDreamsEnabled",label:n("settings.memory.processDreamsFromDailyMemory"," Process dreams from daily memory "),help:n("settings.memory.turnsDailyNotesIntoDREAMSMdAndPromotes","Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md. Default: disabled."),scope:"project",disabled:!G},value:t.memoryDreamsEnabled===!0,onChange:T=>s($=>({...$,memoryDreamsEnabled:T===!0}))}),G&&t.memoryDreamsEnabled===!0&&e.jsxs(e.Fragment,{children:[e.jsx(de,{descriptor:{key:"memoryDreamsSchedule",label:n("settings.memory.dreamSchedule","Dream Schedule"),help:n("settings.memory.cronExpressionForDreamProcessing","Cron expression for dream processing. Default: 0 4 * * * (daily at 4 AM)."),scope:"project"},value:t.memoryDreamsSchedule??"0 4 * * *",onChange:T=>s($=>({...$,memoryDreamsSchedule:T??""}))}),e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:Y,disabled:P||t.memoryDreamsEnabled!==!0,children:P?e.jsxs(e.Fragment,{children:[e.jsx(Ze,{size:14,className:"animate-spin"}),n("settings.memory.dreaming"," Dreaming… ")]}):n("settings.memory.dreamNow","Dream Now")}),e.jsx(B,{settingKey:"memory-dream-now",children:n("settings.memory.manuallyTriggerDreamProcessingNow","Manually trigger dream processing now.")})]})]}),e.jsxs("div",{className:"memory-retrieval-test",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"memoryRetrievalQuery",children:n("settings.memory.testRetrieval","Test Retrieval")}),e.jsx(B,{settingKey:"memoryRetrievalQuery",children:n("settings.memory.runsTheSameQmdBackedMemorySearchPath","Runs the same qmd-backed memory_search path agents use.")})]}),e.jsx("input",{id:"memoryRetrievalQuery",type:"text",value:S,onChange:T=>C(T.target.value),placeholder:n("settings.memory.searchMemoryWithQmd","Search memory with qmd")})]}),e.jsx("div",{className:"form-group",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:m,disabled:y,children:y?n("settings.memory.testing","Testing…"):n("settings.memory.testRetrieval","Test Retrieval")})}),k&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[k.results.length,n("settings.memory.result"," result"),k.results.length===1?"":"s"," ",n("settings.memory.for",'for "'),k.query,'"']}),e.jsxs("small",{children:[n("settings.memory.qmd"," qmd "),k.qmdAvailable?"available":"missing"," · ",k.usedFallback?"local fallback used":"qmd path used"]}),k.results.length>0?e.jsx("ul",{children:k.results.map((T,$)=>e.jsxs("li",{children:[e.jsxs("span",{children:[T.path,":",T.lineStart]}),e.jsx("p",{children:T.snippet})]},`${T.path}-${T.lineStart}-${$}`))}):e.jsx("small",{children:n("settings.memory.noMatchingMemoryFound","No matching memory found.")})]})]}),!G&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:n("settings.memory.memoryIsCurrentlyDisabledYouCanViewThe"," Memory is currently disabled. You can view the file, but editing is read-only until memory is re-enabled. ")}),G&&K&&!z&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:n("settings.memory.memoryIsConfiguredWithAReadOnlyBackend"," Memory is configured with a read-only backend. You can view the file, but saving is disabled. ")}),x?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:n("settings.memory.loadingMemory","Loading memory…")})}):e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"memoryFilePath",children:n("settings.memory.memoryFile","Memory File")}),e.jsx(B,{settingKey:"memoryFilePath",children:"Choose any project memory file to view or edit. Dreams is selected by default."})]}),e.jsx("select",{id:"memoryFilePath",value:h,onChange:T=>{p(T.target.value),D(!1)},disabled:f,children:l.map(T=>e.jsx("option",{value:T.path,title:`${T.label} — ${T.path}`,children:rp(T)},T.path))}),f&&e.jsx("small",{children:"Save or discard the current edits before switching files."})]}),re&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:ce[re.layer]}),e.jsx("strong",{children:re.path}),e.jsxs("small",{children:[re.size.toLocaleString(),n("settings.memory.bytesUpdated"," bytes · updated "),new Date(re.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group memory-editor-form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:re?.label||"Memory Editor"}),e.jsxs(B,{settingKey:"memory-editor",children:[re?.layer==="long-term"&&"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",re?.layer==="daily"&&"Raw daily observations, open loops, and running context for dream processing.",re?.layer==="dreams"&&"Synthesized patterns and open loops promoted from daily memory.",!re&&"Edits the selected memory file."]})]}),e.jsx("div",{className:"memory-editor-frame",children:e.jsx(ad,{content:b,onChange:T=>{w(T),D(!0)},readOnly:!ne,filePath:h})})]})]}),!x&&e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:E,disabled:!ne||f||N,children:N?n("settings.memory.compacting","Compacting…"):n("settings.memory.compactSelectedFile","Compact Selected File")}),e.jsx(B,{settingKey:"memory-compact-file",children:`Compacts ${h} and writes the result back to the same file.`}),f&&e.jsx("small",{children:"Save or discard edits before compacting this file."})]}),f&&ne&&e.jsx("div",{className:"form-group",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:L,children:n("settings.memory.saveMemory","Save Memory")})}),f&&!ne&&e.jsx("div",{className:"form-group",children:e.jsxs("small",{className:"field-error",children:[n("settings.memory.cannotSave","Cannot save: "),G?"Backend is read-only":"Memory is disabled"]})})]})}function op({form:t,setForm:s,researchLimitError:a}){const{t:n}=te("app"),c=t.researchSettings?.limits,d=t.researchSettings?.enabledSources;return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.researchProject.projectResearchSettings","Project Research Settings")}),e.jsx(se,{descriptor:{key:"researchSettings.enabled",label:n("settings.researchProject.enableResearchInThisProject"," Enable research in this project "),help:n("settings.researchProject.enableResearchInThisProjectHint","Default: enabled."),scope:"project"},value:t.researchSettings?.enabled??!0,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},enabled:i===!0}}))}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:n("settings.researchProject.enabledSources","Enabled Sources")}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"research-project-source-webSearch",className:"checkbox-label settings-research-source-locked",children:[e.jsx("input",{id:"research-project-source-webSearch",type:"checkbox",checked:!0,disabled:!0,readOnly:!0}),n("settings.researchProject.webSearch"," Web Search "),e.jsx("span",{className:"settings-muted",children:n("settings.researchProject.alwaysOn","Always on")})]}),e.jsx(B,{settingKey:"research-project-source-webSearch",children:n("settings.researchProject.webSearchIsAlwaysEnabledConfigureTheSearch"," Web search is always enabled. Configure the search provider under Research Defaults. ")})]}),e.jsx("div",{className:"settings-research-source-grid",children:[["pageFetch",n("settings.researchProject.pageFetch","Page Fetch"),"Default: enabled."],["github",n("settings.researchProject.github","GitHub"),"Default: disabled."],["localDocs",n("settings.researchProject.localDocs","Local Docs"),"Default: enabled."],["llmSynthesis",n("settings.researchProject.llmSynthesis","LLM Synthesis"),"Default: enabled."]].map(([i,u,l])=>e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:`research-project-source-${i}`,className:"checkbox-label",children:[e.jsx("input",{id:`research-project-source-${i}`,type:"checkbox",checked:d?.[i]??!1,onChange:h=>s(p=>({...p,researchSettings:{...p.researchSettings??{},enabledSources:{...p.researchSettings?.enabledSources??{},[i]:h.target.checked}}}))}),u]}),e.jsx(B,{settingKey:`research-project-source-${i}`,children:l})]},i))})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-research-limits-grid",children:[e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-max-concurrent",children:n("settings.researchProject.maxConcurrentRuns","Max Concurrent Runs")}),e.jsx(B,{settingKey:"research-project-max-concurrent",children:n("settings.researchProject.maxConcurrentRunsHint","Default: 3.")})]}),e.jsx("input",{id:"research-project-max-concurrent",className:"input",type:"number",min:1,value:c?.maxConcurrentRuns??3,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},maxConcurrentRuns:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-max-sources",children:n("settings.researchProject.maxSourcesPerRun","Max Sources Per Run")}),e.jsx(B,{settingKey:"research-project-max-sources",children:n("settings.researchProject.maxSourcesPerRunHint","Default: 20.")})]}),e.jsx("input",{id:"research-project-max-sources",className:"input",type:"number",min:1,value:c?.maxSourcesPerRun??20,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},maxSourcesPerRun:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-max-duration",children:n("settings.researchProject.maxDurationMs","Max Duration (ms)")}),e.jsx(B,{settingKey:"research-project-max-duration",children:n("settings.researchProject.maxDurationMsHint","Default: 300000 (5 minutes).")})]}),e.jsx("input",{id:"research-project-max-duration",className:"input",type:"number",min:1e3,value:c?.maxDurationMs??3e5,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},maxDurationMs:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-request-timeout",children:n("settings.researchProject.requestTimeoutMs","Request Timeout (ms)")}),e.jsx(B,{settingKey:"research-project-request-timeout",children:n("settings.researchProject.requestTimeoutMsHint","Default: 30000 (30 seconds).")})]}),e.jsx("input",{id:"research-project-request-timeout",className:"input",type:"number",min:1e3,value:c?.requestTimeoutMs??3e4,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},requestTimeoutMs:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),a&&e.jsx("small",{className:"field-error settings-research-limits-error",children:a})]})})]})}function cp({form:t,setForm:s,globalSettings:a,projectId:n,addToast:c}){const{t:d}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:d("settings.nav.mcp","MCP Servers")}),e.jsx(Tr,{scope:"project",form:t,setForm:s,globalSettings:a,projectId:n,addToast:c})]})}function dp({form:t,setForm:s}){const{t:a}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.backups.memoryBackups","Memory Backups")}),e.jsx(se,{descriptor:{key:"memoryBackupEnabled",label:a("settings.backups.enableAutomaticMemoryBackups"," Enable automatic memory backups "),help:a("settings.backups.whenEnabledProjectAndAgentMemoryFilesAre","When enabled, project and agent memory files are backed up automatically on a schedule. Default: disabled."),scope:"project"},value:t.memoryBackupEnabled||!1,onChange:n=>s(c=>({...c,memoryBackupEnabled:n===!0}))}),e.jsx(de,{descriptor:{key:"memoryBackupSchedule",label:a("settings.backups.memoryBackupScheduleCron","Memory Backup Schedule (Cron)"),help:a("settings.backups.cronExpressionForMemoryBackupTimingDefault0","Cron expression for memory backup timing. Default: 0 3 * * * (daily at 3 AM)."),scope:"project",placeholder:a("settings.backups.03","0 3 * * *"),disabled:!t.memoryBackupEnabled},value:t.memoryBackupSchedule||"0 3 * * *",onChange:n=>s(c=>({...c,memoryBackupSchedule:n??""})),error:t.memoryBackupSchedule&&!/^[\s\d*,/-]+$/.test(t.memoryBackupSchedule)?a("settings.backups.invalidCronExpressionFormat","Invalid cron expression format"):void 0}),e.jsx(ye,{descriptor:{key:"memoryBackupRetention",label:a("settings.backups.memoryRetentionCount","Memory Retention Count"),help:a("settings.backups.numberOfMemoryBackupsToKeepOldestAre","Number of memory backups to keep (oldest are deleted first). Range: 1-100. Default: 14."),scope:"project",min:1,max:100,disabled:!t.memoryBackupEnabled},value:t.memoryBackupRetention??null,onChange:n=>s(c=>({...c,memoryBackupRetention:n??void 0})),error:t.memoryBackupRetention!==void 0&&(t.memoryBackupRetention<1||t.memoryBackupRetention>100)?a("settings.backups.mustBeBetween1And100","Must be between 1 and 100"):void 0}),e.jsx(de,{descriptor:{key:"memoryBackupDir",label:a("settings.backups.memoryBackupDirectory","Memory Backup Directory"),help:a("settings.backups.directoryForMemoryBackupsRelativeToProjectRoot","Directory for memory backups, relative to project root. Default: .fusion/backups/memory."),scope:"project",placeholder:a("settings.backups.fusionBackupsMemory",".fusion/backups/memory"),disabled:!t.memoryBackupEnabled},value:t.memoryBackupDir||".fusion/backups/memory",onChange:n=>s(c=>({...c,memoryBackupDir:n??""})),error:t.memoryBackupDir&&t.memoryBackupDir.includes("..")?a("settings.backups.pathCannotContainParentDirectoryTraversal","Path cannot contain parent directory traversal (..)"):void 0}),e.jsx(ke,{descriptor:{key:"memoryBackupScope",label:a("settings.backups.memoryBackupScope","Memory Backup Scope"),help:a("settings.backups.memoryBackupScopeHint","Default: all (project + agents)."),scope:"project",disabled:!t.memoryBackupEnabled,options:[{value:"all",label:a("settings.backups.allProjectAgents","All (project + agents)")},{value:"project",label:a("settings.backups.projectOnlyFusionMemory","Project only (.fusion/memory)")},{value:"agents",label:a("settings.backups.agentsOnlyFusionAgentMemory","Agents only (.fusion/agent-memory)")}]},value:t.memoryBackupScope||"all",onChange:n=>s(c=>({...c,memoryBackupScope:n??"all"}))})]})}function up({form:t,setForm:s,backupInfo:a,backupLoading:n,onBackupNow:c}){const{t:d}=te("app"),i=t.backupSettingsMigrationConflicts??[],u=(l,h)=>{s(p=>({...p,[l.key]:h.value,backupSettingsMigrationConflicts:i.filter(b=>b.key!==l.key)}))};return e.jsxs(e.Fragment,{children:[i.length>0&&e.jsxs("div",{className:"settings-notice settings-notice-warning",role:"status",children:[e.jsx("strong",{children:d("settings.backups.migrationConflict","Choose database backup settings")}),e.jsx("p",{children:d("settings.backups.migrationConflictHelp","Existing projects used different backup settings. Choose the value to use globally.")}),i.map(l=>e.jsxs("div",{children:[e.jsx("span",{children:l.key}),l.candidates.map((h,p)=>e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>u(l,h),children:h.source==="global"?d("settings.backups.existingGlobalValue","Existing global value"):`${d("settings.backups.projectValue","Project value")}: ${h.projectId}`},`${h.source}-${h.projectId??"global"}-${p}`))]},l.key))]}),e.jsx("h4",{className:"settings-section-heading",children:d("settings.backups.databaseBackups","Database Backups")}),e.jsx(se,{descriptor:{key:"autoBackupEnabled",label:d("settings.backups.enableAutomaticDatabaseBackups"," Enable automatic database backups "),help:d("settings.backups.whenEnabledTheDatabaseIsBackedUpAutomatically","When enabled, the database is backed up automatically on a schedule. Default: disabled."),scope:"global"},value:t.autoBackupEnabled||!1,onChange:l=>s(h=>({...h,autoBackupEnabled:l===!0}))}),e.jsx(de,{descriptor:{key:"autoBackupSchedule",label:d("settings.backups.backupScheduleCron","Backup Schedule (Cron)"),help:d("settings.backups.cronExpressionForBackupTimingDefault02"," Cron expression for backup timing. Default: 0 2 * * * (daily at 2 AM). Examples: 0 * * * * (hourly), 0 0 * * 0 (weekly), */15 * * * * (every 15 min) "),scope:"global",placeholder:d("settings.backups.02","0 2 * * *"),disabled:!t.autoBackupEnabled},value:t.autoBackupSchedule||"0 2 * * *",onChange:l=>s(h=>({...h,autoBackupSchedule:l??""})),error:t.autoBackupSchedule&&!/^[\s\d*,/-]+$/.test(t.autoBackupSchedule)?d("settings.backups.invalidCronExpressionFormat","Invalid cron expression format"):void 0}),e.jsx(ye,{descriptor:{key:"autoBackupRetention",label:d("settings.backups.retentionCount","Retention Count"),help:d("settings.backups.numberOfBackupFilesToKeepOldestAre","Number of backup files to keep (oldest are deleted first). Range: 1-100. Default: 7."),scope:"global",min:1,max:100,disabled:!t.autoBackupEnabled},value:t.autoBackupRetention??null,onChange:l=>s(h=>({...h,autoBackupRetention:l??void 0})),error:t.autoBackupRetention!==void 0&&(t.autoBackupRetention<1||t.autoBackupRetention>100)?d("settings.backups.mustBeBetween1And100","Must be between 1 and 100"):void 0}),e.jsx(de,{descriptor:{key:"autoBackupDir",label:d("settings.backups.backupDirectory","Backup Directory"),help:d("settings.backups.directoryForBackupFilesRelativeToProjectRoot","Directory for backup files, relative to the global Fusion directory. Default: .fusion/backups."),scope:"global",placeholder:d("settings.backups.fusionBackups",".fusion/backups"),disabled:!t.autoBackupEnabled},value:t.autoBackupDir||".fusion/backups",onChange:l=>s(h=>({...h,autoBackupDir:l??""})),error:t.autoBackupDir&&t.autoBackupDir.includes("..")?d("settings.backups.pathCannotContainParentDirectoryTraversal","Path cannot contain parent directory traversal (..)"):void 0}),n?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:d("settings.backups.loadingBackupInfo","Loading backup info…")})}):a?e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:d("settings.backups.currentBackups","Current Backups")}),e.jsxs("div",{className:"backup-stats",children:[e.jsxs("div",{className:"backup-stat",children:[e.jsx("span",{className:"backup-stat-value",children:a.count}),e.jsx("span",{className:"backup-stat-label",children:d("settings.backups.backups","backups")})]}),e.jsxs("div",{className:"backup-stat",children:[e.jsx("span",{className:"backup-stat-value",children:a.totalSize>1024*1024?`${(a.totalSize/(1024*1024)).toFixed(1)} MB`:`${(a.totalSize/1024).toFixed(1)} KB`}),e.jsx("span",{className:"backup-stat-label",children:d("settings.backups.totalSize","total size")})]})]}),a.backups.length>0&&e.jsxs("details",{className:"backup-list",children:[e.jsxs("summary",{children:[d("settings.backups.view","View "),a.backups.length,d("settings.backups.backupS"," backup(s)")]}),e.jsxs("ul",{children:[a.backups.slice(0,10).map(l=>e.jsxs("li",{children:[e.jsx("code",{children:l.filename}),e.jsx("span",{className:"backup-size",children:l.size>1024*1024?`${(l.size/(1024*1024)).toFixed(1)} MB`:`${(l.size/1024).toFixed(1)} KB`})]},l.filename)),a.backups.length>10&&e.jsx("li",{children:e.jsxs("em",{children:[d("settings.backups.and","...and "),a.backups.length-10,d("settings.backups.more"," more")]})})]})]})]}):null,e.jsx("div",{className:"form-group",children:e.jsx("button",{type:"button",className:"btn btn-sm",onClick:c,disabled:n,children:n?d("settings.backups.creating","Creating…"):d("settings.backups.backupNow","Backup Now")})})]})}const gp=o.lazy(()=>vr(()=>import("./PluginManager-reQpowmU.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13])).then(t=>({default:t.PluginManager}))),pp=o.lazy(()=>vr(()=>import("./PiExtensionsManager-Di3Q9J6V.js"),__vite__mapDeps([14,1,2,3,4,5,6,7,8,9,15,16,17,18])).then(t=>({default:t.PiExtensionsManager})));function hp({projectId:t,addToast:s,activePluginsSubsection:a,setActivePluginsSubsection:n}){const{t:c}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:c("settings.plugins.plugins","Plugins")}),e.jsxs("div",{className:"settings-plugins-subsection-toggle",role:"tablist","aria-label":c("settings.plugins.pluginManagerType","Plugin manager type"),children:[e.jsx("button",{type:"button",id:"plugins-tab-fusion-plugins",role:"tab","aria-controls":"plugins-panel-fusion-plugins","aria-selected":a==="fusion-plugins",tabIndex:a==="fusion-plugins"?0:-1,className:`settings-plugins-subsection-btn${a==="fusion-plugins"?" active":""}`,onClick:()=>n("fusion-plugins"),children:c("settings.plugins.fusionPlugins"," Fusion Plugins ")}),e.jsx("button",{type:"button",id:"plugins-tab-pi-extensions",role:"tab","aria-controls":"plugins-panel-pi-extensions","aria-selected":a==="pi-extensions",tabIndex:a==="pi-extensions"?0:-1,className:`settings-plugins-subsection-btn${a==="pi-extensions"?" active":""}`,onClick:()=>n("pi-extensions"),children:c("settings.plugins.piExtensions"," Pi Extensions ")})]}),e.jsx("div",{id:"plugins-panel-fusion-plugins",role:"tabpanel","aria-labelledby":"plugins-tab-fusion-plugins",className:"settings-plugins-subsection-panel",hidden:a!=="fusion-plugins",children:a==="fusion-plugins"&&e.jsxs(e.Fragment,{children:[e.jsx(o.Suspense,{fallback:null,children:e.jsx(gp,{addToast:s,projectId:t})}),e.jsx(dn,{slotId:"settings-section",projectId:t})]})}),e.jsx("div",{id:"plugins-panel-pi-extensions",role:"tabpanel","aria-labelledby":"plugins-tab-pi-extensions",className:"settings-plugins-subsection-panel",hidden:a!=="pi-extensions",children:a==="pi-extensions"&&e.jsx(o.Suspense,{fallback:null,children:e.jsx(pp,{addToast:s,projectId:t})})})]})}function tn(t,s){if(!s)return t;const a=t.includes("?")?"&":"?";return`${t}${a}projectId=${encodeURIComponent(s)}`}async function cr(t,s){const a=await fetch(t,{credentials:"same-origin",...s,headers:{"Content-Type":"application/json",...s?.headers??{}}}),n=await a.json();if(!a.ok)throw new Error(n.error??`Request failed (${a.status})`);return n}function mp(t,s){const a=s?.enabled===!0,[n,c]=o.useState({status:"missing"}),[d,i]=o.useState(!1),u=o.useCallback(async()=>{try{const h=await cr(tn("/api/worktrunk/status",t));return c(h),h}catch(h){const p={status:"failed",error:h instanceof Error?h.message:"Failed to load worktrunk status"};return c(p),p}},[t]);o.useEffect(()=>{a&&u()},[a,u]),o.useEffect(()=>nd(tn("/api/events",t),{events:{"approval:updated":()=>{n.pendingApprovalId&&u()},"approval:decided":()=>{n.pendingApprovalId&&u()}}}),[t,u,n.pendingApprovalId]);const l=o.useCallback(async()=>{i(!0),c(h=>({...h,status:"installing",error:void 0}));try{const h=await cr(tn("/api/worktrunk/install-request",t),{method:"POST",body:JSON.stringify({})});c({status:h.status,version:h.version,installPath:h.installPath,pendingApprovalId:h.pendingApprovalId??h.approvalRequestId,error:h.error})}catch(h){c({status:"failed",error:h instanceof Error?h.message:"Failed to request install"})}finally{i(!1)}},[t]);return{...n,refresh:u,requestInstall:l,requesting:d}}const bp=[{sectionId:"appearance",key:"openTasksInRightSidebar",labelKey:"settings.appearance.openTasksInRightSidebar",labelFallback:"Open tasks in the right sidebar",helpKey:"settings.appearance.openTasksInRightSidebarHelp",helpFallback:"When enabled, board task cards open detail in the right sidebar when it is available; mobile and hidden-sidebar states keep the full task panel. Default: disabled.",keywords:["dock","right dock","side panel"]},{sectionId:"appearance",key:"openMobileTasksInPopup",labelKey:"settings.appearance.openMobileTasksInPopup",labelFallback:"Open tasks as popups",helpKey:"settings.appearance.openMobileTasksInPopupHelp",helpFallback:"When enabled, ordinary board task-card, List row/card, and right-dock Tasks-list clicks open the existing movable task popup so the board or list remains visible. Deep-tab and other task opens keep their current behavior. Default: disabled.",keywords:["mobile","floating window","modal"]},{sectionId:"appearance",key:"taskPopupsBoardListOnly",labelKey:"settings.appearance.taskPopupsBoardListOnly",labelFallback:"Keep task popups on the view where they were opened",helpKey:"settings.appearance.taskPopupsBoardListOnlyHelp",helpFallback:"When enabled, each open task-detail popup appears only on the view where it was opened. Switching views hides it without closing; returning restores it in the same position. Default: enabled.",keywords:["popup view attachment","pin popup"]},{sectionId:"appearance",key:"showCostBadgeOnCards",labelKey:"settings.appearance.showCostBadgeOnCards",labelFallback:"Show cost badges on task cards",helpKey:"settings.appearance.showCostBadgeOnCardsHelp",helpFallback:"Default: disabled. When enabled, board cards show derived model cost next to execution time; unavailable pricing displays — and tasks without token usage show no badge.",keywords:["spend","price","tokens","usage"]},{sectionId:"appearance",key:"taskDetailChatFirst",labelKey:"settings.appearance.taskDetailChatFirst",labelFallback:"Open task details with Chat first",helpKey:"settings.appearance.taskDetailChatFirstHelp",helpFallback:"Off by default: task details list Activity first and omitted non-done opens land on Activity. Turn on to restore Chat-first order/default; explicit Chat links still work either way.",keywords:["activity first","default tab"]},{sectionId:"appearance",key:"sessionBannersHidden",labelKey:"settings.appearance.hideAISessionNotificationBanners",labelFallback:"Hide AI session notification banners",helpKey:"settings.appearance.suppressTheLdquoNeedsYourInputRdquoBanner",helpFallback:"Suppress the “needs your input” banner that appears when AI sessions are awaiting input or have failed.",keywords:["needs your input","toast","alert"]}],fp=[{sectionId:"backups",key:"memoryBackupEnabled",labelKey:"settings.backups.enableAutomaticMemoryBackups",labelFallback:" Enable automatic memory backups ",helpKey:"settings.backups.whenEnabledProjectAndAgentMemoryFilesAre",helpFallback:"When enabled, project and agent memory files are backed up automatically on a schedule. Default: disabled.",keywords:["snapshot","restore"]},{sectionId:"backups",key:"memoryBackupSchedule",labelKey:"settings.backups.memoryBackupScheduleCron",labelFallback:"Memory Backup Schedule (Cron)",helpKey:"settings.backups.cronExpressionForMemoryBackupTimingDefault0",helpFallback:"Cron expression for memory backup timing. Default: 0 3 * * * (daily at 3 AM).",keywords:["timing","frequency"]},{sectionId:"backups",key:"memoryBackupRetention",labelKey:"settings.backups.memoryRetentionCount",labelFallback:"Memory Retention Count",helpKey:"settings.backups.numberOfMemoryBackupsToKeepOldestAre",helpFallback:"Number of memory backups to keep (oldest are deleted first). Range: 1-100. Default: 14.",keywords:["how many","prune","rotation"]},{sectionId:"backups",key:"memoryBackupDir",labelKey:"settings.backups.memoryBackupDirectory",labelFallback:"Memory Backup Directory",helpKey:"settings.backups.directoryForMemoryBackupsRelativeToProjectRoot",helpFallback:"Directory for memory backups, relative to project root. Default: .fusion/backups/memory.",keywords:["location","folder","destination"]},{sectionId:"backups",key:"memoryBackupScope",labelKey:"settings.backups.memoryBackupScope",labelFallback:"Memory Backup Scope",helpKey:"settings.backups.memoryBackupScopeHint",helpFallback:"Default: all (project + agents).",keywords:["agent memory",".fusion/memory",".fusion/agent-memory","what to back up"]}],yp=[{sectionId:"backups-global",key:"autoBackupEnabled",labelKey:"settings.backups.enableAutomaticDatabaseBackups",labelFallback:" Enable automatic database backups ",helpKey:"settings.backups.whenEnabledTheDatabaseIsBackedUpAutomatically",helpFallback:"When enabled, the database is backed up automatically on a schedule. Default: disabled.",keywords:["sqlite","snapshot","restore"]},{sectionId:"backups-global",key:"autoBackupSchedule",labelKey:"settings.backups.backupScheduleCron",labelFallback:"Backup Schedule (Cron)",helpKey:"settings.backups.cronExpressionForBackupTimingDefault02",helpFallback:" Cron expression for backup timing. Default: 0 2 * * * (daily at 2 AM). Examples: 0 * * * * (hourly), 0 0 * * 0 (weekly), */15 * * * * (every 15 min) ",keywords:["timing","frequency"]},{sectionId:"backups-global",key:"autoBackupRetention",labelKey:"settings.backups.retentionCount",labelFallback:"Retention Count",helpKey:"settings.backups.numberOfBackupFilesToKeepOldestAre",helpFallback:"Number of backup files to keep (oldest are deleted first). Range: 1-100. Default: 7.",keywords:["how many","prune","rotation"]},{sectionId:"backups-global",key:"autoBackupDir",labelKey:"settings.backups.backupDirectory",labelFallback:"Backup Directory",helpKey:"settings.backups.directoryForBackupFilesRelativeToProjectRoot",helpFallback:"Directory for backup files, relative to project root. Default: .fusion/backups.",keywords:["location","folder","destination"]}],kp=[{sectionId:"commands",key:"testCommand",labelKey:"settings.commands.testCommand",labelFallback:"Test Command",helpKey:"settings.commands.commandUsedToRunTestsInjectedIntoGenerated",helpFallback:"Command used to run tests — injected into generated task specs. No default — unset.",keywords:["verify","verification","vitest","pnpm test"]},{sectionId:"commands",key:"buildCommand",labelKey:"settings.commands.buildCommand",labelFallback:"Build Command",helpKey:"settings.commands.commandUsedToBuildTheProjectInjectedInto",helpFallback:"Command used to build the project — injected into generated task specs. No default — unset.",keywords:["compile","pnpm build"]}],vp=[{sectionId:"general",key:"taskPrefix",labelKey:"settings.general.taskPrefix",labelFallback:"Task Prefix",helpKey:"settings.general.prefixForNewTaskIDsEGKB",helpFallback:"Prefix for new task IDs (e.g. KB, PROJ). No default — unset.",keywords:["task id","identifier","naming"]},{sectionId:"general",key:"ephemeralAgentsCanCreateTasks",labelKey:"settings.general.allowEphemeralAgentsToCreateTasks",labelFallback:" Allow ephemeral agents to create tasks ",helpKey:"settings.general.allowEphemeralAgentsToCreateTasksHint",helpFallback:"When enabled (default), ephemeral task-worker agents can open follow-up tasks via fn_task_create. When disabled, only humans and permanent agents can create tasks; ephemeral callers are rejected.",keywords:["follow-up","permissions"]},{sectionId:"general",key:"workspaceMode",labelKey:"settings.general.workspaceMode",labelFallback:" Workspace mode (multi-repo) ",helpKey:"settings.general.workspaceModeHint",helpFallback:"When enabled, the project root is treated as a workspace containing multiple git sub-repos. Tasks run per-sub-repo and no git repo is created at the root. Disable for single-repo projects. No default — unset (disabled).",keywords:["monorepo","polyrepo"]},{sectionId:"general",key:"allowAbsoluteFileBrowserPaths",labelKey:"settings.general.allowAbsoluteFileBrowserPaths",labelFallback:" Allow absolute file-browser paths ",helpKey:"settings.general.allowAbsoluteFileBrowserPathsHint",helpFallback:"When enabled, slash-prefixed paths such as /tmp can be opened in the workspace file browser. Windows drive-letter paths remain blocked, and other path validators are unchanged. Default: disabled.",keywords:["outside workspace","root paths"]},{sectionId:"general",key:"mobileNavPrimaryItems",labelKey:"settings.general.mobileNavPrimaryItems",labelFallback:"Mobile footer quick actions",helpKey:"settings.general.mobileNavPrimaryItemsHint",helpFallback:"Default: Dashboard, Tasks, Agents, Missions, Chat, Mailbox. Unselected destinations remain in More.",keywords:["mobile","footer","navigation","planning","more"]},{sectionId:"general",key:"quickChatButtonMode",labelKey:"settings.general.quickChatLauncher",labelFallback:"Quick Chat launcher",helpKey:"settings.general.quickChatLauncherHint",helpFallback:"Choose whether Quick Chat opens from the draggable floating button, a footer button beside Terminal, or stays hidden. Default: off (hidden).",keywords:["FAB","floating action button"]},{sectionId:"general",key:"quickChatCloseOnOutsideClick",labelKey:"settings.general.quickChatCloseOnOutsideClick",labelFallback:"Close Quick Chat on outside click",helpKey:"settings.general.quickChatCloseOnOutsideClickHint",helpFallback:"When enabled, clicking outside the Quick Chat window closes it. Disable to keep it open until you close it explicitly. Default: enabled.",keywords:["dismiss","backdrop"]},{sectionId:"general",key:"showTaskChatsInCommonFeed",labelKey:"settings.general.showTaskChatsInCommonFeed",labelFallback:"Show task chats in common Chat feed",helpKey:"settings.general.showTaskChatsInCommonFeedHint",helpFallback:"When enabled, populated task-detail Chat conversations appear in the common Direct feed. Empty task chats stay hidden. Default: disabled.",keywords:["planner chats","inbox"]},{sectionId:"general",key:"chatAutoCleanupDays",labelKey:"settings.general.autoCleanupOldChats",labelFallback:"Auto-cleanup old chats",helpKey:"settings.general.deleteChatSessionsAndRoomsThatHaveBeen",helpFallback:"Delete chat sessions and rooms that have been idle for this many days. Default: Off.",keywords:["retention","prune","purge"]},{sectionId:"general",key:"mailAutoCleanupDays",labelKey:"settings.general.autoPruneOldMail",labelFallback:"Auto-prune old mail",helpKey:"settings.general.deleteInboxOutboxMessagesOlderThanThisMany",helpFallback:"Delete inbox/outbox messages older than this many days. Default: Off. 7 days is the suggested setting.",keywords:["retention","purge","mailbox"]},{sectionId:"general",key:"operationalLogRetentionDays",labelKey:"settings.general.operationalLogRetention",labelFallback:"Operational log retention",helpKey:"settings.general.loweringThisWindowMeansReliabilityMetricsChartsAnd",helpFallback:" Lowering this window means Reliability metrics/charts and the Activity feed will not show history older than the selected range. Per-task task detail history is unaffected. Default: 30 days. ",keywords:["run audit","database size","purge","disk"]},{sectionId:"general",key:"chatRoomRecentVerbatimMessages",labelKey:"settings.general.recentVerbatimRoomMessages",labelFallback:"Recent verbatim room messages",helpKey:"settings.general.numberOfMostRecentChatRoomMessagesKept",helpFallback:"Number of most-recent chat-room messages kept verbatim in the responder transcript. Older messages are compacted into a summary block. Default: 25.",keywords:["context window","history depth"]},{sectionId:"general",key:"chatRoomCompactionFetchLimit",labelKey:"settings.general.roomCompactionFetchLimit",labelFallback:"Room compaction fetch limit",helpKey:"settings.general.upperBoundOnMessagesFetchedFromTheRoom",helpFallback:"Upper bound on messages fetched from the room store for compaction consideration. Default: 200.",keywords:["summarization","context window"]},{sectionId:"general",key:"chatRoomSummaryMaxChars",labelKey:"settings.general.roomSummaryMaxCharacters",labelFallback:"Room summary max characters",helpKey:"settings.general.hardCapOnTheSynthesizedEarlierRoomContext",helpFallback:'Hard cap on the synthesized "Earlier room context" summary block. Default: 3000.',keywords:["compaction","length limit"]},{sectionId:"general",key:"capacityRiskBannerEnabled",labelKey:"settings.general.showCapacityRiskBanner",labelFallback:" Show capacity risk banner ",helpKey:"settings.general.warnOnTheBoardWhenTodoWorkExceeds",helpFallback:"Warn on the board when todo work exceeds the threshold and no idle agents are available. Default: disabled.",keywords:["backlog warning","overload","alert"]},{sectionId:"general",key:"capacityRiskTodoThreshold",labelKey:"settings.general.todoThreshold",labelFallback:"Todo threshold",helpKey:"settings.general.bannerFiresWhenTodoCountIsStrictlyGreater",helpFallback:"Banner fires when todo count is strictly greater than this value (default 20). Applies when the banner is enabled.",keywords:["capacity risk","backlog limit"]},{sectionId:"general",key:"sessionAdvisorEnabledByDefault",labelKey:"settings.general.defaultSessionAdvisorForNewTasks",labelFallback:"Default for new tasks",helpKey:"settings.general.sessionAdvisorHelp",helpFallback:"Controls whether newly created tasks enable the session advisor (live LLM overseer of the executor). Individual tasks can override this from Quick Add or task detail. Also set Session advisor model provider and model id under workflow settings before the advisor can run.",keywords:["session advisor","overseer","oversight","planner"]},{sectionId:"general",key:"githubImportAutoTranslate",labelKey:"settings.general.autoTranslateImportedIssues",labelFallback:"Auto-translate imported issues",helpKey:"settings.general.autoTranslateImportedIssuesHelp",helpFallback:"When enabled, the Import Tasks panel automatically translates foreign-language issue titles and bodies into the target language below and shows the translation by default. You can always switch back to the original text, and imported tasks carry the translated text. Default: disabled.",keywords:["localization","foreign language"]},{sectionId:"general",key:"importTranslateTargetLocale",labelKey:"settings.general.translationTargetLanguage",labelFallback:"Translation target language",helpKey:"settings.general.translationTargetLanguageHelp",helpFallback:"Language imported issues are translated into when auto-translation is enabled. No default — unset inherits the dashboard language.",keywords:["locale","localization"]}],xp=[{sectionId:"global-general",key:"dismissModalsOnOutsideClick",labelKey:"settings.globalGeneral.dismissModalsByClickingOutside",labelFallback:" Dismiss modals by clicking outside ",helpKey:"settings.globalGeneral.dismissModalsByClickingOutsideHint",helpFallback:" When enabled, clicking or tapping a modal backdrop closes the modal. Default: disabled, to prevent accidental dismissal. ",keywords:["dialog","backdrop","accidental close"]},{sectionId:"global-general",key:"skipConfirmationDialogs",labelKey:"settings.globalGeneral.skipConfirmationDialogs",labelFallback:" Skip confirmation dialogs for critical actions ",helpKey:"settings.globalGeneral.skipConfirmationDialogsHint",helpFallback:" When enabled, destructive actions such as deleting a task or resetting progress run immediately without a prompt. Default: disabled",keywords:["confirm","critical action","delete","reset","destructive"]},{sectionId:"global-general",key:"persistAgentToolOutput",labelKey:"settings.globalGeneral.saveToolOutputInAgentLogs",labelFallback:" Save tool output in agent logs ",helpKey:"settings.globalGeneral.whenDisabledToolRowsAreStillLoggedBut",helpFallback:" When disabled, tool rows are still logged but detailed tool payloads are omitted. Very large tool payloads may still be clipped even when this stays enabled. Default: disabled. ",keywords:["persist","transcript","disk usage"]},{sectionId:"global-general",key:"updateCheckFrequency",labelKey:"settings.globalGeneral.frequency",labelFallback:"Frequency",helpKey:"settings.globalGeneral.controlsHowOftenTheDashboardReFetchesThe",helpFallback:" Controls how often the dashboard re-fetches the npm registry. Use the version + refresh control in the header to trigger an immediate check at any time. Default: daily. ",keywords:["update check","cadence","how often","version check"]},{sectionId:"global-general",key:"autoReloadOnVersionChange",labelKey:"settings.globalGeneral.autoReloadDashboardOnVersionChange",labelFallback:" Auto-reload dashboard on version change ",helpKey:"settings.globalGeneral.whenEnabledDefaultTheDashboardAutomaticallyReloadsWhen",helpFallback:" When enabled (default), the dashboard automatically reloads when it detects a new build version — either from server rebuilds or service worker updates. Disable this to stay on the current version until you manually refresh. Default: enabled. ",keywords:["refresh","service worker","hot reload"]}],jp=[{sectionId:"global-models",key:"defaultThinkingLevel",labelKey:"settings.globalModels.thinkingEffort",labelFallback:"Thinking Effort",helpKey:"settings.globalModels.controlsHowMuchReasoningEffortTheAIModel",helpFallback:"Controls how much reasoning effort the AI model uses. Higher levels produce better results but cost more. No default — unset (model's own default effort applies).",keywords:["high","low","medium","xhigh","extended thinking"]},{sectionId:"global-models",key:"openrouterModelSync",labelKey:"settings.globalModels.syncOpenRouterModelListAtStartup",labelFallback:" Sync OpenRouter model list at startup ",helpKey:"settings.globalModels.whenEnabledStartupFetchesTheLatestAvailableModels",helpFallback:" When enabled, startup fetches the latest available models from the OpenRouter API so model pickers always include the newest catalog. Default: enabled. ",keywords:["refresh","boot"]},{sectionId:"global-models",key:"openrouterAppAttribution.referer",labelKey:"settings.globalModels.openRouterHTTPReferer",labelFallback:"OpenRouter HTTP-Referer",helpKey:"settings.globalModels.leaveEmptyToOmitThisHeaderDefaultHttps",helpFallback:"Leave empty to omit this header. No default — unset (Fusion falls back to https://runfusion.ai when unset).",keywords:["attribution","app ranking"]},{sectionId:"global-models",key:"openrouterAppAttribution.title",labelKey:"settings.globalModels.openRouterXTitle",labelFallback:"OpenRouter X-Title",helpKey:"settings.globalModels.leaveEmptyToOmitThisHeaderDefaultFusion",helpFallback:'Leave empty to omit this header. No default — unset (Fusion falls back to the title "Fusion" when unset).',keywords:["attribution","app ranking"]},{sectionId:"global-models",key:"openrouterModelFilters.supported_parameters",labelKey:"settings.globalModels.openRouterSupportedParametersFilter",labelFallback:"OpenRouter supported_parameters filter",helpKey:"settings.globalModels.commaSeparatedValuesSentToOpenRouterModelSync",helpFallback:"Comma-separated values sent to OpenRouter model sync. No default — unset (unfiltered).",keywords:["tools","structured outputs","catalog filter"]},{sectionId:"global-models",key:"openrouterModelFilters.output_modalities",labelKey:"settings.globalModels.openRouterOutputModalitiesFilter",labelFallback:"OpenRouter output_modalities filter",helpKey:"settings.globalModels.commaSeparatedValuesSentToOpenRouterModelSyncOutputModalities",helpFallback:"Comma-separated values sent to OpenRouter model sync. No default — unset (unfiltered).",keywords:["text","image","catalog filter"]},{sectionId:"global-models",key:"openrouterProviderPreferences.order",labelKey:"settings.globalModels.openRouterRoutingOrder",labelFallback:"OpenRouter routing order",helpKey:"settings.globalModels.openRouterRoutingOrderHint",helpFallback:"No default — unset (OpenRouter's own default routing order applies).",keywords:["provider preference","priority"]},{sectionId:"global-models",key:"openrouterProviderPreferences.ignore",labelKey:"settings.globalModels.openRouterRoutingIgnore",labelFallback:"OpenRouter routing ignore",helpKey:"settings.globalModels.openRouterRoutingIgnoreHint",helpFallback:"No default — unset (no providers ignored).",keywords:["exclude","block","deny provider"]},{sectionId:"global-models",key:"openrouterProviderPreferences.only",labelKey:"settings.globalModels.openRouterRoutingOnly",labelFallback:"OpenRouter routing only",helpKey:"settings.globalModels.openRouterRoutingOnlyHint",helpFallback:"No default — unset (no provider restriction).",keywords:["allowlist","restrict","pin provider"]},{sectionId:"global-models",key:"openrouterProviderPreferences.allow_fallbacks",labelKey:"settings.globalModels.openRouterAllowFallbacks",labelFallback:"OpenRouter allow fallbacks",helpKey:"settings.globalModels.openRouterAllowFallbacksHint",helpFallback:"No default — unset (OpenRouter's own default fallback behavior applies).",keywords:["backup provider","failover"]},{sectionId:"global-models",key:"openrouterProviderPreferences.sort",labelKey:"settings.globalModels.openRouterRoutingSort",labelFallback:"OpenRouter routing sort",helpKey:"settings.globalModels.openRouterRoutingSortHint",helpFallback:"No default — unset (OpenRouter's own default sort applies).",keywords:["price","throughput","latency","cheapest","fastest"]},{sectionId:"global-models",key:"openrouterProviderPreferences.require_parameters",labelKey:"settings.globalModels.requireParameters",labelFallback:" Require parameters ",helpKey:"settings.globalModels.requireParametersHint",helpFallback:"Default: disabled.",keywords:["strict routing","provider support"]}],wp=[{sectionId:"memory",key:"memoryEnabled",labelKey:"settings.memory.enableMemoryTools",labelFallback:" Enable memory tools ",helpKey:"settings.memory.agentsGetMemorySearchMemoryGetAndMemory",helpFallback:"Agents get memory_search, memory_get, and memory_append tools. Search defaults to qmd with a local file fallback. Default: enabled.",keywords:["recall","knowledge"]},{sectionId:"memory",key:"memoryAutoSummarizeEnabled",labelKey:"settings.memory.autoSummarizeMemory",labelFallback:" Auto-Summarize Memory ",helpKey:"settings.memory.automaticallyCompactMemoryWhenItExceedsTheThreshold",helpFallback:"Automatically compact memory when it exceeds the threshold on a schedule. Default: disabled.",keywords:["condense","prune","shrink"]},{sectionId:"memory",key:"memoryAutoSummarizeThresholdChars",labelKey:"settings.memory.compactionThresholdChars",labelFallback:"Compaction Threshold (chars)",helpKey:"settings.memory.memoryWillBeCompactedWhenItExceedsThis",helpFallback:"Memory will be compacted when it exceeds this character count. Default: 50000.",keywords:["size limit","trigger"]},{sectionId:"memory",key:"memoryAutoSummarizeSchedule",labelKey:"settings.memory.scheduleCron",labelFallback:"Schedule (cron)",helpKey:"settings.memory.cronExpressionForAutoSummarizeScheduleDefaultDaily",helpFallback:"Cron expression for auto-summarize schedule. Default: 0 3 * * * (daily at 3 AM).",keywords:["auto-summarize","compaction schedule","timing"]},{sectionId:"memory",key:"insightExtractionEnabled",labelKey:"settings.memory.enableInsightExtraction",labelFallback:" Enable Insight Extraction ",helpKey:"settings.memory.periodicallyExtractDurableInsightsFromCompletedTasks",helpFallback:"Periodically extract durable insights/learnings from completed tasks into memory",keywords:["lessons","retrospective"]},{sectionId:"memory",key:"insightExtractionSchedule",labelKey:"settings.memory.scheduleCron",labelFallback:"Schedule (cron)",helpKey:"settings.memory.cronExpressionForInsightExtractionScheduleDefaultDaily",helpFallback:"Cron expression for insight extraction schedule (default: daily at 2 AM)",keywords:["insight","timing"]},{sectionId:"memory",key:"memoryDreamsEnabled",labelKey:"settings.memory.processDreamsFromDailyMemory",labelFallback:" Process dreams from daily memory ",helpKey:"settings.memory.turnsDailyNotesIntoDREAMSMdAndPromotes",helpFallback:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md. Default: disabled.",keywords:["synthesis","consolidation"]},{sectionId:"memory",key:"memoryDreamsSchedule",labelKey:"settings.memory.dreamSchedule",labelFallback:"Dream Schedule",helpKey:"settings.memory.cronExpressionForDreamProcessing",helpFallback:"Cron expression for dream processing. Default: 0 4 * * * (daily at 4 AM).",keywords:["timing"]}],Cp=[{sectionId:"merge",key:"maxAutoMergeRetries",labelKey:"settings.merge.autoMergeConflictRetries",labelFallback:"Auto-merge conflict retries",helpKey:"settings.merge.positiveIntegerRetryCapForAutoMergeConflict",helpFallback:"Positive integer retry cap for auto-merge conflict resolution before a task parks for human recovery. Default 3.",keywords:["attempts","give up","parked","merge failure"]},{sectionId:"merge",key:"merger.maxReviewPasses",labelKey:"settings.merge.maxAIReviewPasses",labelFallback:"Max AI review passes",helpKey:"settings.merge.aICorrectiveRoundsBeforeLandingTheBestResult",helpFallback:"AI corrective rounds before landing the best result (advisory concern) or hard-failing (unfixable correctness concern). Default 3. The reviewer uses your project's reviewer/validator model.",keywords:["clean room","audit","retries","attempts"]},{sectionId:"merge",key:"mergeStrategyOverlapBehavior",labelKey:"settings.merge.smartPreferMainOverlapGuard",labelFallback:"Smart Prefer Main Overlap Guard",helpKey:"settings.merge.whenUsingSmartPreferMainAutomaticallyPreferThe",helpFallback:" When using smart-prefer-main, automatically prefer the branch side for files that main has recently modified to avoid silently discarding branch work. ",keywords:["ours","theirs","lost work","clobber"]}],Sp=[{sectionId:"node-routing",key:"unavailableNodePolicy",labelKey:"settings.nodeRouting.unavailableNodePolicy",labelFallback:"Unavailable Node Policy",helpKey:"settings.nodeRouting.unavailableNodePolicyHint",helpFallback:"Default: block execution.",keywords:["offline node","fallback","unreachable","local execution"]}],Np=[{sectionId:"node-sync",key:"settingsSyncEnabled",labelKey:"settings.nodeSync.enableAutomaticSettingsSync",labelFallback:" Enable automatic settings sync ",helpKey:"settings.nodeSync.automaticallySynchronizeSettingsBetweenThisNodeAndConnected",helpFallback:"Automatically synchronize settings between this node and connected remote nodes. Default: disabled."},{sectionId:"node-sync",key:"settingsSyncAuth",labelKey:"settings.nodeSync.syncModelAuthCredentials",labelFallback:" Sync model auth credentials ",helpKey:"settings.nodeSync.includeAPIKeysAndOAuthTokensInSync",helpFallback:"Include API keys and OAuth tokens in sync operations. Default: disabled.",keywords:["secrets","authentication"]},{sectionId:"node-sync",key:"settingsSyncInterval",labelKey:"settings.nodeSync.syncInterval",labelFallback:"Sync interval",helpKey:"settings.nodeSync.syncIntervalHint",helpFallback:"Default: every 15 minutes.",keywords:["frequency","how often","schedule"]},{sectionId:"node-sync",key:"settingsSyncConflictResolution",labelKey:"settings.nodeSync.conflictResolution",labelFallback:"Conflict resolution",helpKey:"settings.nodeSync.conflictResolutionHint",helpFallback:"Default: last write wins."}],Pp=[{sectionId:"notifications",key:"failureNotificationMode",labelKey:"settings.notifications.failureNotificationMode",labelFallback:"Failure notification mode",helpKey:"settings.notifications.stickyOnlySuppressesRecoveredFailuresTerminalOnlyWaits",helpFallback:"Sticky-only suppresses recovered failures; terminal-only waits for paused/in-review failed tasks; all restores legacy alerts.",keywords:["retry","noise","alerts"]},{sectionId:"notifications",key:"failureNotificationDelayMs",labelKey:"settings.notifications.failureNotificationDelayMs",labelFallback:"Failure notification delay (ms)",helpKey:"settings.notifications.howLongAFailureMustPersistBeforeA",helpFallback:" How long a failure must persist before a push notification is sent. 0 = notify immediately. Default: 30000 (30 seconds). ",keywords:["debounce","wait","throttle"]},{sectionId:"notifications",key:"ntfyDashboardHost",labelKey:"settings.notifications.dashboardHostname",labelFallback:"Dashboard Hostname",helpKey:"settings.notifications.baseURLForDeepLinksInNotificationsWhen",helpFallback:" Base URL for deep links in notifications. When set, clicking a notification opens the dashboard directly to the task. No default — unset. ",keywords:["ntfy","deep link","base url"]},{sectionId:"notifications",key:"webhookUrl",labelKey:"settings.notifications.webhookURL",labelFallback:"Webhook URL",helpKey:"settings.notifications.webhookUrlHint",helpFallback:"No default — unset.",keywords:["endpoint","hook","callback"]},{sectionId:"notifications",key:"webhookFormat",labelKey:"settings.notifications.format",labelFallback:"Format",helpKey:"settings.notifications.webhookFormatHint",helpFallback:"Default: generic.",keywords:["slack","discord","payload","webhook"]},{sectionId:"notifications",key:"ntfyBaseUrl",labelKey:"settings.notifications.customNtfyServerURLOptional",labelFallback:"Custom ntfy server URL (optional)",helpKey:"settings.notifications.leaveBlankToKeepTheDefaultServerHttps",helpFallback:" Leave blank to keep the default server: https://ntfy.sh. Custom servers must use http:// or https://. No default — unset. ",keywords:["self-hosted","custom server"]},{sectionId:"notifications",key:"ntfyAccessToken",labelKey:"settings.notifications.accessTokenOptional",labelFallback:"Access token (optional)",helpKey:"settings.notifications.leaveBlankToPublishWithoutAuthenticationWhenSet",helpFallback:" Leave blank to publish without authentication. When set, Fusion sends an Authorization Bearer header with ntfy requests. No default — unset. ",keywords:["auth","bearer","credential","secret"]}],Tp=[{sectionId:"project-models",key:"tokenCap",labelKey:"settings.projectModels.tokenCap",labelFallback:"Token Cap",helpKey:"settings.projectModels.automaticallyCompactContextWhenApproachingThisTokenCount",helpFallback:"Automatically compact context when approaching this token count. Leave empty for no cap (compact only on overflow errors). Set a number to proactively compact when reaching this token count. No default — unset (no cap).",keywords:["context window","limit","budget"]},{sectionId:"project-models",key:"chatNewSessionMode",labelKey:"settings.projectModels.chatNewSessionMode",labelFallback:"New Chat behavior",helpKey:"settings.projectModels.chatNewSessionModeHelp",helpFallback:"Prompt mode opens New Chat with this default preselected. Always-default mode skips the dialog when the configured default is complete.",keywords:["direct chat","skip dialog"]},{sectionId:"project-models",key:"autoSelectModelPreset",labelKey:"settings.projectModels.autoSelectPresetBasedOnTaskSize",labelFallback:" Auto-select preset based on task size ",helpKey:"settings.projectModels.autoSelectModelPresetHint",helpFallback:"Default: disabled.",keywords:["small","medium","large","S M L"]},{sectionId:"project-models",key:"taskDefinitionInInputLanguage",labelKey:"settings.projectModels.taskDefinitionInInputLanguage",labelFallback:"Write task definitions in the operator's input language",helpKey:"settings.projectModels.taskDefinitionInInputLanguageHelp",helpFallback:"When enabled, generated task-definition prose uses supported detectable input languages (Spanish, French, Korean, or Chinese as zh-CN). Headings, markers, and code stay English. Unsupported or undetectable input stays English. Default: disabled.",keywords:["task definition","prompt language","localized prose","Spanish","French","Korean","Chinese"]},{sectionId:"project-models",key:"autoSummarizeTitles",labelKey:"settings.projectModels.autoSummarizeLongDescriptionsAsTitles",labelFallback:" Auto-summarize long descriptions as titles ",helpKey:"settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut",helpFallback:" When enabled, tasks created without a title but with descriptions over 200 characters will automatically get an AI-generated title (max 60 characters). The same model is also used to generate fallback merge commit message bodies when the branch's commit log is empty (e.g. squash merges with no unique commits), and GitHub tracking issue titles when a tracked task has no title yet. Default: disabled. "},{sectionId:"project-models",key:"useAiMergeCommitSummary",labelKey:"settings.projectModels.aIMergeCommitSummaries",labelFallback:" AI merge commit summaries ",helpKey:"settings.projectModels.whenEnabledMergeCommitMessagesIncludeAnAI",helpFallback:" When enabled, merge commit messages include an AI-generated subject plus body summary (narrative + bullets + diff-stat) instead of just listing step commit subjects. Uses the title summarization model. Default: enabled. "},{sectionId:"project-models",key:"prTitlePromptInstructions",labelKey:"settings.projectModels.prTitlePromptInstructions",labelFallback:"PR title prompt guidance",helpKey:"settings.projectModels.prTitlePromptInstructionsHelp",helpFallback:"Guides the AI-generated Create PR title. Leave blank to use the default PR metadata prompt. No default — unset.",keywords:["pull request","conventional commit"]},{sectionId:"project-models",key:"prDescriptionPromptInstructions",labelKey:"settings.projectModels.prDescriptionPromptInstructions",labelFallback:"PR description prompt guidance",helpKey:"settings.projectModels.prDescriptionPromptInstructionsHelp",helpFallback:"Guides the AI-generated Create PR summary, changes, and testing sections. Leave blank to use the default PR metadata prompt. No default — unset.",keywords:["pull request","body"]}],Ap=[{sectionId:"remote",key:"remoteTailscaleAcceptRoutes",labelKey:"settings.remote.acceptRoutes",labelFallback:" Accept routes ",helpKey:"settings.remote.acceptRoutesHint",helpFallback:"Default: disabled.",keywords:["tailscale","subnet","tailnet","funnel"]},{sectionId:"remote",key:"remoteShortLivedEnabled",labelKey:"settings.remote.enableShortLivedTokens",labelFallback:" Enable short-lived tokens ",helpKey:"settings.remote.shortLivedEnabledHint",helpFallback:"Default: disabled.",keywords:["expiring token","temporary access","auth link"]},{sectionId:"remote",key:"remoteShortLivedTtlMs",labelKey:"settings.remote.shortLivedTTLMs",labelFallback:"Short-lived TTL (ms)",helpKey:"settings.remote.shortLivedTtlMsHint",helpFallback:"Default: 900000 (15 minutes).",keywords:["expiry","lifetime","time to live","token duration"]},{sectionId:"remote",key:"remoteRememberLastRunning",labelKey:"settings.remote.rememberLastRunningState",labelFallback:" Remember last running state ",helpKey:"settings.remote.automaticallyRestoreTunnelOnStartupIfItWas",helpFallback:"Automatically restore tunnel on startup if it was running when last stopped. Default: disabled.",keywords:["cloudflared","autostart","reconnect","persist tunnel"]},{sectionId:"remote",key:"remoteCloudflareTunnelName",labelKey:"settings.remote.tunnelName",labelFallback:"Tunnel name",keywords:["cloudflare","named tunnel","cloudflared"]},{sectionId:"remote",key:"remoteCloudflareTunnelToken",labelKey:"settings.remote.tunnelToken",labelFallback:"Tunnel token",keywords:["cloudflare","named tunnel","credential","secret"]},{sectionId:"remote",key:"remoteCloudflareIngressUrl",labelKey:"settings.remote.ingressURL",labelFallback:"Ingress URL",keywords:["cloudflare","named tunnel","hostname","domain"]}],Mp=[{sectionId:"research-global",key:"researchGlobalWebSearchProvider",labelKey:"settings.researchGlobal.searchProvider",labelFallback:"Search Provider",keywords:["SearXNG","Brave","Google Custom Search","Tavily","external search providers","built-in"]},{sectionId:"research-global",key:"researchGlobalSearxngUrl",labelKey:"settings.researchGlobal.searXNGURL",labelFallback:"SearXNG URL",helpKey:"settings.researchGlobal.searXNGURLHint",helpFallback:"No default — unset.",keywords:["endpoint","instance","self-hosted"]},{sectionId:"research-global",key:"researchGlobalGoogleSearchCx",labelKey:"settings.researchGlobal.googleSearchCX",labelFallback:"Google Search CX",helpKey:"settings.researchGlobal.googleSearchCXHint",helpFallback:"No default — unset.",keywords:["custom search engine id","programmable search"]}],Ip=[{sectionId:"research-project",key:"researchSettings.enabled",labelKey:"settings.researchProject.enableResearchInThisProject",labelFallback:" Enable research in this project ",helpKey:"settings.researchProject.enableResearchInThisProjectHint",helpFallback:"Default: enabled.",keywords:["research","web search","citations","sources","turn off research"]}],Rp=[{sectionId:"scheduled-evals",key:"evalSettings.enabled",labelKey:"settings.scheduledEvals.enableScheduledEvalRunsForThisProject",labelFallback:" Enable scheduled eval runs for this project ",helpKey:"settings.scheduledEvals.enabledHint",helpFallback:"Default: disabled.",keywords:["evaluation","benchmark","quality"]},{sectionId:"scheduled-evals",key:"evalSettings.intervalMs",labelKey:"settings.scheduledEvals.intervalMs",labelFallback:"Interval (ms)",helpKey:"settings.scheduledEvals.intervalMsHint",helpFallback:"Default: 86400000 (24 hours).",keywords:["frequency","how often","schedule"]},{sectionId:"scheduled-evals",key:"evalSettings.evaluatorProvider",labelKey:"settings.scheduledEvals.evaluatorProvider",labelFallback:"Evaluator Provider",helpKey:"settings.scheduledEvals.evaluatorProviderHint",helpFallback:"No default — unset (inherits the project validator lane provider)."},{sectionId:"scheduled-evals",key:"evalSettings.evaluatorModelId",labelKey:"settings.scheduledEvals.evaluatorModel",labelFallback:"Evaluator Model",helpKey:"settings.scheduledEvals.leaveProviderAndModelBlankToInheritThe",helpFallback:" Leave provider and model blank to inherit the project validator lane model settings. No default — unset. "},{sectionId:"scheduled-evals",key:"evalSettings.followUpPolicy",labelKey:"settings.scheduledEvals.followUpPolicy",labelFallback:"Follow-up Policy",helpKey:"settings.scheduledEvals.followUpPolicyHint",helpFallback:"Default: suggest only.",keywords:["auto-create tasks","suggestions"]},{sectionId:"scheduled-evals",key:"evalSettings.retentionDays",labelKey:"settings.scheduledEvals.retentionDays",labelFallback:"Retention (days)",helpKey:"settings.scheduledEvals.retentionDaysHint",helpFallback:"Default: 30.",keywords:["prune","cleanup","history"]}],Ep=[{sectionId:"scheduling-global",key:"globalMaxConcurrent",labelKey:"settings.scheduling.globalMaxConcurrent",labelFallback:"Global Max Concurrent",helpKey:"settings.scheduling.maximumConcurrentAgentsAcrossAllProjects",helpFallback:"Maximum concurrent agents across all projects. Default: 4.",keywords:["parallelism","capacity","machine wide","cap"]}],Fp=[{sectionId:"scheduling",key:"maxConcurrent",labelKey:"settings.scheduling.maxConcurrentTasks",labelFallback:"Max Concurrent Tasks",helpKey:"settings.scheduling.maxConcurrentTasksHint",helpFallback:"Default: 2.",keywords:["parallelism","capacity","how many tasks at once","agents","cap"]},{sectionId:"scheduling",key:"maxConcurrentVerifications",labelKey:"settings.scheduling.maxConcurrentVerifications",labelFallback:"Max Concurrent Verifications",helpKey:"settings.scheduling.maxConcurrentVerificationsHint",helpFallback:"Caps stacked typecheck/build verification across tasks. Default: 1. Range: 1–8.",keywords:["parallelism","tests","cpu","load"]},{sectionId:"scheduling",key:"maxTriageConcurrent",labelKey:"settings.scheduling.maxTriageConcurrent",labelFallback:"Max Triage Concurrent",helpKey:"settings.scheduling.maximumConcurrentPlanningAgents",helpFallback:"Maximum concurrent planning agents. Default: 2.",keywords:["parallelism","capacity","spec"]},{sectionId:"scheduling",key:"executorToolFailureRetryCount",labelKey:"settings.scheduling.executorToolFailureRetryCount",labelFallback:"Executor tool-failure retries",helpKey:"settings.scheduling.executorToolFailureRetryCountHelp",helpFallback:"Same-model retries after consecutive tool-call failures. Set 0 to disable. Default: 2.",keywords:["executor","tool error","auto retry","same model","failure"]},{sectionId:"scheduling",key:"executorToolFailureRetryBackoffMs",labelKey:"settings.scheduling.executorToolFailureRetryBackoffMs",labelFallback:"Tool-failure retry backoff (ms)",helpKey:"settings.scheduling.executorToolFailureRetryBackoffMsHelp",helpFallback:"Unref'd wait before retrying. Default: 2000.",keywords:["executor","delay","wait","auto retry","tool error"]},{sectionId:"scheduling",key:"executorToolFailureThreshold",labelKey:"settings.scheduling.executorToolFailureThreshold",labelFallback:"Consecutive tool failures",helpKey:"settings.scheduling.executorToolFailureThresholdHelp",helpFallback:"Terminal tool errors required before retrying. Default: 3.",keywords:["executor","tool error","threshold","auto retry"]},{sectionId:"scheduling",key:"executorModelEscalationEnabled",labelKey:"settings.scheduling.executorModelEscalationEnabled",labelFallback:"Escalate after tool-failure retries",helpKey:"settings.scheduling.executorModelEscalationEnabledHelp",helpFallback:"After same-model retries are exhausted, try one configured alternate model or node. Disabled by default.",keywords:["executor","model","node","escalation","tool error"]},{sectionId:"scheduling",key:"executorEscalationProvider",labelKey:"settings.scheduling.executorEscalationProvider",labelFallback:"Escalation provider",helpKey:"settings.scheduling.executorEscalationProviderHelp",helpFallback:"Provider for the alternate model. Requires an alternate model ID.",keywords:["executor","model","provider","escalation"]},{sectionId:"scheduling",key:"executorEscalationModelId",labelKey:"settings.scheduling.executorEscalationModelId",labelFallback:"Escalation model ID",helpKey:"settings.scheduling.executorEscalationModelIdHelp",helpFallback:"Alternate model ID. Requires an escalation provider.",keywords:["executor","model","escalation"]},{sectionId:"scheduling",key:"executorEscalationNodeId",labelKey:"settings.scheduling.executorEscalationNodeId",labelFallback:"Escalation node ID",helpKey:"settings.scheduling.executorEscalationNodeIdHelp",helpFallback:"Optional configured node; a node target re-enters scheduler routing.",keywords:["executor","node","routing","escalation"]},{sectionId:"scheduling",key:"pollIntervalMs",labelKey:"settings.scheduling.pollIntervalMs",labelFallback:"Poll Interval (ms)",helpKey:"settings.scheduling.pollIntervalMsHint",helpFallback:"Default: 15000 (15 seconds).",keywords:["tick","engine loop","frequency","refresh"]},{sectionId:"scheduling",key:"heartbeatScopeDiscipline",labelKey:"settings.scheduling.heartbeatScopeDiscipline",labelFallback:"Heartbeat Scope Discipline",helpKey:"settings.scheduling.strictCoordinationFocusedHigherPerTickTokensLite",helpFallback:"Strict — coordination-focused; higher per-tick tokens. Lite — pre-2026-05-11 behavior. Off — minimal procedure.",keywords:["agent prompt","token cost"]},{sectionId:"scheduling",key:"engineerBacklogAutoClaim",labelKey:"settings.scheduling.letEngineerAgentsAutoClaimBacklogTasks",labelFallback:" Let engineer agents auto-claim backlog tasks ",helpKey:"settings.scheduling.backlogNoTaskAutoClaimIsExecutorOnly",helpFallback:"Backlog/no-task auto-claim is executor-only by default. Enable to let engineer-role agents auto-claim unowned backlog tasks; explicit routing and delegation are unchanged. Default: off.",keywords:["pick up work","unassigned","todo"]},{sectionId:"scheduling",key:"taskStuckTimeoutMs",labelKey:"settings.scheduling.stuckTaskTimeoutMinutes",labelFallback:"Stuck Task Timeout (minutes)",helpKey:"settings.scheduling.timeoutInMinutesForDetectingStuckTasksWhen",helpFallback:"Timeout in minutes for detecting stuck tasks. When a task's agent session shows no activity for longer than this duration, the task is terminated and retried. Leave empty to disable. Suggested: 10. Default: 10 minutes (600000ms).",keywords:["hung","frozen","watchdog","kill"]},{sectionId:"scheduling",key:"buildTimeoutMs",labelKey:"settings.scheduling.buildTimeoutMinutes",labelFallback:"Build/Verification Timeout (minutes)",helpKey:"settings.scheduling.maximumTimeInMinutesForBuildVerificationCommands",helpFallback:"Maximum time in minutes for build/verification commands before they are killed. Raise for large monorepo or Docker builds. Default: 5.",keywords:["test timeout","compile","slow build"]},{sectionId:"scheduling",key:"staleHighFanoutBlockerAgeThresholdMs",labelKey:"settings.scheduling.staleHighFanOutEscalationHours",labelFallback:"Stale High Fan-out Escalation (hours)",helpKey:"settings.scheduling.escalateHighFanOutBlockersOnlyAfterThey",helpFallback:"Escalate high fan-out blockers only after they remain in in-progress or in-review for this many hours (age source: columnMovedAt, fallback updatedAt). Default: 2 hours.",keywords:["dependencies","alert","notify"]},{sectionId:"scheduling",key:"preserveProgressOnStuckRequeue",labelKey:"settings.scheduling.preserveStepProgressOnStuckTaskRequeue",labelFallback:" Preserve step progress on stuck-task requeue ",helpKey:"settings.scheduling.whenTheStuckDetectorKillsAndReQueues",helpFallback:"When the stuck detector kills and re-queues a task, keep completed step statuses so the agent can resume from where it left off. Disable to reset every step to pending on each stuck retry. Default: enabled.",keywords:["resume","restart","retry"]},{sectionId:"scheduling",key:"specStalenessEnabled",labelKey:"settings.scheduling.enablePlanStalenessEnforcement",labelFallback:" Enable plan staleness enforcement ",helpKey:"settings.scheduling.whenEnabledTasksWithStalePlansPROMPTMd",helpFallback:"When enabled, tasks with stale plans (PROMPT.md older than the threshold) are automatically sent back to planning for replanning. Default: disabled.",keywords:["spec","replan","outdated"]},{sectionId:"scheduling",key:"specStalenessMaxAgeMs",labelKey:"settings.scheduling.staleSpecThresholdHours",labelFallback:"Stale Spec Threshold (hours)",helpKey:"settings.scheduling.maximumAgeInHoursBeforeAPlanIs",helpFallback:"Maximum age in hours before a plan is considered stale. Default: 6 hours.",keywords:["PROMPT.md","replan","age"]},{sectionId:"scheduling",key:"autoArchiveDoneTasksEnabled",labelKey:"settings.scheduling.enableAutomaticTaskArchiving",labelFallback:" Enable automatic task archiving ",helpKey:"settings.scheduling.completedTasksOlderThanTheThresholdAreMoved",helpFallback:"Completed tasks older than the threshold are moved out of the active task database. Default: enabled.",keywords:["done column","cleanup","prune","board clutter"]},{sectionId:"scheduling",key:"autoArchiveDoneAfterMs",labelKey:"settings.scheduling.archiveCompletedTasksAfterDays",labelFallback:"Archive Completed Tasks After (days)",helpKey:"settings.scheduling.numberOfDaysATaskCanStayIn",helpFallback:"Number of days a task can stay in Done before it is archived. Default: 2 days (48 hours).",keywords:["retention","cleanup","age"]},{sectionId:"scheduling",key:"archiveAgentLogMode",labelKey:"settings.scheduling.archiveAgentLog",labelFallback:"Archive Agent Log",helpKey:"settings.scheduling.compactModeKeepsArchiveSizeLowWhilePreserving",helpFallback:"Compact mode keeps archive size low while preserving recent agent activity for context. Default: compact.",keywords:["history","transcript","disk space","retention"]},{sectionId:"scheduling",key:"autoArchiveDuplicateTasksEnabled",labelKey:"settings.scheduling.autoArchiveDuplicateTasks",labelFallback:" Automatically archive duplicate tasks ",helpKey:"settings.scheduling.autoArchiveDuplicateTasksHelp",helpFallback:"Automatically archive tasks detected as same-agent duplicates on creation (off by default). When disabled, duplicates are flagged in place with the yellow Duplicate chip and Keep/Archive actions instead of being archived automatically.",keywords:["near duplicate","dedupe","repeat"]},{sectionId:"scheduling",key:"triageDuplicateResolution",labelKey:"settings.scheduling.triageDuplicateResolution",labelFallback:"Triage duplicate resolution",helpKey:"settings.scheduling.triageDuplicateResolutionHelp",helpFallback:"Block triage-detected duplicates for a Keep/Delete decision with a link to the duplicate (default), keep automatically, or delete automatically.",keywords:["duplicate","triage","keep","delete","decision"]},{sectionId:"scheduling",key:"maxStuckKills",labelKey:"settings.scheduling.maxStuckRetries",labelFallback:"Max Stuck Retries",helpKey:"settings.scheduling.maximumStuckDetectorRetriesBeforeATaskIs",helpFallback:"Maximum stuck-detector retries before a task is marked failed. Default: 6.",keywords:["give up","attempts","hung"]},{sectionId:"scheduling",key:"groupOverlappingFiles",labelKey:"settings.scheduling.serializeTasksWithOverlappingFiles",labelFallback:" Serialize tasks with overlapping files ",helpKey:"settings.scheduling.whenEnabledTasksThatModifyTheSameFiles",helpFallback:"When enabled, tasks that modify the same files are queued serially to avoid merge conflicts. Default: enabled.",keywords:["file scope","collision","queue","lease"]},{sectionId:"scheduling",key:"ignoreHiddenOverlapPaths",labelKey:"settings.scheduling.ignoreHiddenDotPathsInOverlapChecks",labelFallback:" Ignore hidden dot paths in overlap checks ",helpKey:"settings.scheduling.ignoreHiddenDotPathsHelp",helpFallback:"When enabled, overlap checks ignore hidden path segments such as .fusion/, .changeset/, .github/, .env, and nested .cache/ directories. Uncheck to restore legacy counting for stricter serialization. Default: enabled.",keywords:["dotfiles","collision","file scope"]}],Dp=[{sectionId:"source-control-global",key:"gitlabInstanceUrl",labelKey:"settings.globalGeneral.gitLabInstanceUrl",labelFallback:"Global GitLab instance URL",helpKey:"settings.globalGeneral.gitLabInstanceUrlHint",helpFallback:"Blank defaults to GitLab.com. Projects inherit this self-managed GitLab URL unless they set their own project value. No default — unset.",keywords:["self managed","self-hosted","fallback","inherit"]},{sectionId:"source-control-global",key:"gitlabApiBaseUrl",labelKey:"settings.globalGeneral.gitLabApiBaseUrlOptional",labelFallback:"Global GitLab API base URL (optional / advanced)",helpKey:"settings.globalGeneral.gitLabApiBaseUrlHint",helpFallback:"Blank derives <instance>/api/v4. Override only for self-managed GitLab API gateways that use a different absolute http:// or https:// URL. No default — unset.",keywords:["api v4","gateway","fallback","self managed"]},{sectionId:"source-control-global",key:"gitlabAuthTokenType",labelKey:"settings.globalGeneral.gitLabTokenType",labelFallback:"Global GitLab token type",helpKey:"settings.globalGeneral.gitLabTokenTypeHint",helpFallback:"No default — unset (the selector falls back to personal access token until you choose otherwise).",keywords:["personal access token","project access token","group access token","pat"]},{sectionId:"source-control-global",key:"gitlabAuthToken",labelKey:"settings.globalGeneral.gitLabAccessToken",labelFallback:"Global GitLab access token",helpKey:"settings.globalGeneral.gitLabAuthTokenHint",helpFallback:"Projects inherit this fallback only when they do not set a project GitLab token. Read-only operations need read_api or api; write actions need api; project/group tokens remain limited by resource membership. No default — unset.",keywords:["glpat","private-token","credentials","secret","fallback"]}],Lp=[{sectionId:"source-control",key:"githubLinkImportedIssuesToTracking",labelKey:"settings.general.alwaysLinkImportedGitHubIssuesToTracking",labelFallback:" Always link imported GitHub issues to GitHub tracking ",helpKey:"settings.general.whenEnabledImportedGitHubIssuesUseTheirSource",helpFallback:"When enabled, GitHub issue imports become tracked tasks that adopt the source issue. This does not turn GitHub tracking on for ordinary new tasks. Default: disabled.",keywords:["adopt issue","import"]},{sectionId:"source-control",key:"githubTrackingDedupEnabled",labelKey:"settings.general.searchTheTrackingRepoForLikelyDuplicatesBefore",labelFallback:" Search the tracking repo for likely duplicates before opening a new issue ",helpKey:"settings.general.whenEnabledFusionChecksOpenAndClosedIssues",helpFallback:" When enabled, Fusion checks open and closed issues in the target repo for likely duplicates (using File Scope paths and key symptoms) before creating a new tracking issue. Uncheck to always create a new issue. Default: enabled. ",keywords:["dedupe","deduplication"]},{sectionId:"source-control",key:"githubAuthMode",labelKey:"settings.merge.gitHubAuthMode",labelFallback:"GitHub auth mode",keywords:["gh cli","personal access token","pat","credentials","login"]},{sectionId:"source-control",key:"githubAuthToken",labelKey:"settings.merge.gitHubPersonalAccessToken",labelFallback:"GitHub personal access token",helpKey:"settings.merge.githubAuthTokenHint",helpFallback:"No default — unset.",keywords:["pat","credentials","secret","ghp"]},{sectionId:"source-control",key:"gitlabInstanceUrl",labelKey:"settings.general.gitLabInstanceUrl",labelFallback:"GitLab instance URL",helpKey:"settings.general.gitLabInstanceUrlHint",helpFallback:"Blank uses GitLab.com or the global default. Set an absolute http:// or https:// URL for self-managed GitLab, such as https://gitlab.example.com/gitlab.",keywords:["self managed","self-hosted","on premise"]},{sectionId:"source-control",key:"gitlabApiBaseUrl",labelKey:"settings.general.gitLabApiBaseUrlOptional",labelFallback:"GitLab API base URL (optional / advanced)",helpKey:"settings.general.gitLabApiBaseUrlHint",helpFallback:"Blank derives <instance>/api/v4. Override only when a self-managed GitLab API is served from a different absolute http:// or https:// URL.",keywords:["api v4","gateway","self managed"]},{sectionId:"source-control",key:"gitlabAuthTokenType",labelKey:"settings.merge.gitLabTokenType",labelFallback:"GitLab token type",keywords:["personal access token","project access token","group access token","pat"]},{sectionId:"source-control",key:"gitlabAuthToken",labelKey:"settings.merge.gitLabAccessToken",labelFallback:"GitLab access token",helpKey:"settings.merge.gitLabAuthTokenHint",helpFallback:"Read-only GitLab operations need read_api or api. Future write actions such as comments and auto-close need api. Project and group tokens are limited to their associated resource and role membership. No default — unset.",keywords:["glpat","private-token","credentials","secret","read_api"]}],Op=[{sectionId:"worktrees",key:"maxWorktrees",labelKey:"settings.worktrees.maxWorktrees",labelFallback:"Max Worktrees",helpKey:"settings.worktrees.limitsTotalGitWorktreesIncludingInReviewTasks",helpFallback:"Limits total git worktrees including in-review tasks. Default: 4.",keywords:["concurrency","parallel tasks","capacity","limit"]},{sectionId:"worktrees",key:"worktreeInitCommand",labelKey:"settings.worktrees.worktreeInitCommand",labelFallback:"Worktree Init Command",helpKey:"settings.worktrees.shellCommandToRunInEachNewWorktree",helpFallback:"Shell command to run in each new worktree after creation. No default — unset.",keywords:["setup script","bootstrap","install dependencies","post-create"]},{sectionId:"worktrees",key:"recycleWorktrees",labelKey:"settings.worktrees.recycleWorktrees",labelFallback:" Recycle worktrees ",helpKey:"settings.worktrees.offByDefaultOptInWhenEnabledCompleted",helpFallback:"Off by default (opt-in). When enabled, completed task worktrees are returned to an idle pool instead of being deleted, preserving build caches for faster startup",keywords:["reuse","warm pool"]},{sectionId:"worktrees",key:"showWorktreeGrouping",labelKey:"settings.worktrees.showWorktreeGrouping",labelFallback:" Show worktree grouping on the board ",helpKey:"settings.worktrees.showWorktreeGroupingHelp",helpFallback:"Off by default. When enabled, WIP and processing columns always group tasks by worktree and show worktree names, including workflow-mode processing columns.",keywords:["group by","swimlane"]},{sectionId:"worktrees",key:"worktreeNaming",labelKey:"settings.worktrees.worktreeNamingStyle",labelFallback:"Worktree Naming Style",helpKey:"settings.worktrees.howToNameFreshWorktreeDirectories",helpFallback:"How to name fresh worktree directories. Only applies when recycling is off. Default: random.",keywords:["folder name","directory name","branch naming"]},{sectionId:"worktrees",key:"worktreeRebaseBeforeMerge",labelKey:"settings.worktrees.rebaseFromRemoteBeforeMerge",labelFallback:" Rebase from remote before merge ",helpKey:"settings.worktrees.whenEnabledTheMergerFetchesFromTheConfigured",helpFallback:"When enabled, the merger fetches from the configured remote and rebases the task branch onto the latest default-branch tip before merging — catching concurrent pushes from other collaborators or fusion workers. Any conflicts the rebase surfaces flow into the existing smart/AI resolve pipeline. Default: enabled.",keywords:["pull","up to date","prerebase"]},{sectionId:"worktrees",key:"worktreeRebaseLocalBase",labelKey:"settings.worktrees.alsoRebaseOntoLocalDefaultBranchHEAD",labelFallback:" Also rebase onto local default-branch HEAD ",helpKey:"settings.worktrees.inAdditionToTheRemoteRebaseAboveAlso",helpFallback:" In addition to the remote rebase above, also rebase the task branch onto the local default-branch HEAD (rootDir). This catches sibling tasks that merged locally but haven't been pushed yet — without it, two concurrent tasks where one deletes code can have the other silently re-introduce it via the fallback strategy. Enabled by default; only disable if it causes issues with your workflow. ",keywords:["main","unpushed","prerebase"]}],Kp=[...bp,...fp,...yp,...kp,...vp,...xp,...jp,...wp,...Cp,...Sp,...Np,...Pp,...Tp,...Ap,...Mp,...Ip,...Rp,...Ep,...Fp,...Dp,...Lp,...Op];function ls(t){return t.trim().toLocaleLowerCase()}const Bp=0,Gp=1,Hp=2,_p=3,Wp=4,Up=5;function $p(t,s,a,n){const c=ls(a);return c===s?Bp:c.startsWith(s)?Gp:c.includes(s)?Hp:t.keywords?.some(d=>ls(d).includes(s))?_p:ls(t.key).includes(s)?Wp:n&&ls(n).includes(s)?Up:null}function zp(t,s,a){const n=ls(s);if(!n)return[];const c=[];for(const d of t){const i=a(d.labelKey,d.labelFallback),u=d.helpKey&&d.helpFallback?a(d.helpKey,d.helpFallback):void 0,l=$p(d,n,i,u);l!==null&&c.push({...d,label:i,help:u,score:l})}return c.sort((d,i)=>d.score-i.score||d.label.localeCompare(i.label))}function qp(t){return new Set(t.map(s=>s.sectionId))}const Rr="fusion_github_star_count",Er=900*1e3,dr="fusion:github-star-clicked";function Gs(t){return t.startsWith("/")}function Vp({size:t=13}){return e.jsx("svg",{"data-testid":"discord-icon",width:t,height:t,viewBox:"0 0 24 24",role:"img","aria-hidden":"true",fill:"currentColor",children:e.jsx("path",{d:"M20.317 4.369A19.791 19.791 0 0 0 15.885 3a13.66 13.66 0 0 0-.696 1.412 18.27 18.27 0 0 0-6.378 0A13.627 13.627 0 0 0 8.115 3a19.736 19.736 0 0 0-4.432 1.369C.878 8.604.111 12.734.494 16.803a19.916 19.916 0 0 0 5.993 3.048 14.43 14.43 0 0 0 1.286-2.106 12.94 12.94 0 0 1-2.024-.977c.17-.122.337-.249.499-.381 3.908 1.838 8.149 1.838 12.01 0 .163.132.329.259.5.381a12.936 12.936 0 0 1-2.028.978 14.344 14.344 0 0 0 1.287 2.105 19.85 19.85 0 0 0 5.996-3.049c.449-4.713-.766-8.806-3.696-12.433zM8.02 14.335c-1.184 0-2.157-1.085-2.157-2.419 0-1.334.95-2.418 2.157-2.418 1.217 0 2.167 1.095 2.157 2.418 0 1.334-.95 2.419-2.157 2.419zm7.975 0c-1.184 0-2.157-1.085-2.157-2.419 0-1.334.95-2.418 2.157-2.418 1.217 0 2.167 1.095 2.157 2.418 0 1.334-.94 2.419-2.157 2.419z"})})}function Yp(t){const s=new Map;for(const a of t){const n=`${a.owner}/${a.repo}`;s.has(n)||s.set(n,{value:n,label:n})}return[...s.values()].sort((a,n)=>a.value.localeCompare(n.value))}function Qp(){const[t,s]=o.useState(()=>{try{return localStorage.getItem(dr)==="true"}catch{return!1}}),a=o.useCallback(()=>{s(!0);try{localStorage.setItem(dr,"true")}catch{}},[]);return[t,a]}function ur(){try{const t=localStorage.getItem(Rr);if(!t)return null;const s=JSON.parse(t);return Number.isFinite(s.count)&&Number.isFinite(s.fetchedAt)?s:null}catch{return null}}function Jp(t){return t!==null&&Date.now()-t.fetchedAt<Er}function Xp(){const[t,s]=o.useState(()=>ur()?.count??null),a=o.useRef(!1),n=o.useCallback(()=>{document.hidden||a.current||Jp(ur())||(a.current=!0,fetch("https://api.github.com/repos/Runfusion/Fusion",{cache:"no-store"}).then(async c=>{if(!c.ok)return null;const d=await c.json();return typeof d.stargazers_count=="number"&&Number.isFinite(d.stargazers_count)?d.stargazers_count:null}).then(c=>{if(c===null)return;const d={count:c,fetchedAt:Date.now()};try{localStorage.setItem(Rr,JSON.stringify(d))}catch{}s(c)}).catch(()=>{}).finally(()=>{a.current=!1}))},[]);return o.useEffect(()=>{n();const c=()=>{document.hidden||n()};document.addEventListener("visibilitychange",c);const d=window.setInterval(n,Er);return()=>{document.removeEventListener("visibilitychange",c),window.clearInterval(d)}},[n]),t}const gr="(max-width: 768px)",sn=".fusion/memory/DREAMS.md",Fr="fusion:settings:show-advanced",Zp=1600,an=8;function eh(){return typeof window>"u"||typeof window.matchMedia!="function"||window.matchMedia("(prefers-reduced-motion: reduce)").matches?"auto":"smooth"}const Dr="fusion:settings-nav-width",Lr=248,Or=200,Kr=420,pr=new Set(["node-sync","global-mcp","cli-agents","research-global","remote","experimental","hermes-runtime","openclaw-runtime","paperclip-runtime","scheduled-evals","node-routing","agent-permissions","memory","backups","research-project","secrets","mcp","prompts","plugins"]);function th(){try{return localStorage.getItem(Fr)==="true"}catch{return!1}}function Br(t){return Number.isFinite(t)?Math.min(Kr,Math.max(Or,Math.round(t))):Lr}function sh(){try{const t=Number.parseFloat(localStorage.getItem(Dr)??"");return Br(t)}catch{return Lr}}function ah(t){return t.filter((s,a)=>{if(!s.isGroupHeader)return!0;for(const n of t.slice(a+1))return!n.isGroupHeader;return!1})}function Gr(t){return t.trim().toLocaleLowerCase()}function nh(t,s,a,n,c){return!s||t.isGroupHeader||c?.has(t.id)?!0:[a,...t.searchableText??[],...(t.searchableKeys??[]).map(d=>n(d))].map(Gr).some(d=>d.includes(s))}function lh(t,s,a,n,c){if(!s)return t;const d=new Set(t.filter(i=>!i.isGroupHeader&&nh(i,s,a(i),n,c)).map(i=>i.id));return t.filter((i,u)=>{if(!i.isGroupHeader)return d.has(i.id);for(const l of t.slice(u+1)){if(l.isGroupHeader)return!1;if(d.has(l.id))return!0}return!1})}function hr(t,s){return t.find(a=>!a.isGroupHeader)?.id??s}const rh=/ · (Global|Project)$/,ih=new Set(["authentication"]);function oh(t,s){return rh.test(s)?s:t.scope==="global"||ih.has(t.id)?`${s} · Global`:t.scope==="project"?`${s} · Project`:s}function mr(t){const s=Number(t?.maxAutoMergeRetries);return Number.isFinite(s)&&s>0?Math.floor(s):3}function Hs(t,s){const a=Number(t);return Number.isFinite(a)&&a>=0?Math.floor(a):s}const nn=[{id:"__preferences_header",label:"Preferences",labelKey:"settings.nav.preferencesHeader",scope:void 0,isGroupHeader:!0},{id:"appearance",label:"Appearance",labelKey:"settings.nav.appearance",scope:"global",searchableText:["theme","color","sidebar","dock","task popup","task popups","board list popups","popup view attachment","open tasks as popups","quick chat"]},{id:"keyboard-shortcuts",label:"Keyboard Shortcuts",labelKey:"settings.nav.keyboardShortcuts",scope:"global",searchableText:["keyboard shortcuts","hotkeys","quick chat shortcut","terminal shortcut","open files","open settings","command center","new task shortcut","record shortcut"]},{id:"notifications",label:"Notifications",labelKey:"settings.nav.notifications",scope:"global",searchableText:["ntfy","webhook","events","failure notifications","sticky","toast"]},{id:"global-general",label:"General · Global",labelKey:"settings.nav.globalGeneral",scope:"global",searchableText:["global defaults","modal outside dismiss","agent logs","persist tool output","thinking logs"]},{id:"cli-binary",label:"CLI Binary",labelKey:"settings.nav.cliBinary",scope:"global",searchableText:["fn binary","cli","install","version","path","upgrade","homebrew","binary check"]},{id:"__project_header",label:"Project",labelKey:"settings.nav.projectHeader",scope:void 0,isGroupHeader:!0},{id:"general",label:"General · Project",labelKey:"settings.nav.projectGeneral",scope:"project",searchableText:["project general","Completion Documentation Automation","Quick Chat launcher","ephemeral task-worker agents","chat rooms","auto-cleanup old chats","translate","translation","auto translate","auto-translate","autotranslate","auto translate issues","translate issues","translate imported issues","githubImportAutoTranslate","importTranslateTargetLocale","target language","translation target language","translation language","language","foreign language issues","import language","localize","localization"],searchableKeys:["settings.general.autoTranslateImportedIssues","settings.general.autoTranslateImportedIssuesHelp","settings.general.translationTargetLanguage","settings.general.translationTargetLanguageHelp","settings.general.followDashboardLanguage"]},{id:"commands",label:"Commands & Scripts",labelKey:"settings.nav.commands",scope:"project",searchableText:["test command","build command","verification command","workflow scripts","commands"]},{id:"worktrees",label:"Worktrees",labelKey:"settings.nav.worktrees",scope:"project",searchableText:["worktree directory","copy files","recycle worktrees","branch naming","sibling branch rename"]},{id:"merge",label:"Merge",labelKey:"settings.nav.merge",scope:"project",searchableText:["auto merge","AI merge","merge strategy","plan approval","direct merge","integration branch","push after merge"]},{id:"__ai_header",label:"AI & Models",labelKey:"settings.nav.aiHeader",scope:void 0,isGroupHeader:!0},{id:"authentication",label:"Authentication",labelKey:"settings.nav.authentication",scope:void 0,icon:Us,searchableText:["login","OAuth","API key","custom providers","Anthropic","OpenAI","provider credentials"]},{id:"global-models",label:"Models · Global",labelKey:"settings.nav.globalModels",scope:"global",searchableText:["global models","model presets","favorite providers","model pricing overrides","LiteLLM pricing","token pricing","translate","translation model","import translation model","import auto-translation model"]},{id:"project-models",label:"Models · Project",labelKey:"settings.nav.projectModels",scope:"project",searchableText:["default provider","default model","workflow model lanes","Plan/Triage","Executor","Reviewer","summarization model","summarize","summarize titles","auto summarize","auto-summarize","auto summarize titles","auto-summarize titles","autoSummarizeTitles","task definition language","task definitions input language","taskDefinitionInInputLanguage","localized task prose","title summarization","title summarizer","AI title","AI merge commit summaries","merge commit summary","chat","new chat","new chat behavior","chat default","chat default model","chat default agent","chat model","chat agent","prompt for model","always use default","translate","translation","translation model","import translation model","import auto-translation model","auto-translate model"],searchableKeys:["settings.projectModels.chatHeading","settings.projectModels.chatDescription","settings.projectModels.chatNewSessionMode","settings.projectModels.chatNewSessionModePrompt","settings.projectModels.chatNewSessionModeAlwaysDefault","settings.projectModels.chatDefaultKind","settings.projectModels.chatDefaultModel","settings.projectModels.chatDefaultAgent","settings.projectModels.aITitleAndGitCommitMessageSummarization","settings.projectModels.autoSummarizeLongDescriptionsAsTitles","settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut","settings.projectModels.aIMergeCommitSummaries","settings.projectModels.whenEnabledMergeCommitMessagesIncludeAnAI"]},{id:"cli-agents",label:"CLI Agents",labelKey:"settings.nav.cliAgents",scope:"global",searchableText:["Droid CLI","Cursor CLI","agent runtime","command line agents","Adapter","Command override","Path or name of the binary to launch","Extra arguments","Appended after the adapter's computed arguments","Environment variable additions","Comma-separated variable names forwarded","Autonomy mode","Elevated autonomy requires a per-project approval"],searchableKeys:["settings.cliAgents.adapterLabel","settings.cliAgents.commandLabel","settings.cliAgents.commandHelp","settings.cliAgents.extraArgsLabel","settings.cliAgents.extraArgsHelp","settings.cliAgents.envLabel","settings.cliAgents.envHelp","settings.cliAgents.autonomyLabel","settings.cliAgents.autonomyHelp","settings.cliAgents.approvedNote"]},{id:"agent-permissions",label:"Agents & Permissions",labelKey:"settings.nav.agentPermissions",scope:"project",searchableText:["agent provisioning","approval","permissions","policy","agent creation"]},{id:"prompts",label:"Prompts",labelKey:"settings.nav.prompts",scope:"project",searchableText:["prompt instructions","PR title prompt","PR description prompt","custom prompts"]},{id:"memory",label:"Memory",labelKey:"settings.nav.memory",scope:"project",searchableText:["memory backend","Dreams","long-term memory","qmd","memory file","retrieval"]},{id:"research-global",label:"Research · Global",labelKey:"settings.nav.researchGlobal",scope:"global",searchableText:["research providers","external search providers","fetch limits","global research defaults","citations"]},{id:"research-project",label:"Research · Project",labelKey:"settings.nav.researchProject",scope:"project",searchableText:["project research","research runs","citations","search limits","fetch synthesis"]},{id:"__automation_header",label:"Automation",labelKey:"settings.nav.automationHeader",scope:void 0,isGroupHeader:!0},{id:"scheduling-global",label:"Scheduling · Global",labelKey:"settings.nav.schedulingGlobal",scope:"global",searchableText:["global max concurrent","concurrency cap","all projects","machine wide","parallel agents","scheduler"]},{id:"scheduling",label:"Scheduling · Project",labelKey:"settings.nav.scheduling",scope:"project",searchableText:["max concurrent","capacity","stuck tasks","poll interval","parallel steps","scheduler"]},{id:"scheduled-evals",label:"Scheduled Evals",labelKey:"settings.nav.scheduledEvals",scope:"project",searchableText:["scheduled evals","evaluation schedule","eval runs","quality jobs"]},{id:"__integrations_header",label:"Integrations",labelKey:"settings.nav.integrationsHeader",scope:void 0,isGroupHeader:!0},{id:"source-control-global",label:"Source Control · Global",labelKey:"settings.nav.sourceControlGlobal",scope:"global",icon:Al,searchableText:["GitLab instance URL","global tracking repo","GitLab","GitHub","global GitLab token","GitLab fallback","source control","forge"]},{id:"source-control",label:"Source Control · Project",labelKey:"settings.nav.sourceControl",scope:"project",icon:Al,searchableText:["GitHub tracking","GitLab integration","GitHub auth mode","GitLab access token","GitHub personal access token","tracking repo","source control","forge","gh cli","issue tracking"]},{id:"global-mcp",label:"MCP Servers · Global",labelKey:"settings.nav.globalMcp",scope:"global",searchableText:["global MCP servers","shared MCP","user MCP","tool servers"]},{id:"mcp",label:"MCP Servers · Project",labelKey:"settings.nav.mcp",scope:"project",searchableText:["project MCP servers","workspace MCP","project tool servers","mcp config"]},{id:"plugins",label:"Plugins",labelKey:"settings.nav.plugins",scope:"project",searchableText:["Fusion plugins","Pi extensions","plugin manager","extension marketplace"]},{id:"hermes-runtime",label:"Hermes",labelKey:"settings.nav.hermesRuntime",scope:"global",searchableText:["Hermes runtime","plugin runtime","printer runtime"]},{id:"openclaw-runtime",label:"OpenClaw",labelKey:"settings.nav.openclawRuntime",scope:"global",searchableText:["OpenClaw runtime","plugin runtime","open claw"]},{id:"paperclip-runtime",label:"Paperclip",labelKey:"settings.nav.paperclipRuntime",scope:"global",searchableText:["Paperclip runtime","plugin runtime"]},{id:"secrets",label:"Secrets",labelKey:"settings.nav.secrets",scope:"project",searchableText:["secrets","secret storage","environment","credentials"]},{id:"__infrastructure_header",label:"Infrastructure",labelKey:"settings.nav.infrastructureHeader",scope:void 0,isGroupHeader:!0},{id:"node-sync",label:"Node Sync",labelKey:"settings.nav.nodeSync",scope:"global",searchableText:["sync","node","distributed","heartbeat","coordination"]},{id:"node-routing",label:"Node Routing",labelKey:"settings.nav.nodeRouting",scope:"project",searchableText:["node routing","routing rules","node selection","execution nodes"]},{id:"remote",label:"Remote Access",labelKey:"settings.nav.remote",scope:"global",searchableText:["cloudflared","tunnel","QR","persistent token","remote URL"]},{id:"backups-global",label:"Database Backups",labelKey:"settings.backups.databaseBackups",scope:"global",searchableText:["database backup","restore","shared cluster"]},{id:"backups",label:"Memory Backups",labelKey:"settings.backups.memoryBackups",scope:"project",searchableText:["memory backup","memory snapshot"]},{id:"__advanced_header",label:"Advanced",labelKey:"settings.nav.advancedHeader",scope:void 0,isGroupHeader:!0},{id:"experimental",label:"Experimental Features",labelKey:"settings.nav.experimental",scope:"global",searchableText:["feature flags","experiments","research view","evals view","sandbox","subtask breakdown"]}],ch={insights:"Insights",memoryView:"Memory Editor",skillsView:"Skills View",nodesView:"Nodes View",devServerView:"Dev Server",todoView:"Todo List",researchView:"Research View",evalsView:"Evals View",qualityPlugin:"Quality Plugin",goalsView:"Goals View",subtaskBreakdown:"Subtask Breakdown",leftSidebarNav:"Left Sidebar Navigation",sandbox:"Sandbox (command isolation)",chatRooms:"Chat Rooms",agentOnboarding:"Planning-style Agent Onboarding",workflowInterpreterDualObserve:"Workflow Graph Engine — dual-observe parity (diagnostic)"},dh=new Set(["chatRooms","goalsView","insights","memoryView","remoteAccess","roadmap","rightDock","skillsView","todoView","workflowColumns","workflowGraphExecutor","workflowInterpreterDualObserve"]),Hr=new Set(["leftSidebarNav"]),Qs={devServer:"devServerView"};function jn(t){return Qs[t]??t}function pn(t,s){return t[s]===!0?!0:t[s]===!1?!1:Object.entries(Qs).some(([a,n])=>n===s&&t[a]===!0)?!0:Hr.has(s)}function uh(t,s){const a=jn(s);return Hr.has(a)&&t[a]===void 0?!0:pn(t,a)}function gh(t){if(!t)return{};const s={};for(const[a,n]of Object.entries(t))s[jn(a)]=n;for(const[a,n]of Object.entries(Qs))s[n]!==void 0&&!(a in s)&&(s[a]=null);return s}function ph(t){const s=new Set,a=[];for(const n of t??[]){const c=n.trim();!c||s.has(c)||(s.add(c),a.push(c))}return a}const ln="appearance";function hh({projectId:t,addToast:s}){const{t:a}=te("app"),{confirm:n}=xr(),[c,d]=o.useState([]),[i,u]=o.useState({}),[l,h]=o.useState({}),[p,b]=o.useState("");o.useEffect(()=>{let S=!1;return(async()=>{try{const[C,y]=await Promise.all([fetch("/api/cli-agents"),fetch("/api/cli-agents/settings")]),k=C.ok?await C.json():{adapters:[]},R=y.ok?await y.json():{cliAgents:{}};if(S)return;const P=k.adapters??[];d(P),u(R.cliAgents??{}),P.length>0&&b(N=>N||P[0].id)}catch{}})(),()=>{S=!0}},[]),o.useEffect(()=>{if(!p)return;let S=!1;return fetch(`/api/cli-agents/${p}/autonomy`).then(C=>C.ok?C.json():null).then(C=>{S||!C||h(y=>({...y,[p]:!!C.approved}))}).catch(()=>{}),()=>{S=!0}},[p]);const w=i[p]??{},x=o.useCallback(async(S,C)=>{try{const y=await fetch("/api/cli-agents/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({adapterId:S,config:C})});if(!y.ok)throw new Error(`HTTP ${y.status}`);const k=await y.json();u(k.cliAgents??{})}catch(y){s(xe(y)||a("settings.cliAgents.saveFailed"),"error")}},[s,a]),f=o.useCallback(S=>{if(!p)return;const C={...w,...S};u(y=>({...y,[p]:C})),x(p,C)},[p,w,x]),D=o.useCallback(async S=>{if(p){if(S==="elevated"){if(!await n({title:a("settings.cliAgents.elevatedConfirmTitle"),message:a("settings.cliAgents.elevatedConfirmBody"),confirmLabel:a("settings.cliAgents.elevatedConfirmAction"),danger:!0}))return;try{const y=await fetch(`/api/cli-agents/${p}/approve-autonomy`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({confirm:!0})});if(!y.ok)throw new Error(`HTTP ${y.status}`);h(k=>({...k,[p]:!0}))}catch(y){s(xe(y)||a("settings.cliAgents.approveFailed"),"error");return}}f({autonomyMode:S})}},[p,n,a,s,f]);return e.jsxs("div",{"data-testid":"cli-agents-settings",children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.cliAgents.heading")}),e.jsx("p",{className:"settings-section-description",children:a("settings.cliAgents.description")}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentAdapter",children:a("settings.cliAgents.adapterLabel")}),e.jsx("select",{id:"cliAgentAdapter",value:p,onChange:S=>b(S.target.value),children:c.map(S=>e.jsxs("option",{value:S.id,children:[S.name," (",a(`settings.cliAgents.tier.${S.tier}`),")"]},S.id))})]}),p&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentCommand",children:a("settings.cliAgents.commandLabel")}),e.jsx("input",{id:"cliAgentCommand",type:"text",placeholder:c.find(S=>S.id===p)?.defaultCommand??"",value:w.commandOverride??"",onChange:S=>f({commandOverride:S.target.value||void 0})}),e.jsx("p",{className:"settings-field-help",children:a("settings.cliAgents.commandHelp")})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentExtraArgs",children:a("settings.cliAgents.extraArgsLabel")}),e.jsx("input",{id:"cliAgentExtraArgs",type:"text",value:(w.extraArgs??[]).join(" "),onChange:S=>f({extraArgs:S.target.value.split(/\s+/).filter(C=>C.length>0)})}),e.jsx("p",{className:"settings-field-help",children:a("settings.cliAgents.extraArgsHelp")})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentEnv",children:a("settings.cliAgents.envLabel")}),e.jsx("input",{id:"cliAgentEnv",type:"text",value:(w.envAdditions??[]).join(", "),onChange:S=>f({envAdditions:S.target.value.split(",").map(C=>C.trim()).filter(C=>C.length>0)})}),e.jsx("p",{className:"settings-field-help",children:a("settings.cliAgents.envHelp")})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentAutonomy",children:a("settings.cliAgents.autonomyLabel")}),e.jsxs("select",{id:"cliAgentAutonomy",value:w.autonomyMode??"default",onChange:S=>void D(S.target.value),children:[e.jsx("option",{value:"default",children:a("settings.cliAgents.autonomy.default")}),e.jsx("option",{value:"elevated",children:a("settings.cliAgents.autonomy.elevated")})]}),e.jsx("p",{className:"settings-field-help",children:l[p]?a("settings.cliAgents.approvedNote"):a("settings.cliAgents.autonomyHelp")})]})]})]})}function mh({onClose:t,addToast:s,projectId:a,initialSection:n,themeMode:c="system",colorTheme:d="shadcn-ember",onThemeModeChange:i,onColorThemeChange:u,dashboardFontScalePct:l=100,shadcnCustomColors:h={},resolvedThemeMode:p,onDashboardFontScaleChange:b,onShadcnCustomColorsChange:w,onQuickChatButtonModeChange:x,onMobileNavPrimaryItemsChange:f,onReopenOnboarding:D,onOpenApprovals:S,onOpenWorkflowSettings:C,presentation:y="modal"}){const{isEmbedded:k,scrollLockEnabled:R,resizePersistEnabled:P,escapeEnabled:N,overlayDismissEnabled:U}=Bd(y),{t:m}=te("app"),{confirm:Y}=xr(),E=ld();rd(R);const{keyboardOverlap:L,viewportHeight:G,viewportOffsetTop:K,keyboardOpen:z}=id({enabled:E==="mobile"}),ne=z?{"--keyboard-overlap":`${L}px`,"--vv-offset-top":`${K}px`,...G!==null?{"--vv-height":`${G}px`}:{}}:{},re=o.useRef(null),ce=o.useRef(null),T=o.useRef(null),$=o.useCallback(r=>{r&&(T.current=r)},[]);od(re,P,"fusion:settings-modal-size");const ge=cd(),[O,X]=o.useState({maxConcurrent:2,maxConcurrentVerifications:1,maxTriageConcurrent:2,maxWorktrees:4,pollIntervalMs:15e3,heartbeatMultiplier:1,groupOverlappingFiles:!0,ignoreHiddenOverlapPaths:!0,overlapIgnorePaths:[],allowAbsoluteFileBrowserPaths:!1,autoMerge:!0,planApprovalMode:"auto-approve-all",mergeStrategy:"direct",maxAutoMergeRetries:3,executorToolFailureRetryCount:2,executorToolFailureRetryBackoffMs:2e3,executorToolFailureThreshold:3,executorModelEscalationEnabled:!1,executorEscalationProvider:"",executorEscalationModelId:"",executorEscalationNodeId:"",mergeIntegrationWorktree:"reuse-task-worktree",mergeAdvanceAutoSync:"stash-and-ff",merger:{mode:"ai",maxReviewPasses:3,allowDirtyLocalCheckoutSync:!0},recycleWorktrees:!1,showWorktreeGrouping:!1,openTasksInRightSidebar:!1,openMobileTasksInPopup:!1,taskPopupsBoardListOnly:!0,showCostBadgeOnCards:!1,taskDetailChatFirst:!1,executorAllowSiblingBranchRename:!1,worktreeNaming:"random",worktreeCopyFiles:[],worktreesDir:"",worktrunk:{enabled:!1,binaryPath:"",onFailure:"fail"},includeTaskIdInCommit:!0,worktreeInitCommand:"",ntfyEnabled:!1,agentClarificationEnabled:!1,ntfyTopic:void 0,ntfyAccessToken:void 0,failureNotificationMode:"sticky-only",failureNotificationDelayMs:3e4,webhookEnabled:!1,webhookUrl:void 0,webhookFormat:"generic",webhookEvents:void 0,githubLinkImportedIssuesToTracking:!1,prTitlePromptInstructions:"",prDescriptionPromptInstructions:""}),[me,I]=o.useState(!0),[we,je]=o.useState(!1),[Ke,F]=o.useState(null),[_,ie]=o.useState(null),[be,ve]=o.useState(null),[le,V]=o.useState(null),pe=o.useCallback(r=>({...O,mcpServers:Lt(r,_)}),[O,_]),Ce=o.useCallback(r=>g=>{ie(j=>{if(!j)return j;const H={...O,mcpServers:Lt(r,j)},Q=typeof g=="function"?g(H):g;return r==="global"?{...j,global:{...j.global,mcpServers:Q.mcpServers}}:{...j,project:{...j.project,mcpServers:Q.mcpServers}}})},[O]),A=nn.find(r=>!r.isGroupHeader),[M,W]=o.useState(()=>n==="pi-extensions"?"plugins":n??ln),Z=mp(a,{enabled:M==="worktrees"||O.worktrunk?.enabled===!0}),oe=Z.status==="installed",[fe,he]=o.useState(()=>n==="pi-extensions"?"pi-extensions":"fusion-plugins"),[Pe,et]=o.useState(null),Fe=o.useRef(!1),[_e,is]=o.useState(()=>E==="mobile"||(typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia(gr)?.matches===!0:!1)),[Be,Js]=o.useState(()=>sh()),St=o.useRef(null),[Nt,tt]=o.useState(""),[ct,os]=o.useState(()=>{const r=n==="pi-extensions"?"plugins":n;return th()||r!==void 0&&pr.has(r)}),cs=o.useCallback(r=>{os(r);try{localStorage.setItem(Fr,String(r))}catch{}},[]),vt=o.useCallback(r=>{const g=Br(r);Js(g);try{localStorage.setItem(Dr,String(g))}catch{}return g},[]),[Xs,Zs]=o.useState(!1),[We,v]=o.useState(null),[q,J]=o.useState(!1),[ae,Ne]=o.useState(null),[De,Ge]=o.useState(!1),[st,dt]=o.useState(null),[Bt,ds]=o.useState(),[Gt,us]=o.useState(!1),[wn,ea]=o.useState(!1),[ta,Ht]=o.useState(null),_t=Xp(),[_r,Wr]=Qp(),[sa,Ur]=o.useState(null),[$r,Wt]=o.useState(null),[Ue,aa]=o.useState(null),[Cn,Sn]=o.useState(!1),[$e,na]=o.useState(null),[Ut,gs]=o.useState(!1),[at,ps]=o.useState(!1),{entries:zr,currentPath:nt,setPath:la,loading:qr,error:Vr,refresh:Yr}=_a("project",Ue!==null,a,{allowAbsolutePaths:!1}),{entries:Qr,currentPath:lt,setPath:ra,loading:Jr,error:Xr,refresh:Zr}=_a("project",Cn,a,{allowAbsolutePaths:!1}),{entries:ei,currentPath:ia,setPath:oa,loading:ti,error:si,refresh:ai}=_a("project",$e!==null,a,{allowAbsolutePaths:!1}),{nodes:ni}=dd(),Nn=O.experimentalFeatures??{},hs=pn(Nn,"researchView"),ms=pn(Nn,"evalsView"),ze=o.useMemo(()=>ah(nn.filter(r=>!ct&&pr.has(r.id)?!1:r.id==="research-global"||r.id==="research-project"?hs:r.id==="scheduled-evals"?ms:!0)),[hs,ms,ct]),$t=ze.some(r=>r.id===ln)?ln:hr(ze,A?.id??"general"),Pt=Gr(Nt),ut=o.useMemo(()=>{if(!Pt)return[];const r=new Set(ze.map(g=>g.id));return zp(Kp.filter(g=>r.has(g.sectionId)),Pt,(g,j)=>m(g,j))},[Pt,m,ze]),Pn=o.useMemo(()=>qp(ut),[ut]),gt=o.useMemo(()=>lh(ze,Pt,r=>m(r.labelKey,r.label),r=>m(r),Pn),[Pt,m,ze,Pn]),Tn=gt.filter(r=>!r.isGroupHeader),zt=Pt.length>0,qt=Tn.length>0,An=E==="mobile",bs=!An||Xs,Mn=hr(gt,$t),li=o.useCallback((r,g)=>{Fe.current=!0,W(r),et(g)},[]);o.useEffect(()=>{if(Fe.current){Fe.current=!1;return}ce.current&&(ce.current.scrollTop=0)},[M]),o.useEffect(()=>{if(!Pe)return;const r=ce.current;if(!r)return;const g=r.querySelector(`[data-settings-key="${CSS.escape(Pe)}"]`);if(!g)return;for(let H=g.parentElement;H;H=H.parentElement)H instanceof HTMLDetailsElement&&(H.open=!0);g.scrollIntoView({block:"center",behavior:eh()});const j=window.setTimeout(()=>et(null),Zp);return()=>window.clearTimeout(j)},[Pe,M]);const ca=ze.find(r=>r.id===M)?.scope;o.useEffect(()=>{if((M==="research-global"||M==="research-project")&&!hs){W($t);return}if(M==="scheduled-evals"&&!ms){W($t);return}if(!ze.some(r=>r.id===M)){W($t);return}zt&&qt&&!gt.some(r=>r.id===M)&&W(Mn)},[M,hs,ms,$t,Mn,zt,qt,gt,ze]);const[pt,da]=o.useState([]),[ri,In]=o.useState(!1),[ii,Le]=o.useState(null),[oi,ua]=o.useState({}),[ci,Rn]=o.useState({}),[ga,En]=o.useState({}),[pa,ha]=o.useState({}),[di,ma]=o.useState(null),[ba,fa]=o.useState({}),[ui,fs]=o.useState({}),[gi,Vt]=o.useState({}),Ie=o.useRef(null),Yt=o.useRef({}),[Fn,Dn]=o.useState([]),[Ln,On]=o.useState(!1),[Tt,ya]=o.useState([]),[At,ka]=o.useState([]),[pi,Kn]=o.useState({}),[hi,ys]=o.useState({}),[Qt,Bn]=o.useState(null),[rt,Gn]=o.useState(null),[mi,va]=o.useState(null),[bi,ks]=o.useState(!1),[qe,vs]=o.useState(null),[xa,ja]=o.useState(null),[fi,Hn]=o.useState(null),[yi,_n]=o.useState(!1),[ki,wa]=o.useState(null),[vi,xi]=o.useState("persistent"),[ji,wi]=o.useState(null),[Ci,Si]=o.useState(null),[Ni,Pi]=o.useState(null),[Ti,Mt]=o.useState(null),[Ca,xs]=o.useState(""),[Ai,Wn]=o.useState(!1),[Sa,js]=o.useState(!1),[Un,ws]=o.useState([]),[Mi,$n]=o.useState([]),[Ii,Ri]=o.useState(!1),[Ei,zn]=o.useState([]),[Fi,qn]=o.useState(!1),[Di,Vn]=o.useState(null),[Li,Yn]=o.useState([]),[Oi,Qn]=o.useState(!1),[Ki,Na]=o.useState(null),Pa=o.useRef(!1),[Bi,Jn]=o.useState([]),[Ve,Ta]=o.useState(sn),[Aa,Gi]=o.useState(""),[Hi,Xn]=o.useState(!1),[_i,Zn]=o.useState(null),[Wi,el]=o.useState(!1),[Ui,tl]=o.useState(!1),[$i,sl]=o.useState(!1),Ma=o.useRef(!1),[Cs,al]=o.useState(4),nl=o.useRef(4),ll=o.useRef(!1),Ss=o.useRef(!1),[rl,il]=o.useState(!1),[zi,Jt]=o.useState(!1),[,Ia]=o.useState(null),[Ye,ol]=o.useState(null),[Ns,Ps]=o.useState(!1),[Ra,qi]=o.useState("both"),[Ea,Vi]=o.useState(!0),cl=o.useRef(null),{status:Yi,capabilities:Qi,loading:Ji,error:Xi,refresh:dl}=Jd({projectId:a,enabled:M==="memory"}),ht=!_e,Zi=ht?{"--settings-nav-width":`${Be}px`}:void 0,Xt=o.useCallback((r,g)=>{const j=St.current;if(j&&(document.body.style.userSelect=j.previousUserSelect,St.current=null,typeof r=="number"&&g instanceof HTMLElement&&typeof g.releasePointerCapture=="function"))try{g.releasePointerCapture(r)}catch{}},[]),Fa=o.useCallback(r=>{const g=St.current;g&&(r.preventDefault(),vt(g.startWidth+r.clientX-g.startX))},[vt]),Zt=o.useCallback(r=>{Xt(r.pointerId,r.target)},[Xt]),eo=o.useCallback(r=>{ht&&(r.preventDefault(),r.stopPropagation(),typeof r.currentTarget.setPointerCapture=="function"&&r.currentTarget.setPointerCapture(r.pointerId),St.current={startX:r.clientX,startWidth:Be,previousUserSelect:document.body.style.userSelect},document.body.style.userSelect="none")},[ht,Be]),to=o.useCallback(r=>{ht&&(r.key!=="ArrowLeft"&&r.key!=="ArrowRight"||(r.preventDefault(),vt(Be+(r.key==="ArrowRight"?16:-16))))},[vt,ht,Be]);o.useEffect(()=>{if(!ht){Xt();return}return document.addEventListener("pointermove",Fa),document.addEventListener("pointerup",Zt),document.addEventListener("pointercancel",Zt),()=>{document.removeEventListener("pointermove",Fa),document.removeEventListener("pointerup",Zt),document.removeEventListener("pointercancel",Zt),Xt()}},[Xt,Fa,Zt,ht]),o.useEffect(()=>{if(typeof window>"u"||typeof window.matchMedia!="function")return;const r=window.matchMedia(gr);if(!r)return;const g=j=>{is(E==="mobile"||(j?j.matches:r.matches))};return g(),r.addEventListener("change",g),()=>r.removeEventListener("change",g)},[E]);const es=o.useCallback(r=>Promise.all([Ml(a),ud(a)]).then(([g,j])=>{const H={...g,ignoreHiddenOverlapPaths:g.ignoreHiddenOverlapPaths??!0,allowAbsoluteFileBrowserPaths:g.allowAbsoluteFileBrowserPaths===!0,showCostBadgeOnCards:g.showCostBadgeOnCards===!0,taskDetailChatFirst:g.taskDetailChatFirst===!0,githubLinkImportedIssuesToTracking:g.githubLinkImportedIssuesToTracking===!0,mergeIntegrationWorktree:zl(g.mergeIntegrationWorktree),mergeAdvanceAutoSync:ql(g.mergeAdvanceAutoSync),maxAutoMergeRetries:mr(g),executorToolFailureRetryCount:Hs(g.executorToolFailureRetryCount,2),executorToolFailureRetryBackoffMs:Hs(g.executorToolFailureRetryBackoffMs,2e3),executorToolFailureThreshold:Math.max(1,Math.floor(Number(g.executorToolFailureThreshold??3)||3)),executorModelEscalationEnabled:g.executorModelEscalationEnabled===!0,executorEscalationProvider:g.executorEscalationProvider??"",executorEscalationModelId:g.executorEscalationModelId??"",executorEscalationNodeId:g.executorEscalationNodeId??"",worktreeCopyFiles:Array.isArray(g.worktreeCopyFiles)?g.worktreeCopyFiles:[]};X(H),F(H),ie(j),ve({gitlabEnabled:j.global.gitlabEnabled,gitlabInstanceUrl:j.global.gitlabInstanceUrl,gitlabApiBaseUrl:j.global.gitlabApiBaseUrl,gitlabAuthToken:j.global.gitlabAuthToken,gitlabAuthTokenType:j.global.gitlabAuthTokenType}),V({...j,project:{...j.project,mergeIntegrationWorktree:j.project.mergeIntegrationWorktree===void 0?void 0:zl(j.project.mergeIntegrationWorktree),mergeAdvanceAutoSync:j.project.mergeAdvanceAutoSync===void 0?void 0:ql(j.project.mergeAdvanceAutoSync)}}),r&&I(!1)}).catch(g=>{s(xe(g),"error"),r&&I(!1)}),[s,a]);o.useEffect(()=>{es(!0)},[s,a]),o.useEffect(()=>{if(M!=="scheduling"&&M!=="scheduling-global"||ll.current)return;let r=!1;return gd().then(g=>{r||(Ss.current||al(g.globalMaxConcurrent),nl.current=g.globalMaxConcurrent,ll.current=!0,il(!0))}).catch(()=>{il(!0)}),()=>{r=!0}},[M]),o.useEffect(()=>{let r=!1;return pd().then(g=>{r||typeof g.version=="string"&&g.version.trim().length>0&&v(g.version)}).catch(()=>{}),()=>{r=!0}},[]);const so=o.useCallback(async()=>{J(!0),dt(null),ds(void 0),us(!1),ea(!1),Ht(null);try{const r=await hd();Ne(r),r.error&&s(r.error,"error")}catch(r){const g=xe(r)||m("settings.general.updateCheckFailed","Failed to check for updates");Ne({currentVersion:We??"unknown",latestVersion:null,updateAvailable:!1,error:g}),s(g,"error")}finally{J(!1)}},[s,We,m]),ul=o.useCallback(async()=>{Ge(!0),dt(null),us(!1),ea(!1),Ht(null);try{const r=await md(a);if(dt(r),r.error){s(r.error,"error");return}r.updated&&s(m("settings.general.updateSuccessToast","Update installed. Restart Fusion to apply it."),"success")}catch(r){const g=xe(r)||m("settings.general.updateFailed","Update failed");dt({currentVersion:ae?.currentVersion??We??"unknown",latestVersion:ae?.latestVersion??null,updated:!1,error:g}),s(g,"error")}finally{Ge(!1)}},[s,We,a,m,ae]);o.useEffect(()=>{if(!ae?.updateAvailable&&st?.updated!==!0)return;let r=!1;return ds(void 0),bd().then(g=>{r||ds(g.restartSupported)}).catch(()=>{r||ds(!1)}),()=>{r=!0}},[ae?.updateAvailable,st?.updated]);const gl=o.useCallback(async()=>{if(!(Gt||Bt!==!0)){us(!0),Ht(null);try{(await fd("settings-update")).scheduled?ea(!0):Ht(m("settings.general.restartFailed","Restart could not be scheduled. Try restarting Fusion manually."))}catch(r){Ht(xe(r)||m("settings.general.restartFailed","Restart could not be scheduled. Try restarting Fusion manually."))}finally{us(!1)}}},[Gt,Bt,m]),ao=o.useCallback(()=>{if(!ae)return null;if(ae.error)return ae.error;if(ae.updateAvailable&&ae.latestVersion){const r=st?.updated===!0,g=st?.error;return e.jsxs(e.Fragment,{children:[e.jsxs("span",{children:[m("settings.general.updateAvailablePrefix","v{{version}} available",{version:ae.latestVersion})," ·"," ",e.jsx("a",{href:"https://runfusion.ai",target:"_blank",rel:"noreferrer",className:"settings-update-result-link",children:m("settings.general.learnMore","Learn more")})]}),r?e.jsxs("span",{className:"settings-update-install-succeeded",children:[e.jsx("span",{className:"settings-update-install-status settings-update-install-status--success","aria-live":"polite",children:m("settings.general.updateSuccess","Updated to v{{version}} — restart Fusion to apply",{version:st.latestVersion??ae.latestVersion})}),wn?e.jsx("span",{className:"settings-update-install-status","aria-live":"polite",children:m("settings.general.restarting","Restarting… Your connection will close shortly.")}):e.jsx("button",{type:"button",className:"btn btn-sm settings-update-now-btn",onClick:()=>{gl()},disabled:Bt!==!0||Gt,children:Gt?e.jsxs(e.Fragment,{children:[e.jsx(rs,{size:12,className:"spinning","aria-hidden":"true"}),m("settings.general.restarting","Restarting…")]}):e.jsxs(e.Fragment,{children:[e.jsx(yd,{size:12,"aria-hidden":"true"}),m("settings.general.restartNow","Restart Fusion")]})}),Bt!==!0&&e.jsx("span",{className:"settings-update-install-status","aria-live":"polite",children:m("settings.general.restartUnavailable","Needs a supervising parent — restart Fusion manually without --no-supervise.")}),ta&&e.jsx("span",{className:"settings-update-install-status settings-update-install-status--error","aria-live":"polite",children:ta})]}):e.jsx("button",{type:"button",className:"btn btn-sm settings-update-now-btn",onClick:()=>{ul()},disabled:De,children:De?e.jsxs(e.Fragment,{children:[e.jsx(rs,{size:12,className:"spinning","aria-hidden":"true"}),m("settings.general.updating","Updating…")]}):m("settings.general.updateNow","Update now")}),g&&e.jsx("span",{className:"settings-update-install-status settings-update-install-status--error","aria-live":"polite",children:m("settings.general.updateFailedWithMessage","Update failed: {{message}}",{message:g})})]})}return m("settings.general.upToDate","You're up to date ✓")},[ul,gl,ta,Gt,wn,Bt,m,ae,De,st]),Te=o.useCallback(async()=>{try{const{providers:r}=await Il(),g=Rl(r);da(g),ua(j=>{const H={};for(const[Q,ee]of Object.entries(j)){const ue=g.find(Se=>Se.id===Q);ue&&!ue.authenticated&&(H[Q]=ee)}return Object.keys(H).length===Object.keys(j).length?j:H})}catch{}},[]);o.useEffect(()=>{(M==="global-models"||M==="project-models")&&(On(!0),kd().then(r=>{Dn(r.models),ya(r.favoriteProviders),ka(r.favoriteModels)}).catch(()=>Dn([])).finally(()=>On(!1)))},[M]),o.useEffect(()=>{M==="backups"&&(ks(!0),El(a).then(r=>va(r)).catch(()=>va(null)).finally(()=>ks(!1)))},[M,a]);const Ts=o.useCallback(async()=>{const[r,g]=await Promise.allSettled([bu(a),za(a)]);r.status==="fulfilled"&&X(j=>({...j,...r.value.settings})),g.status==="fulfilled"&&(vs(g.value),ja(g.value.externalTunnel??null))},[a]);o.useEffect(()=>{const r=qe?.state;(r==="running"||r==="starting")&&ja(null)},[qe?.state]),o.useEffect(()=>{M==="remote"&&Ts().catch(()=>{vs(null)})},[M,Ts]),o.useEffect(()=>{if(M!=="remote")return;const r=qe?.state;if(r!=="starting"&&r!=="stopping")return;const g=setInterval(()=>{za(a).then(j=>{vs(j),ja(j.externalTunnel??null)}).catch(()=>{})},1e3);return()=>clearInterval(g)},[M,a,qe?.state]),o.useEffect(()=>{if(M!=="remote")return;if(qe?.state!=="running"){Mt(null);return}let r=!1;return(async()=>{try{const g=await gn("image/svg",{projectId:a,tokenType:"persistent"});if(r)return;Mt({url:g.url,qrSvg:g.data??null})}catch{if(r)return;try{const g=await Cr({projectId:a,tokenType:"persistent"});if(r)return;Mt({url:g.url,qrSvg:null})}catch{r||Mt(null)}}})(),()=>{r=!0}},[M,a,qe?.state,qe?.url]),o.useEffect(()=>{if(M!=="remote")return;const r=xa?.url;if(qe?.state!=="stopped"||!r)return;let g=!1;return(async()=>{try{const j=await gn("image/svg",{projectId:a,tokenType:"persistent"});if(g)return;Mt({url:r,qrSvg:j.data??null})}catch{g||Mt({url:r,qrSvg:null})}})(),()=>{g=!0}},[M,xa?.url,a,qe?.state]),o.useEffect(()=>{M==="worktrees"&&Fl(a).then(r=>ws(r)).catch(()=>ws([]))},[M,a]),o.useEffect(()=>{M==="merge"&&(Fl(a).then(r=>ws(r)).catch(()=>ws([])),vd(a).then(r=>{const g=r.map(ee=>ee.name).filter(ee=>typeof ee=="string"&&ee.length>0),j=new Set,H=["main","master","trunk","develop"],Q=[];for(const ee of H)g.includes(ee)&&!j.has(ee)&&(Q.push(ee),j.add(ee));for(const ee of[...g].sort((ue,Se)=>ue.localeCompare(Se)))j.has(ee)||(j.add(ee),Q.push(ee));$n(Q)}).catch(()=>$n([])))},[M,a]),o.useEffect(()=>{if(M!=="source-control")return;let r=!1;return qn(!0),Vn(null),Dl(a).then(g=>{r||zn(Yp(g))}).catch(()=>{r||(zn([]),Vn("Could not load detected remotes. Enter a custom owner/repo value."))}).finally(()=>{r||qn(!1)}),()=>{r=!0}},[M,a]),o.useEffect(()=>{if(M!=="source-control-global"||Pa.current)return;let r=!1;return Qn(!0),Na(null),xd().then(async g=>{const j=await Promise.allSettled(g.map(async ue=>(await Dl(ue.id)).map(Ae=>({value:`${Ae.owner}/${Ae.repo}`,label:`${Ae.owner}/${Ae.repo}`,source:ue.name}))));if(r)return;const H=new Map;let Q=0;for(const ue of j)if(ue.status==="fulfilled"){Q+=1;for(const Se of ue.value)H.has(Se.value)||H.set(Se.value,Se)}const ee=[...H.values()].sort((ue,Se)=>ue.value.localeCompare(Se.value));Yn(ee),g.length>0&&Q===0&&Na("Could not load remotes from registered projects. Enter a custom owner/repo value."),Pa.current=!0}).catch(()=>{r||(Yn([]),Na("Could not load project list. Enter a custom owner/repo value."),Pa.current=!0)}).finally(()=>{r||Qn(!1)}),()=>{r=!0}},[M,a]),o.useEffect(()=>{if(M!=="memory"||Sa)return;if(Ma.current){Ma.current=!1;return}let r=!1;return Wn(!0),Ol(a).then(async({files:g})=>{if(r)return;Jn(g);const j=g.some(Q=>Q.path===Ve)?Ve:g.find(Q=>Q.path===sn)?.path??g.find(Q=>Q.layer==="dreams")?.path??g[0]?.path??sn;Ta(j);const{content:H}=await Xd(j,a);r||(xs(H),js(!1))}).catch(g=>{r||(s(xe(g)||"Failed to load project memory","error"),xs(""))}).finally(()=>{r||Wn(!1)}),()=>{r=!0}},[M,Sa,Ve,a,s]),o.useEffect(()=>((M==="authentication"||M==="research-global")&&(In(!0),Te().finally(()=>In(!1))),()=>{Ie.current&&(clearInterval(Ie.current),Ie.current=null)}),[M,Te]),o.useEffect(()=>{if(M!=="authentication"||!pt.some(j=>j.type!=="api_key"&&j.loginInProgress))return;const g=setInterval(()=>{Te()},2e3);return()=>clearInterval(g)},[M,pt,Te]);const As=o.useRef({});o.useEffect(()=>{for(const r of pt){const g=r.loginError;if(!g){r.id in As.current&&delete As.current[r.id];continue}As.current[r.id]!==g&&(As.current[r.id]=g,s(`${r.name} login failed: ${g}`,"error"))}},[pt,s]);const Ms=o.useCallback(()=>{ce.current?.scrollTo({top:0,behavior:"smooth"})},[]),xt=o.useCallback(r=>{if(r in Yt.current){const g={...Yt.current};delete g[r],Yt.current=g}ua(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j}),Rn(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j}),ha(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j}),En(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j})},[]);o.useEffect(()=>{const r=ga["github-copilot"];r?.userCode&&Yt.current["github-copilot"]!==r.userCode&&(Yt.current["github-copilot"]=r.userCode,mn(r.userCode))},[ga]);const no=o.useCallback(async r=>{const g=pt.find(j=>j.id===r);if(!(g?.requiresManualCode===!0&&!await Y({title:m("settings.auth.manualPasteTitle","Heads up — manual paste-back required"),message:m("settings.auth.manualPasteMessage","After you sign in with {{name}}, the browser will try to redirect to a localhost address that this dashboard can't reach. The redirect tab will look like it failed. Before that happens, copy the full URL from the browser address bar — you'll paste it back here to finish login. Continue?",{name:g.name}),confirmLabel:m("settings.auth.continueToLogin","Continue to login"),cancelLabel:m("settings.actions.cancel","Cancel")}))){Le(r),xt(r);try{const{url:j,instructions:H,manualCode:Q,deviceCode:ee}=await jd(r);H?.trim()&&!(r==="github-copilot"&&ee)&&ua(ue=>({...ue,[r]:H})),Q&&Rn(ue=>({...ue,[r]:Q})),ee&&r==="github-copilot"&&En(ue=>({...ue,[r]:ee})),(r!=="github-copilot"||!ee)&&window.open(kr(ee?.verificationUri??j),"_blank"),Ie.current=setInterval(async()=>{try{const{providers:ue}=await Il(),Se=Rl(ue);da(Se);const Ae=Se.find(Ga=>Ga.id===r);if(Ae?.authenticated){Ie.current&&(clearInterval(Ie.current),Ie.current=null),Le(null),xt(r),s(m("settings.auth.loginSuccessful","Login successful"),"success"),window.dispatchEvent(new CustomEvent(wd,{detail:{providerId:r}})),Ms();return}Ae?.loginInProgress||(Ie.current&&(clearInterval(Ie.current),Ie.current=null),Le(null),xt(r),s(m("settings.auth.loginDidNotComplete","Login did not complete. Please try again."),"error"))}catch{}},2e3)}catch(j){const H=xe(j)||"Login failed";H.includes("already in progress")||typeof j=="object"&&j!==null&&"status"in j&&j.status===409?(s(m("settings.auth.loginAlreadyInProgress","Login already in progress. You can cancel it and retry."),"warning"),await Te()):s(H,"error"),Le(null),xt(r)}}},[s,pt,xt,Y,Te,Ms]),lo=o.useCallback(async r=>{const g=pa[r]?.trim();if(!g){s(m("settings.auth.pasteRedirectUrlFirst","Paste the full redirect URL or authorization code first."),"warning");return}ma(r);try{(await Cd(r,g)).submitted?(ha(H=>{if(!(r in H))return H;const Q={...H};return delete Q[r],Q}),s(m("settings.auth.authCodeReceived","Authorization code received. Finishing login…"),"success")):s(m("settings.auth.authCodeAlreadySubmitted","That authorization code was already submitted. Waiting for login…"),"warning")}catch(j){s(xe(j)||"Failed to submit authorization code","error")}finally{ma(null)}},[s,pa]),ro=o.useCallback(async r=>{Le(r),da(g=>g.map(j=>j.id===r?{...j,loginInProgress:!1}:j));try{await Sd(r),xt(r),await Te().catch(()=>{}),s(m("settings.auth.loginCancelled","Login cancelled"),"success")}catch(g){s(xe(g)||"Failed to cancel login","error")}finally{Le(null),ma(g=>g===r?null:g),Ie.current&&(clearInterval(Ie.current),Ie.current=null)}},[s,xt,Te]),io=o.useCallback(async r=>{Le(r);try{await Nd(r),await Te(),s(m("settings.auth.loggedOut","Logged out"),"success")}catch(g){s(xe(g)||"Logout failed","error")}finally{Le(null)}},[s,Te]),oo=o.useCallback(async r=>{const g=ba[r]?.trim();if(!g){fs(j=>({...j,[r]:"API key is required"}));return}Le(r),fs(j=>{const H={...j};return delete H[r],H});try{const j=await Pd(r,g);if(fa(H=>{const Q={...H};return delete Q[r],Q}),await Te(),r==="opencode"||r==="opencode-go"){const H=j.modelsRefreshed,Q=j.refreshReason,ee=j.refreshError;ee?Vt(ue=>({...ue,[r]:{tone:"error",message:`Saved, but model refresh failed: ${ee}. Make sure the \`opencode\` CLI is installed on PATH.`}})):Q==="no-models-from-cli"?Vt(ue=>({...ue,[r]:{tone:"error",message:"Saved. The local `opencode` CLI returned no models — run `opencode auth login` and `opencode models opencode --refresh`, then click Save again."}})):typeof H=="number"&&H>0?Vt(ue=>({...ue,[r]:{tone:"success",message:`Refreshed ${H} opencode-go models.`}})):Vt(ue=>{const Se={...ue};return delete Se[r],Se})}s(m("settings.auth.apiKeySaved","API key saved"),"success"),Ms()}catch(j){fs(H=>({...H,[r]:xe(j)||"Failed to save API key"})),(r==="opencode"||r==="opencode-go")&&Vt(H=>{const Q={...H};return delete Q[r],Q})}finally{Le(null)}},[ba,s,Te,Ms]),co=o.useCallback(async r=>{Le(r);try{await Td(r),fa(g=>{const j={...g};return delete j[r],j}),fs(g=>{const j={...g};return delete j[r],j}),await Te(),s(m("settings.auth.apiKeyCleared","API key cleared"),"success")}catch(g){s(xe(g)||"Failed to clear API key","error")}finally{Le(null)}},[s,Te]),uo=o.useCallback(async r=>{if(!((r==="ntfy"||r==="ntfy-message"||r==="ntfy-room")&&(!O.ntfyEnabled||!O.ntfyTopic||!/^[a-zA-Z0-9_-]{1,64}$/.test(O.ntfyTopic)))){if(r==="webhook"){if(!O.webhookEnabled||!O.webhookUrl?.trim())return;try{const g=new URL(O.webhookUrl.trim());if(g.protocol!=="http:"&&g.protocol!=="https:")return}catch{return}}Kn(g=>({...g,[r]:!0})),ys(g=>{const j={...g};return delete j[r],j});try{const g={ntfyEnabled:O.ntfyEnabled,ntfyTopic:O.ntfyTopic,...O.ntfyBaseUrl?.trim()?{ntfyBaseUrl:O.ntfyBaseUrl.trim()}:{},...O.ntfyAccessToken?.trim()?{ntfyAccessToken:O.ntfyAccessToken.trim()}:{}},j=r==="ntfy"?g:r==="ntfy-message"?{...g,messageEventType:"message:agent-to-user"}:r==="ntfy-room"?{...g,messageEventType:"message:room"}:{webhookUrl:O.webhookUrl,webhookFormat:O.webhookFormat||"generic"};if((await Ad(r==="ntfy-message"||r==="ntfy-room"?"ntfy":r,j,a)).success){const Q=r==="ntfy"?"Test notification sent — check your ntfy app!":r==="ntfy-message"?"Message inbox test sent — check your ntfy inbox for the agent-to-user message.":r==="ntfy-room"?"Room reply test sent — check your ntfy inbox for the room reply.":"Test notification sent — check your webhook endpoint!";ys(ee=>({...ee,[r]:{status:"success",message:Q}})),s(Q,"success")}else{const Q=r==="ntfy-message"?"Failed to send message inbox test":r==="ntfy-room"?"Failed to send room reply test":"Failed to send test notification";ys(ee=>({...ee,[r]:{status:"error",message:Q}})),s(Q,"error")}}catch(g){const j=xe(g)||"Failed to send test notification";ys(H=>({...H,[r]:{status:"error",message:j}})),s(j,"error")}finally{Kn(g=>({...g,[r]:!1}))}}},[s,O.ntfyAccessToken,O.ntfyBaseUrl,O.ntfyEnabled,O.ntfyTopic,O.webhookEnabled,O.webhookFormat,O.webhookUrl,a]),go=o.useCallback(async()=>{ks(!0);try{const r=await Md(a);if(r.success){s(m("settings.backups.backupCreated","Backup created successfully"),"success");const g=await El(a);va(g)}else s(r.error||m("settings.backups.createFailed","Failed to create backup"),"error")}catch(r){s(xe(r)||m("settings.backups.createFailed","Failed to create backup"),"error")}finally{ks(!1)}},[s,a]),po=o.useCallback(async()=>{try{const r=ca==="global"?"global":ca==="project"?"project":"both",g=await Id(r,a),j=new Blob([JSON.stringify(g,null,2)],{type:"application/json"}),H=URL.createObjectURL(j),Q=document.createElement("a"),ee=`fusion-settings-${new Date().toISOString().replace(/[:.]/g,"-").slice(0,19)}.json`;Q.href=H,Q.download=ee,document.body.appendChild(Q),Q.click(),document.body.removeChild(Q),URL.revokeObjectURL(H);const ue=r==="global"?m("settings.importExport.scopeLabel.global","global"):r==="project"?m("settings.importExport.scopeLabel.project","project"):m("settings.importExport.scopeLabel.all","all");s(m("settings.importExport.exported","Settings exported ({{scope}} scope)",{scope:ue}),"success")}catch(r){s(xe(r)||m("settings.importExport.exportFailed","Failed to export settings"),"error")}},[s,ca,a]),ho=o.useCallback(async r=>{const g=r.target.files?.[0];if(g){Ia(g),Ps(!0);try{const j=await g.text(),H=JSON.parse(j);ol(H),Jt(!0)}catch(j){s(m("settings.importExport.invalidJson","Invalid JSON file: {{error}}",{error:xe(j)}),"error"),Ia(null)}finally{Ps(!1)}}},[s]),mo=o.useCallback(async()=>{if(Ye){Ps(!0);try{const r=await Rd(Ye,{scope:Ra,merge:Ea},a);if(r.success){const g=[];r.globalCount>0&&g.push(m("settings.importExport.counts.global","{{count}} global",{count:r.globalCount})),r.projectCount>0&&g.push(m("settings.importExport.counts.project","{{count}} project",{count:r.projectCount})),r.workflowSettingsCount>0&&g.push(m("settings.importExport.counts.workflowSettings","{{count}} workflow setting value",{count:r.workflowSettingsCount})),s(m("settings.importExport.imported","Imported {{counts}} setting(s)",{counts:g.join(", ")}),"success"),Jt(!1),ol(null),Ia(null);const j=await Ml(a);X({...j,ignoreHiddenOverlapPaths:j.ignoreHiddenOverlapPaths??!0,allowAbsoluteFileBrowserPaths:j.allowAbsoluteFileBrowserPaths===!0})}else s(r.error||m("settings.importExport.importFailed","Import failed"),"error")}catch(r){s(xe(r)||m("settings.importExport.importFailedDetailed","Failed to import settings"),"error")}finally{Ps(!1)}}},[s,Ye,Ra,Ea,a]),pl=o.useCallback(async r=>{const g=Tt,H=g.includes(r)?g.filter(Q=>Q!==r):[r,...g];ya(H);try{await Dt({favoriteProviders:H,favoriteModels:At})}catch{ya(g)}},[Tt,At]),hl=o.useCallback(async r=>{const g=At,H=g.includes(r)?g.filter(Q=>Q!==r):[r,...g];ka(H);try{await Dt({favoriteProviders:Tt,favoriteModels:H})}catch{ka(g)}},[At,Tt]);o.useEffect(()=>{if(!N)return;const r=g=>{g.key==="Escape"&&!Ut&&t()};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[t,N,Ut]);const bo=Ed(t),fo=U?bo:{},ml=[{laneId:"default",label:"Default Model",globalProviderKey:"defaultProvider",globalModelKey:"defaultModelId",projectProviderKey:"defaultProviderOverride",projectModelKey:"defaultModelIdOverride",projectThinkingKey:"defaultThinkingLevelOverride",helperText:"Default AI model used for task execution when no per-task override is set.",fallbackOrder:"Project override → Global default lane → Automatic resolution"},{laneId:"execution",label:"Execution Model",globalProviderKey:"executionGlobalProvider",globalModelKey:"executionGlobalModelId",globalThinkingKey:"executionGlobalThinkingLevel",projectProviderKey:"executionProvider",projectModelKey:"executionModelId",helperText:"AI model used for task implementation (executor agent).",fallbackOrder:"Project override → Global execution lane → Global default lane → Automatic resolution"},{laneId:"planning",label:"Planning Model",globalProviderKey:"planningGlobalProvider",globalModelKey:"planningGlobalModelId",globalThinkingKey:"planningGlobalThinkingLevel",projectProviderKey:"planningProvider",projectModelKey:"planningModelId",helperText:"AI model used for task planning.",fallbackOrder:"Project override → Global planning lane → Global default lane → Automatic resolution"},{laneId:"validator",label:"Reviewer Model",globalProviderKey:"validatorGlobalProvider",globalModelKey:"validatorGlobalModelId",globalThinkingKey:"validatorGlobalThinkingLevel",projectProviderKey:"validatorProvider",projectModelKey:"validatorModelId",helperText:"AI model used for code and specification review.",fallbackOrder:"Project override → Global reviewer lane → Global default lane → Automatic resolution"},{laneId:"merger",label:"Merger Model",globalProviderKey:"mergerGlobalProvider",globalModelKey:"mergerGlobalModelId",globalThinkingKey:"mergerGlobalThinkingLevel",projectProviderKey:"mergerProvider",projectModelKey:"mergerModelId",projectThinkingKey:"mergerThinkingLevel",helperText:"AI model used for merge conflict resolution, clean-room merge, stash-conflict recovery, and related merger agent sessions.",fallbackOrder:"Project override → Global merger lane → Project default lane → Global default lane → Automatic resolution"},{laneId:"summarization",label:"Title and Git Commit Message Summarization Model",globalProviderKey:"titleSummarizerGlobalProvider",globalModelKey:"titleSummarizerGlobalModelId",globalThinkingKey:"titleSummarizerGlobalThinkingLevel",projectProviderKey:"titleSummarizerProvider",projectModelKey:"titleSummarizerModelId",projectThinkingKey:"titleSummarizerThinkingLevel",helperText:"AI model used for auto-generating task titles and merge commit summaries.",fallbackOrder:"Project override → Global summarization lane → Project planning lane → Project default lane → Global default lane → Automatic resolution"},{laneId:"import-translate",label:"Import Auto-Translation Model",globalProviderKey:"importTranslateGlobalProvider",globalModelKey:"importTranslateGlobalModelId",globalThinkingKey:"importTranslateGlobalThinkingLevel",projectProviderKey:"importTranslateProvider",projectModelKey:"importTranslateModelId",projectThinkingKey:"importTranslateThinkingLevel",helperText:"AI model used to translate foreign-language GitHub/GitLab issue titles and bodies in the Import Tasks panel.",fallbackOrder:"Project override → Global import-translate lane → Summarization lane → Project default → Global default"}];function Da(r){if(!_?.project)return"inherited";const g=_.project[r.projectProviderKey],j=_.project[r.projectModelKey];return g!==void 0||j!==void 0?"overridden":"inherited"}function yo(r){const g=O[r.projectProviderKey],j=O[r.projectModelKey];return g&&j?`${g}/${j}`:""}function ko(r,g){if(g){const j=g.indexOf("/");X(H=>({...H,[r.projectProviderKey]:g.slice(0,j),[r.projectModelKey]:g.slice(j+1)}))}else{if(Da(r)==="inherited")return;X(H=>({...H,[r.projectProviderKey]:void 0,[r.projectModelKey]:void 0}))}}function vo(r){Da(r)!=="inherited"&&X(j=>({...j,[r.projectProviderKey]:void 0,[r.projectModelKey]:void 0}))}function bl(r,g="project"){const j=g==="project"?r.projectThinkingKey:r.globalThinkingKey;return j?O[j]??"":""}function La(r,g,j="project"){const H=j==="project"?r.projectThinkingKey:r.globalThinkingKey;H&&X(Q=>({...Q,[H]:g||void 0}))}function fl(r,g="project"){La(r,"",g)}const xo=o.useCallback(r=>{aa(r),la(".")},[la]),mt=o.useCallback(()=>{aa(null)},[]),Oa=o.useCallback(r=>{Ue!==null&&(Gs(r)||(X(g=>{const j=g.overlapIgnorePaths&&g.overlapIgnorePaths.length>0?[...g.overlapIgnorePaths]:[""];return j[Ue]=r,{...g,overlapIgnorePaths:j}}),mt()))},[Ue,mt]),jo=o.useCallback(()=>{if(nt===".")return;const r=nt.endsWith("/")?nt:`${nt}/`;Oa(r)},[nt,Oa]),wo=o.useCallback(r=>{r.target===r.currentTarget&&mt()},[mt]),Co=o.useCallback(()=>{ra("."),Sn(!0)},[ra]),bt=o.useCallback(()=>{Sn(!1)},[]),So=o.useCallback(r=>{if(Gs(r))return;const g=r.endsWith("/")?r:`${r}/`;X(j=>({...j,worktreesDir:g})),bt()},[bt]),No=o.useCallback(()=>{if(Gs(lt))return;const r=lt==="."?"./":lt.endsWith("/")?lt:`${lt}/`;X(g=>({...g,worktreesDir:r})),bt()},[lt,bt]),Po=o.useCallback(r=>{r.target===r.currentTarget&&bt()},[bt]),To=o.useCallback(r=>{na(r),oa(".")},[oa]),ft=o.useCallback(()=>{na(null)},[]),Ao=o.useCallback(r=>{$e!==null&&(Gs(r)||(X(g=>{const j=g.worktreeCopyFiles&&g.worktreeCopyFiles.length>0?[...g.worktreeCopyFiles]:[""];return j[$e]=r,{...g,worktreeCopyFiles:j}}),ft()))},[$e,ft]),Mo=o.useCallback(r=>{r.target===r.currentTarget&&ft()},[ft]),Io=o.useCallback((r,g)=>{X(j=>{const H=j.worktreeCopyFiles&&j.worktreeCopyFiles.length>0?[...j.worktreeCopyFiles]:[""];return H[r]=g,{...j,worktreeCopyFiles:H}})},[]),Ro=o.useCallback(r=>{if(X(g=>{const H=(g.worktreeCopyFiles&&g.worktreeCopyFiles.length>0?[...g.worktreeCopyFiles]:[""]).filter((Q,ee)=>ee!==r);return{...g,worktreeCopyFiles:H.length>0?H:[]}}),$e===r){ft();return}$e!==null&&$e>r&&na($e-1)},[$e,ft]),Eo=o.useCallback(()=>{X(r=>{const g=r.worktreeCopyFiles&&r.worktreeCopyFiles.length>0?r.worktreeCopyFiles:[""];return{...r,worktreeCopyFiles:[...g,""]}})},[]),Fo=o.useCallback((r,g)=>{X(j=>{const H=j.overlapIgnorePaths&&j.overlapIgnorePaths.length>0?[...j.overlapIgnorePaths]:[""];return H[r]=g,{...j,overlapIgnorePaths:H}})},[]),Do=o.useCallback(r=>{if(X(g=>{const H=(g.overlapIgnorePaths&&g.overlapIgnorePaths.length>0?[...g.overlapIgnorePaths]:[""]).filter((Q,ee)=>ee!==r);return{...g,overlapIgnorePaths:H.length>0?H:[]}}),Ue===r){mt();return}Ue!==null&&Ue>r&&aa(Ue-1)},[Ue,mt]),Lo=o.useCallback(()=>{X(r=>{const g=r.overlapIgnorePaths&&r.overlapIgnorePaths.length>0?r.overlapIgnorePaths:[""];return{...r,overlapIgnorePaths:[...g,""]}})},[]),Oo=o.useCallback(async()=>{if(we||sa||rt)return;const r=O.researchSettings?.limits;if(r?.maxConcurrentRuns!==void 0&&(!Number.isFinite(r.maxConcurrentRuns)||r.maxConcurrentRuns<1)){Wt("Research max concurrent runs must be at least 1.");return}if(r?.maxSourcesPerRun!==void 0&&(!Number.isFinite(r.maxSourcesPerRun)||r.maxSourcesPerRun<1)){Wt("Research max sources per run must be at least 1.");return}if(r?.maxDurationMs!==void 0&&(!Number.isFinite(r.maxDurationMs)||r.maxDurationMs<1e3)){Wt("Research max duration must be at least 1000 ms.");return}if(r?.requestTimeoutMs!==void 0&&(!Number.isFinite(r.requestTimeoutMs)||r.requestTimeoutMs<1e3)){Wt("Research request timeout must be at least 1000 ms.");return}Wt(null);const g=fr(O.dashboardKeyboardShortcuts??{});if(g){s(g,"error");return}je(!0);try{const j=ph(O.worktreeCopyFiles);let H=oe;O.worktrunk?.enabled===!0&&!H&&(H=(await Z.refresh()).status==="installed");const Q=M==="source-control-global"&&be?be:O,ee={...O,worktreeInitCommand:O.worktreeInitCommand?.trim()||void 0,worktreesDir:O.worktreesDir?.trim()||void 0,worktrunk:{enabled:H&&O.worktrunk?.enabled===!0,binaryPath:O.worktrunk?.binaryPath?.trim()||void 0,onFailure:O.worktrunk?.onFailure??"fail"},maxAutoMergeRetries:mr(O),executorToolFailureRetryCount:Hs(O.executorToolFailureRetryCount,2),executorToolFailureRetryBackoffMs:Hs(O.executorToolFailureRetryBackoffMs,2e3),executorToolFailureThreshold:Math.max(1,Math.floor(Number(O.executorToolFailureThreshold??3)||3)),executorModelEscalationEnabled:O.executorModelEscalationEnabled===!0,executorEscalationProvider:O.executorEscalationProvider?.trim()||void 0,executorEscalationModelId:O.executorEscalationModelId?.trim()||void 0,executorEscalationNodeId:O.executorEscalationNodeId?.trim()||void 0,taskPrefix:O.taskPrefix?.trim()||void 0,githubTrackingDefaultRepo:O.githubTrackingDefaultRepo?.trim()||void 0,dashboardKeyboardShortcuts:Object.fromEntries(Object.entries(on(O.dashboardKeyboardShortcuts)).map(([Ae,Ga])=>[Ae,hn(Ga).normalized])),gitlabEnabled:Q.gitlabEnabled,gitlabInstanceUrl:Q.gitlabInstanceUrl?.trim()||void 0,gitlabApiBaseUrl:Q.gitlabApiBaseUrl?.trim()||void 0,gitlabAuthToken:Q.gitlabAuthToken?.trim()||void 0,gitlabAuthTokenType:Q.gitlabAuthTokenType??"personal",githubAuthToken:O.githubAuthToken?.trim()||void 0,prTitlePromptInstructions:O.prTitlePromptInstructions?.trim()||void 0,prDescriptionPromptInstructions:O.prDescriptionPromptInstructions?.trim()||void 0,pushRemote:O.pushAfterMerge&&O.pushRemote?.trim()||void 0,overlapIgnorePaths:(O.overlapIgnorePaths??[]).map(Ae=>Ae.trim()).filter(Ae=>Ae.length>0),worktreeCopyFiles:j.length>0||le?.project?.worktreeCopyFiles!==void 0?j:void 0,experimentalFeatures:gh(O.experimentalFeatures)};M==="source-control"&&Ul({project:{gitlabInstanceUrl:ee.gitlabInstanceUrl,gitlabApiBaseUrl:ee.gitlabApiBaseUrl}}),M==="source-control-global"&&Ul({global:{gitlabInstanceUrl:ee.gitlabInstanceUrl,gitlabApiBaseUrl:ee.gitlabApiBaseUrl}});const{globalPatch:ue,projectPatch:Se}=Pu({payload:ee,initialValues:Ke,initialScopedValues:le,activeSection:M,scopedMcpValues:_?{global:Lt("global",_),project:Lt("project",_)}:void 0});await Promise.all([Object.keys(ue).length>0?Dt(ue):Promise.resolve(),Object.keys(Se).length>0?Wa(Se,a):Promise.resolve(),Cs!==nl.current?Fd({globalMaxConcurrent:Cs??4}):Promise.resolve()]),await T.current?.(),s(m("settings.general.settingsSaved","Settings saved"),"success"),t()}catch(j){if(j instanceof Mr)return;s(xe(j),"error")}finally{je(!1)}},[O,be,Cs,sa,rt,Ke,le,_,t,s,a,M,we,m]),It=o.useMemo(()=>Au(M),[M]),Ka=o.useMemo(()=>Mu(M),[M]),Ba=o.useMemo(()=>{const r=nn.find(g=>g.id===M);return r?m(r.labelKey,r.label):M},[M,m]),Ko=o.useCallback(async()=>{if(!(at||!It)){ps(!0);try{if(It.scope==="global"){const r={};for(const g of It.keys)r[g]=Dd[g];await Dt(r)}else{const r={};for(const g of It.keys)r[g]=null;await Wa(r,a)}await es(!1),s(m("settings.reset.menuResetSuccess","{{section}} settings reset to defaults",{section:Ba}),"success"),gs(!1)}catch(r){s(xe(r),"error")}finally{ps(!1)}}},[at,It,a,es,s,m,Ba]),Bo=o.useCallback(async()=>{if(!at){ps(!0);try{const r={};for(const g of Iu)r[g]=null;await Wa(r,a),await es(!1),s(m("settings.reset.allProjectResetSuccess","All project settings reset to defaults"),"success"),gs(!1)}catch(r){s(xe(r),"error")}finally{ps(!1)}}},[at,a,es,s,m]),Rt=o.useCallback(()=>{at||gs(!1)},[at]),Go=o.useCallback(r=>{r.target===r.currentTarget&&Rt()},[Rt]);o.useEffect(()=>{if(!Ut)return;const r=g=>{g.key==="Escape"&&(g.stopPropagation(),Rt())};return document.addEventListener("keydown",r,!0),()=>document.removeEventListener("keydown",r,!0)},[Ut,Rt]);const Ho=o.useCallback(async()=>{try{await Zd(Ve,Ca,a),js(!1),s(m("settings.memory.memorySaved","Memory saved"),"success")}catch(r){s(xe(r)||"Failed to save memory","error")}},[Ve,Ca,a,s]),_o=o.useCallback(async()=>{tl(!0);try{const{path:r,content:g}=await eu(Ve,a),j=r??Ve;Ve!==j&&(Ma.current=!0),Ta(j),xs(g),js(!1);const{files:H}=await Ol(a);Jn(H),s(m("settings.memory.memoryCompacted","Memory file compacted"),"success")}catch(r){s(xe(r)||"Failed to compact memory","error")}finally{tl(!1)}},[Ve,a,s]),Wo=o.useCallback(async()=>{Xn(!0),Zn(null);try{const r=await tu(Aa,a);Zn(r),s(r.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",r.qmdAvailable?"success":"warning")}catch(r){s(xe(r)||"Failed to test memory retrieval","error")}finally{Xn(!1)}},[Aa,a,s]),Uo=o.useCallback(async()=>{el(!0);try{await su(a),s(m("settings.memory.dreamCompleted","Dream processing completed"),"success")}catch(r){s(r instanceof Error?r.message:"Failed to run dream processing","error")}finally{el(!1)}},[a,s]),$o=o.useCallback(async()=>{sl(!0);try{const r=await au(a);await dl(),s(r.qmdAvailable?m("settings.memory.qmdInstalled","qmd installed successfully"):m("settings.memory.qmdInstallUnavailable","qmd install finished, but qmd is still unavailable"),r.qmdAvailable?"success":"warning")}catch(r){s(xe(r)||m("settings.memory.qmdInstallFailed","Failed to install qmd"),"error")}finally{sl(!1)}},[a,dl,s]),zo=()=>{if(!rt)return;const r=rt.name.trim();if(!r){s(m("settings.models.presetNameRequired","Preset name is required"),"error");return}const g=O.modelPresets||[];let j;Qt?j=Qt:j=Hd(r,g);const H={id:j,name:r,executorProvider:rt.executorProvider,executorModelId:rt.executorModelId,validatorProvider:rt.validatorProvider,validatorModelId:rt.validatorModelId};X(Q=>{const ee=Q.modelPresets||[],ue=Qt?ee.map(Se=>Se.id===Qt?H:Se):[...ee,H];return{...Q,modelPresets:ue}}),Bn(null),Gn(null)},qo=o.useCallback(async(r,g)=>{Hn(r);try{await g(),await Ts()}catch(j){s(xe(j)||`Failed to ${r}`,"error")}finally{Hn(null)}},[s,Ts]),Vo=o.useCallback(()=>{if(typeof navigator<"u"&&navigator.userAgent.includes("Windows"))return"winget install Cloudflare.cloudflared";const r=typeof navigator<"u"?navigator.platform:"",g=typeof navigator<"u"?navigator.userAgent:"",j=/(Mac|iPhone|iPad|iPod)/i.test(r),H=/(arm64|aarch64)/i.test(`${r} ${g}`);return j?"brew install cloudflared":`curl -L --output /tmp/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${H?"arm64":"amd64"} && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared # If sudo is unavailable, use: mkdir -p ~/.local/bin && mv /tmp/cloudflared ~/.local/bin/cloudflared`},[]),Yo=o.useCallback(()=>typeof navigator>"u"||!/(Mac|iPhone|iPad|iPod)/i.test(navigator.platform)?null:`curl -L --output /tmp/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-${/(arm64|aarch64)/i.test(`${navigator.platform} ${navigator.userAgent}`)?"arm64":"amd64"} && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared`,[]),Qo=o.useCallback(async()=>{_n(!0),wa(null);try{const r=await fu(a);if(!r.success){wa(r.error??m("settings.remote.installationFailed","Installation failed"));return}const g=await za(a);vs(g),s(m("settings.remote.cloudflaredInstalled","cloudflared installed successfully"),"success")}catch(r){wa(r instanceof Error?r.message:m("settings.remote.installationFailed","Installation failed"))}finally{_n(!1)}},[s,a]),Jo=()=>{switch(M){case"cli-agents":return e.jsx(hh,{projectId:a,addToast:s});case"general":return e.jsx(Eg,{form:O,setForm:X,projectId:a,addToast:s,prefixError:sa,setPrefixError:Ur,onQuickChatButtonModeChange:x,onMobileNavPrimaryItemsChange:f});case"source-control":return e.jsx(ep,{form:O,setForm:X,projectTrackingRepoOptions:Ei,projectTrackingRepoLoading:Fi,projectTrackingRepoError:Di});case"source-control-global":return e.jsx(tp,{form:O,setForm:X,globalSettings:be,onGlobalGitlabSettingsChange:r=>ve(g=>({gitlabEnabled:g?.gitlabEnabled,gitlabInstanceUrl:g?.gitlabInstanceUrl,gitlabApiBaseUrl:g?.gitlabApiBaseUrl,gitlabAuthToken:g?.gitlabAuthToken,gitlabAuthTokenType:g?.gitlabAuthTokenType,...r})),globalTrackingRepoOptions:Li,globalTrackingRepoLoading:Oi,globalTrackingRepoError:Ki});case"global-general":return e.jsx(Hu,{form:O,setForm:X});case"keyboard-shortcuts":return e.jsx(Wu,{form:O,setForm:X});case"global-models":return e.jsx(ag,{form:O,setForm:X,availableModels:Fn,modelsLoading:Ln,globalModelLanes:ml.filter(r=>r.laneId!=="default"),getLaneThinkingValue:r=>bl(r,"global"),updateLaneThinkingValue:(r,g)=>La(r,g,"global"),resetLaneThinkingValue:r=>fl(r,"global"),favoriteProviders:Tt,favoriteModels:At,onToggleFavorite:pl,onToggleModelFavorite:hl,addToast:s,projectId:a});case"secrets":return e.jsx(Pg,{addToast:s});case"global-mcp":return e.jsx(Xu,{form:pe("global"),setForm:Ce("global"),projectId:a,addToast:s});case"mcp":return e.jsx(cp,{form:pe("project"),setForm:Ce("project"),globalSettings:_?.global??null,projectId:a,addToast:s});case"project-models":return e.jsx(Kg,{form:O,setForm:X,projectId:a,addToast:s,onOpenWorkflowSettings:C,registerWorkflowLaneSaver:$,models:{modelLanes:ml,getLaneStatus:Da,getLaneValue:yo,updateLaneValue:ko,resetLaneValue:vo,getLaneThinkingValue:bl,updateLaneThinkingValue:La,resetLaneThinkingValue:fl,availableModels:Fn,modelsLoading:Ln,favoriteProviders:Tt,favoriteModels:At,onToggleFavorite:pl,onToggleModelFavorite:hl,editingPresetId:Qt,setEditingPresetId:Bn,presetDraft:rt,setPresetDraft:Gn,onSavePresetDraft:zo,confirmDelete:Y}});case"appearance":return e.jsx(Ou,{form:O,setForm:X,themeMode:c,colorTheme:d,dashboardFontScalePct:l,shadcnCustomColors:h,resolvedThemeMode:p,onThemeModeChange:i,onColorThemeChange:u,onDashboardFontScaleChange:b,onShadcnCustomColorsChange:w,sessionBannersHidden:ge,setSessionBannersHidden:Gd});case"scheduling-global":return e.jsx(Hg,{globalMaxConcurrent:Cs,concurrencyLoading:M==="scheduling-global"&&!rl&&!Ss.current,onGlobalMaxConcurrentChange:r=>{Ss.current=!0,al(r)}});case"scheduling":return e.jsx(Gg,{form:O,setForm:X,concurrencyLoading:M==="scheduling"&&!rl&&!Ss.current,onOverlapIgnorePathChange:Fo,onOpenOverlapPathPicker:xo,onRemoveOverlapIgnorePath:Do,onAddOverlapIgnorePath:Lo,onOpenWorkflowSettings:C});case"scheduled-evals":return e.jsx(Ug,{form:O,setForm:X});case"node-routing":return e.jsx(zg,{form:O,setForm:X,nodes:ni});case"worktrees":return e.jsx(qg,{form:O,setForm:X,gitRemotes:Un,worktrunkInstall:Z,worktrunkInstallVerified:oe,onOpenWorktreesDirPicker:Co,onWorktreeCopyFileChange:Io,onRemoveWorktreeCopyFile:Ro,onAddWorktreeCopyFile:Eo,onOpenWorktreeCopyFilePicker:To,onOpenApprovals:S});case"commands":return e.jsx(Vg,{form:O,setForm:X});case"merge":return e.jsx(Xg,{form:O,setForm:X,integrationBranchOptions:Mi,integrationBranchCustomMode:Ii,setIntegrationBranchCustomMode:Ri,onOpenWorkflowSettings:C,gitRemoteOptions:Un.map(r=>r.name),projectId:a});case"agent-permissions":return e.jsx(ap,{form:O,setForm:X});case"memory":return e.jsx(ip,{form:O,setForm:X,memory:{memoryCapabilities:Qi,memoryBackendStatus:Yi,memoryBackendLoading:Ji,memoryBackendError:Xi,memoryFiles:Bi,selectedMemoryPath:Ve,setSelectedMemoryPath:Ta,memoryContent:Ca,setMemoryContent:xs,memoryLoading:Ai,memoryDirty:Sa,setMemoryDirty:js,memoryTestQuery:Aa,setMemoryTestQuery:Gi,memoryTestLoading:Hi,memoryTestResult:_i,qmdInstallLoading:$i,dreamRunning:Wi,memoryCompactLoading:Ui,onInstallQmd:$o,onTestMemoryRetrieval:Wo,onDreamNow:Uo,onCompactMemory:_o,onSaveMemory:Ho}});case"research-global":return e.jsx(Uu,{form:O,setForm:X,authProviders:pt,onNavigateToSection:W});case"research-project":return e.jsx(op,{form:O,setForm:X,researchLimitError:$r});case"cli-binary":return e.jsx(Wg,{});case"experimental":return e.jsx(Ku,{form:O,setForm:X,knownFeatures:ch,legacyAliases:Qs,getCanonicalKey:jn,isFeatureEnabled:uh,hiddenFeatureKeys:dh});case"backups-global":return e.jsx(up,{form:O,setForm:X,backupInfo:mi,backupLoading:bi,onBackupNow:go});case"backups":return e.jsx(dp,{form:O,setForm:X});case"notifications":return e.jsx(Gu,{form:O,setForm:X,testNotificationLoading:pi,testNotificationResult:hi,onTestProviderNotification:uo});case"node-sync":return e.jsx(Bu,{form:O,setForm:X});case"remote":return e.jsx($u,{form:O,setForm:X,remote:{projectId:a,addToast:s,remoteStatus:qe,externalTunnel:xa,tunnelShareLink:Ti,remoteBusyAction:fi,cloudflaredInstalling:yi,cloudflaredInstallError:ki,cloudflaredManualInstallCommand:Vo,cloudflaredMacFallbackCommand:Yo,handleInstallCloudflared:Qo,runRemoteAction:qo,remoteShortLivedToken:Ni,setRemoteShortLivedToken:Pi,remoteAuthLinkTokenType:vi,setRemoteAuthLinkTokenType:xi,remoteUrlPreview:ji,setRemoteUrlPreview:wi,remoteQrSvg:Ci,setRemoteQrSvg:Si}});case"prompts":return e.jsx(Rg,{form:O,setForm:X,onOpenWorkflowSettings:C});case"plugins":return e.jsx(hp,{projectId:a,addToast:s,activePluginsSubsection:fe,setActivePluginsSubsection:he});case"authentication":return e.jsx(gg,{auth:{projectId:a,addToast:s,authProviders:pt,authLoading:ri,authActionInProgress:ii,apiKeyInputs:ba,setApiKeyInputs:fa,apiKeyErrors:ui,opencodeApiKeyRefreshStatus:gi,deviceCodes:ga,loginInstructions:oi,manualCodeConfigs:ci,manualCodeInputs:pa,setManualCodeInputs:ha,manualCodeSubmitInProgress:di,loadAuthStatus:Te,handleLogin:no,handleLogout:io,handleCancelLogin:ro,handleSaveApiKey:oo,handleClearApiKey:co,handleSubmitManualCode:lo,onReopenOnboarding:D}});case"hermes-runtime":return e.jsx(Cg,{});case"openclaw-runtime":return e.jsx(Sg,{});case"paperclip-runtime":return e.jsx(Ng,{})}};return e.jsxs("div",{className:k?"settings-embedded right-dock-embedded-view":"modal-overlay open settings-modal-overlay",...fo,"data-testid":k?"settings-view":void 0,role:k?"region":"dialog","aria-label":k?m("settings.title","Settings"):void 0,"aria-modal":k?void 0:"true",children:[e.jsxs("div",{className:k?"modal modal-lg settings-modal settings-modal--embedded":"modal modal-lg settings-modal",ref:re,style:k?void 0:ne,children:[e.jsxs("div",{className:k?"modal-header modal-header--embedded":"modal-header",children:[e.jsx("div",{className:"settings-modal-heading",children:e.jsxs("h3",{children:[k&&e.jsx(Ld,{size:20,"aria-hidden":"true"}),e.jsx("span",{children:m("settings.title","Settings")})]})}),e.jsxs("div",{className:"settings-header-actions",children:[e.jsxs("a",{href:"https://github.com/Runfusion/Fusion",target:"_blank",rel:"noopener noreferrer",className:"settings-github-star-btn","aria-label":m("settings.header.starFusion","Star Fusion on GitHub"),title:m("settings.header.starFusion","Star Fusion on GitHub"),onClick:Wr,"data-clicked":_r?"true":"false",children:[e.jsxs("span",{className:"settings-github-star-btn__action",children:[e.jsx(it,{provider:"github",size:"sm"}),e.jsx(Od,{size:11,"aria-hidden":"true"}),m("settings.header.star","Star")]}),_t!==null&&e.jsx("span",{className:"settings-github-star-btn__count","aria-label":`${_t.toLocaleString()} stars`,children:_t>=1e3?`${(_t/1e3).toFixed(1)}k`:_t.toLocaleString()})]}),e.jsxs("a",{href:"https://discord.gg/ksrfuy7WYR",target:"_blank",rel:"noopener noreferrer",className:"btn btn-sm settings-header-discord-btn","aria-label":m("settings.header.joinDiscord","Join our Discord"),title:m("settings.header.joinDiscord","Join our Discord"),children:[e.jsx(Vp,{size:13}),m("settings.header.discord","Discord")]})]}),!k&&e.jsx("button",{className:"modal-close",onClick:t,"aria-label":m("actions.close","Close"),children:"×"}),k&&E==="mobile"&&e.jsx("button",{className:"modal-close settings-embedded-mobile-close",onClick:t,"aria-label":m("actions.close","Close"),children:"×"})]}),me?e.jsx("div",{className:"settings-empty-state settings-loading",children:e.jsx(kt,{label:m("settings.loading","Loading…")})}):e.jsxs("div",{className:"settings-layout",children:[e.jsxs("aside",{className:"settings-navigation","aria-label":m("settings.search.navigationLabel","Settings navigation"),style:Zi,children:[_e&&e.jsx("div",{className:"settings-mobile-section-picker",children:e.jsxs("div",{className:"settings-mobile-section-picker-control-row",children:[qt?e.jsx("select",{id:"settings-mobile-section","aria-label":m("settings.mobileNav.label","Settings Section"),className:"select touch-target",value:M,onChange:r=>W(r.target.value),children:gt.map((r,g)=>{if(!r.isGroupHeader)return null;const j=gt.slice(g+1).filter(ee=>!ee.isGroupHeader),H=gt.slice(g+1).findIndex(ee=>ee.isGroupHeader),Q=H===-1?j:j.slice(0,H);return Q.length===0?null:e.jsx("optgroup",{label:m(r.labelKey,r.label),children:Q.map(ee=>{const ue=m(ee.labelKey,ee.label);return e.jsx("option",{value:ee.id,children:oh(ee,ue)},ee.id)})},r.id)})}):e.jsx("p",{className:"settings-search-empty-hint",children:m("settings.search.noMobileOptions","No sections match this search.")}),An&&e.jsx("button",{type:"button",className:"btn btn-sm btn-icon settings-search-toggle",onClick:()=>Zs(r=>!r),"aria-expanded":bs,"aria-controls":"settings-search-row-region","aria-label":bs?m("settings.search.toggleHide","Hide search"):m("settings.search.toggleShow","Show search"),children:bs?e.jsx(yr,{size:16}):e.jsx(cn,{size:16})})]})}),e.jsxs("label",{className:"settings-advanced-toggle",children:[e.jsx("input",{type:"checkbox",checked:ct,onChange:r=>cs(r.target.checked)}),e.jsx("span",{children:m("settings.advanced.toggle","Advanced settings")})]}),bs&&e.jsx("div",{className:"settings-search","data-testid":"settings-search",children:e.jsxs("div",{id:"settings-search-row-region",className:"settings-search-row",children:[e.jsx("label",{className:"settings-search-label",htmlFor:"settings-search-input",children:m("settings.search.label","Search settings")}),e.jsxs("div",{className:"settings-search-input-wrap",children:[e.jsx("input",{id:"settings-search-input","data-testid":"settings-search-input",className:"input settings-search-input",type:"search",value:Nt,onChange:r=>tt(r.target.value),onKeyDown:r=>{r.key==="Escape"&&zt&&(r.stopPropagation(),tt(""))},placeholder:m("settings.search.placeholder","Search by setting or section"),"aria-describedby":"settings-search-results"}),zt&&e.jsx("button",{type:"button",className:"btn btn-sm settings-search-clear",onClick:()=>tt(""),"aria-label":m("settings.search.clear","Clear settings search"),children:m("actions.clear","Clear")})]}),e.jsx("div",{id:"settings-search-results",className:"settings-search-results","aria-live":"polite",children:zt?ut.length>0?m("settings.search.settingResultCount",{count:ut.length}):m("settings.search.resultCount",{count:Tn.length}):m("settings.search.allSections","Showing all settings sections")}),ut.length>0&&e.jsxs("ul",{className:"settings-search-hits","data-testid":"settings-search-hits",children:[ut.slice(0,an).map(r=>{const g=ze.find(j=>j.id===r.sectionId);return e.jsx("li",{children:e.jsxs("button",{type:"button",className:"settings-search-hit","data-testid":`settings-search-hit-${r.key}`,onClick:()=>li(r.sectionId,r.key),children:[e.jsx("span",{className:"settings-search-hit-label",children:r.label}),g&&e.jsx("span",{className:"settings-search-hit-section",children:m(g.labelKey,g.label)})]})},`${r.sectionId}:${r.key}`)}),ut.length>an&&e.jsx("li",{className:"settings-search-hits-more",children:m("settings.search.moreResults","{{count}} more — keep typing to narrow",{count:ut.length-an})})]})]})}),e.jsx("nav",{className:"settings-sidebar",children:qt?gt.map(r=>r.isGroupHeader?e.jsx("div",{className:"settings-group-header",children:m(r.labelKey,r.label)},r.id):e.jsxs("button",{className:`settings-nav-item${M===r.id?" active":""}`,onClick:()=>W(r.id),title:r.scope==="global"?m("settings.nav.tooltip.global","Shared across all projects"):r.scope==="project"?m("settings.nav.tooltip.project","Specific to this project"):void 0,children:[r.icon?e.jsx(r.icon,{className:"settings-scope-icon","aria-label":r.scope==="project"?m("settings.nav.aria.project","Project setting"):m("settings.nav.aria.global","Global setting"),size:16}):e.jsxs(e.Fragment,{children:[r.scope==="global"&&e.jsx(Us,{className:"settings-scope-icon","aria-label":m("settings.nav.aria.global","Global setting"),size:16}),r.scope==="project"&&e.jsx(Kd,{className:"settings-scope-icon","aria-label":m("settings.nav.aria.project","Project setting"),size:16})]}),m(r.labelKey,r.label)]},r.id)):e.jsxs("div",{className:"settings-search-empty",role:"status",children:[e.jsx("p",{children:m("settings.search.noResults",'No settings sections match "{{query}}".',{query:Nt.trim()})}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>tt(""),children:m("settings.search.clear","Clear settings search")})]})})]}),ht&&e.jsx("div",{className:"settings-nav-resize-handle",role:"separator","aria-orientation":"vertical","aria-label":m("settings.nav.resize","Resize settings navigation"),"aria-valuemin":Or,"aria-valuemax":Kr,"aria-valuenow":Be,tabIndex:0,onPointerDown:eo,onKeyDown:to}),e.jsx("div",{className:"settings-content",ref:ce,"data-show-advanced":ct?"true":"false",children:qt?e.jsx(Wd,{highlightedKey:Pe,children:Jo()}):e.jsxs("div",{className:"settings-empty-state settings-search-content-empty",role:"status",children:[e.jsx("p",{children:m("settings.search.noResults",'No settings sections match "{{query}}".',{query:Nt.trim()})}),e.jsx("button",{type:"button",className:"btn",onClick:()=>tt(""),children:m("settings.search.clear","Clear settings search")})]})})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsxs("div",{className:"settings-modal-footer-version",children:[e.jsx("a",{href:"https://github.com/Runfusion/Fusion/discussions",target:"_blank",rel:"noopener noreferrer",className:"btn btn-sm settings-footer-help-btn","aria-label":m("settings.footer.helpDiscussions","Help and discussions"),title:m("settings.footer.helpDiscussions","Help and discussions"),children:m("settings.footer.help","Help")}),e.jsxs("div",{className:"settings-update-check",children:[We&&e.jsxs("button",{type:"button",className:"settings-version-check-btn",onClick:()=>{so()},disabled:q,"aria-label":m("settings.footer.checkUpdates","Check for updates"),title:m("settings.footer.checkUpdates","Check for updates"),children:[e.jsx("span",{className:"settings-modal-version",children:E==="mobile"?m("settings.footer.versionShort","v{{version}}",{version:We}):m("settings.footer.version","Version {{version}}",{version:We})}),e.jsx(rs,{size:12,className:q?"spinning":void 0})]}),ae&&e.jsx("span",{"aria-live":"polite",className:`settings-update-result ${ae.error?"settings-update-result--error":ae.updateAvailable?"settings-update-result--available":"settings-update-result--up-to-date"}`,children:ao()})]})]}),e.jsxs("div",{className:"modal-actions-left",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:po,title:m("settings.importExport.exportTitle","Export settings to JSON file"),children:m("settings.importExport.exportBtn","Export")}),e.jsx("input",{type:"file",ref:cl,accept:".json,application/json",style:{display:"none"},onChange:ho}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>cl.current?.click(),disabled:Ns,title:m("settings.importExport.importTitleAttr","Import settings from JSON file"),children:Ns?m("settings.importExport.loadingFile","Loading…"):m("settings.importExport.importBtn","Import")}),e.jsx("button",{type:"button",className:"btn btn-sm","data-testid":"settings-reset",onClick:()=>gs(!0),disabled:me,title:m("settings.reset.buttonTitle","Reset settings to their defaults"),children:E==="mobile"?m("settings.reset.buttonShort","Reset"):m("settings.reset.button","Reset Settings")})]}),e.jsxs("div",{className:"modal-actions-right",children:[!k&&e.jsx("button",{className:"btn btn-sm",onClick:t,children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:Oo,disabled:me||we,children:m("settings.actions.save","Save")})]})]})]}),Ue!==null&&e.jsx("div",{className:"modal-overlay open",onClick:wo,role:"dialog","aria-modal":"true","aria-label":m("settings.scheduling.browseWorkspacePath","Browse workspace path"),children:e.jsxs("div",{className:"modal modal-lg settings-overlap-path-picker-modal",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.scheduling.selectIgnoredOverlapPath","Select ignored overlap path")}),e.jsx("button",{className:"modal-close",onClick:mt,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body settings-overlap-path-picker-body",children:[e.jsx("p",{className:"settings-overlap-path-picker-note",children:m("settings.scheduling.overlapPickerNote","Choose a file to ignore directly, or navigate into a folder and select the current directory.")}),e.jsx(Ua,{entries:zr,currentPath:nt,onSelectFile:Oa,onNavigate:la,loading:qr,error:Vr,onRetry:Yr,workspace:"project",projectId:a})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("div",{className:"modal-actions-left",children:e.jsxs("small",{children:[m("settings.fileBrowser.currentDirectory","Current directory:")," ",e.jsx("code",{children:nt==="."?m("settings.fileBrowser.projectRoot","(project root)"):nt})]})}),e.jsxs("div",{className:"modal-actions-right",children:[e.jsx("button",{className:"btn btn-sm",onClick:mt,children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:jo,disabled:nt===".",children:m("settings.scheduling.selectCurrentDir","Select current directory")})]})]})]})}),Cn&&e.jsx("div",{className:"modal-overlay open",onClick:Po,role:"dialog","aria-modal":"true","aria-label":m("settings.worktrees.browseWorktreesDirectory","Browse worktrees directory"),children:e.jsxs("div",{className:"modal modal-lg settings-overlap-path-picker-modal",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.worktrees.selectWorktreesDir","Select worktrees directory")}),e.jsx("button",{className:"modal-close",onClick:bt,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body settings-overlap-path-picker-body",children:[e.jsx("p",{className:"settings-overlap-path-picker-note",children:m("settings.worktrees.worktreesPickerNote","Navigate to the folder where Fusion should create task worktrees, then select the current directory.")}),e.jsx(Ua,{entries:Qr,currentPath:lt,onSelectFile:So,onNavigate:ra,loading:Jr,error:Xr,onRetry:Zr,workspace:"project",projectId:a})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("div",{className:"modal-actions-left",children:e.jsxs("small",{children:[m("settings.fileBrowser.currentDirectory","Current directory:")," ",e.jsx("code",{children:lt==="."?m("settings.fileBrowser.projectRoot","(project root)"):lt})]})}),e.jsxs("div",{className:"modal-actions-right",children:[e.jsx("button",{className:"btn btn-sm",onClick:bt,children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:No,children:m("settings.scheduling.selectCurrentDir","Select current directory")})]})]})]})}),$e!==null&&e.jsx("div",{className:"modal-overlay open",onClick:Mo,role:"dialog","aria-modal":"true","aria-label":m("settings.worktrees.browseCopyFile","Browse file to copy into new worktrees"),children:e.jsxs("div",{className:"modal modal-lg settings-overlap-path-picker-modal",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.worktrees.selectCopyFile","Select file to copy")}),e.jsx("button",{className:"modal-close",onClick:ft,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body settings-overlap-path-picker-body",children:[e.jsx("p",{className:"settings-overlap-path-picker-note",children:m("settings.worktrees.copyFilePickerNote","Choose a repository file to copy into each newly assigned task worktree. Directories are not selected from this picker.")}),e.jsx(Ua,{entries:ei,currentPath:ia,onSelectFile:Ao,onNavigate:oa,loading:ti,error:si,onRetry:ai,workspace:"project",projectId:a})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("div",{className:"modal-actions-left",children:e.jsxs("small",{children:[m("settings.fileBrowser.currentDirectory","Current directory:")," ",e.jsx("code",{children:ia==="."?m("settings.fileBrowser.projectRoot","(project root)"):ia})]})}),e.jsx("div",{className:"modal-actions-right",children:e.jsx("button",{className:"btn btn-sm",onClick:ft,children:m("settings.actions.cancel","Cancel")})})]})]})}),zi&&Ye&&e.jsx("div",{className:"modal-overlay open",onClick:r=>r.target===r.currentTarget&&Jt(!1),role:"dialog","aria-modal":"true",children:e.jsxs("div",{className:"modal modal-md",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.importExport.importTitle","Import Settings")}),e.jsx("button",{className:"modal-close",onClick:()=>Jt(!1),"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("p",{children:m("settings.importExport.reviewPrompt","Review the settings to be imported:")}),Ye.global&&Object.keys(Ye.global).length>0&&e.jsxs("div",{className:"form-group",children:[e.jsx("strong",{children:m("settings.importExport.globalSettings","Global Settings:")}),e.jsx("ul",{className:"import-preview-list",children:Object.entries(Ye.global).filter(([,r])=>r!==void 0).map(([r])=>e.jsx("li",{children:r},r))})]}),Ye.project&&Object.keys(Ye.project).length>0&&e.jsxs("div",{className:"form-group",children:[e.jsx("strong",{children:m("settings.importExport.projectSettings","Project Settings:")}),e.jsx("ul",{className:"import-preview-list",children:Object.entries(Ye.project).filter(([,r])=>r!==void 0).map(([r])=>e.jsx("li",{children:r},r))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"import-scope",children:m("settings.importExport.importScope","Import Scope:")}),e.jsxs("select",{id:"import-scope",value:Ra,onChange:r=>qi(r.target.value),children:[e.jsx("option",{value:"both",children:m("settings.importExport.scopeBoth","Both global and project settings")}),e.jsx("option",{value:"global",children:m("settings.importExport.scopeGlobal","Global settings only")}),e.jsx("option",{value:"project",children:m("settings.importExport.scopeProject","Project settings only")})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"import-merge",className:"checkbox-label",children:[e.jsx("input",{id:"import-merge",type:"checkbox",checked:Ea,onChange:r=>Vi(r.target.checked)}),m("settings.importExport.mergeExisting","Merge with existing settings (recommended)")]}),e.jsx(B,{settingKey:"import-merge",children:m("settings.importExport.replaceWarning","If unchecked, existing settings will be replaced with imported values.")})]})})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>Jt(!1),children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:mo,disabled:Ns,children:Ns?m("settings.importExport.importing","Importing…"):m("settings.importExport.confirmImport","Confirm Import")})]})]})}),Ut&&e.jsx("div",{className:"modal-overlay open",onClick:Go,role:"dialog","aria-modal":"true","aria-label":m("settings.reset.dialogAriaLabel","Reset settings"),"data-testid":"settings-reset-dialog",children:e.jsxs("div",{className:"modal modal-md settings-reset-dialog",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.reset.dialogTitle","Reset Settings")}),e.jsx("button",{className:"modal-close",onClick:Rt,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("p",{children:m("settings.reset.dialogBody","Choose what to reset to its defaults. This cannot be undone.")}),e.jsxs("div",{className:"settings-reset-dialog__choice",children:[e.jsx("button",{type:"button",className:"btn btn-danger settings-reset-dialog__choice-btn","data-testid":"settings-reset-menu",onClick:()=>void Ko(),disabled:at||!It,title:Ka,children:m("settings.reset.resetMenuAction","Reset this menu ({{section}})",{section:Ba})}),Ka&&e.jsx("small",{className:"settings-reset-dialog__ineligible-reason",children:Ka})]}),e.jsx("div",{className:"settings-reset-dialog__choice",children:e.jsx("button",{type:"button",className:"btn btn-danger settings-reset-dialog__choice-btn","data-testid":"settings-reset-all-project",onClick:()=>void Bo(),disabled:at,children:m("settings.reset.resetAllProjectAction","Reset all project settings")})})]}),e.jsx("div",{className:"modal-actions",children:e.jsx("div",{className:"modal-actions-right",children:e.jsx("button",{className:"btn btn-sm",onClick:Rt,disabled:at,children:m("settings.actions.cancel","Cancel")})})})]})})]})}function Ah(t){return e.jsx(mh,{presentation:"embedded",...t})}export{Rr as GITHUB_STAR_CACHE_KEY,Er as GITHUB_STAR_CACHE_TTL_MS,nn as SETTINGS_SECTIONS,mh as SettingsModal,Ah as SettingsView,lh as filterSettingsSectionsForSearch,Gr as normalizeSettingsSearchText,nh as sectionMatchesSettingsSearch,Xp as useGitHubStarCount};
|
|
21
|
+
Be brief and precise — avoid verbosity.`,builtIn:!0}],Tg={"executor-welcome":{key:"executor-welcome",name:"Executor Welcome",roles:["executor"],description:"Introductory section for the executor agent",defaultContent:"You are a task execution agent..."},"executor-guardrails":{key:"executor-guardrails",name:"Executor Guardrails",roles:["executor"],description:"Behavioral guardrails and constraints for the executor",defaultContent:"Treat the File Scope in PROMPT.md..."},"executor-spawning":{key:"executor-spawning",name:"Executor Spawning",roles:["executor"],description:"Instructions for spawning child agents",defaultContent:"You can spawn child agents..."},"executor-completion":{key:"executor-completion",name:"Executor Completion",roles:["executor"],description:"Completion criteria and signaling for executor",defaultContent:"After all steps are done..."},"triage-welcome":{key:"triage-welcome",name:"Triage Welcome",roles:["triage"],description:"Introductory section for the triage/specification agent",defaultContent:"You are a task specification agent..."},"triage-context":{key:"triage-context",name:"Triage Context",roles:["triage"],description:"Context-gathering instructions for triage",defaultContent:"What you receive: A raw task title..."},"reviewer-verdict":{key:"reviewer-verdict",name:"Reviewer Verdict",roles:["reviewer"],description:"Verdict criteria and format for code/review agent",defaultContent:"APPROVE — Step will achieve its stated outcomes..."},"merger-conflicts":{key:"merger-conflicts",name:"Merger Conflicts",roles:["merger"],description:"Merge conflict resolution instructions for merger",defaultContent:"If there are merge conflicts..."},"agent-generation-system":{key:"agent-generation-system",name:"Agent Generation System",roles:["executor"],description:"System prompt for generating agent specifications",defaultContent:"You are an agent specification generator..."},"workflow-step-refine":{key:"workflow-step-refine",name:"Workflow Step Refine",roles:["executor"],description:"System prompt for refining workflow step descriptions",defaultContent:"You are an expert at creating detailed agent prompts..."},"planning-system":{key:"planning-system",name:"Planning System",roles:["triage"],description:"System prompt for the AI planning assistant",defaultContent:"You are a planning assistant for the fn task board system..."},"subtask-breakdown-system":{key:"subtask-breakdown-system",name:"Subtask Breakdown System",roles:["executor"],description:"System prompt for AI subtask decomposition",defaultContent:"You are a task decomposition assistant..."},"mission-interview-system":{key:"mission-interview-system",name:"Mission Interview System",roles:["triage"],description:"System prompt for AI-assisted mission planning",defaultContent:"You are a mission planning assistant..."},"ai-refine-system":{key:"ai-refine-system",name:"AI Refine System",roles:["executor"],description:"System prompt for AI-powered text refinement",defaultContent:"You are a text refinement assistant..."},"agent-onboarding-system":{key:"agent-onboarding-system",name:"Agent Onboarding System",roles:["executor"],description:"System prompt for AI-guided agent onboarding interview",defaultContent:"You are an agent onboarding assistant for the fn task board system..."}},rr=["executor","triage","reviewer","merger"],Ag={executor:{key:"agentPrompts.roles.executor",defaultValue:"Executor Agent"},triage:{key:"agentPrompts.roles.triage",defaultValue:"Triage Agent"},reviewer:{key:"agentPrompts.roles.reviewer",defaultValue:"Reviewer Agent"},merger:{key:"agentPrompts.roles.merger",defaultValue:"Merger Agent"},scheduler:{key:"agentPrompts.roles.scheduler",defaultValue:"Scheduler Agent"},engineer:{key:"agentPrompts.roles.engineer",defaultValue:"Engineer Agent"},custom:{key:"agentPrompts.roles.custom",defaultValue:"Custom Agent"}},ns=t=>`prompt-role-tone--${t}`,Xa={name:"",description:"",role:"executor",prompt:""};function Mg(t,s){const a=t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,50),n=new Set(Et.map(i=>i.id)),c=new Set(s.map(i=>i.id));if(!n.has(a)&&!c.has(a))return a;let d=2;for(;n.has(`${a}-${d}`)||c.has(`${a}-${d}`);)d++;return`${a}-${d}`}function Ig({value:t,onChange:s,promptOverrides:a,onPromptOverridesChange:n}){const{t:c}=te("app"),d=F=>{const _=Ag[F];return c(_.key,_.defaultValue)},[i,u]=o.useState("templates"),[l,h]=o.useState(null),[p,b]=o.useState(!1),[w,x]=o.useState(Xa),[f,D]=o.useState(null),[S,C]=o.useState(null),[y,k]=o.useState(new Set),[R,P]=o.useState(null),[N,U]=o.useState(!1),[m,Y]=o.useState(null),E=o.useRef(null),L=t?.templates??[],G=t?.roleAssignments??{},K=m===null?null:m.source==="builtin"?Et.find(F=>F.id===m.id):L.find(F=>F.id===m.id),z=o.useCallback(F=>{const _=Et.filter(be=>be.role===F),ie=L.filter(be=>be.role===F);return[..._,...ie]},[L]);o.useEffect(()=>{m!==null&&E.current?.focus()},[m]);const ne=o.useCallback(()=>{b(!0),h(null),x(Xa),D(null),Y(null)},[]),re=o.useCallback(F=>{h(F.id),b(!1),x({name:F.name,description:F.description,role:F.role,prompt:F.prompt}),D(null),Y(null)},[]),ce=o.useCallback(()=>{h(null),b(!1),x(Xa),D(null),Y(null),U(!1)},[]),T=o.useCallback(()=>{const F=w.name.trim();if(!F){D(c("agentPrompts.errors.nameRequired","Template name is required"));return}let _;if(p){if(_=Mg(F,L),new Set(Et.map(V=>V.id)).has(_)){D(c("agentPrompts.errors.idConflict",'Template ID "{{templateId}}" conflicts with a built-in template. Please use a different name.',{templateId:_}));return}}else _=l;const ie={id:_,name:F,description:w.description.trim(),role:w.role,prompt:w.prompt,builtIn:!1};let be;p?be=[...L,ie]:be=L.map(le=>le.id===_?ie:le);const ve={...G};for(const[le,V]of Object.entries(ve))V===_&&w.role!==le&&delete ve[le];s({...t,templates:be,roleAssignments:Object.keys(ve).length>0?ve:void 0}),ce()},[w,p,l,L,G,t,s,ce]),$=o.useCallback(F=>{const _=L.filter(ve=>ve.id!==F),ie={...G};let be=!1;for(const[ve,le]of Object.entries(ie))le===F&&(delete ie[ve],be=!0);s({...t,templates:_.length>0?_:void 0,roleAssignments:Object.keys(ie).length>0||be?Object.keys(ie).length>0?ie:void 0:G}),C(null),l===F&&ce()},[L,G,t,s,l,ce]),ge=o.useCallback((F,_)=>{const ie={...G};_===""?delete ie[F]:ie[F]=_,s({...t,roleAssignments:Object.keys(ie).length>0?ie:void 0})},[G,t,s]),O=o.useCallback((F,_)=>{const ie={...a};ie[F]=_||null,n(ie)},[a,n]),X=o.useCallback(F=>{const _={...a};_[F]=null,n(_)},[a,n]),me=o.useCallback(F=>{k(_=>{const ie=new Set(_);return ie.has(F)?ie.delete(F):ie.add(F),ie})},[]),I=o.useCallback(F=>{P(_=>_===F?null:F)},[]),we=o.useCallback((F,_)=>{U(!1),Y({source:F,id:_})},[]),je=o.useCallback(()=>{Y(null),U(F=>!F)},[]),Ke=F=>Et.some(_=>_.id===F);return e.jsxs("div",{className:"prompt-manager",children:[e.jsxs("div",{className:"prompt-manager-tabs",children:[e.jsxs("button",{type:"button",className:`prompt-manager-tab ${i==="templates"?"active":""}`,onClick:()=>u("templates"),"data-testid":"tab-templates",children:[e.jsx(Vd,{size:14}),c("agentPrompts.tabs.templates","Templates")]}),e.jsxs("button",{type:"button",className:`prompt-manager-tab ${i==="assignments"?"active":""}`,onClick:()=>u("assignments"),"data-testid":"tab-assignments",children:[e.jsx(Qd,{size:14}),c("agentPrompts.tabs.assignments","Assignments")]}),e.jsxs("button",{type:"button",className:`prompt-manager-tab ${i==="overrides"?"active":""}`,onClick:()=>u("overrides"),"data-testid":"tab-overrides",children:[e.jsx(lu,{size:14}),c("agentPrompts.tabs.overrides","Overrides")]})]}),e.jsxs("div",{className:"prompt-manager-content",children:[i==="templates"&&e.jsxs("div",{className:"prompt-manager-templates-tab","data-testid":"templates-tab",children:[(p||l!==null)&&e.jsxs("div",{className:"prompt-template-editor","data-testid":"template-editor",children:[e.jsx("h4",{className:"prompt-template-editor-title",children:p?c("agentPrompts.editor.newTemplate","New Custom Template"):c("agentPrompts.editor.editTemplate","Edit Custom Template")}),e.jsxs("div",{className:"prompt-template-editor-fields",children:[e.jsxs("div",{className:"prompt-template-field",children:[e.jsx("label",{htmlFor:"template-name",children:c("agentPrompts.labels.name","Name")}),e.jsx("input",{id:"template-name",type:"text",value:w.name,onChange:F=>x(_=>({..._,name:F.target.value})),placeholder:c("agentPrompts.placeholders.templateName","e.g. My Custom Executor"),"data-testid":"template-name-input"})]}),e.jsxs("div",{className:"prompt-template-field",children:[e.jsx("label",{htmlFor:"template-description",children:c("agentPrompts.labels.description","Description")}),e.jsx("input",{id:"template-description",type:"text",value:w.description,onChange:F=>x(_=>({..._,description:F.target.value})),placeholder:c("agentPrompts.placeholders.description","Brief description of this template"),"data-testid":"template-description-input"})]}),e.jsxs("div",{className:"prompt-template-field",children:[e.jsx("label",{htmlFor:"template-role",children:c("agentPrompts.labels.role","Role")}),e.jsx("select",{id:"template-role",value:w.role,onChange:F=>x(_=>({..._,role:F.target.value})),"data-testid":"template-role-select",children:rr.map(F=>e.jsx("option",{value:F,children:d(F)},F))})]}),e.jsxs("div",{className:"prompt-template-field",children:[e.jsxs("div",{className:"prompt-template-prompt-label-row",children:[e.jsx("label",{htmlFor:"template-prompt",children:c("agentPrompts.labels.prompt","Prompt")}),e.jsx("button",{type:"button",className:"btn-icon prompt-template-fullscreen-btn",onClick:je,"aria-label":c("agentPrompts.ariaLabels.expandPrompt","Expand prompt to fullscreen"),"data-testid":"template-prompt-fullscreen",children:e.jsx(Is,{size:14})})]}),N?e.jsxs("div",{className:"prompt-override-fullscreen",onKeyDown:F=>{F.key==="Escape"&&(F.preventDefault(),U(!1))},children:[e.jsxs("div",{className:"prompt-override-fullscreen-header",children:[e.jsx("div",{className:"prompt-override-fullscreen-title",children:c("agentPrompts.titles.editPrompt","Edit Prompt")}),e.jsxs("button",{type:"button",className:"prompt-override-fullscreen-close",onClick:()=>U(!1),"data-testid":"template-prompt-collapse",children:[e.jsx(Ha,{size:14}),c("agentPrompts.actions.collapse","Collapse")]})]}),e.jsx("textarea",{id:"template-prompt-fullscreen","aria-label":c("agentPrompts.ariaLabels.templatePromptFullscreen","Template prompt - fullscreen"),className:"prompt-template-prompt-textarea",value:w.prompt,onChange:F=>x(_=>({..._,prompt:F.target.value})),placeholder:c("agentPrompts.placeholders.prompt","Enter the system prompt for this template..."),rows:30,autoFocus:!0,"data-testid":"template-prompt-input-fullscreen"}),e.jsx("div",{className:"prompt-override-footer",children:e.jsx("small",{className:"prompt-override-hint",children:c("agents.charactersCount","{{count}} characters",{count:w.prompt.length})})})]}):e.jsx("textarea",{id:"template-prompt",value:w.prompt,onChange:F=>x(_=>({..._,prompt:F.target.value})),placeholder:c("agentPrompts.placeholders.prompt","Enter the system prompt for this template..."),rows:8,className:"prompt-template-prompt-textarea","data-testid":"template-prompt-input"})]}),f&&e.jsx("div",{className:"prompt-template-error","data-testid":"template-error",children:f}),e.jsxs("div",{className:"prompt-template-editor-actions",children:[e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:ce,"data-testid":"cancel-template-btn",children:c("agentPrompts.actions.cancel","Cancel")}),e.jsx("button",{type:"button",className:"btn btn-primary",onClick:T,"data-testid":"save-template-btn",children:p?c("agentPrompts.actions.create","Create"):c("agentPrompts.actions.save","Save")})]})]})]}),e.jsxs("div",{className:"prompt-template-section","data-testid":"builtin-templates",children:[e.jsx("h4",{className:"prompt-template-section-title",children:c("agentPrompts.sections.builtinTemplates","Built-in Templates")}),e.jsx("p",{className:"prompt-template-section-desc",children:c("agentPrompts.descriptions.builtinTemplates","These templates are provided by Fusion and cannot be modified.")}),e.jsx("div",{className:"prompt-template-list",children:Et.map(F=>e.jsxs("div",{className:"prompt-template-card","data-testid":`builtin-template-${F.id}`,children:[e.jsxs("div",{className:"prompt-template-card-header",children:[e.jsxs("div",{className:"prompt-template-card-info",children:[e.jsx("span",{className:"prompt-template-card-name",children:F.name}),e.jsx("span",{className:`prompt-template-badge-built-in ${ns(F.role)}`,children:c("agentPrompts.badges.builtin","Built-in")}),e.jsx("span",{className:`prompt-template-badge-role ${ns(F.role)}`,children:d(F.role)})]}),e.jsx("div",{className:"prompt-template-card-actions",children:e.jsx("button",{type:"button",className:"btn-icon prompt-template-fullscreen-btn",onClick:()=>we("builtin",F.id),title:c("agentPrompts.titles.viewFullPrompt","View full prompt"),"aria-label":c("agentPrompts.ariaLabels.viewFullPromptFor","View full prompt for {{name}}",{name:F.name}),"data-testid":`expand-view-${F.id}`,children:e.jsx(Is,{size:14})})})]}),e.jsx("p",{className:"prompt-template-card-description",children:F.description}),e.jsx("div",{className:"prompt-template-card-preview",children:e.jsx("code",{children:F.prompt})})]},F.id))})]}),e.jsxs("div",{className:"prompt-template-section","data-testid":"custom-templates",children:[e.jsx("h4",{className:"prompt-template-section-title",children:c("agentPrompts.sections.customTemplates","Custom Templates")}),e.jsx("p",{className:"prompt-template-section-desc",children:c("agentPrompts.descriptions.customTemplates","Create custom templates to override built-in prompts for specific roles.")}),L.length===0&&!p&&e.jsx("div",{className:"prompt-template-empty",children:c("agentPrompts.emptyStates.noCustomTemplates","No custom templates yet. Create one to get started.")}),L.length>0&&e.jsx("div",{className:"prompt-template-list",children:L.map(F=>e.jsx("div",{className:"prompt-template-card","data-testid":`custom-template-${F.id}`,children:S===F.id?e.jsxs("div",{className:"prompt-template-delete-confirm",children:[e.jsx("p",{children:c("agentPrompts.confirmations.deleteTemplate",'Delete "{{name}}"?',{name:F.name})}),e.jsxs("div",{className:"prompt-template-delete-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm btn-danger",onClick:()=>$(F.id),"data-testid":`confirm-delete-${F.id}`,children:c("agentPrompts.actions.delete","Delete")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>C(null),"data-testid":`cancel-delete-${F.id}`,children:c("agentPrompts.actions.cancel","Cancel")})]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"prompt-template-card-header",children:[e.jsxs("div",{className:"prompt-template-card-info",children:[e.jsx("span",{className:"prompt-template-card-name",children:F.name}),e.jsx("span",{className:"prompt-template-badge-custom",children:c("agentPrompts.badges.custom","Custom")}),e.jsx("span",{className:`prompt-template-badge-role ${ns(F.role)}`,children:d(F.role)}),Ke(F.id)&&e.jsx("span",{className:"prompt-template-badge-override",children:c("agentPrompts.badges.overridesBuiltin","Overrides built-in")})]}),e.jsxs("div",{className:"prompt-template-card-actions",children:[e.jsx("button",{type:"button",className:"btn-icon prompt-template-fullscreen-btn",onClick:()=>we("custom",F.id),title:c("agentPrompts.titles.viewFullPrompt","View full prompt"),"aria-label":c("agentPrompts.ariaLabels.viewFullPromptFor","View full prompt for {{name}}",{name:F.name}),"data-testid":`expand-view-${F.id}`,children:e.jsx(Is,{size:14})}),e.jsx("button",{type:"button",className:"btn-icon",onClick:()=>re(F),title:c("agentPrompts.titles.edit","Edit"),"aria-label":c("agentPrompts.ariaLabels.editTemplate","Edit {{name}}",{name:F.name}),"data-testid":`edit-${F.id}`,children:e.jsx(zs,{size:14})}),e.jsx("button",{type:"button",className:"btn-icon",onClick:()=>C(F.id),title:c("agentPrompts.titles.delete","Delete"),"aria-label":c("agentPrompts.ariaLabels.deleteTemplate","Delete {{name}}",{name:F.name}),"data-testid":`delete-${F.id}`,children:e.jsx(qs,{size:14})})]})]}),e.jsx("p",{className:"prompt-template-card-description",children:F.description}),e.jsx("div",{className:"prompt-template-card-preview",children:e.jsx("code",{children:F.prompt})})]})},F.id))}),!p&&l===null&&e.jsxs("button",{type:"button",className:"btn btn-primary prompt-template-add-btn",onClick:ne,"data-testid":"add-template-btn",children:[e.jsx($s,{size:14}),c("agentPrompts.actions.addCustomTemplate","Add Custom Template")]})]}),K&&e.jsxs("div",{ref:E,className:"prompt-override-fullscreen",role:"dialog","aria-modal":"true",tabIndex:-1,onKeyDown:F=>{F.key==="Escape"&&(F.preventDefault(),Y(null))},children:[e.jsxs("div",{className:"prompt-override-fullscreen-header",children:[e.jsxs("div",{className:"prompt-override-fullscreen-title",children:[K.name,e.jsx("span",{className:`prompt-template-badge-role ${ns(K.role)}`,children:d(K.role)})]}),e.jsxs("button",{type:"button",className:"prompt-override-fullscreen-close",onClick:()=>Y(null),"data-testid":`collapse-view-${K.id}`,children:[e.jsx(Ha,{size:14}),c("agentPrompts.actions.collapse","Collapse")]})]}),e.jsx("pre",{className:"prompt-template-fullscreen-pre",children:K.prompt})]})]}),i==="assignments"&&e.jsxs("div",{className:"prompt-manager-assignments-tab","data-testid":"assignments-tab",children:[e.jsx("p",{className:"prompt-assignments-desc",children:c("agentPrompts.descriptions.assignments","Assign specific templates to agent roles. When a role has an assignment, that template will be used instead of the default built-in.")}),e.jsx("div",{className:"prompt-role-assignment-list",children:rr.map(F=>{const _=z(F),ie=G[F]??"",be=_.find(le=>le.id===ie),ve=!!ie;return e.jsxs("div",{className:"prompt-role-assignment-row","data-testid":`assignment-${F}`,children:[e.jsxs("div",{className:"prompt-role-assignment-label",children:[e.jsx("span",{className:`prompt-role-badge ${ns(F)}`,children:d(F)}),ve&&e.jsxs("span",{className:"prompt-role-assignment-status",children:[be?.name??c("agentPrompts.labels.custom","Custom")," (",c("agentPrompts.labels.overridesDefault","overrides default"),")"]})]}),e.jsxs("select",{className:"prompt-role-select",value:ie,onChange:le=>ge(F,le.target.value),"data-testid":`select-${F}`,children:[e.jsx("option",{value:"",children:c("agentPrompts.options.useDefault","Use default")}),_.map(le=>e.jsxs("option",{value:le.id,children:[le.name,Ke(le.id)?` (${c("agentPrompts.labels.builtIn","built-in")})`:` (${c("agentPrompts.labels.custom","custom")})`]},le.id))]})]},F)})}),Object.keys(G).length>0&&e.jsxs("div",{className:"prompt-assignments-note",children:[e.jsxs("strong",{children:[c("agentPrompts.labels.note","Note"),":"]})," ",c("agentPrompts.descriptions.assignmentNote","Role assignments are stored in the agentPrompts configuration. Custom templates override built-ins by ID.")]})]}),i==="overrides"&&e.jsxs("div",{className:"prompt-manager-overrides-tab","data-testid":"overrides-tab",children:[e.jsx("p",{className:"prompt-overrides-desc",children:c("agentPrompts.descriptions.overrides","Customize specific segments of AI agent prompts. Edits override built-in defaults. Use the Reset button to restore the original default for any prompt.")}),e.jsx("div",{className:"prompt-overrides-list",children:Object.values(Tg).map(F=>{const _=F.key,ie=a?.[_]??"",be=ie!=="",ve=y.has(_);return e.jsxs("div",{className:"prompt-override-item","data-testid":`override-${_}`,children:[e.jsxs("div",{className:"prompt-override-header",children:[e.jsxs("button",{type:"button",className:"prompt-override-info",onClick:()=>me(_),children:[e.jsx("span",{className:"prompt-override-name",children:F.name}),e.jsx("code",{className:"prompt-override-key",children:_}),be&&e.jsx("span",{className:"prompt-override-badge",children:c("agentPrompts.badges.customized","customized")})]}),e.jsxs("div",{className:"prompt-override-header-actions",children:[ve&&e.jsx("button",{type:"button",className:"prompt-override-fullscreen-btn",onClick:le=>{le.stopPropagation(),I(_)},"aria-label":c("agentPrompts.ariaLabels.expandToFullscreen","Expand to fullscreen"),"data-testid":`fullscreen-${_}`,children:e.jsx(Is,{size:14})}),e.jsx("button",{type:"button",className:"prompt-override-expand-btn","aria-label":ve?c("agentPrompts.ariaLabels.collapse","Collapse"):c("agentPrompts.ariaLabels.expand","Expand"),"data-testid":`expand-${_}`,onClick:le=>{le.stopPropagation(),me(_)},children:ve?e.jsx(Oc,{size:16}):e.jsx(Kc,{size:16})})]})]}),e.jsx("p",{className:"prompt-override-description",children:F.description}),ve&&(R===_?e.jsxs("div",{className:"prompt-override-fullscreen",onKeyDown:le=>{le.key==="Escape"&&(le.preventDefault(),P(null))},children:[e.jsxs("div",{className:"prompt-override-fullscreen-header",children:[e.jsxs("div",{className:"prompt-override-fullscreen-title",children:[F.name,e.jsx("code",{className:"prompt-override-key",children:_})]}),e.jsxs("button",{type:"button",className:"prompt-override-fullscreen-close",onClick:()=>P(null),"data-testid":`collapse-fullscreen-${_}`,children:[e.jsx(Ha,{size:14}),c("agentPrompts.actions.collapse","Collapse")]})]}),e.jsx("textarea",{id:`prompt-${_}-fullscreen`,"aria-label":c("agentPrompts.ariaLabels.promptOverrideFullscreen","{{name}} prompt override ({{key}}) - fullscreen",{name:F.name,key:_}),className:"prompt-override-textarea",value:ie,onChange:le=>{O(_,le.target.value)},placeholder:`Default: ${F.defaultContent.slice(0,100)}${F.defaultContent.length>100?"...":""}`,rows:30,autoFocus:!0,"data-testid":`override-input-fullscreen-${_}`}),e.jsxs("div",{className:"prompt-override-footer",children:[be&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",onClick:()=>X(_),"data-testid":`reset-fullscreen-${_}`,children:c("agentPrompts.actions.reset","Reset")}),e.jsx("small",{className:"prompt-override-hint",children:be?c("agentPrompts.hints.customOverrideActive","Custom override active. Click Reset to restore default."):c("agentPrompts.hints.noOverrideSet","No override set. Using built-in default ({{chars}} chars).",{chars:F.defaultContent.length})})]})]}):e.jsxs("div",{className:"prompt-override-editor",children:[e.jsx("textarea",{id:`prompt-${_}`,"aria-label":c("agentPrompts.ariaLabels.promptOverride","{{name}} prompt override ({{key}})",{name:F.name,key:_}),className:"prompt-override-textarea",value:ie,onChange:le=>{O(_,le.target.value)},placeholder:c("agentPrompts.placeholders.promptDefault","Default: {{preview}}",{preview:F.defaultContent.slice(0,100)+(F.defaultContent.length>100?"...":"")}),rows:4,"data-testid":`override-input-${_}`}),e.jsxs("div",{className:"prompt-override-footer",children:[be&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",onClick:le=>{le.stopPropagation(),X(_)},"data-testid":`reset-${_}`,children:c("agentPrompts.actions.reset","Reset")}),e.jsx("small",{className:"prompt-override-hint",children:be?c("agentPrompts.hints.customOverrideActive","Custom override active. Click Reset to restore default."):c("agentPrompts.hints.noOverrideSet","No override set. Using built-in default ({{chars}} chars).",{chars:F.defaultContent.length})})]})]}))]},_)})})]})]})]})}function xn({message:t,onOpenWorkflowSettings:s}){const{t:a}=te("app");return e.jsxs("div",{className:"settings-moved-stub",role:"note",children:[e.jsx("p",{className:"settings-moved-stub__message",children:t}),e.jsx("button",{type:"button",className:"settings-moved-stub__action",onClick:s,disabled:!s,children:a("settings.movedStub.openWorkflowSettings","Open workflow settings")})]})}function Rg({form:t,setForm:s,onOpenWorkflowSettings:a}){const{t:n}=te("app");return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.nav.prompts","Prompts")}),e.jsx(B,{settingKey:"prompts-section",children:n("settings.prompts.surfaceExplanation","Use this section for agent role system prompt templates, role assignments, and global PromptKey segment overrides. Per-workflow step prompts for prompt and gate nodes are edited in the Workflow Editor. No default — unset (built-in role prompts apply until overridden).")})]}),e.jsx(xn,{message:n("settings.prompts.workflowPromptsRedirect","Per-workflow step prompts for prompt and gate nodes live in the Workflow Editor."),onOpenWorkflowSettings:a}),e.jsx(Ig,{value:t.agentPrompts,onChange:c=>{s(d=>({...d,agentPrompts:c}))},promptOverrides:t.promptOverrides,onPromptOverridesChange:c=>{s(d=>({...d,promptOverrides:c}))}})]})}function Eg({form:t,setForm:s,projectId:a,addToast:n,prefixError:c,setPrefixError:d,onQuickChatButtonModeChange:i,onMobileNavPrimaryItemsChange:u}){const{t:l}=te("app"),[h,p]=o.useState([]);o.useEffect(()=>{let y=!1;return Sl(a,{includeDisabledBuiltins:!0}).then(k=>{y||p(k.filter(R=>R.id.startsWith("builtin:")&&R.kind!=="fragment"&&!Bc.has(R.id)))}).catch(()=>{y||p([])}),()=>{y=!0}},[a]);const[b,w]=o.useState([]);o.useEffect(()=>{let y=!1;return Sl(a).then(k=>{y||w(k.filter(R=>R.kind!=="fragment"))}).catch(()=>{y||w([])}),()=>{y=!0}},[a]);const x=t.aiUndoTaskWorkflowId??"builtin:review-heavy",f=x===""||b.some(y=>y.id===x),D=o.useMemo(()=>{const y=Array.isArray(t.enabledBuiltinWorkflowIds)?t.enabledBuiltinWorkflowIds:void 0;return new Set(y??h.map(k=>k.id))},[h,t.enabledBuiltinWorkflowIds]),S=(y,k)=>{s(R=>{const P=h.map(m=>m.id),N=new Set(Array.isArray(R.enabledBuiltinWorkflowIds)?R.enabledBuiltinWorkflowIds:P);k?N.add(y):N.delete(y);const U=P.filter(m=>N.has(m));return{...R,enabledBuiltinWorkflowIds:U.length===P.length?void 0:U}})},C=()=>{window.confirm(l("settings.general.clearLocalDataConfirm","Clear all cached data and UI preferences stored in this browser? This frees space used by stale chat, task, and board caches. Your tasks and project settings are safe (stored server-side). The dashboard will reload."))&&($c(),window.location.reload())};return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:l("settings.general.general","General")}),e.jsx(de,{descriptor:{key:"taskPrefix",label:l("settings.general.taskPrefix","Task Prefix"),help:l("settings.general.prefixForNewTaskIDsEGKB","Prefix for new task IDs (e.g. KB, PROJ). No default — unset."),scope:"project",placeholder:l("settings.general.fN","FN")},value:t.taskPrefix||"",onChange:y=>{const k=y??"";s(R=>({...R,taskPrefix:k||void 0})),k&&!/^[A-Z]{1,5}$/.test(k)?d(l("settings.general.prefixMustBe15UppercaseLetters","Prefix must be 1–5 uppercase letters")):d(null)},error:c??void 0}),e.jsxs("div",{className:"form-group",children:[e.jsx(Gc,{projectId:a,addToast:n}),e.jsx(B,{settingKey:"projectDefaultWorkflow",children:l("settings.general.newTasksInheritThisCustomWorkflowsStepsOverridable","New tasks inherit this custom workflow's steps (overridable per task). No default — unset (built-in default workflow).")})]}),h.length>0&&e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:l("settings.general.fusionWorkflows","Fusion workflows")}),e.jsx(B,{settingKey:"enabledBuiltinWorkflowIds",children:l("settings.general.disabledFusionWorkflowsAreHiddenFromWorkflow","Disabled Fusion workflows are hidden from workflow pickers. Existing tasks that already use one continue to resolve. Default: all built-in workflows enabled (unset).")})]}),e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:"var(--space-sm)"},children:h.map(y=>e.jsxs("label",{htmlFor:`builtin-workflow-${y.id}`,className:"checkbox-label",children:[e.jsx("input",{id:`builtin-workflow-${y.id}`,type:"checkbox",checked:D.has(y.id),onChange:k=>S(y.id,k.target.checked)}),e.jsx(Hc,{workflowId:y.id,decorative:!0}),e.jsx("span",{children:y.name})]},y.id))})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"aiUndoTaskWorkflowId",children:l("settings.general.aiUndoTaskWorkflow","AI-undo task workflow")}),e.jsx(B,{settingKey:"aiUndoTaskWorkflowId",children:l("settings.general.aiUndoTaskWorkflowHelp",'Workflow assigned to AI-undo (revert) tasks, which reverse already-shipped code and warrant stricter review. Choose "Inherit project default workflow" to leave them on the project default. Default: review-heavy.')})]}),e.jsxs("select",{id:"aiUndoTaskWorkflowId",className:"select","data-testid":"ai-undo-workflow-select",value:x,onChange:y=>s(k=>({...k,aiUndoTaskWorkflowId:y.target.value})),children:[e.jsx("option",{value:"",children:l("settings.general.aiUndoTaskWorkflowInherit","Inherit project default workflow")}),b.map(y=>e.jsx("option",{value:y.id,children:y.name},y.id)),!f&&e.jsx("option",{value:x,children:x})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"ephemeralAgentsEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"ephemeralAgentsEnabled",type:"checkbox",checked:t.ephemeralAgentsEnabled!==!1,onChange:y=>s(k=>({...k,ephemeralAgentsEnabled:y.target.checked}))}),l("settings.general.useEphemeralTaskWorkerAgents"," Use ephemeral task-worker agents ")]}),e.jsxs(B,{settingKey:"ephemeralAgentsEnabled",children:[l("settings.general.whenEnabledDefaultFusionSpawnsShortLived"," When enabled (default), Fusion spawns short-lived "),e.jsx("code",{children:"executor-FN-XXXX"}),l("settings.general.agentsToRunEachTaskWhenDisabledOnly"," agents to run each task. When disabled, only permanent agents execute tasks and the scheduler auto-assigns work using the agent reporting chain. Tasks with no eligible permanent agent stay queued. ")]})]})}),e.jsx(se,{descriptor:{key:"ephemeralAgentsCanCreateTasks",label:l("settings.general.allowEphemeralAgentsToCreateTasks"," Allow ephemeral agents to create tasks "),help:l("settings.general.allowEphemeralAgentsToCreateTasksHint","When enabled (default), ephemeral task-worker agents can open follow-up tasks via fn_task_create. When disabled, only humans and permanent agents can create tasks; ephemeral callers are rejected."),scope:"project"},value:t.ephemeralAgentsCanCreateTasks!==!1,onChange:y=>s(k=>({...k,ephemeralAgentsCanCreateTasks:y===!0}))}),e.jsx(se,{descriptor:{key:"workspaceMode",label:l("settings.general.workspaceMode"," Workspace mode (multi-repo) "),help:l("settings.general.workspaceModeHint","When enabled, the project root is treated as a workspace containing multiple git sub-repos. Tasks run per-sub-repo and no git repo is created at the root. Disable for single-repo projects. No default — unset (disabled)."),scope:"project"},value:t.workspaceMode===!0,onChange:y=>s(k=>({...k,workspaceMode:y===!0}))}),e.jsx(se,{descriptor:{key:"allowAbsoluteFileBrowserPaths",label:l("settings.general.allowAbsoluteFileBrowserPaths"," Allow absolute file-browser paths "),help:l("settings.general.allowAbsoluteFileBrowserPathsHint","When enabled, slash-prefixed paths such as /tmp can be opened in the workspace file browser. Windows drive-letter paths remain blocked, and other path validators are unchanged. Default: disabled."),scope:"project"},value:t.allowAbsoluteFileBrowserPaths===!0,onChange:y=>s(k=>({...k,allowAbsoluteFileBrowserPaths:y===!0}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"completionDocumentationMode",children:l("settings.general.completionDocumentationAutomation","Completion Documentation Automation")}),e.jsxs(B,{settingKey:"completionDocumentationMode",children:[l("settings.general.controlsHowFutureTaskSpecsHandleReleaseNote"," Controls how future task specs handle release-note artifacts at completion. Use changeset mode for repositories that follow "),e.jsx("code",{children:".changeset"}),l("settings.general.workflowsOrChangelogModeWhenContributorsShouldUpdate"," workflows, or changelog mode when contributors should update an existing changelog file. Default: off. ")]})]}),e.jsxs("select",{id:"completionDocumentationMode",value:t.completionDocumentationMode||"off",onChange:y=>s(k=>({...k,completionDocumentationMode:y.target.value})),children:[e.jsx("option",{value:"off",children:l("settings.general.off","Off")}),e.jsx("option",{value:"changeset",children:l("settings.general.requireChangesetChangesetMd","Require changeset (.changeset/*.md)")}),e.jsx("option",{value:"changelog",children:l("settings.general.requireChangelogUpdateExistingChangelog","Require changelog update (existing changelog)")})]})]}),e.jsx(ke,{descriptor:{key:"quickChatButtonMode",label:l("settings.general.quickChatLauncher","Quick Chat launcher"),help:l("settings.general.quickChatLauncherHint","Choose whether Quick Chat opens from the draggable floating button, a footer button beside Terminal, or stays hidden. Default: off (hidden)."),scope:"project",options:[{value:"floating",label:l("settings.general.quickChatLauncherFloating","Floating button")},{value:"footer",label:l("settings.general.quickChatLauncherFooter","Footer button")},{value:"off",label:l("settings.general.off","Off")}]},value:t.quickChatButtonMode??(t.showQuickChatFAB?"floating":"off"),onChange:y=>s(k=>{const R=y??"off";return i?.(R),{...k,quickChatButtonMode:R,showQuickChatFAB:R==="floating"}})}),e.jsx(_d,{htmlFor:"mobileNavPrimaryItems",label:l("settings.general.mobileNavPrimaryItems","Mobile footer quick actions"),help:l("settings.general.mobileNavPrimaryItemsHint","Default: Dashboard, Tasks, Agents, Missions, Chat, Mailbox. Add eligible destinations; unselected destinations remain in More."),scope:"project",children:e.jsx("div",{role:"group","aria-label":l("settings.general.mobileNavPrimaryItems","Mobile footer quick actions"),children:(()=>{const y=Array.isArray(t.mobileNavPrimaryItems)&&t.mobileNavPrimaryItems.length>0?t.mobileNavPrimaryItems.filter(P=>Nl.includes(P)):[..._c],k=P=>{s(N=>({...N,mobileNavPrimaryItems:P})),u?.(P)},R=Nl.filter(P=>!y.includes(P));return e.jsxs(e.Fragment,{children:[y.map((P,N)=>{const U=l(Pl[P],P),m=Y=>{const E=[...y];[E[N],E[N+Y]]=[E[N+Y],E[N]],k(E)};return e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("span",{children:U}),e.jsxs("span",{children:[e.jsx("button",{type:"button",className:"btn btn-icon",disabled:N===0,"aria-label":l("settings.general.moveNavItemEarlier","Move {{item}} earlier",{item:U}),onClick:()=>m(-1),children:"↑"}),e.jsx("button",{type:"button",className:"btn btn-icon",disabled:N===y.length-1,"aria-label":l("settings.general.moveNavItemLater","Move {{item}} later",{item:U}),onClick:()=>m(1),children:"↓"}),e.jsx("button",{type:"button",className:"btn btn-icon","aria-label":l("settings.general.removeNavItem","Remove {{item}}",{item:U}),onClick:()=>k(y.filter(Y=>Y!==P)),children:"×"})]})]},P)}),e.jsxs("label",{className:"checkbox-label",children:[e.jsx("span",{children:l("settings.general.addNavItem","Add quick action")}),e.jsxs("select",{id:"mobileNavPrimaryItems",value:"",disabled:y.length>=Wc,onChange:P=>{P.target.value&&k([...y,P.target.value])},children:[e.jsx("option",{value:"",children:l("settings.general.selectNavItem","Choose a destination")}),R.map(P=>e.jsx("option",{value:P,children:l(Pl[P],P)},P))]})]})]})})()})}),e.jsx(se,{descriptor:{key:"quickChatCloseOnOutsideClick",label:l("settings.general.quickChatCloseOnOutsideClick","Close Quick Chat on outside click"),help:l("settings.general.quickChatCloseOnOutsideClickHint","When enabled, clicking outside the Quick Chat window closes it. Disable to keep it open until you close it explicitly. Default: enabled."),scope:"project"},value:t.quickChatCloseOnOutsideClick!==!1,onChange:y=>s(k=>({...k,quickChatCloseOnOutsideClick:y===!0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.chatHistory","Chat history")}),e.jsx(se,{descriptor:{key:"showTaskChatsInCommonFeed",label:l("settings.general.showTaskChatsInCommonFeed","Show task chats in common Chat feed"),help:l("settings.general.showTaskChatsInCommonFeedHint","When enabled, populated task-detail Chat conversations appear in the common Direct feed. Empty task chats stay hidden. Default: disabled."),scope:"project"},value:t.showTaskChatsInCommonFeed===!0,onChange:y=>s(k=>({...k,showTaskChatsInCommonFeed:y===!0}))}),e.jsx(ke,{descriptor:{key:"chatAutoCleanupDays",label:l("settings.general.autoCleanupOldChats","Auto-cleanup old chats"),help:l("settings.general.deleteChatSessionsAndRoomsThatHaveBeen","Delete chat sessions and rooms that have been idle for this many days. Default: Off."),scope:"project",options:[{value:"0",label:l("settings.general.off","Off")},{value:"7",label:l("settings.general.7Days","7 days")},{value:"14",label:l("settings.general.14Days","14 days")},{value:"30",label:l("settings.general.30Days","30 days")},{value:"60",label:l("settings.general.60Days","60 days")},{value:"90",label:l("settings.general.90Days","90 days")}]},value:String(t.chatAutoCleanupDays??0),onChange:y=>s(k=>({...k,chatAutoCleanupDays:Number(y)||0}))}),e.jsx(ke,{descriptor:{key:"mailAutoCleanupDays",label:l("settings.general.autoPruneOldMail","Auto-prune old mail"),help:l("settings.general.deleteInboxOutboxMessagesOlderThanThisMany","Delete inbox/outbox messages older than this many days. Default: Off. 7 days is the suggested setting."),scope:"project",options:[{value:"0",label:l("settings.general.off","Off")},{value:"7",label:l("settings.general.7Days","7 days")},{value:"14",label:l("settings.general.14Days","14 days")},{value:"30",label:l("settings.general.30Days","30 days")},{value:"60",label:l("settings.general.60Days","60 days")},{value:"90",label:l("settings.general.90Days","90 days")}]},value:String(t.mailAutoCleanupDays??0),onChange:y=>s(k=>({...k,mailAutoCleanupDays:Number(y)||0}))}),e.jsx(ke,{descriptor:{key:"operationalLogRetentionDays",label:l("settings.general.operationalLogRetention","Operational log retention"),help:l("settings.general.loweringThisWindowMeansReliabilityMetricsChartsAnd"," Lowering this window means Reliability metrics/charts and the Activity feed will not show history older than the selected range. Per-task task detail history is unaffected. Default: 30 days. "),scope:"project",options:[{value:"0",label:l("settings.general.off","Off")},{value:"7",label:l("settings.general.7Days","7 days")},{value:"14",label:l("settings.general.14Days","14 days")},{value:"30",label:l("settings.general.30Days","30 days")},{value:"60",label:l("settings.general.60Days","60 days")},{value:"90",label:l("settings.general.90Days","90 days")}]},value:String(t.operationalLogRetentionDays??30),onChange:y=>s(k=>({...k,operationalLogRetentionDays:Number(y)||0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.chatRooms","Chat Rooms")}),e.jsx(ye,{descriptor:{key:"chatRoomRecentVerbatimMessages",label:l("settings.general.recentVerbatimRoomMessages","Recent verbatim room messages"),help:l("settings.general.numberOfMostRecentChatRoomMessagesKept","Number of most-recent chat-room messages kept verbatim in the responder transcript. Older messages are compacted into a summary block. Default: 25."),scope:"project",min:1,placeholder:l("settings.general.25","25")},value:t.chatRoomRecentVerbatimMessages??null,onChange:y=>s(k=>({...k,chatRoomRecentVerbatimMessages:y||void 0}))}),e.jsx(ye,{descriptor:{key:"chatRoomCompactionFetchLimit",label:l("settings.general.roomCompactionFetchLimit","Room compaction fetch limit"),help:l("settings.general.upperBoundOnMessagesFetchedFromTheRoom","Upper bound on messages fetched from the room store for compaction consideration. Default: 200."),scope:"project",min:1,placeholder:l("settings.general.200","200")},value:t.chatRoomCompactionFetchLimit??null,onChange:y=>s(k=>({...k,chatRoomCompactionFetchLimit:y||void 0}))}),e.jsx(ye,{descriptor:{key:"chatRoomSummaryMaxChars",label:l("settings.general.roomSummaryMaxCharacters","Room summary max characters"),help:l("settings.general.hardCapOnTheSynthesizedEarlierRoomContext",'Hard cap on the synthesized "Earlier room context" summary block. Default: 3000.'),scope:"project",min:200,placeholder:l("settings.general.3000","3000")},value:t.chatRoomSummaryMaxChars??null,onChange:y=>s(k=>({...k,chatRoomSummaryMaxChars:y||void 0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.capacityRiskBanner","Capacity Risk Banner")}),e.jsx(se,{descriptor:{key:"capacityRiskBannerEnabled",label:l("settings.general.showCapacityRiskBanner"," Show capacity risk banner "),help:l("settings.general.warnOnTheBoardWhenTodoWorkExceeds","Warn on the board when todo work exceeds the threshold and no idle agents are available. Default: disabled."),scope:"project"},value:t.capacityRiskBannerEnabled===!0,onChange:y=>s(k=>({...k,capacityRiskBannerEnabled:y===!0}))}),e.jsx(ye,{descriptor:{key:"capacityRiskTodoThreshold",label:l("settings.general.todoThreshold","Todo threshold"),help:l("settings.general.bannerFiresWhenTodoCountIsStrictlyGreater","Banner fires when todo count is strictly greater than this value (default 20). Applies when the banner is enabled."),scope:"project",min:0},value:t.capacityRiskTodoThreshold??20,onChange:y=>s(k=>({...k,capacityRiskTodoThreshold:y===null?0:Math.max(0,Math.trunc(y)||0)}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.sessionAdvisor","Session advisor (overseer agent)")}),e.jsx(ke,{descriptor:{key:"sessionAdvisorEnabledByDefault",label:l("settings.general.defaultSessionAdvisorForNewTasks","Default for new tasks"),help:l("settings.general.sessionAdvisorHelp","Controls whether newly created tasks enable the session advisor (live LLM overseer of the executor). Individual tasks can override this from Quick Add or task detail. Also set Session advisor model provider and model id under workflow settings before the advisor can run."),scope:"project",options:[{value:"off",label:l("settings.general.offDefault","Off (default)")},{value:"new-tasks",label:l("settings.general.onForNewTasks","On for new tasks")}]},value:t.sessionAdvisorEnabledByDefault?"new-tasks":"off",onChange:y=>s(k=>({...k,sessionAdvisorEnabledByDefault:y==="new-tasks"}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.gitHubTracking","GitHub Tracking")}),e.jsx(se,{descriptor:{key:"githubImportAutoTranslate",label:l("settings.general.autoTranslateImportedIssues","Auto-translate imported issues"),help:l("settings.general.autoTranslateImportedIssuesHelp","When enabled, the Import Tasks panel automatically translates foreign-language issue titles and bodies into the target language below and shows the translation by default. You can always switch back to the original text, and imported tasks carry the translated text. Default: disabled."),scope:"project"},value:t.githubImportAutoTranslate===!0,onChange:y=>s(k=>({...k,githubImportAutoTranslate:y===!0?!0:void 0}))}),e.jsx(ke,{descriptor:{key:"importTranslateTargetLocale",label:l("settings.general.translationTargetLanguage","Translation target language"),help:l("settings.general.translationTargetLanguageHelp","Language imported issues are translated into when auto-translation is enabled. No default — unset inherits the dashboard language."),scope:"project",options:[{value:"",label:l("settings.general.followDashboardLanguage","Follow dashboard language")},...br.map(y=>({value:y,label:Uc(y)}))]},value:t.importTranslateTargetLocale??"",onChange:y=>s(k=>({...k,importTranslateTargetLocale:y&&Ft(y)?y:void 0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:l("settings.general.browserData","Browser Data")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:l("settings.general.clearLocalData","Clear local data")}),e.jsx(B,{settingKey:"clearLocalData",children:l("settings.general.clearLocalDataHint","Remove cached board snapshots, chat threads, and UI preferences stored in this browser. Frees space when the dashboard runs low on browser storage. Your tasks and project settings are stored server-side and are not affected.")})]}),e.jsx("div",{style:{marginTop:"var(--space-sm)"},children:e.jsx("button",{type:"button",className:"btn btn-sm",onClick:C,children:l("settings.general.clearLocalDataButton","Clear local data")})})]})]})}const Za="builtin:coding",Fg=[{id:"planning",providerId:"planningProvider",modelId:"planningModelId",thinkingId:"planningThinkingLevel",label:"Plan/Triage Model",help:"Provider and model used when planning or triaging tasks. Leave unset to inherit from the workflow default."},{id:"planning-fallback",providerId:"planningFallbackProvider",modelId:"planningFallbackModelId",thinkingId:"planningFallbackThinkingLevel",label:"Planning Fallback Model",help:"Fallback provider and model used when the primary Plan/Triage model cannot be used."},{id:"execution",providerId:"executionProvider",modelId:"executionModelId",thinkingId:"executionThinkingLevel",label:"Executor Model",help:"Provider and model used while executing workflow steps. Leave unset to inherit from the workflow default."},{id:"execution-fallback",providerId:"executionFallbackProvider",modelId:"executionFallbackModelId",thinkingId:"executionFallbackThinkingLevel",label:"Executor Fallback Model",help:"Fallback provider and model used when the primary Executor model cannot be used."},{id:"validator",providerId:"validatorProvider",modelId:"validatorModelId",thinkingId:"validatorThinkingLevel",label:"Reviewer Model",help:"Provider and model used for workflow review or validation lanes. Leave unset to inherit from the workflow default."},{id:"validator-fallback",providerId:"validatorFallbackProvider",modelId:"validatorFallbackModelId",thinkingId:"validatorFallbackThinkingLevel",label:"Reviewer Fallback Model",help:"Fallback provider and model used when the primary Reviewer model cannot be used."}];function Dg(t){const s=new Map((t??[]).map(a=>[a.id,a]));return Fg.filter(a=>{const n=s.get(a.providerId),c=s.get(a.modelId),d=a.thinkingId?s.get(a.thinkingId):void 0;return n?.type==="string"&&c?.type==="string"&&(!a.thinkingId||d?.type==="enum"||d?.type==="string")})}function Lg(t,s){const a=t[s.providerId],n=t[s.modelId];return typeof a=="string"&&typeof n=="string"&&a&&n?`${a}/${n}`:""}function Og(t,s){return Object.is(t,s)?!0:Array.isArray(t)&&Array.isArray(s)?t.length===s.length&&t.every((a,n)=>Object.is(a,s[n])):!1}class Mr extends Error{rejections;constructor(s){super("Workflow model lane settings were rejected"),this.name="WorkflowLaneFlushRejection",this.rejections=s}}function Kg({form:t,setForm:s,models:a,projectId:n,onOpenWorkflowSettings:c,registerWorkflowLaneSaver:d}){const{t:i}=te("app"),{agents:u,loading:l}=zc(n),{modelLanes:h,getLaneStatus:p,getLaneValue:b,updateLaneValue:w,resetLaneValue:x,getLaneThinkingValue:f,updateLaneThinkingValue:D,resetLaneThinkingValue:S,availableModels:C,modelsLoading:y,favoriteProviders:k,favoriteModels:R,onToggleFavorite:P,onToggleModelFavorite:N,editingPresetId:U,setEditingPresetId:m,presetDraft:Y,setPresetDraft:E,onSavePresetDraft:L,confirmDelete:G}=a,K=t.modelPresets||[],z=K.map(v=>({id:v.id,name:v.name})),ne=new Set(Object.values(t.defaultPresetBySize||{}).filter(Boolean)),re=typeof t.defaultWorkflowId=="string"&&t.defaultWorkflowId.trim()?t.defaultWorkflowId:Za,[ce,T]=o.useState(re),[$,ge]=o.useState(null),[O,X]=o.useState(!1),[me,I]=o.useState({}),[we,je]=o.useState({}),[Ke,F]=o.useState([]),_=o.useRef(0),ie=Object.keys(me).length>0;o.useEffect(()=>{T(re)},[re]),o.useEffect(()=>{if(!n){ge(null),I({}),je({}),F([]);return}const v=++_.current;X(!0),Promise.all([qc(ce,n),Vc(ce,n)]).then(([q,J])=>{if(_.current!==v)return;ge(J),I({}),je({});const ae="settings"in q.ir?q.ir.settings:void 0;F(Dg(ae))}).catch(q=>{if(_.current===v){if(q instanceof Tl&&q.status===404&&ce!==Za){T(Za);return}ge({stored:{},effective:{},orphaned:[]}),F([])}}).finally(()=>{_.current===v&&X(!1)})},[n,ce]);const be=o.useMemo(()=>({...$?.effective??{},...Object.fromEntries(Object.entries(me).filter(([,v])=>v!==null))}),[$,me]),ve=o.useCallback((v,q)=>{je(J=>{const ae={...J};return delete ae[v.providerId],delete ae[v.modelId],ae}),I(J=>{if(!q)return{...J,[v.providerId]:null,[v.modelId]:null};const ae=q.indexOf("/");return ae<=0?J:{...J,[v.providerId]:q.slice(0,ae),[v.modelId]:q.slice(ae+1)}})},[]),le=o.useCallback((v,q)=>{v.thinkingId&&(je(J=>{if(!v.thinkingId||!J[v.thinkingId])return J;const ae={...J};return delete ae[v.thinkingId],ae}),I(J=>({...J,[v.thinkingId]:q||null})))},[]),V=o.useCallback(v=>{ve(v,""),le(v,"")},[ve,le]),pe=o.useCallback(async()=>{if(!n||!ie)return;const v={...me},q=Object.keys(v);try{const J=await Yc(ce,v,n);ge(J),I(ae=>{const Ne={...ae};for(const De of q)Og(ae[De],v[De])&&delete Ne[De];return Ne}),je({})}catch(J){if(J instanceof Tl&&J.status===400&&J.details){const ae=J.details.rejections??[];if(ae.length>0)throw je(Object.fromEntries(ae.map(Ne=>[Ne.settingId,Ne]))),new Mr(ae)}throw J}},[n,ie,ce,me]);o.useEffect(()=>(d?.(pe),()=>d?.(null)),[d,pe]);const Ce=h.filter(v=>["default","merger","import-translate"].includes(v.laneId)),A=h.find(v=>v.laneId==="summarization"),M=v=>v.laneId==="default"?"Project Default Model":v.laneId==="merger"?"Project Merger Model":v.laneId==="summarization"?"Project Summarization Model":v.laneId==="import-translate"?"Project Import Auto-Translation Model":v.label,W=v=>v.laneId==="default"?"Project-wide default AI model used when no more specific task or project lane override is set.":v.laneId==="merger"?"Model used for merge conflict resolution, clean-room merge, stash-conflict recovery, and related merger agent sessions.":v.laneId==="summarization"?"Model used for title auto-summarization, merge commit summaries, GitHub tracking issue titles, and PR title/body generation.":v.laneId==="import-translate"?"Model used to translate foreign-language GitHub/GitLab issue titles and bodies in the Import Tasks panel. One short readonly call per issue — a cheap, fast model is usually the right pick.":v.helperText,Z=t.mergerFallbackProvider&&t.mergerFallbackModelId?`${t.mergerFallbackProvider}/${t.mergerFallbackModelId}`:"",oe=typeof t.mergerFallbackThinkingLevel=="string"?t.mergerFallbackThinkingLevel:"",fe=!!(Z||oe),he=v=>{if(!v){s(J=>({...J,mergerFallbackProvider:void 0,mergerFallbackModelId:void 0,mergerFallbackThinkingLevel:void 0}));return}const q=v.indexOf("/");s(J=>({...J,mergerFallbackProvider:v.slice(0,q),mergerFallbackModelId:v.slice(q+1)}))},Pe=v=>{s(q=>({...q,mergerFallbackThinkingLevel:v||void 0}))},et=()=>{s(v=>({...v,mergerFallbackProvider:void 0,mergerFallbackModelId:void 0,mergerFallbackThinkingLevel:void 0}))},Fe=()=>e.jsxs("div",{className:"form-group","data-testid":"project-model-lane-merger-fallback",children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:"mergerFallbackModel",children:i("settings.projectModels.mergerFallbackModel","Merger Fallback Model")}),e.jsx("span",{className:`settings-lane-badge ${fe?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:fe?"Explicitly set for this project":"Inherited from global settings",children:fe?"Override (Project)":"Inherited (Global)"}),e.jsx(B,{settingKey:"mergerFallbackModel",children:i("settings.projectModels.mergerFallbackHelp","Fallback provider and model used when a merger session retries. Leave unset to use the shared global fallback model pair.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:"mergerFallbackModel",label:"Merger Fallback Model",models:C,value:Z,onChange:he,placeholder:i("settings.projectModels.useGlobal","Use global"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!0,thinkingLevel:oe,onThinkingLevelChange:Pe,defaultThinkingLevel:t.defaultThinkingLevel})}),fe&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromGlobal","Reset to inherit from global"),onClick:et,children:i("settings.projectModels.reset"," Reset ")})]})]}),_e=t.titleSummarizerFallbackProvider&&t.titleSummarizerFallbackModelId?`${t.titleSummarizerFallbackProvider}/${t.titleSummarizerFallbackModelId}`:"",is=typeof t.titleSummarizerFallbackThinkingLevel=="string"?t.titleSummarizerFallbackThinkingLevel:"",Be=!!(_e||is),Js=v=>{if(!v){s(J=>({...J,titleSummarizerFallbackProvider:void 0,titleSummarizerFallbackModelId:void 0,titleSummarizerFallbackThinkingLevel:void 0}));return}const q=v.indexOf("/");s(J=>({...J,titleSummarizerFallbackProvider:v.slice(0,q),titleSummarizerFallbackModelId:v.slice(q+1)}))},St=v=>{s(q=>({...q,titleSummarizerFallbackThinkingLevel:v||void 0}))},Nt=()=>{s(v=>({...v,titleSummarizerFallbackProvider:void 0,titleSummarizerFallbackModelId:void 0,titleSummarizerFallbackThinkingLevel:void 0}))},tt=v=>{const q=p(v),J=b(v),ae=f(v),Ne=q==="overridden"||!!ae,De=M(v);return e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:`${v.laneId}Model`,children:De}),e.jsx("span",{className:`settings-lane-badge ${Ne?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:Ne?"Explicitly set for this project":"Inherited from global settings",children:Ne?"Override (Project)":"Inherited (Global)"}),e.jsxs(B,{settingKey:`${v.laneId}Model`,children:[W(v),i("settings.projectModels.fallsBackTo"," Falls back to: "),v.fallbackOrder,"."]})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:`${v.laneId}Model`,label:De,models:C,value:J,onChange:Ge=>w(v,Ge),placeholder:v.laneId==="default"?"Use global default":"Use global",favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!!v.projectThinkingKey,thinkingLevel:ae,onThinkingLevelChange:Ge=>D(v,Ge),defaultThinkingLevel:t.defaultThinkingLevel})}),Ne&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromGlobal","Reset to inherit from global"),onClick:()=>{x(v),S(v)},style:{whiteSpace:"nowrap"},children:i("settings.projectModels.reset"," Reset ")})]})]},v.laneId)},ct=t.chatDefaultKind??"model",os=t.chatDefaultModelProvider&&t.chatDefaultModelId?`${t.chatDefaultModelProvider}/${t.chatDefaultModelId}`:"",cs=typeof t.chatDefaultThinkingLevel=="string"?t.chatDefaultThinkingLevel:"",vt=!!(t.chatNewSessionMode||t.chatDefaultKind||t.chatDefaultAgentId||os||cs),Xs=v=>{if(!v){s(J=>({...J,chatDefaultKind:"model",chatDefaultAgentId:void 0,chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0}));return}const q=v.indexOf("/");q<=0||s(J=>({...J,chatDefaultKind:"model",chatDefaultAgentId:void 0,chatDefaultModelProvider:v.slice(0,q),chatDefaultModelId:v.slice(q+1)}))},Zs=v=>{s(q=>({...q,chatDefaultThinkingLevel:v||void 0}))},We=()=>{s(v=>({...v,chatNewSessionMode:void 0,chatDefaultKind:void 0,chatDefaultAgentId:void 0,chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0}))};return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:i("settings.projectModels.tokenCap","Token Cap")}),e.jsx(ye,{descriptor:{key:"tokenCap",label:i("settings.projectModels.tokenCap","Token Cap"),help:i("settings.projectModels.automaticallyCompactContextWhenApproachingThisTokenCount","Automatically compact context when approaching this token count. Leave empty for no cap (compact only on overflow errors). Set a number to proactively compact when reaching this token count. No default — unset (no cap)."),scope:"project",placeholder:i("settings.projectModels.noCap","No cap")},value:t.tokenCap??null,onChange:v=>s(q=>({...q,tokenCap:v?Math.trunc(v):null})),clearable:t.tokenCap!=null}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.modelLanes","Model Lanes")}),e.jsx(B,{settingKey:"project-model-lanes",children:i("settings.projectModels.overrideGlobalModelSettingsAtTheProjectLevel"," Override global model settings at the project level. Each lane controls a specific AI usage context. Unset lanes inherit from the corresponding global lane. The Project Default Model is the fallback for this project when a more specific lane is unset. ")})]}),y?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:i("settings.projectModels.loadingAvailableModels","Loading available models…")})}):C.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationFirst"," No models available. Configure authentication first. ")}):e.jsxs(e.Fragment,{children:[Ce.filter(v=>v.laneId==="default"||v.laneId==="merger").map(tt),Fe(),Ce.filter(v=>v.laneId==="import-translate").map(tt)]}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.chatHeading","Chat")}),e.jsx(B,{settingKey:"project-chat-defaults",children:i("settings.projectModels.chatDescription","Choose the default target for new Direct chats and whether New Chat should prompt or immediately use that default.")})]}),e.jsx(ke,{descriptor:{key:"chatNewSessionMode",label:i("settings.projectModels.chatNewSessionMode","New Chat behavior"),help:i("settings.projectModels.chatNewSessionModeHelp","Prompt mode opens New Chat with this default preselected. Always-default mode skips the dialog when the configured default is complete."),scope:"project",options:[{value:"prompt",label:i("settings.projectModels.chatNewSessionModePrompt","Prompt for model each time")},{value:"always-default",label:i("settings.projectModels.chatNewSessionModeAlwaysDefault","Always use configured default")}]},value:t.chatNewSessionMode??"prompt",onChange:v=>s(q=>({...q,chatNewSessionMode:v==="always-default"?"always-default":void 0}))}),e.jsxs("div",{className:"form-group","data-testid":"project-models-chat-kind",children:[e.jsx("label",{children:i("settings.projectModels.chatDefaultKind","Chat default target")}),e.jsxs("div",{className:"chat-new-dialog-mode-toggle","data-testid":"project-models-chat-kind-toggle",children:[e.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${ct==="model"?" chat-new-dialog-mode-btn--active":""}`,onClick:()=>s(v=>({...v,chatDefaultKind:"model",chatDefaultAgentId:void 0})),children:i("settings.projectModels.chatDefaultKindModel","Model")}),e.jsx("button",{type:"button",className:`chat-new-dialog-mode-btn${ct==="agent"?" chat-new-dialog-mode-btn--active":""}`,onClick:()=>s(v=>({...v,chatDefaultKind:"agent",chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0})),children:i("settings.projectModels.chatDefaultKindAgent","Agent")})]})]}),ct==="model"?e.jsxs("div",{className:"form-group","data-testid":"project-models-chat-model",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"chatDefaultModel",children:i("settings.projectModels.chatDefaultModel","Chat Default Model")}),e.jsx(B,{settingKey:"chatDefaultModel",children:i("settings.projectModels.chatDefaultModelHelp","Model-mode New Chat uses the built-in Fusion chat agent with this provider/model pair. Leave empty to fall back to prompting.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:"chatDefaultModel",label:i("settings.projectModels.chatDefaultModel","Chat Default Model"),models:C,value:os,onChange:Xs,placeholder:i("settings.projectModels.selectChatDefaultModel","Select a chat default model"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!0,thinkingLevel:cs,onThinkingLevelChange:Zs,defaultThinkingLevel:t.defaultThinkingLevel})}),vt&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.chatDefaultReset","Reset Chat default"),onClick:We,children:i("settings.projectModels.reset"," Reset ")})]})]}):e.jsxs("div",{className:"form-group","data-testid":"project-models-chat-agent",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"chatDefaultAgentId",children:i("settings.projectModels.chatDefaultAgent","Chat Default Agent")}),e.jsx(B,{settingKey:"chatDefaultAgentId",children:i("settings.projectModels.chatDefaultAgentHelp","Agent-mode New Chat starts a Direct chat with the selected durable agent.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsxs("select",{id:"chatDefaultAgentId",value:t.chatDefaultAgentId??"",disabled:l||u.length===0,onChange:v=>s(q=>({...q,chatDefaultKind:"agent",chatDefaultAgentId:v.target.value||void 0,chatDefaultModelProvider:void 0,chatDefaultModelId:void 0,chatDefaultThinkingLevel:void 0})),children:[e.jsx("option",{value:"",children:l?i("settings.projectModels.loadingAgents","Loading agents…"):i("settings.projectModels.selectChatDefaultAgent","Select a chat default agent")}),u.map(v=>e.jsxs("option",{value:v.id,children:[v.name," (",v.role,")"]},v.id))]})}),vt&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.chatDefaultReset","Reset Chat default"),onClick:We,children:i("settings.projectModels.reset"," Reset ")})]}),u.length===0&&!l?e.jsx("small",{children:i("settings.projectModels.chatDefaultAgentEmpty","No agents are available for this project yet.")}):null]}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.defaultWorkflowModelLanes","Default workflow model lanes")}),e.jsxs(B,{settingKey:"default-workflow-model-lanes",children:[i("settings.movedStub.modelLanes","Per-phase model lanes (execution, planning, reviewer, and their fallbacks) now live on the workflow."),i("settings.projectModels.theseProjectOverridesApplyToTheActiveDefault"," These project overrides apply to the active default workflow. ")]})]}),n?O?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:i("settings.projectModels.loadingWorkflowModelLanes","Loading workflow model lanes…")})}):C.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationBeforeSelectingWorkflow"," No models available. Configure authentication before selecting workflow model lanes. ")}):e.jsxs(e.Fragment,{children:[Ke.map(v=>{const q=Lg(be,v),J=v.thinkingId?be[v.thinkingId]:void 0,ae=typeof J=="string"?J:"",Ne=Object.prototype.hasOwnProperty.call(me,v.providerId)?me[v.providerId]!==null:!!($?.stored&&(Object.prototype.hasOwnProperty.call($.stored,v.providerId)||Object.prototype.hasOwnProperty.call($.stored,v.modelId))),De=v.thinkingId?Object.prototype.hasOwnProperty.call(me,v.thinkingId)?me[v.thinkingId]!==null:!!($?.stored&&Object.prototype.hasOwnProperty.call($.stored,v.thinkingId)):!1,Ge=Ne||De,st=we[v.providerId]?.message??we[v.modelId]?.message??(v.thinkingId?we[v.thinkingId]?.message:void 0);return e.jsxs("div",{className:"form-group","data-testid":`workflow-model-lane-${v.id}`,children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:`workflow-${v.id}-model`,children:v.label}),e.jsx("span",{className:`settings-lane-badge ${Ge?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:Ge?"Explicitly set for this project workflow":"Inherited from workflow defaults",children:Ge?"Override (Project)":"Inherited (Workflow)"}),v.help?e.jsx(B,{settingKey:`workflow-${v.id}-model`,children:v.help}):null]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:`workflow-${v.id}-model`,label:v.label,models:C,value:q,onChange:dt=>ve(v,dt),placeholder:i("settings.projectModels.useWorkflowDefault","Use workflow default"),defaultOptionLabel:"Use workflow default",favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!!v.thinkingId,thinkingLevel:ae,onThinkingLevelChange:v.thinkingId?dt=>le(v,dt):void 0,defaultThinkingLevel:typeof t.defaultThinkingLevel=="string"?t.defaultThinkingLevel:"off"})}),Ge&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromWorkflow","Reset to inherit from workflow"),onClick:()=>V(v),style:{whiteSpace:"nowrap"},children:i("settings.projectModels.reset"," Reset ")})]}),st?e.jsx("small",{className:"settings-error","data-testid":`workflow-model-lane-error-${v.id}`,children:st}):null]},v.id)}),c?e.jsx("div",{className:"settings-model-lane-actions","aria-label":i("settings.projectModels.defaultWorkflowModelLaneActions","Default workflow model lane actions"),children:e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",onClick:c,children:i("settings.projectModels.advancedWorkflowPolicy"," Advanced workflow policy ")})}):null]}):e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.openAProjectToEditWorkflowModelLanes","Open a project to edit workflow model lanes.")}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.modelPresets","Model Presets")}),e.jsxs("div",{className:"form-group settings-model-presets",children:[e.jsx("label",{children:i("settings.projectModels.configuredPresets","Configured presets")}),K.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noPresetsConfiguredYet","No presets configured yet.")}):e.jsx("div",{className:"settings-preset-list",children:K.map(v=>{const q=Qc(v),J=`${q.executorValue||"default"} / ${q.validatorValue||"default"}`;return e.jsxs("div",{className:"settings-preset-item",children:[e.jsxs("div",{className:"settings-preset-item-meta",children:[e.jsx("strong",{children:v.name}),e.jsx("span",{className:"settings-muted settings-preset-summary",children:J})]}),e.jsxs("div",{className:"settings-preset-item-actions",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>{m(v.id),E({...v})},children:i("settings.projectModels.edit"," Edit ")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:async()=>{ne.has(v.id)&&!await G({title:i("settings.models.deletePresetTitle","Delete Preset"),message:i("settings.models.deletePresetMessage",'Preset "{{name}}" is used in auto-selection. Delete it anyway?',{name:v.name}),danger:!0})||(s(ae=>({...ae,modelPresets:(ae.modelPresets||[]).filter(Ne=>Ne.id!==v.id),defaultPresetBySize:Object.fromEntries(Object.entries(ae.defaultPresetBySize||{}).filter(([,Ne])=>Ne!==v.id))})),U===v.id&&(m(null),E(null)))},children:i("settings.projectModels.delete"," Delete ")})]})]},v.id)})}),Y?null:e.jsx("div",{className:"settings-preset-actions",children:e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>{m(null),E({id:"",name:"",executorProvider:void 0,executorModelId:void 0,validatorProvider:void 0,validatorModelId:void 0})},children:i("settings.projectModels.addPreset"," Add Preset ")})})]}),Y?e.jsxs("div",{className:"form-group settings-preset-editor",children:[e.jsx("label",{children:i("settings.projectModels.presetEditor","Preset editor")}),e.jsxs("div",{className:"settings-preset-editor-fields",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"preset-name",children:i("settings.projectModels.name","Name")}),e.jsx("input",{id:"preset-name",type:"text",value:Y.name,onChange:v=>{const q=v.target.value;E(J=>J&&{...J,name:q})}})]}),C.length===0?e.jsx("small",{children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationFirst2","No models available. Configure authentication first.")}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"preset-executor-model",children:i("settings.projectModels.executorModel","Executor model")}),e.jsx(Qe,{id:"preset-executor-model",label:"Preset executor model",models:C,value:Y.executorProvider&&Y.executorModelId?`${Y.executorProvider}/${Y.executorModelId}`:"",onChange:v=>{if(!v){E(J=>J&&{...J,executorProvider:void 0,executorModelId:void 0});return}const q=v.indexOf("/");E(J=>J&&{...J,executorProvider:v.slice(0,q),executorModelId:v.slice(q+1)})},placeholder:i("settings.projectModels.useDefault","Use default"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable"})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"preset-validator-model",children:i("settings.projectModels.reviewerModel","Reviewer model")}),e.jsx(Qe,{id:"preset-validator-model",label:"Preset reviewer model",models:C,value:Y.validatorProvider&&Y.validatorModelId?`${Y.validatorProvider}/${Y.validatorModelId}`:"",onChange:v=>{if(!v){E(J=>J&&{...J,validatorProvider:void 0,validatorModelId:void 0});return}const q=v.indexOf("/");E(J=>J&&{...J,validatorProvider:v.slice(0,q),validatorModelId:v.slice(q+1)})},placeholder:i("settings.projectModels.useDefault","Use default"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable"})]})]})]}),e.jsxs("div",{className:"modal-actions settings-preset-editor-actions",children:[e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:L,children:i("settings.models.savePreset","Save preset")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>{m(null),E(null)},children:i("settings.actions.cancel","Cancel")})]})]}):null,e.jsx(se,{descriptor:{key:"autoSelectModelPreset",label:i("settings.projectModels.autoSelectPresetBasedOnTaskSize"," Auto-select preset based on task size "),help:i("settings.projectModels.autoSelectModelPresetHint","Default: disabled."),scope:"project"},value:t.autoSelectModelPreset||!1,onChange:v=>s(q=>({...q,autoSelectModelPreset:v===!0}))}),t.autoSelectModelPreset?e.jsx("div",{className:"settings-preset-size-grid",children:["S","M","L"].map(v=>e.jsxs("div",{className:"form-group settings-preset-size-row",children:[e.jsx("label",{htmlFor:`preset-size-${v}`,children:v==="S"?"Small tasks (S):":v==="M"?"Medium tasks (M):":"Large tasks (L):"}),e.jsxs("select",{id:`preset-size-${v}`,value:t.defaultPresetBySize?.[v]||"",onChange:q=>{const J=q.target.value||void 0;s(ae=>({...ae,defaultPresetBySize:{...ae.defaultPresetBySize||{},[v]:J}}))},children:[e.jsx("option",{value:"",children:i("settings.projectModels.noPreset","No preset")}),z.map(q=>e.jsx("option",{value:q.id,children:q.name},q.id))]})]},v))}):null,e.jsx(se,{descriptor:{key:"taskDefinitionInInputLanguage",label:i("settings.projectModels.taskDefinitionInInputLanguage","Write task definitions in the operator's input language"),help:i("settings.projectModels.taskDefinitionInInputLanguageHelp","When enabled, generated task-definition prose uses supported detectable input languages (Spanish, French, Korean, or Chinese as zh-CN). Headings, markers, and code stay English. Unsupported or undetectable input stays English. Default: disabled."),scope:"project"},value:t.taskDefinitionInInputLanguage||!1,onChange:v=>s(q=>({...q,taskDefinitionInInputLanguage:v===!0}))}),e.jsxs("section",{"data-testid":"project-models-ai-summarization",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:i("settings.projectModels.aITitleAndGitCommitMessageSummarization"," AI Title and Git Commit Message Summarization ")}),e.jsxs(B,{settingKey:"project-ai-summarization",children:[i("settings.projectModels.configuresTheModelUsedForTwoShortSummary"," Configures the model used for two short-summary jobs: auto-generating task titles from long descriptions, and generating merge commit summaries from step commits and diff stats. "),t.autoSummarizeTitles||t.useAiMergeCommitSummary||t.githubTrackingEnabledByDefault?i("settings.movedStub.summarizerModelInline","These summarization model controls govern title auto-summarization, merge commit summaries, GitHub tracking titles, and PR metadata generation."):""]})]}),y?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:i("settings.projectModels.loadingAvailableModels","Loading available models…")})}):C.length===0?e.jsx("div",{className:"settings-empty-state settings-muted",children:i("settings.projectModels.noModelsAvailableConfigureAuthenticationFirst"," No models available. Configure authentication first. ")}):e.jsxs(e.Fragment,{children:[A?tt(A):null,e.jsxs("div",{className:"form-group","data-testid":"project-model-lane-title-summarizer-fallback",children:[e.jsxs("div",{className:"settings-model-lane-label-row",children:[e.jsx("label",{htmlFor:"titleSummarizerFallbackModel",children:i("settings.projectModels.titleSummarizerFallbackModel","Title Summarizer Fallback Model")}),e.jsx("span",{className:`settings-lane-badge ${Be?"settings-lane-badge--override":"settings-lane-badge--inherited"}`,title:Be?"Explicitly set for this project":"Inherited from global settings",children:Be?"Override (Project)":"Inherited (Global)"}),e.jsx(B,{settingKey:"titleSummarizerFallbackModel",children:i("settings.projectModels.titleSummarizerFallbackHelp","Fallback provider and model used when the primary Title Summarizer model cannot be used. Falls back to the global summarization lane and then the default model chain.")})]}),e.jsxs("div",{className:"settings-model-lane-control-row",children:[e.jsx("div",{className:"settings-model-lane-control-main",children:e.jsx(Qe,{id:"titleSummarizerFallbackModel",label:"Title Summarizer Fallback Model",models:C,value:_e,onChange:Js,placeholder:i("settings.projectModels.useGlobal","Use global"),favoriteProviders:k,onToggleFavorite:P,favoriteModels:R,onToggleModelFavorite:N,menuWidth:"readable",showThinkingLevel:!0,thinkingLevel:is,onThinkingLevelChange:St,defaultThinkingLevel:t.defaultThinkingLevel})}),Be&&e.jsx("button",{type:"button",className:"btn btn-ghost btn-sm",title:i("settings.projectModels.resetToInheritFromGlobal","Reset to inherit from global"),onClick:Nt,style:{whiteSpace:"nowrap"},children:i("settings.projectModels.reset"," Reset ")})]})]})]}),e.jsx(se,{descriptor:{key:"autoSummarizeTitles",label:i("settings.projectModels.autoSummarizeLongDescriptionsAsTitles"," Auto-summarize long descriptions as titles "),help:i("settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut"," When enabled, tasks created without a title but with descriptions over 200 characters will automatically get an AI-generated title (max 60 characters). The same model is also used to generate fallback merge commit message bodies when the branch's commit log is empty (e.g. squash merges with no unique commits), and GitHub tracking issue titles when a tracked task has no title yet. Default: disabled. "),scope:"project"},value:t.autoSummarizeTitles||!1,onChange:v=>s(q=>({...q,autoSummarizeTitles:v===!0}))}),e.jsx(se,{descriptor:{key:"useAiMergeCommitSummary",label:i("settings.projectModels.aIMergeCommitSummaries"," AI merge commit summaries "),help:i("settings.projectModels.whenEnabledMergeCommitMessagesIncludeAnAI"," When enabled, merge commit messages include an AI-generated subject plus body summary (narrative + bullets + diff-stat) instead of just listing step commit subjects. Uses the title summarization model. Default: enabled. "),scope:"project"},value:t.useAiMergeCommitSummary||!1,onChange:v=>s(q=>({...q,useAiMergeCommitSummary:v===!0}))}),e.jsx(Ll,{descriptor:{key:"prTitlePromptInstructions",label:i("settings.projectModels.prTitlePromptInstructions","PR title prompt guidance"),help:i("settings.projectModels.prTitlePromptInstructionsHelp","Guides the AI-generated Create PR title. Leave blank to use the default PR metadata prompt. No default — unset."),scope:"project",placeholder:i("settings.projectModels.prTitlePromptInstructionsPlaceholder","Example: Use conventional-commit style and keep titles under 72 characters.")},value:t.prTitlePromptInstructions||"",onChange:v=>s(q=>({...q,prTitlePromptInstructions:v??""}))}),e.jsx(Ll,{descriptor:{key:"prDescriptionPromptInstructions",label:i("settings.projectModels.prDescriptionPromptInstructions","PR description prompt guidance"),help:i("settings.projectModels.prDescriptionPromptInstructionsHelp","Guides the AI-generated Create PR summary, changes, and testing sections. Leave blank to use the default PR metadata prompt. No default — unset."),scope:"project",placeholder:i("settings.projectModels.prDescriptionPromptInstructionsPlaceholder","Example: Emphasize operator-facing behavior and list verification commands exactly.")},value:t.prDescriptionPromptInstructions||"",onChange:v=>s(q=>({...q,prDescriptionPromptInstructions:v??""}))})]})]})}const ir=1440*60*1e3,Bg=2;function Gg({form:t,setForm:s,concurrencyLoading:a=!1,onOverlapIgnorePathChange:n,onOpenOverlapPathPicker:c,onRemoveOverlapIgnorePath:d,onAddOverlapIgnorePath:i,onOpenWorkflowSettings:u}){const{t:l}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:l("settings.scheduling.scheduling","Scheduling")}),e.jsx(ye,{descriptor:{key:"executorToolFailureRetryCount",label:l("settings.scheduling.executorToolFailureRetryCount","Executor tool-failure retries"),help:l("settings.scheduling.executorToolFailureRetryCountHelp","Same-model retries after consecutive tool-call failures. Set 0 to disable. Default: 2."),scope:"project",min:0,step:1},value:t.executorToolFailureRetryCount??2,onChange:h=>s(p=>({...p,executorToolFailureRetryCount:Math.max(0,Math.floor(h??2))}))}),e.jsx(ye,{descriptor:{key:"executorToolFailureRetryBackoffMs",label:l("settings.scheduling.executorToolFailureRetryBackoffMs","Tool-failure retry backoff (ms)"),help:l("settings.scheduling.executorToolFailureRetryBackoffMsHelp","Unref'd wait before retrying. Default: 2000."),scope:"project",min:0,step:1},value:t.executorToolFailureRetryBackoffMs??2e3,onChange:h=>s(p=>({...p,executorToolFailureRetryBackoffMs:Math.max(0,Math.floor(h??2e3))}))}),e.jsx(ye,{descriptor:{key:"executorToolFailureThreshold",label:l("settings.scheduling.executorToolFailureThreshold","Consecutive tool failures"),help:l("settings.scheduling.executorToolFailureThresholdHelp","Terminal tool errors required before retrying. Default: 3."),scope:"project",min:1,step:1},value:t.executorToolFailureThreshold??3,onChange:h=>s(p=>({...p,executorToolFailureThreshold:Math.max(1,Math.floor(h??3))}))}),e.jsx(se,{descriptor:{key:"executorModelEscalationEnabled",label:l("settings.scheduling.executorModelEscalationEnabled","Escalate after tool-failure retries"),help:l("settings.scheduling.executorModelEscalationEnabledHelp","After same-model retries are exhausted, try one configured alternate model or node. Disabled by default."),scope:"project"},value:t.executorModelEscalationEnabled===!0,onChange:h=>s(p=>({...p,executorModelEscalationEnabled:h===!0}))}),e.jsx(de,{descriptor:{key:"executorEscalationProvider",label:l("settings.scheduling.executorEscalationProvider","Escalation provider"),help:l("settings.scheduling.executorEscalationProviderHelp","Provider for the alternate model. Requires an alternate model ID."),scope:"project"},value:t.executorEscalationProvider??"",onChange:h=>s(p=>({...p,executorEscalationProvider:h??""}))}),e.jsx(de,{descriptor:{key:"executorEscalationModelId",label:l("settings.scheduling.executorEscalationModelId","Escalation model ID"),help:l("settings.scheduling.executorEscalationModelIdHelp","Alternate model ID. Requires an escalation provider."),scope:"project"},value:t.executorEscalationModelId??"",onChange:h=>s(p=>({...p,executorEscalationModelId:h??""}))}),e.jsx(de,{descriptor:{key:"executorEscalationNodeId",label:l("settings.scheduling.executorEscalationNodeId","Escalation node ID"),help:l("settings.scheduling.executorEscalationNodeIdHelp","Optional configured node; a node target re-enters scheduler routing."),scope:"project"},value:t.executorEscalationNodeId??"",onChange:h=>s(p=>({...p,executorEscalationNodeId:h??""}))}),e.jsx(ye,{descriptor:{key:"maxConcurrent",label:l("settings.scheduling.maxConcurrentTasks","Max Concurrent Tasks"),help:l("settings.scheduling.maxConcurrentTasksHint","Default: 2."),scope:"project",min:1,max:10,disabled:a},value:t.maxConcurrent??null,onChange:h=>s(p=>({...p,maxConcurrent:h??void 0}))}),e.jsx(ye,{descriptor:{key:"maxConcurrentVerifications",label:l("settings.scheduling.maxConcurrentVerifications","Max Concurrent Verifications"),help:l("settings.scheduling.maxConcurrentVerificationsHint","Caps stacked typecheck/build verification across tasks. Default: 1. Range: 1–8."),scope:"project",min:1,max:8,disabled:a},value:t.maxConcurrentVerifications??null,onChange:h=>{if(h===null){s(b=>({...b,maxConcurrentVerifications:void 0}));return}const p=Math.min(8,Math.max(1,Math.floor(h)||1));s(b=>({...b,maxConcurrentVerifications:p}))}}),e.jsx(ye,{descriptor:{key:"maxTriageConcurrent",label:l("settings.scheduling.maxTriageConcurrent","Max Triage Concurrent"),help:l("settings.scheduling.maximumConcurrentPlanningAgents","Maximum concurrent planning agents. Default: 2."),scope:"project",min:1,max:10,disabled:a},value:t.maxTriageConcurrent??null,onChange:h=>s(p=>({...p,maxTriageConcurrent:h??void 0}))}),e.jsx(ye,{descriptor:{key:"pollIntervalMs",label:l("settings.scheduling.pollIntervalMs","Poll Interval (ms)"),help:l("settings.scheduling.pollIntervalMsHint","Default: 15000 (15 seconds)."),scope:"project",min:5e3,step:1e3},value:t.pollIntervalMs??null,onChange:h=>s(p=>({...p,pollIntervalMs:h??void 0}))}),e.jsx(ke,{descriptor:{key:"heartbeatScopeDiscipline",label:l("settings.scheduling.heartbeatScopeDiscipline","Heartbeat Scope Discipline"),help:l("settings.scheduling.strictCoordinationFocusedHigherPerTickTokensLite","Strict — coordination-focused; higher per-tick tokens. Lite — pre-2026-05-11 behavior. Off — minimal procedure."),scope:"project",options:[{value:"strict",label:l("settings.scheduling.strictDefault","Strict (default)")},{value:"lite",label:l("settings.scheduling.lite","Lite")},{value:"off",label:l("settings.scheduling.off","Off")}]},value:t.heartbeatScopeDiscipline??"strict",onChange:h=>s(p=>({...p,heartbeatScopeDiscipline:h}))}),e.jsx(se,{descriptor:{key:"engineerBacklogAutoClaim",label:l("settings.scheduling.letEngineerAgentsAutoClaimBacklogTasks"," Let engineer agents auto-claim backlog tasks "),help:l("settings.scheduling.backlogNoTaskAutoClaimIsExecutorOnly","Backlog/no-task auto-claim is executor-only by default. Enable to let engineer-role agents auto-claim unowned backlog tasks; explicit routing and delegation are unchanged. Default: off."),scope:"project"},value:t.engineerBacklogAutoClaim===!0,onChange:h=>s(p=>({...p,engineerBacklogAutoClaim:h===!0}))}),e.jsx(ye,{descriptor:{key:"taskStuckTimeoutMs",label:l("settings.scheduling.stuckTaskTimeoutMinutes","Stuck Task Timeout (minutes)"),help:l("settings.scheduling.timeoutInMinutesForDetectingStuckTasksWhen","Timeout in minutes for detecting stuck tasks. When a task's agent session shows no activity for longer than this duration, the task is terminated and retried. Leave empty to disable. Suggested: 10. Default: 10 minutes (600000ms)."),scope:"project",min:1,step:1},value:t.taskStuckTimeoutMs?Math.round(t.taskStuckTimeoutMs/6e4):null,onChange:h=>s(p=>({...p,taskStuckTimeoutMs:h!==null&&h>0?h*6e4:void 0}))}),e.jsx(ye,{descriptor:{key:"buildTimeoutMs",label:l("settings.scheduling.buildTimeoutMinutes","Build/Verification Timeout (minutes)"),help:l("settings.scheduling.maximumTimeInMinutesForBuildVerificationCommands","Maximum time in minutes for build/verification commands before they are killed. Raise for large monorepo or Docker builds. Default: 5."),scope:"project",min:1,step:1},value:t.buildTimeoutMs?Math.round(t.buildTimeoutMs/6e4):null,onChange:h=>s(p=>({...p,buildTimeoutMs:h!==null&&h>0?h*6e4:void 0}))}),e.jsx(ye,{descriptor:{key:"staleHighFanoutBlockerAgeThresholdMs",label:l("settings.scheduling.staleHighFanOutEscalationHours","Stale High Fan-out Escalation (hours)"),help:l("settings.scheduling.escalateHighFanOutBlockersOnlyAfterThey","Escalate high fan-out blockers only after they remain in in-progress or in-review for this many hours (age source: columnMovedAt, fallback updatedAt). Default: 2 hours."),scope:"project",min:1,step:1},value:t.staleHighFanoutBlockerAgeThresholdMs?Math.round(t.staleHighFanoutBlockerAgeThresholdMs/36e5):null,onChange:h=>s(p=>({...p,staleHighFanoutBlockerAgeThresholdMs:h!==null&&h>0?h*36e5:void 0}))}),e.jsx(se,{descriptor:{key:"preserveProgressOnStuckRequeue",label:l("settings.scheduling.preserveStepProgressOnStuckTaskRequeue"," Preserve step progress on stuck-task requeue "),help:l("settings.scheduling.whenTheStuckDetectorKillsAndReQueues","When the stuck detector kills and re-queues a task, keep completed step statuses so the agent can resume from where it left off. Disable to reset every step to pending on each stuck retry. Default: enabled."),scope:"project"},value:t.preserveProgressOnStuckRequeue!==!1,onChange:h=>s(p=>({...p,preserveProgressOnStuckRequeue:h===!0}))}),e.jsx(se,{descriptor:{key:"specStalenessEnabled",label:l("settings.scheduling.enablePlanStalenessEnforcement"," Enable plan staleness enforcement "),help:l("settings.scheduling.whenEnabledTasksWithStalePlansPROMPTMd","When enabled, tasks with stale plans (PROMPT.md older than the threshold) are automatically sent back to planning for replanning. Default: disabled."),scope:"project"},value:t.specStalenessEnabled||!1,onChange:h=>s(p=>({...p,specStalenessEnabled:h===!0}))}),e.jsx(ye,{descriptor:{key:"specStalenessMaxAgeMs",label:l("settings.scheduling.staleSpecThresholdHours","Stale Spec Threshold (hours)"),help:l("settings.scheduling.maximumAgeInHoursBeforeAPlanIs","Maximum age in hours before a plan is considered stale. Default: 6 hours."),scope:"project",min:0,step:1,disabled:!t.specStalenessEnabled},value:t.specStalenessMaxAgeMs!==void 0?Math.round(t.specStalenessMaxAgeMs/36e5):null,onChange:h=>s(p=>({...p,specStalenessMaxAgeMs:h!==null?h*36e5:void 0}))}),e.jsx(se,{descriptor:{key:"autoArchiveDoneTasksEnabled",label:l("settings.scheduling.enableAutomaticTaskArchiving"," Enable automatic task archiving "),help:l("settings.scheduling.completedTasksOlderThanTheThresholdAreMoved","Completed tasks older than the threshold are moved out of the active task database. Default: enabled."),scope:"project"},value:t.autoArchiveDoneTasksEnabled??!0,onChange:h=>s(p=>({...p,autoArchiveDoneTasksEnabled:h===!0}))}),e.jsx(ye,{descriptor:{key:"autoArchiveDoneAfterMs",label:l("settings.scheduling.archiveCompletedTasksAfterDays","Archive Completed Tasks After (days)"),help:l("settings.scheduling.numberOfDaysATaskCanStayIn","Number of days a task can stay in Done before it is archived. Default: 2 days (48 hours)."),scope:"project",min:1,step:1,disabled:t.autoArchiveDoneTasksEnabled===!1},value:t.autoArchiveDoneAfterMs!==void 0?Math.round(t.autoArchiveDoneAfterMs/ir):Bg,onChange:h=>s(p=>({...p,autoArchiveDoneAfterMs:h===null?void 0:h*ir}))}),e.jsx(ke,{descriptor:{key:"archiveAgentLogMode",label:l("settings.scheduling.archiveAgentLog","Archive Agent Log"),help:l("settings.scheduling.compactModeKeepsArchiveSizeLowWhilePreserving","Compact mode keeps archive size low while preserving recent agent activity for context. Default: compact."),scope:"project",disabled:t.autoArchiveDoneTasksEnabled===!1,options:[{value:"compact",label:l("settings.scheduling.compactSummaryAndRecentEntries","Compact summary and recent entries")},{value:"none",label:l("settings.scheduling.doNotArchiveAgentLogs","Do not archive agent logs")},{value:"full",label:l("settings.scheduling.fullAgentLog","Full agent log")}]},value:t.archiveAgentLogMode??"compact",onChange:h=>s(p=>({...p,archiveAgentLogMode:h}))}),e.jsx(se,{descriptor:{key:"autoArchiveDuplicateTasksEnabled",label:l("settings.scheduling.autoArchiveDuplicateTasks"," Automatically archive duplicate tasks "),help:l("settings.scheduling.autoArchiveDuplicateTasksHelp","Automatically archive tasks detected as same-agent duplicates on creation (off by default). When disabled, duplicates are flagged in place with the yellow Duplicate chip and Keep/Archive actions instead of being archived automatically."),scope:"project"},value:t.autoArchiveDuplicateTasksEnabled??!1,onChange:h=>s(p=>({...p,autoArchiveDuplicateTasksEnabled:h===!0}))}),e.jsx(ke,{descriptor:{key:"triageDuplicateResolution",label:l("settings.scheduling.triageDuplicateResolution","Triage duplicate resolution"),help:l("settings.scheduling.triageDuplicateResolutionHelp","Block triage duplicates for a linked Keep/Delete decision (default), keep automatically, or delete automatically."),scope:"project",options:[{value:"prompt",label:l("settings.scheduling.triageDuplicateResolutionPrompt","Block for decision (default)")},{value:"keep",label:l("settings.scheduling.triageDuplicateResolutionKeep","Keep automatically")},{value:"delete",label:l("settings.scheduling.triageDuplicateResolutionDelete","Delete automatically")}]},value:t.triageDuplicateResolution??"prompt",onChange:h=>s(p=>({...p,triageDuplicateResolution:h}))}),e.jsx(ye,{descriptor:{key:"maxStuckKills",label:l("settings.scheduling.maxStuckRetries","Max Stuck Retries"),help:l("settings.scheduling.maximumStuckDetectorRetriesBeforeATaskIs","Maximum stuck-detector retries before a task is marked failed. Default: 6."),scope:"project",min:1,step:1},value:t.maxStuckKills??null,onChange:h=>s(p=>({...p,maxStuckKills:h!==null&&h>0?h:void 0}))}),e.jsx(se,{descriptor:{key:"groupOverlappingFiles",label:l("settings.scheduling.serializeTasksWithOverlappingFiles"," Serialize tasks with overlapping files "),help:l("settings.scheduling.whenEnabledTasksThatModifyTheSameFiles","When enabled, tasks that modify the same files are queued serially to avoid merge conflicts. Default: enabled."),scope:"project"},value:t.groupOverlappingFiles,onChange:h=>s(p=>({...p,groupOverlappingFiles:h===!0}))}),e.jsx(se,{descriptor:{key:"ignoreHiddenOverlapPaths",label:l("settings.scheduling.ignoreHiddenDotPathsInOverlapChecks"," Ignore hidden dot paths in overlap checks "),help:l("settings.scheduling.ignoreHiddenDotPathsHelp","When enabled, overlap checks ignore hidden path segments such as .fusion/, .changeset/, .github/, .env, and nested .cache/ directories. Uncheck to restore legacy counting for stricter serialization. Default: enabled."),scope:"project"},value:t.ignoreHiddenOverlapPaths!==!1,onChange:h=>s(p=>({...p,ignoreHiddenOverlapPaths:h===!0}))}),e.jsxs("div",{className:"form-group settings-overlap-ignore-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:l("settings.scheduling.ignoredOverlapPaths","Ignored overlap paths")}),e.jsxs(B,{settingKey:"overlapIgnorePaths",children:[l("settings.scheduling.optionalFileOrDirectoryPathsToIgnoreWhen"," No default — unset (empty). Optional file or directory paths to ignore when overlap serialization is enabled. Paths are project-relative (for example "),e.jsx("code",{children:"docs/"}),l("settings.scheduling.or"," or "),e.jsx("code",{children:"generated/*"}),l("settings.scheduling.closeParenPeriod",").")]})]}),e.jsx("div",{className:"settings-overlap-ignore-list",children:(t.overlapIgnorePaths&&t.overlapIgnorePaths.length>0?t.overlapIgnorePaths:[""]).map((h,p)=>e.jsxs("div",{className:"settings-overlap-ignore-row",children:[e.jsxs("div",{className:"settings-overlap-ignore-path-controls",children:[e.jsx("input",{className:"input",type:"text",value:h,placeholder:l("settings.scheduling.docs","docs/"),onChange:b=>n(p,b.target.value)}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>c(p),"aria-label":`Browse path for ignored overlap entry ${p+1}`,children:l("settings.scheduling.browse"," Browse ")})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>d(p),disabled:(t.overlapIgnorePaths??[]).length===0&&p===0,children:l("settings.scheduling.remove"," Remove ")})]},`overlap-ignore-${p}`))}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:i,children:l("settings.scheduling.addIgnoredPath"," Add ignored path ")})]}),e.jsx("div",{className:"settings-section-divider"}),e.jsx("h5",{className:"settings-section-heading",children:l("settings.scheduling.stepExecution","Step Execution")}),e.jsx(xn,{message:l("settings.movedStub.stepExecution","Step execution settings (run steps in new sessions, max parallel steps) now live on the workflow."),onOpenWorkflowSettings:u})]})}function Hg({globalMaxConcurrent:t,concurrencyLoading:s=!1,onGlobalMaxConcurrentChange:a}){const{t:n}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.scheduling.scopeGlobalTitle","Global — applies to all projects")}),e.jsx("p",{className:"settings-section-description",children:n("settings.scheduling.scopeGlobalCaption","Shared by every project on this machine.")}),e.jsx(ye,{descriptor:{key:"globalMaxConcurrent",label:n("settings.scheduling.globalMaxConcurrent","Global Max Concurrent"),help:n("settings.scheduling.maximumConcurrentAgentsAcrossAllProjects","Maximum concurrent agents across all projects. Default: 4."),min:0,max:1e4,disabled:s},value:t??null,onChange:c=>a(c??void 0)})]})}function _g({defer:t=!1}){const{t:s}=te("app"),[a,n]=o.useState(null),[c,d]=o.useState(!1),[i,u]=o.useState(!1),[l,h]=o.useState(null),[p,b]=o.useState(null),[w,x]=o.useState(null),f=k=>{switch(k){case"installed":return{text:s("cliBinary.stateInstalled","Installed"),tone:"ok"};case"missing":return{text:s("cliBinary.stateMissing","Not installed"),tone:"err"};case"version-mismatch":return{text:s("cliBinary.stateVersionMismatch","Version mismatch"),tone:"warn"};case"skipped":return{text:s("cliBinary.stateCheckDisabled","Check disabled"),tone:"warn"}}},D=o.useCallback(async()=>{d(!0),b(null);try{const k=await Jc();n(k)}catch(k){b(k instanceof Error?k.message:String(k))}finally{d(!1)}},[]);o.useEffect(()=>{t||D()},[t,D]);const S=o.useCallback(async()=>{u(!0),h(null),b(null);try{const k=await Xc();n({binary:k.binary,expectedVersion:k.expectedVersion,state:k.state,install:k.install}),h(k.installResult)}catch(k){b(k instanceof Error?k.message:String(k))}finally{u(!1)}},[]),C=o.useCallback(async(k,R)=>{await mn(R)&&(x(k),setTimeout(()=>x(N=>N===k?null:N),1500))},[]),y=a?f(a.state):null;return e.jsxs("div",{className:"cli-binary-panel",children:[e.jsxs("div",{className:"cli-binary-header",children:[e.jsx("h4",{className:"settings-section-heading",children:s("cliBinary.heading","CLI Binary")}),y&&e.jsx("span",{className:`cli-binary-pill cli-binary-pill--${y.tone}`,children:y.text})]}),e.jsx("small",{className:"cli-binary-help",children:s("cliBinary.help","Installing the global CLI lets you run fn and fusion from any terminal. Automations and scripts work without it via npx, but a global install is faster and more convenient.")}),c&&!a&&e.jsx("p",{className:"cli-binary-status-line",children:s("cliBinary.checking","Checking…")}),a&&e.jsxs("div",{className:"cli-binary-detail",children:[a.binary.installed?e.jsxs("ul",{className:"cli-binary-info-list",children:[e.jsxs("li",{children:[e.jsx("span",{children:s("cliBinary.binaryLabel","Binary:")}),e.jsx("code",{children:a.binary.binary})]}),a.binary.path&&e.jsxs("li",{children:[e.jsx("span",{children:s("cliBinary.pathLabel","Path:")}),e.jsx("code",{children:a.binary.path})]}),e.jsxs("li",{children:[e.jsx("span",{children:s("cliBinary.versionLabel","Version:")}),e.jsx("code",{children:a.binary.version??"unknown"}),e.jsx("span",{className:"cli-binary-expected",children:s("cliBinary.expectedVersion","(expected {{version}})",{version:a.expectedVersion})})]})]}):e.jsx("p",{className:"cli-binary-status-line",children:s("cliBinary.notOnPath","Neither fn nor fusion was found on PATH.")}),e.jsxs("div",{className:"cli-binary-actions",children:[e.jsx("button",{type:"button",className:"cli-binary-install-btn",onClick:S,disabled:i,children:i?s("cliBinary.installing","Installing…"):a.binary.installed?s("cliBinary.reinstall","Reinstall"):s("cliBinary.installWithNpm","Install with npm")}),e.jsx("button",{type:"button",className:"cli-binary-refresh-btn",onClick:()=>void D(),disabled:c||i,children:s("cliBinary.refresh","Refresh")})]}),e.jsxs("div",{className:"cli-binary-commands",children:[e.jsx("label",{children:s("cliBinary.orCopyLabel","Or copy and run yourself:")}),[{label:"npm",command:a.install.npm},{label:"curl",command:a.install.curl}].map(({label:k,command:R})=>e.jsxs("div",{className:"cli-binary-command-row",children:[e.jsx("code",{children:R}),e.jsx("button",{type:"button",onClick:()=>void C(k,R),className:"cli-binary-copy-btn",children:w===k?s("cliBinary.copied","Copied"):s("cliBinary.copy","Copy")})]},k))]})]}),l&&e.jsxs("details",{className:"cli-binary-install-log",open:!l.success,children:[e.jsx("summary",{children:l.success?s("cliBinary.succeededDuration","Install succeeded in {{duration}}s",{duration:(l.durationMs/1e3).toFixed(1)}):s("cliBinary.failedExit","Install failed (exit {{code}})",{code:l.exitCode??"n/a"})}),l.permissionsHint&&e.jsx("p",{className:"cli-binary-permissions-hint",children:l.permissionsHint}),l.stdout&&e.jsx("pre",{className:"cli-binary-install-output",children:l.stdout}),l.stderr&&e.jsx("pre",{className:"cli-binary-install-output cli-binary-install-output--err",children:l.stderr})]}),p&&e.jsx("p",{className:"field-error",children:p})]})}function Wg(){const{t}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:t("settings.nav.cliBinary","CLI Binary")}),e.jsx(_g,{})]})}function Ug({form:t,setForm:s}){const{t:a}=te("app"),n=t.evalSettings??{},c=n.enabled??!1;return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.scheduledEvals.scheduledEvals","Scheduled Evals")}),e.jsx(se,{descriptor:{key:"evalSettings.enabled",label:a("settings.scheduledEvals.enableScheduledEvalRunsForThisProject"," Enable scheduled eval runs for this project "),help:a("settings.scheduledEvals.enabledHint","Default: disabled."),scope:"project"},value:c,onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},enabled:d===!0}}))}),e.jsx(ye,{descriptor:{key:"evalSettings.intervalMs",label:a("settings.scheduledEvals.intervalMs","Interval (ms)"),help:a("settings.scheduledEvals.intervalMsHint","Default: 86400000 (24 hours)."),scope:"project",disabled:!c,min:6e4,max:6048e5,step:1e3},value:n.intervalMs??864e5,onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},intervalMs:d===null?void 0:d}}))}),e.jsx(de,{descriptor:{key:"evalSettings.evaluatorProvider",label:a("settings.scheduledEvals.evaluatorProvider","Evaluator Provider"),help:a("settings.scheduledEvals.evaluatorProviderHint","No default — unset (inherits the project validator lane provider)."),scope:"project",placeholder:a("settings.scheduledEvals.openai","openai")},value:n.evaluatorProvider??"",onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},evaluatorProvider:(d??"").trim()===""?void 0:d??void 0}}))}),e.jsx(de,{descriptor:{key:"evalSettings.evaluatorModelId",label:a("settings.scheduledEvals.evaluatorModel","Evaluator Model"),help:a("settings.scheduledEvals.leaveProviderAndModelBlankToInheritThe"," Leave provider and model blank to inherit the project validator lane model settings. No default — unset. "),scope:"project",placeholder:a("settings.scheduledEvals.gpt5","gpt-5")},value:n.evaluatorModelId??"",onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},evaluatorModelId:(d??"").trim()===""?void 0:d??void 0}}))}),e.jsx(ke,{descriptor:{key:"evalSettings.followUpPolicy",label:a("settings.scheduledEvals.followUpPolicy","Follow-up Policy"),help:a("settings.scheduledEvals.followUpPolicyHint","Default: suggest only."),scope:"project",disabled:!c,options:[{value:"disabled",label:a("settings.scheduledEvals.disabled","Disabled")},{value:"suggest-only",label:a("settings.scheduledEvals.suggestOnly","Suggest only")},{value:"auto-create",label:a("settings.scheduledEvals.autoCreateTasks","Auto-create tasks")}]},value:n.followUpPolicy??"suggest-only",onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},followUpPolicy:d}}))}),e.jsx(ye,{descriptor:{key:"evalSettings.retentionDays",label:a("settings.scheduledEvals.retentionDays","Retention (days)"),help:a("settings.scheduledEvals.retentionDaysHint","Default: 30."),scope:"project",disabled:!c,min:1,max:365,step:1},value:n.retentionDays??30,onChange:d=>s(i=>({...i,evalSettings:{...i.evalSettings??{},retentionDays:d===null?void 0:d}}))})]})}function $g(t,s){return t==="online"?s("settings.nodeRouting.statusOnline","Online"):t==="connecting"?s("settings.nodeRouting.statusConnecting","Connecting"):t==="error"?s("settings.nodeRouting.statusError","Error"):s("settings.nodeRouting.statusOffline","Offline")}function zg({form:t,setForm:s,nodes:a}){const{t:n}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.nodeRouting.nodeRouting","Node Routing")}),e.jsx("p",{className:"settings-section-description",children:n("settings.nodeRouting.configureHowTasksAreRoutedToExecutionNodes","Configure how tasks are routed to execution nodes.")}),e.jsx("p",{className:"settings-node-routing-note",children:n("settings.nodeRouting.theseSettingsApplyAtTheProjectLevel","These settings apply at the project level.")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"defaultNodeId",children:n("settings.nodeRouting.defaultExecutionNode","Default Execution Node")}),e.jsx(B,{settingKey:"defaultNodeId",children:n("settings.nodeRouting.usedWhenATaskHasNoNodeOverride","Used when a task has no node override. Node status is shown for safer routing selection. No default — unset (local execution).")})]}),e.jsxs("select",{id:"defaultNodeId",className:"select",value:typeof t.defaultNodeId=="string"?t.defaultNodeId:"",onChange:c=>{const d=c.target.value;s(i=>({...i,defaultNodeId:d||void 0}))},children:[e.jsx("option",{value:"",children:n("settings.nodeRouting.localExecutionNoDefaultNode","Local execution (no default node)")}),a.map(c=>e.jsxs("option",{value:c.id,children:[c.name," (",$g(c.status,n),")"]},c.id))]}),(()=>{const c=a.find(d=>d.id===t.defaultNodeId);return c?e.jsxs("div",{className:"settings-node-status",children:[e.jsx("span",{children:n("settings.nodeRouting.selectedNode","Selected node:")}),e.jsx(Zc,{status:c.status,showLabel:!0})]}):null})()]}),e.jsx(ke,{descriptor:{key:"unavailableNodePolicy",label:n("settings.nodeRouting.unavailableNodePolicy","Unavailable Node Policy"),help:n("settings.nodeRouting.unavailableNodePolicyHint","Default: block execution."),scope:"project",options:[{value:"block",label:n("settings.nodeRouting.blockExecution","Block execution")},{value:"fallback-local",label:n("settings.nodeRouting.fallBackToLocal","Fall back to local")}]},value:t.unavailableNodePolicy==="fallback-local"?"fallback-local":"block",onChange:c=>s(d=>({...d,unavailableNodePolicy:c}))})]})}function qg({form:t,setForm:s,gitRemotes:a,worktrunkInstall:n,worktrunkInstallVerified:c,onOpenWorktreesDirPicker:d,onWorktreeCopyFileChange:i,onRemoveWorktreeCopyFile:u,onAddWorktreeCopyFile:l,onOpenWorktreeCopyFilePicker:h,onOpenApprovals:p}){const{t:b}=te("app"),w=(t.worktreeCopyFiles?.length??0)>0?t.worktreeCopyFiles??[]:[""];return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:b("settings.worktrees.worktrees","Worktrees")}),e.jsx(ye,{descriptor:{key:"maxWorktrees",label:b("settings.worktrees.maxWorktrees","Max Worktrees"),help:b("settings.worktrees.limitsTotalGitWorktreesIncludingInReviewTasks","Limits total git worktrees including in-review tasks. Default: 4."),scope:"project",min:1,max:20},value:t.maxWorktrees??null,onChange:x=>s(f=>({...f,maxWorktrees:x??void 0}))}),e.jsx(de,{descriptor:{key:"worktreeInitCommand",label:b("settings.worktrees.worktreeInitCommand","Worktree Init Command"),help:b("settings.worktrees.shellCommandToRunInEachNewWorktree","Shell command to run in each new worktree after creation. No default — unset."),scope:"project",placeholder:b("settings.worktrees.pnpmInstallFrozenLockfile","pnpm install --frozen-lockfile")},value:t.worktreeInitCommand??null,onChange:x=>s(f=>({...f,worktreeInitCommand:x??""}))}),e.jsx(se,{descriptor:{key:"recycleWorktrees",label:b("settings.worktrees.recycleWorktrees"," Recycle worktrees "),help:t.worktreeNaming==="task-id"&&t.recycleWorktrees!==!0?b("settings.worktrees.recycleNotApplicableWithTaskIdNaming","Not available with Task ID worktree naming — that mode pins each task to its own worktree directory, which is mutually exclusive with the recycle pool. Switch naming to Random or Task title to enable recycling."):b("settings.worktrees.offByDefaultOptInWhenEnabledCompleted","Off by default (opt-in). When enabled, completed task worktrees are returned to an idle pool instead of being deleted, preserving build caches for faster startup. Mutually exclusive with Task ID worktree naming."),scope:"project",disabled:t.worktreeNaming==="task-id"&&t.recycleWorktrees!==!0},value:t.recycleWorktrees===!0,onChange:x=>s(f=>({...f,recycleWorktrees:x===!0}))}),e.jsx(se,{descriptor:{key:"showWorktreeGrouping",label:b("settings.worktrees.showWorktreeGrouping"," Show worktree grouping on the board "),help:b("settings.worktrees.showWorktreeGroupingHelp","Off by default. When enabled, WIP and processing columns always group tasks by worktree and show worktree names, including workflow-mode processing columns."),scope:"project"},value:t.showWorktreeGrouping===!0,onChange:x=>s(f=>({...f,showWorktreeGrouping:x===!0}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:b("settings.worktrees.filesToCopyIntoNewWorktrees","Files to copy into new worktrees")}),e.jsx(B,{settingKey:"worktreeCopyFiles",children:b("settings.worktrees.copyFilesHelp","Optional. Repository-root-relative regular files are copied into fresh or pooled task worktrees before init commands run. Missing files or directories are skipped without exposing contents. Default: empty (no files copied).")})]}),e.jsx("div",{className:"settings-overlap-ignore-list","data-testid":"worktree-copy-files-list",children:w.map((x,f)=>e.jsxs("div",{className:"settings-overlap-ignore-row",children:[e.jsxs("div",{className:"settings-overlap-ignore-path-controls",children:[e.jsx("input",{id:`worktreeCopyFile-${f}`,type:"text",className:"input",placeholder:b("settings.worktrees.copyFilePlaceholder",".env"),value:x,onChange:D=>i(f,D.target.value),"aria-label":b("settings.worktrees.copyFilePathLabel","File to copy into new worktrees")}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>h(f),"aria-label":b("settings.worktrees.browseCopyFile","Browse file to copy into new worktrees"),children:b("settings.worktrees.browse"," Browse ")})]}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>u(f),"aria-label":b("settings.worktrees.removeCopyFile","Remove copied worktree file"),children:b("settings.worktrees.remove","Remove")})]},f))}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:l,children:b("settings.worktrees.addCopyFile","Add file")})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"executorAllowSiblingBranchRename",className:"checkbox-label",children:[e.jsx("input",{id:"executorAllowSiblingBranchRename",type:"checkbox",checked:t.executorAllowSiblingBranchRename===!0,onChange:x=>s(f=>({...f,executorAllowSiblingBranchRename:x.target.checked}))}),b("settings.worktrees.allowSilentSiblingBranchRenameDuringExecutorConflicts"," Allow silent sibling branch rename during executor conflicts ")]}),e.jsxs(B,{settingKey:"executorAllowSiblingBranchRename",children:[b("settings.worktrees.discouragedThisRestoresTheLegacyBehaviorWhereA"," Discouraged. This restores the legacy behavior where a live "),e.jsx("code",{children:"fusion/<task-id>"}),b("settings.worktrees.branchCollisionSilentlyForksWorkOntoSiblingBranches"," branch collision silently forks work onto sibling branches like "),e.jsx("code",{children:"-2"}),b("settings.worktrees.andCanHidePriorCommitsFromTheDefault"," and can hide prior commits from the default recovery flow. Default: disabled. ")]})]})}),e.jsx(ke,{descriptor:{key:"worktreeNaming",label:b("settings.worktrees.worktreeNamingStyle","Worktree Naming Style"),help:t.recycleWorktrees?b("settings.worktrees.namingStyleNotApplicableWhenRecycling",'Naming style is not applicable when recycling worktrees — pooled worktrees retain their existing names. "Task ID" is unavailable here because task-pinned worktrees are mutually exclusive with recycling; turn off Recycle worktrees to use it.'):b("settings.worktrees.howToNameFreshWorktreeDirectories",'How to name fresh worktree directories. Only applies when recycling is off. "Task ID" also pins each task to its own worktree directory for its whole lifecycle (mutually exclusive with recycling). Default: random.'),scope:"project",disabled:t.recycleWorktrees,options:[{value:"random",label:b("settings.worktrees.randomNamesEGSwiftFalcon","Random names (e.g., swift-falcon)")},{value:"task-id",label:b("settings.worktrees.taskIDEGFN042","Task ID (e.g., FN-042)")},{value:"task-title",label:b("settings.worktrees.taskTitleEGFixLoginBug","Task title (e.g., fix-login-bug)")}]},value:t.worktreeNaming||"random",onChange:x=>s(f=>({...f,worktreeNaming:x}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktreesDir",children:b("settings.worktrees.worktreesDirectory","Worktrees Directory")}),e.jsx(B,{settingKey:"worktreesDir",children:t.worktrunk?.enabled===!0?"Disabled because Worktrunk integration is enabled — worktrunk manages the worktree directory layout. Disable worktrunk integration to use a custom directory.":e.jsxs(e.Fragment,{children:[b("settings.worktrees.optionalSupports"," Optional. Supports "),e.jsx("code",{children:"~"}),b("settings.worktrees.and"," and "),e.jsx("code",{children:"{repo}"}),b("settings.worktrees.defaultsTo",". Defaults to "),e.jsx("code",{children:"<projectRoot>/.worktrees"}),b("settings.worktrees.whenUnsetOnlyAffectsNewlyCreatedWorktrees"," when unset. Only affects newly-created worktrees. ")]})})]}),e.jsxs("div",{className:"settings-overlap-ignore-path-controls",children:[e.jsx("input",{id:"worktreesDir",type:"text",placeholder:b("settings.worktrees.defaultsToWorktreesLeaveEmptyUnlessOverriding","Defaults to .worktrees — leave empty unless overriding"),value:t.worktreesDir||"",disabled:t.worktrunk?.enabled===!0,onChange:x=>s(f=>({...f,worktreesDir:x.target.value}))}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:d,"aria-label":b("settings.worktrees.browseWorktreesDirectory","Browse worktrees directory"),disabled:t.worktrunk?.enabled===!0,children:b("settings.worktrees.browse"," Browse ")})]})]}),e.jsx(se,{descriptor:{key:"worktreeRebaseBeforeMerge",label:b("settings.worktrees.rebaseFromRemoteBeforeMerge"," Rebase from remote before merge "),help:b("settings.worktrees.whenEnabledTheMergerFetchesFromTheConfigured","When enabled, the merger fetches from the configured remote and rebases the task branch onto the latest default-branch tip before merging — catching concurrent pushes from other collaborators or fusion workers. Any conflicts the rebase surfaces flow into the existing smart/AI resolve pipeline. Default: enabled."),scope:"project"},value:t.worktreeRebaseBeforeMerge!==!1,onChange:x=>s(f=>({...f,worktreeRebaseBeforeMerge:x===!0}))}),t.worktreeRebaseBeforeMerge!==!1&&e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktreeRebaseRemote",children:b("settings.worktrees.rebaseRemote","Rebase Remote")}),e.jsxs(B,{settingKey:"worktreeRebaseRemote",children:[b("settings.worktrees.whichRemoteToFetchForThePreMerge",' Which remote to fetch for the pre-merge rebase. "Use git default" falls back to the remote configured for the default branch (typically '),e.jsx("code",{children:"origin"}),b("settings.worktrees.closeParenPeriod",").")]})]}),e.jsxs("select",{id:"worktreeRebaseRemote",value:t.worktreeRebaseRemote??"",onChange:x=>s(f=>({...f,worktreeRebaseRemote:x.target.value||void 0})),children:[e.jsx("option",{value:"",children:b("settings.worktrees.useGitDefault","Use git default")}),a.map(x=>e.jsxs("option",{value:x.name,children:[x.name," (",x.fetchUrl,")"]},x.name))]})]}),e.jsx(se,{descriptor:{key:"worktreeRebaseLocalBase",label:b("settings.worktrees.alsoRebaseOntoLocalDefaultBranchHEAD"," Also rebase onto local default-branch HEAD "),help:b("settings.worktrees.inAdditionToTheRemoteRebaseAboveAlso"," In addition to the remote rebase above, also rebase the task branch onto the local default-branch HEAD (rootDir). This catches sibling tasks that merged locally but haven't been pushed yet — without it, two concurrent tasks where one deletes code can have the other silently re-introduce it via the fallback strategy. Enabled by default; only disable if it causes issues with your workflow. "),scope:"project"},value:t.worktreeRebaseLocalBase!==!1,onChange:x=>s(f=>({...f,worktreeRebaseLocalBase:x===!0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:b("settings.worktrees.worktrunkIntegration","Worktrunk integration")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"worktrunkEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"worktrunkEnabled",type:"checkbox",checked:t.worktrunk?.enabled===!0,disabled:!c&&t.worktrunk?.enabled!==!0,onChange:x=>s(f=>({...f,worktrunk:{enabled:x.target.checked,binaryPath:f.worktrunk?.binaryPath??"",onFailure:f.worktrunk?.onFailure??"fail"}}))}),b("settings.worktrees.enableWorktrunkIntegration"," Enable worktrunk integration ")]}),e.jsxs(B,{settingKey:"worktrunkEnabled",children:[b("settings.worktrees.disabledByDefaultOptInWhenEnabledFusion"," Disabled by default (opt-in). When enabled, Fusion shells out to "),e.jsx("code",{children:"worktrunk"}),b("settings.worktrees.forWorktreeCreateSyncPruneAndRemoveOperations"," for worktree create, sync, prune, and remove operations and follows worktrunk's directory layout. ")]})]}),!c&&t.worktrunk?.enabled!==!0&&e.jsx("small",{className:"settings-muted",children:b("settings.worktrees.installTheWorktrunkBinaryBelowToEnableThis","Install the worktrunk binary below to enable this integration.")})]}),e.jsxs("div",{className:"form-group","data-testid":"worktrunk-install-affordance",children:[n.status==="installed"&&e.jsxs("small",{className:"settings-muted",children:[b("settings.worktrees.worktrunk"," worktrunk "),n.version??"",b("settings.worktrees.installedAt"," installed at "),n.installPath??"~/.fusion/bin/worktrunk"]}),(n.status==="missing"||n.status==="installing")&&e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"btn btn-primary",onClick:()=>void n.requestInstall(),disabled:n.requesting||n.status==="installing",children:b("settings.worktrees.installWorktrunk","Install worktrunk binary")}),e.jsx("small",{className:"settings-muted",children:b("settings.worktrees.enableWorktrunkAndRequestApprovalToInstallThe","Enable worktrunk and request approval to install the pinned release.")})]}),n.status==="pending-approval"&&e.jsxs(e.Fragment,{children:[e.jsx("small",{className:"settings-muted",children:b("settings.worktrees.awaitingApproval","Awaiting approval — open Approvals to continue.")}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:()=>p?.(n.pendingApprovalId),children:b("settings.worktrees.openApprovals","Open Approvals")})]}),(n.status==="denied"||n.status==="failed")&&e.jsxs(e.Fragment,{children:[e.jsx("small",{style:{color:"var(--color-error)"},children:n.error??"Worktrunk install failed."}),e.jsx("button",{type:"button",className:"btn btn-secondary",onClick:()=>void n.requestInstall(),children:b("settings.worktrees.tryAgain","Try again")})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktrunkBinaryPath",children:b("settings.worktrees.worktrunkBinaryPath","Worktrunk binary path")}),e.jsx(B,{settingKey:"worktrunkBinaryPath",children:b("settings.worktrees.optionalLeaveBlankToAutoResolveFusionWill","Optional. Leave blank to auto-resolve; Fusion will offer to install on first use.")})]}),e.jsx("input",{id:"worktrunkBinaryPath",type:"text",className:"input",placeholder:b("settings.worktrees.autoDetectFusionBinWorktrunkOrPATH","auto-detect (~/.fusion/bin/worktrunk or $PATH)"),value:t.worktrunk?.binaryPath??"",disabled:t.worktrunk?.enabled!==!0,onChange:x=>s(f=>({...f,worktrunk:{enabled:f.worktrunk?.enabled===!0,binaryPath:x.target.value,onFailure:f.worktrunk?.onFailure??"fail"}}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"worktrunkOnFailure",children:b("settings.worktrees.worktrunkFailureBehavior","Worktrunk failure behavior")}),e.jsxs(B,{settingKey:"worktrunkOnFailure",children:[e.jsx("code",{children:"fail"}),b("settings.worktrees.stopsOnWorktrunkErrorsForExplicitOperatorRecovery"," stops on worktrunk errors for explicit operator recovery; "),e.jsx("code",{children:"fallback-native"}),b("settings.worktrees.keepsProgressMovingBySwitchingToFusionApos"," keeps progress moving by switching to Fusion's built-in worktree backend. ")]})]}),e.jsxs("select",{id:"worktrunkOnFailure",className:"select",value:t.worktrunk?.onFailure??"fail",disabled:t.worktrunk?.enabled!==!0,onChange:x=>s(f=>({...f,worktrunk:{enabled:f.worktrunk?.enabled===!0,binaryPath:f.worktrunk?.binaryPath??"",onFailure:x.target.value}})),children:[e.jsx("option",{value:"fail",children:b("settings.worktrees.failAndPauseTheTaskDefault","Fail and pause the task (default)")}),e.jsx("option",{value:"fallback-native",children:b("settings.worktrees.fallBackToFusionsNativeWorktreeBackend","Fall back to Fusion's native worktree backend")})]})]})]})}function Vg({form:t,setForm:s}){const{t:a}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.commands.commands","Commands")}),e.jsx(de,{descriptor:{key:"testCommand",label:a("settings.commands.testCommand","Test Command"),help:a("settings.commands.commandUsedToRunTestsInjectedIntoGenerated","Command used to run tests — injected into generated task specs. No default — unset."),scope:"project",placeholder:a("settings.commands.eGPnpmTest","e.g. pnpm test")},value:t.testCommand??null,onChange:n=>s(c=>({...c,testCommand:n||void 0}))}),e.jsx(de,{descriptor:{key:"buildCommand",label:a("settings.commands.buildCommand","Build Command"),help:a("settings.commands.commandUsedToBuildTheProjectInjectedInto","Command used to build the project — injected into generated task specs. No default — unset."),scope:"project",placeholder:a("settings.commands.eGPnpmBuild","e.g. pnpm build")},value:t.buildCommand??null,onChange:n=>s(c=>({...c,buildCommand:n||void 0}))})]})}function Yg(t){const s=(t??"").trim().split(/\s+/).filter(Boolean);return{remote:s[0]??"origin",branch:s.slice(1).join(" ")}}function Ks(t,s){const a=t.trim()||"origin",n=s.trim();return n?`${a} ${n}`:a==="origin"?void 0:a}function Qg(t){const s=Number(t);return Number.isFinite(s)&&s>0?Math.floor(s):3}async function Jg(t){if(!t.ok)throw new Error(await t.text()||"Failed to load legacy auto-merge stamps");return t.json()}function Xg({form:t,setForm:s,integrationBranchOptions:a,integrationBranchCustomMode:n,setIntegrationBranchCustomMode:c,onOpenWorkflowSettings:d,gitRemoteOptions:i=[],projectId:u}){const{t:l}=te("app"),h=Yg(t.pushRemote),[p,b]=o.useState([]),[w,x]=o.useState(!1);o.useEffect(()=>{if(!t.pushAfterMerge||i.length===0)return;let E=!1;return ed(h.remote,u).then(L=>{E||b(L)}).catch(()=>{E||b([])}),()=>{E=!0}},[t.pushAfterMerge,h.remote,u,i.length]);const[f,D]=o.useState([]),[S,C]=o.useState(!0),[y,k]=o.useState(!1),[R,P]=o.useState(null),[N,U]=o.useState(null),m=o.useCallback(async()=>{C(!0),P(null);try{const E=await Jg(await fetch("/api/maintenance/legacy-automerge-stamps"));D(Array.isArray(E.candidates)?E.candidates:[])}catch(E){P(E instanceof Error?E.message:"Failed to load legacy auto-merge stamps")}finally{C(!1)}},[]);o.useEffect(()=>{m()},[m]);const Y=async()=>{if(window.confirm("Apply cleanup for legacy auto-merge stamps? This clears only legacy non-override in-review stamps returned by the store and never touches genuine per-task overrides.")){k(!0),P(null),U(null);try{const L=await fetch("/api/maintenance/legacy-automerge-stamps/apply",{method:"POST"});if(!L.ok)throw new Error(await L.text()||"Failed to apply legacy auto-merge stamp cleanup");const G=await L.json();U(`Cleared ${G.count} legacy auto-merge stamp${G.count===1?"":"s"}.`),await m()}catch(L){P(L instanceof Error?L.message:"Failed to apply legacy auto-merge stamp cleanup")}finally{k(!1)}}};return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:l("settings.merge.merge","Merge")}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"autoMerge",className:"checkbox-label",children:[e.jsx("input",{id:"autoMerge",type:"checkbox",checked:t.autoMerge,onChange:E=>s(L=>({...L,autoMerge:E.target.checked}))}),l("settings.merge.autoMergeCompletedTasks"," Auto-merge completed tasks ")]}),e.jsx(B,{settingKey:"autoMerge",children:l("settings.merge.whenEnabledTasksThatPassReviewAreAutomatically","When enabled, tasks that pass review are automatically merged into the main branch. Default: enabled.")})]})}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"planApprovalMode",children:l("settings.merge.planApprovalMode","Plan approval mode")}),e.jsx(B,{settingKey:"planApprovalMode",children:l("settings.merge.planApprovalModeHelp","Project-wide override for the planning approval gate. Leave on workflow to use each workflow's Require plan approval setting, or force all approved specs to bypass or wait for manual approval.")})]}),e.jsxs("select",{id:"planApprovalMode",className:"select",value:t.planApprovalMode??"auto-approve-all",onChange:E=>{const L=E.target.value;s(G=>({...G,planApprovalMode:L}))},"data-testid":"plan-approval-mode-select",children:[e.jsx("option",{value:"workflow",children:l("settings.merge.planApprovalModeWorkflow","Use workflow setting")}),e.jsx("option",{value:"auto-approve-all",children:l("settings.merge.planApprovalModeAutoApproveAll","Auto-approve all tasks (default)")}),e.jsx("option",{value:"require-all",children:l("settings.merge.planApprovalModeRequireAll","Require approval for all tasks")})]})]}),e.jsx(ye,{descriptor:{key:"maxAutoMergeRetries",label:l("settings.merge.autoMergeConflictRetries","Auto-merge conflict retries"),help:l("settings.merge.positiveIntegerRetryCapForAutoMergeConflict","Positive integer retry cap for auto-merge conflict resolution before a task parks for human recovery. Default 3."),scope:"project",min:1,step:1},value:t.maxAutoMergeRetries??3,onChange:E=>s(L=>({...L,maxAutoMergeRetries:E===null?void 0:Qg(E)}))}),e.jsxs("div",{className:"form-group","data-testid":"legacy-automerge-stamp-cleanup-panel",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h5",{className:"settings-section-heading",children:l("settings.merge.legacyAutoMergeStampCleanup","Legacy auto-merge stamp cleanup")}),e.jsx(B,{settingKey:"legacy-automerge-stamp-cleanup",children:l("settings.merge.findsInReviewTasksWhoseAutoMergeValue"," Finds in-review tasks whose auto-merge value came from the legacy review-entry stamp. Dry-run is automatic; applying delegates to the store cleanup and preserves genuine per-task overrides. ")})]}),S?e.jsx("small",{"aria-live":"polite",children:l("settings.merge.checkingForLegacyAutoMergeStamps","Checking for legacy auto-merge stamps…")}):f.length===0?e.jsx("small",{"data-testid":"legacy-automerge-stamp-empty-state",children:l("settings.merge.noLegacyAutoMergeStampsToCleanUp"," No legacy auto-merge stamps to clean up. ")}):e.jsxs(e.Fragment,{children:[e.jsxs("small",{children:[f.length,l("settings.merge.legacyAutoMergeStamp"," legacy auto-merge stamp"),f.length===1?"":"s",l("settings.merge.readyToCleanUp"," ready to clean up.")]}),e.jsx("ul",{children:f.map(E=>e.jsxs("li",{"data-testid":"legacy-automerge-stamp-candidate-row",children:[e.jsx("strong",{children:E.taskId})," — ",E.column]},E.taskId))}),e.jsx("button",{type:"button",className:"btn",onClick:Y,disabled:y,"data-testid":"legacy-automerge-stamp-apply-button",children:y?"Applying cleanup…":"Apply cleanup"})]}),N?e.jsx("small",{className:"settings-success","aria-live":"polite",children:N}):null,R?e.jsx("small",{className:"settings-error",role:"alert",children:R}):null]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergerMode",children:l("settings.merge.aIMerge","AI merge")}),e.jsxs(B,{settingKey:"mergerMode",children:[l("settings.merge.aIModeMergesTheTaskBranchIntoAn"," AI mode merges the task branch into an isolated clean-room checkout at the target branch's tip, has an AI reviewer audit the squash (with corrective retries — advisory concerns land with a logged warning, an unfixable correctness concern hard-fails), then fast-forwards the target branch and syncs your local checkout (AI reconciles a conflicting restore). Each task merges to its own target branch, or the default integration branch. "),e.jsx("strong",{children:l("settings.merge.theLegacyMergeSettingsBelowDoNotApply","The legacy merge settings below do not apply while AI merge is on.")})]})]}),e.jsxs("select",{id:"mergerMode",className:"select",value:t.merger?.mode??"ai",onChange:E=>s(L=>({...L,merger:{...L.merger??{},mode:E.target.value}})),children:[e.jsx("option",{value:"ai",children:l("settings.merge.aIMergeDefaultAIMergesInAClean","AI merge (default) — AI merges in a clean room, an AI reviewer audits with retries, then lands")}),e.jsx("option",{value:"deterministic",children:l("settings.merge.deterministicLegacyRebaseConflictStrategyAuditPipeline","Deterministic (legacy) — rebase / conflict-strategy / audit pipeline")})]})]}),(t.merger?.mode??"ai")==="ai"&&e.jsxs(e.Fragment,{children:[e.jsx(ye,{descriptor:{key:"merger.maxReviewPasses",label:l("settings.merge.maxAIReviewPasses","Max AI review passes"),help:l("settings.merge.aICorrectiveRoundsBeforeLandingTheBestResult","AI corrective rounds before landing the best result (advisory concern) or hard-failing (unfixable correctness concern). Default 3. The reviewer uses your project's reviewer/validator model."),scope:"project",min:0,max:10},value:t.merger?.maxReviewPasses??3,onChange:E=>s(L=>({...L,merger:{...L.merger??{},maxReviewPasses:E??void 0}}))}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"mergerAllowDirtyLocalCheckoutSync",className:"checkbox-label",children:[e.jsx("input",{id:"mergerAllowDirtyLocalCheckoutSync",type:"checkbox",checked:t.merger?.allowDirtyLocalCheckoutSync===!0,onChange:E=>s(L=>({...L,merger:{...L.merger??{},allowDirtyLocalCheckoutSync:E.target.checked}}))}),l("settings.merge.allowAIMergeToSyncADirtyChecked"," Allow AI merge to sync a dirty checked-out integration branch ")]}),e.jsx(B,{settingKey:"merger.allowDirtyLocalCheckoutSync",children:l("settings.merge.dangerousCompatibilityEscapeHatchLeaveOffUnlessYou"," Dangerous compatibility escape hatch — restores the legacy stash → fast-forward → restore behavior when your checked-out integration branch has unrelated local edits. When off, AI merge blocks before advancing the branch so dirty project-root edits cannot contaminate a completed merge. Default: enabled (new/unconfigured projects sync a dirty checkout). ")})]})})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"testMode",className:"checkbox-label",children:[e.jsx("input",{id:"testMode",type:"checkbox",checked:t.testMode===!0,onChange:E=>s(L=>({...L,testMode:E.target.checked}))}),l("settings.merge.enableTestMode"," Enable test mode ")]}),e.jsx(B,{settingKey:"testMode",children:l("settings.merge.forcesAllAILanesToUseTheDeterministic","Forces all AI lanes to use the deterministic mock provider. No network calls, zero token cost. No default — unset (disabled).")})]})}),e.jsx(xn,{message:l("settings.movedStub.reviewVerification","Review, verification auto-fix, and scope-enforcement settings now live on the workflow."),onOpenWorkflowSettings:d}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeStrategy",children:l("settings.merge.autoCompletionMode","Auto-completion mode")}),e.jsx(B,{settingKey:"mergeStrategy",children:l("settings.merge.controlsWhatHappensAfterATaskReachesIn"," Controls what happens after a task reaches In Review. Direct mode merges into the current branch locally. Pull request mode keeps the task in In Review while Fusion waits for GitHub reviews and required checks before merging the PR. ")})]}),e.jsxs("select",{id:"mergeStrategy",value:t.mergeStrategy||"direct",onChange:E=>s(L=>({...L,mergeStrategy:E.target.value})),children:[e.jsx("option",{value:"direct",children:l("settings.merge.directMergeIntoTheCurrentBranch","Direct merge into the current branch (default)")}),e.jsx("option",{value:"pull-request",children:l("settings.merge.createMonitorAndMergeAGitHubPullRequest","Create, monitor, and merge a GitHub pull request")})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"integrationBranch",children:l("settings.merge.integrationBranch","Integration branch")}),e.jsxs(B,{settingKey:"integrationBranch",children:[l("settings.merge.theCanonicalBranchFusionMergesTasksIntoAnd"," No default — unset (auto-detect). The canonical branch Fusion merges tasks into and uses as the reference for all ahead/behind / overlap / pre-rebase computations. Leave on "),e.jsx("em",{children:l("settings.merge.autoDetect","auto-detect")}),l("settings.merge.toResolveViaTheStandardCascade"," to resolve via the standard cascade ("),e.jsx("code",{children:"integrationBranch"}),l("settings.merge.legacy"," → legacy "),e.jsx("code",{children:"baseBranch"})," →",e.jsx("code",{children:"origin/HEAD"}),l("settings.merge.symbolicRefFallback"," symbolic ref → fallback "),e.jsx("code",{children:"main"}),l("settings.merge.pickALocalBranchFromTheDropdownCommon","). Pick a local branch from the dropdown — common integration names like "),e.jsx("code",{children:"main"}),",",e.jsx("code",{children:"master"}),", ",e.jsx("code",{children:"trunk"}),l("settings.merge.and",", and "),e.jsx("code",{children:"develop"}),l("settings.merge.areListedFirstOrChoose"," are listed first — or choose "),e.jsx("em",{children:l("settings.merge.custom","Custom…")}),l("settings.merge.toTypeABranchThatDoesnAposT"," to type a branch that doesn't exist locally yet. Applies to both direct merges and pull-request mode; individual tasks can still override via task metadata. ")]})]}),(()=>{const E=t.integrationBranch??"",L=E.length>0&&a.includes(E);if(n||E.length>0&&!L)return e.jsxs("div",{className:"form-inline-group",children:[e.jsx("input",{id:"integrationBranch",type:"text",className:"input",placeholder:l("settings.merge.branchName","branch name"),value:E,onChange:ne=>{const re=ne.target.value.trim();s(ce=>({...ce,integrationBranch:re.length===0?void 0:re}))},"data-testid":"integration-branch-custom-input"}),e.jsx("button",{type:"button",className:"btn-link",onClick:()=>{c(!1),s(ne=>({...ne,integrationBranch:void 0}))},"data-testid":"integration-branch-use-dropdown",children:l("settings.merge.useDropdown"," Use dropdown ")})]});const K="__fusion-custom__",z="";return e.jsxs("select",{id:"integrationBranch",className:"select",value:E,onChange:ne=>{const re=ne.target.value;if(re===K){c(!0);return}s(ce=>({...ce,integrationBranch:re===z?void 0:re}))},"data-testid":"integration-branch-select",children:[e.jsx("option",{value:z,children:l("settings.merge.autoDetectOriginHEADMain","(auto-detect — origin/HEAD → main)")}),a.map(ne=>e.jsx("option",{value:ne,children:ne},ne)),e.jsx("option",{value:K,children:l("settings.merge.custom","Custom…")})]})})()]}),t.mergeStrategy!=="pull-request"&&(t.merger?.mode??"ai")!=="ai"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"directMergeCommitStrategy",children:l("settings.merge.directMergeCommitRouting","Direct merge commit routing")}),e.jsxs(B,{settingKey:"directMergeCommitStrategy",children:[l("settings.merge.autoKeepsTodayAposSSquashBehaviorFor"," Auto keeps today's squash behavior for branches with zero or one substantive commit, but switches multi-substantive branches to a history-preserving rebase-and-merge path. Individual tasks can override this in PROMPT.md with "),e.jsx("code",{children:"**Direct Merge Commit Strategy:** auto|always-squash|always-rebase"}),"."]})]}),e.jsxs("select",{id:"directMergeCommitStrategy",className:"select",value:t.directMergeCommitStrategy??"always-squash",onChange:E=>s(L=>({...L,directMergeCommitStrategy:E.target.value})),children:[e.jsx("option",{value:"auto",children:l("settings.merge.autoSquashSingleSubstantiveBranchesPreserveMultiSubstantive","Auto — squash single-substantive branches, preserve multi-substantive history")}),e.jsx("option",{value:"always-squash",children:l("settings.merge.alwaysSquashDirectMerges","Always squash direct merges (default)")}),e.jsx("option",{value:"always-rebase",children:l("settings.merge.alwaysPreserveDirectMergeCommitHistory","Always preserve direct-merge commit history")})]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeIntegrationWorktree",children:l("settings.merge.integrationWorktree","Integration worktree")}),e.jsx(B,{settingKey:"mergeIntegrationWorktree",children:l("settings.merge.autoMergeRunsInTheTaskWorktreeBy"," Auto-merge runs in the task worktree by default. Switch to the legacy project-root path only if you need the pre-FN-5279 fallback; worktrunk-managed projects still defer to worktrunk. ")})]}),e.jsxs("select",{id:"mergeIntegrationWorktree",className:"select",value:t.mergeIntegrationWorktree??"reuse-task-worktree",onChange:E=>s(L=>({...L,mergeIntegrationWorktree:E.target.value})),children:[e.jsx("option",{value:"reuse-task-worktree",children:l("settings.merge.reuseTaskWorktreeDefault","Reuse task worktree (default)")}),e.jsx("option",{value:"cwd-main",children:l("settings.merge.useProjectRootLegacy","Use project root (legacy)")})]}),(t.mergeIntegrationWorktree??"reuse-task-worktree")!=="reuse-task-worktree"&&e.jsxs("div",{className:"settings-warning-banner",role:"alert","aria-live":"polite","data-testid":"merge-integration-worktree-warning",children:[e.jsx("strong",{children:l("settings.merge.legacyIntegrationBranchMode","Legacy integration-branch mode.")})," ",l("settings.merge.autoMergeWillRunRebaseConflictResolutionAnd"," Auto-merge will run rebase, conflict resolution, and squash commits inside the project root (the user's checked-out integration-branch worktree) instead of the task worktree. Fusion assumes that directory is already on the integration branch and clean; if it isn't, merges may fail or touch the user's working tree. Reuse-task-worktree is the recommended default (FN-5279). Switch back unless you have a specific reason to opt in (FN-5348). ")]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeAdvanceAutoSync",children:l("settings.merge.autoSyncProjectCheckoutAfterMerge","Auto-sync project checkout after merge")}),e.jsxs(B,{settingKey:"mergeAdvanceAutoSync",children:[l("settings.merge.afterFusionAdvancesTheIntegrationBranchRefThe"," After Fusion advances the integration branch ref, the merger can auto-sync other worktrees still checked out on that branch (typically your project-root checkout). "),e.jsx("code",{children:"Stash + fast-forward"}),l("settings.merge.snapshotsRealLocalEditsAsAPatchAgainst"," snapshots real local edits as a patch against the previous tip, snaps the worktree to the new tip, then reapplies the patch — untracked files that collide with newly-tracked paths are left in a temp dir for manual recovery. "),e.jsx("code",{children:"Fast-forward only"}),l("settings.merge.snapsCleanlyWhenTheWorktreeHasNoEdits"," snaps cleanly when the worktree has no edits and skips otherwise. "),e.jsx("code",{children:"Off"}),l("settings.merge.isTheLegacyBehavior"," is the legacy behavior: "),e.jsx("code",{children:"git status"}),l("settings.merge.inYourProjectRootWillShowTheNew"," in your project root will show the new commits inverted as "staged changes" until you pull manually. Only applies to direct merges. ")]})]}),e.jsxs("select",{id:"mergeAdvanceAutoSync",className:"select",value:t.mergeAdvanceAutoSync??"stash-and-ff",onChange:E=>s(L=>({...L,mergeAdvanceAutoSync:E.target.value})),"data-testid":"merge-advance-auto-sync-select",children:[e.jsx("option",{value:"stash-and-ff",children:l("settings.merge.stashFastForwardDefaultPreserveLocalEdits","Stash + fast-forward (default) — preserve local edits")}),e.jsx("option",{value:"ff-only",children:l("settings.merge.fastForwardOnlySkipDirtyWorktrees","Fast-forward only — skip dirty worktrees")}),e.jsx("option",{value:"off",children:l("settings.merge.offLeaveTheProjectRootStaleLegacyBehavior","Off — leave the project root stale (legacy behavior)")})]})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"includeTaskIdInCommit",className:"checkbox-label",children:[e.jsx("input",{id:"includeTaskIdInCommit",type:"checkbox",checked:t.includeTaskIdInCommit!==!1,onChange:E=>s(L=>({...L,includeTaskIdInCommit:E.target.checked}))}),l("settings.merge.includeTaskIDInCommitScope"," Include task ID in commit scope ")]}),e.jsxs(B,{settingKey:"includeTaskIdInCommit",children:[l("settings.merge.whenDisabledMergeCommitMessagesOmitTheTask","When disabled, merge commit messages omit the task ID from the scope (e.g. "),e.jsx("code",{children:"feat: ..."}),l("settings.merge.insteadOf"," instead of "),e.jsx("code",{children:"feat(KB-001): ..."}),l("settings.merge.includeTaskIdInCommitDefault","). Default: enabled.")]})]})}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"commitAuthorEnabled",className:"checkbox-label",children:[e.jsx("input",{id:"commitAuthorEnabled",type:"checkbox",checked:t.commitAuthorEnabled!==!1,onChange:E=>s(L=>({...L,commitAuthorEnabled:E.target.checked}))}),l("settings.merge.addFusionAsCoAuthorOnCommits"," Add Fusion as co-author on commits ")]}),e.jsxs(B,{settingKey:"commitAuthorEnabled",children:[l("settings.merge.whenEnabledCommitsMadeByFusionKeepYour"," When enabled, commits made by Fusion keep your git identity as the primary author and append a "),e.jsx("code",{children:"Co-authored-by"}),l("settings.merge.trailerCreditingFusionRecognizedByGitHubForShared"," trailer crediting Fusion (recognized by GitHub for shared attribution). Default: enabled. ")]})]})}),t.commitAuthorEnabled!==!1&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"commitAuthorName",children:l("settings.merge.coAuthorName","Co-author Name")}),e.jsxs(B,{settingKey:"commitAuthorName",children:[l("settings.merge.nameUsedInThe","Name used in the "),e.jsx("code",{children:"Co-authored-by"}),l("settings.merge.trailer"," trailer. Default: Fusion.")]})]}),e.jsx("input",{id:"commitAuthorName",type:"text",value:t.commitAuthorName??"",placeholder:l("settings.merge.fusion","Fusion"),onChange:E=>s(L=>({...L,commitAuthorName:E.target.value||void 0}))})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"commitAuthorEmail",children:l("settings.merge.coAuthorEmail","Co-author Email")}),e.jsxs(B,{settingKey:"commitAuthorEmail",children:[l("settings.merge.emailUsedInThe","Email used in the "),e.jsx("code",{children:"Co-authored-by"}),l("settings.merge.trailerEmail"," trailer. Default: noreply@runfusion.ai.")]})]}),e.jsx("input",{id:"commitAuthorEmail",type:"email",value:t.commitAuthorEmail??"",placeholder:l("settings.merge.noreplyRunfusionAi","noreply@runfusion.ai"),onChange:E=>s(L=>({...L,commitAuthorEmail:E.target.value||void 0}))})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"autoResolveConflicts",className:"checkbox-label",children:[e.jsx("input",{id:"autoResolveConflicts",type:"checkbox",checked:t.autoResolveConflicts!==!1,onChange:E=>s(L=>({...L,autoResolveConflicts:E.target.checked}))}),l("settings.merge.autoResolveConflictsInLockFilesAndGenerated"," Auto-resolve conflicts in lock files and generated files ")]}),e.jsx(B,{settingKey:"autoResolveConflicts",children:l("settings.merge.whenEnabledLockFilesPackageLockJsonPnpm","When enabled, lock files (package-lock.json, pnpm-lock.yaml, etc.), generated files (dist/*, *.gen.ts), and trivial whitespace conflicts are resolved automatically without AI intervention. Complex code conflicts still require AI review. Default: enabled.")})]})}),(t.merger?.mode??"ai")!=="ai"&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"smartConflictResolution",className:"checkbox-label",children:[e.jsx("input",{id:"smartConflictResolution",type:"checkbox",checked:t.smartConflictResolution!==!1,onChange:E=>s(L=>({...L,smartConflictResolution:E.target.checked}))}),l("settings.merge.smartConflictResolution"," Smart conflict resolution ")]}),e.jsx(B,{settingKey:"smartConflictResolution",children:l("settings.merge.whenEnabledLockFilesPackageLockJsonPnpm2","When enabled, lock files (package-lock.json, pnpm-lock.yaml, etc.) are resolved using 'ours' strategy, generated files (dist/*, *.gen.ts) using 'theirs' strategy, and trivial whitespace conflicts are auto-resolved without spawning an AI agent. Complex code conflicts still require AI review. Default: enabled.")})]})}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"mergeConflictStrategy",children:l("settings.merge.conflictFallbackStrategy","Conflict Fallback Strategy")}),e.jsxs(B,{settingKey:"mergeConflictStrategy",children:[l("settings.merge.both"," Both "),e.jsx("strong",{children:l("settings.merge.smart","Smart")}),l("settings.merge.optionsStartWithABestEffort"," options start with a best-effort "),e.jsx("code",{children:"git fetch"}),l("settings.merge.fastForwardOfLocalMainFrom"," + fast-forward of local main from "),e.jsx("code",{children:"origin"}),l("settings.merge.soAFreshlyPushedSiblingCommitDoesntGet"," (so a freshly-pushed sibling commit doesn't get clobbered), then run an AI agent, then auto-resolve handles lock/generated/trivial files. They differ only in the "),e.jsx("em",{children:l("settings.merge.finalFallback","final fallback")}),":"," ",e.jsx("strong",{children:l("settings.merge.smartPreferMain","Smart, prefer main")}),l("settings.merge.uses"," uses "),e.jsx("code",{children:"-X ours"}),l("settings.merge.soMainWinsProtectsJustMergedSiblingWork"," so main wins — protects just-merged sibling work and is the new default. ")," ",e.jsx("strong",{children:l("settings.merge.smartPreferTask","Smart, prefer task")}),l("settings.merge.uses"," uses "),e.jsx("code",{children:"-X theirs"}),l("settings.merge.soTheTaskBranchWinsFastButCan"," so the task branch wins — fast, but can resurrect code an earlier sibling task deleted (the FN-2887 class of regression). ")," ",e.jsx("strong",{children:l("settings.merge.aIOnly","AI only")}),l("settings.merge.retriesTheAIAgentRatherThanAutoPicking"," retries the AI agent rather than auto-picking a side. ")," ",e.jsx("strong",{children:l("settings.merge.abort","Abort")}),l("settings.merge.stopsAfterTheFirstAIAttemptAndWaits"," stops after the first AI attempt and waits for a human. ")," ",e.jsxs("em",{children:[l("settings.merge.legacy2","Legacy "),e.jsx("code",{children:'"smart"'}),l("settings.merge.and2"," and "),e.jsx("code",{children:'"prefer-main"'}),l("settings.merge.valuesFromOlderSettingsAreMigratedAutomatically"," values from older settings are migrated automatically.")]})]})]}),e.jsxs("select",{id:"mergeConflictStrategy",value:t.mergeConflictStrategy??"smart-prefer-main",onChange:E=>s(L=>({...L,mergeConflictStrategy:E.target.value})),children:[e.jsx("option",{value:"smart-prefer-main",children:l("settings.merge.smartPreferMainOnFallbackFetchFfOrigin","Smart, prefer main on fallback — fetch+ff origin → AI → auto-resolve → -X ours (default; protects just-merged sibling work)")}),e.jsx("option",{value:"smart-prefer-branch",children:l("settings.merge.smartPreferTaskOnFallbackFetchFfOrigin",'Smart, prefer task on fallback — fetch+ff origin → AI → auto-resolve → -X theirs (legacy "smart" behavior; task branch wins)')}),e.jsx("option",{value:"ai-only",children:l("settings.merge.aIOnlyAIAutoResolveAIRetryNever","AI only — AI → auto-resolve → AI retry; never silently pick a side")}),e.jsx("option",{value:"abort",children:l("settings.merge.abortOneAIAttemptRequireManualResolutionIf","Abort — one AI attempt; require manual resolution if it fails")})]})]}),e.jsx(ke,{descriptor:{key:"mergeStrategyOverlapBehavior",label:l("settings.merge.smartPreferMainOverlapGuard","Smart Prefer Main Overlap Guard"),help:l("settings.merge.whenUsingSmartPreferMainAutomaticallyPreferThe"," When using smart-prefer-main, automatically prefer the branch side for files that main has recently modified to avoid silently discarding branch work. "),scope:"project",options:[{value:"flip-to-prefer-branch",label:l("settings.merge.flipOverlappingFilesToPreferTheTaskBranch","Flip overlapping files to prefer the task branch (default)")},{value:"warn-only",label:l("settings.merge.warnOnlyKeepLegacyMainWinsFallback","Warn only — keep legacy main-wins fallback")},{value:"ignore",label:l("settings.merge.ignoreOverlapDetectionPreserveLegacyBehavior","Ignore overlap detection — preserve legacy behavior")}]},value:t.mergeStrategyOverlapBehavior??"flip-to-prefer-branch",onChange:E=>s(L=>({...L,mergeStrategyOverlapBehavior:E}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"postMergeAuditMode",children:l("settings.merge.postMergeAuditMode","Post-merge audit mode")}),e.jsxs(B,{settingKey:"postMergeAuditMode",children:[l("settings.merge.controlsThePostMergeAuditGate"," Controls the post-merge audit gate. "),e.jsx("strong",{children:l("settings.merge.warn","Warn")}),l("settings.merge.defaultLogsFindingsButAutoCompletesTheMerge"," (default) logs findings but auto-completes the merge. "),e.jsx("strong",{children:l("settings.merge.block","Block")}),l("settings.merge.isTheStricterOptInModeThatRefuses"," is the stricter opt-in mode that refuses to auto-complete merges with duplicate-subject or touched-file overlap risks. "),e.jsx("strong",{children:l("settings.merge.off","Off")}),l("settings.merge.skipsTheAuditEntirelySwitchingToOffIs"," skips the audit entirely. Switching to Off is recommended only if you trust your branches don't silently drop edits. ")]})]}),e.jsxs("select",{className:"select",id:"postMergeAuditMode",value:t.postMergeAuditMode??"warn",onChange:E=>s(L=>({...L,postMergeAuditMode:E.target.value})),children:[e.jsx("option",{value:"block",children:l("settings.merge.blockStrict","Block (strict)")}),e.jsx("option",{value:"warn",children:l("settings.merge.warnDefaultLogFindingsContinue","Warn (default; log findings, continue)")}),e.jsx("option",{value:"off",children:l("settings.merge.offSkipAudit","Off (skip audit)")})]})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"pushAfterMerge",className:"checkbox-label",children:[e.jsx("input",{id:"pushAfterMerge",type:"checkbox",checked:t.pushAfterMerge===!0,onChange:E=>s(L=>({...L,pushAfterMerge:E.target.checked}))}),l("settings.merge.pushToRemoteAfterMerge"," Push to remote after merge ")]}),e.jsx(B,{settingKey:"pushAfterMerge",children:l("settings.merge.whenEnabledTheMergedResultIsAutomaticallyPushed","When enabled, the merged result is automatically pushed to the configured git remote. This includes pulling the latest from the remote first (rebase) and resolving any conflicts with AI if needed. Default: disabled.")})]})}),t.pushAfterMerge&&(i.length===0?e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"pushRemote",children:l("settings.merge.pushRemote","Push Remote")}),e.jsx(B,{settingKey:"pushRemote",children:l("settings.merge.gitRemoteToPushToEGOrigin",'Git remote to push to (e.g. "origin"). Can include branch name (e.g. "origin main"). Default: "origin".')})]}),e.jsx("input",{id:"pushRemote",type:"text",placeholder:l("settings.merge.origin","origin"),value:t.pushRemote||"",onChange:E=>s(L=>({...L,pushRemote:E.target.value||void 0}))})]}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"pushRemote",children:l("settings.merge.pushRemote","Push Remote")}),e.jsx(B,{settingKey:"pushRemote",children:l("settings.merge.gitRemoteThatMergedResultsArePushedTo",'Git remote that merged results are pushed to. Default: "origin".')})]}),e.jsxs("select",{id:"pushRemote",className:"select",value:h.remote,onChange:E=>{const L=E.target.value;x(!1),s(G=>({...G,pushRemote:Ks(L,"")}))},"data-testid":"push-remote-select",children:[!i.includes(h.remote)&&e.jsx("option",{value:h.remote,children:h.remote}),i.map(E=>e.jsx("option",{value:E,children:E},E))]})]}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"pushRemoteBranch",children:l("settings.merge.pushTargetBranch","Push target branch")}),e.jsx(B,{settingKey:"pushRemoteBranch",children:l("settings.merge.pushTargetBranchHelp","Branch on the remote that merged results are pushed to. Leave on the default to push the integration branch to its same-named remote branch; pick a listed remote branch or choose Custom… to type one that doesn't exist on the remote yet (the push creates it).")})]}),(()=>{const E=h.branch,L=E.length>0&&p.includes(E);if(w||E.length>0&&!L)return e.jsxs("div",{className:"form-inline-group",children:[e.jsx("input",{id:"pushRemoteBranch",type:"text",className:"input",placeholder:l("settings.merge.branchName","branch name"),value:E,onChange:K=>{const z=K.target.value.trim();s(ne=>({...ne,pushRemote:Ks(h.remote,z)}))},"data-testid":"push-remote-branch-custom-input"}),e.jsx("button",{type:"button",className:"btn-link",onClick:()=>{x(!1),s(K=>({...K,pushRemote:Ks(h.remote,"")}))},"data-testid":"push-remote-branch-use-dropdown",children:l("settings.merge.useDropdown"," Use dropdown ")})]});const G="__fusion-custom__";return e.jsxs("select",{id:"pushRemoteBranch",className:"select",value:E,onChange:K=>{const z=K.target.value;if(z===G){x(!0);return}s(ne=>({...ne,pushRemote:Ks(h.remote,z)}))},"data-testid":"push-remote-branch-select",children:[e.jsx("option",{value:"",children:l("settings.merge.sameAsIntegrationBranchDefault","(same as integration branch — default)")}),p.map(K=>e.jsx("option",{value:K,children:K},K)),e.jsx("option",{value:G,children:l("settings.merge.custom","Custom…")})]})})()]})]}))]})}const Bs="__custom__";function Zg(t){const s=new Map;for(const a of t){const n=a.value.trim();!n||s.has(n)||s.set(n,{...a,value:n,label:a.label?.trim()||n})}return[...s.values()].sort((a,n)=>a.value.localeCompare(n.value))}function Ir({id:t,value:s,onChange:a,options:n,loading:c=!1,error:d,placeholder:i="owner/repo",ariaLabel:u}){const{t:l}=te("app"),h=o.useRef(null),p=o.useId(),[b,w]=o.useState(!1),x=o.useMemo(()=>Zg(n),[n]),f=x.find(y=>y.value===s),D=f?f.value:Bs;o.useEffect(()=>{w(D===Bs)},[D]);const S=y=>{if(y===Bs){w(!0),requestAnimationFrame(()=>{h.current?.focus()});return}w(!1),a(y)},C=d||(c?l("trackingRepoSelect.loadingHint","Loading detected GitHub remotes…"):null);return e.jsxs("div",{className:"tracking-repo-select",children:[e.jsxs("select",{id:t,className:"select",value:D,onChange:y=>S(y.target.value),"aria-label":u,"aria-describedby":C?p:void 0,children:[x.map(y=>e.jsx("option",{value:y.value,children:y.source?`${y.label} — ${y.source}`:y.label},y.value)),e.jsx("option",{value:Bs,children:l("trackingRepoSelect.customOption","Custom…")})]}),b?e.jsx("input",{ref:h,className:"input tracking-repo-select__custom-input",type:"text",value:s,placeholder:i,onChange:y=>a(y.target.value),"aria-describedby":C?p:void 0}):null,C?e.jsx("small",{id:p,className:d?"tracking-repo-select__hint tracking-repo-select__hint--error":"tracking-repo-select__hint",children:C}):null]})}function ep({form:t,setForm:s,projectTrackingRepoOptions:a,projectTrackingRepoLoading:n,projectTrackingRepoError:c}){const{t:d}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:d("settings.general.gitHubTracking","GitHub Tracking")}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"githubTrackingMode",children:d("settings.general.defaultTrackingModeForNewTasks","Default tracking mode for new tasks")}),e.jsxs(B,{settingKey:"githubTrackingMode",children:[d("settings.general.controlsWhetherNewlyCreatedTasksHaveGitHubIssue"," Controls whether newly created tasks have GitHub issue tracking enabled by default. Individual tasks can still override this from the task detail modal. "),d("settings.general.trackingIssuesUseThisTaskAposSTitle"," Tracking issues use this task's title. If a task has no title yet, Fusion can summarize its description using the title summarization model in Project Models. "),!t.autoSummarizeTitles&&!t.useAiMergeCommitSummary&&!t.githubTrackingEnabledByDefault?d("settings.general.enableSummarizationInProjectModelsToConfigureThatModel"," Enable summarization in Project Models to configure that model."):""]})]}),e.jsxs("select",{id:"githubTrackingMode",className:"select",value:t.githubTrackingEnabledByDefault?"new-tasks":"off",onChange:i=>s(u=>({...u,githubTrackingEnabledByDefault:i.target.value==="new-tasks"})),children:[e.jsx("option",{value:"off",children:d("settings.general.offDefault","Off (default)")}),e.jsx("option",{value:"new-tasks",children:d("settings.general.onForNewTasks","On for new tasks")})]})]}),e.jsx(se,{descriptor:{key:"githubLinkImportedIssuesToTracking",label:d("settings.general.alwaysLinkImportedGitHubIssuesToTracking"," Always link imported GitHub issues to GitHub tracking "),help:d("settings.general.whenEnabledImportedGitHubIssuesUseTheirSource","When enabled, GitHub issue imports become tracked tasks that adopt the source issue. This does not turn GitHub tracking on for ordinary new tasks. Default: disabled."),scope:"project"},value:t.githubLinkImportedIssuesToTracking===!0,onChange:i=>s(u=>({...u,githubLinkImportedIssuesToTracking:i===!0}))}),e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"projectGithubTrackingDefaultRepoGeneral",children:d("settings.general.projectDefaultTrackingRepo","Project default tracking repo")}),e.jsx(B,{settingKey:"projectGithubTrackingDefaultRepoGeneral",children:d("settings.general.defaultRepoUsedWhenCreatingGitHubIssuesFor","Default repo used when creating GitHub issues for tracked tasks. Falls back to the global default if blank.")})]}),e.jsx(Ir,{id:"projectGithubTrackingDefaultRepoGeneral",ariaLabel:"Project default tracking repo",value:t.githubTrackingDefaultRepo??"",options:a,loading:n,error:c??void 0,placeholder:d("settings.general.ownerRepo","owner/repo"),onChange:i=>s(u=>({...u,githubTrackingDefaultRepo:i||void 0}))})]}),e.jsx(se,{descriptor:{key:"githubTrackingDedupEnabled",label:d("settings.general.searchTheTrackingRepoForLikelyDuplicatesBefore"," Search the tracking repo for likely duplicates before opening a new issue "),help:d("settings.general.whenEnabledFusionChecksOpenAndClosedIssues"," When enabled, Fusion checks open and closed issues in the target repo for likely duplicates (using File Scope paths and key symptoms) before creating a new tracking issue. Uncheck to always create a new issue. Default: enabled. "),scope:"project"},value:t.githubTrackingDedupEnabled!==!1,onChange:i=>s(u=>({...u,githubTrackingDedupEnabled:i===!0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:d("settings.merge.gitHubAuthentication","GitHub Authentication")}),e.jsx(ke,{descriptor:{key:"githubAuthMode",label:d("settings.merge.gitHubAuthMode","GitHub auth mode"),scope:"project",options:[{value:"gh-cli",label:d("settings.merge.gitHubCLIGhAuth","GitHub CLI (gh auth) (default)")},{value:"token",label:d("settings.merge.personalAccessToken","Personal access token")}]},value:t.githubAuthMode??"gh-cli",onChange:i=>s(u=>({...u,githubAuthMode:i}))}),(t.githubAuthMode??"gh-cli")==="token"&&e.jsx(de,{descriptor:{key:"githubAuthToken",label:d("settings.merge.gitHubPersonalAccessToken","GitHub personal access token"),help:d("settings.merge.githubAuthTokenHint","No default — unset."),scope:"project",type:"password"},value:t.githubAuthToken??"",onChange:i=>s(u=>({...u,githubAuthToken:i||void 0}))}),e.jsx("h4",{className:"settings-section-heading settings-section-heading--spaced",children:d("settings.general.gitLabConfiguration","GitLab Configuration")}),e.jsxs("details",{className:"settings-gitlab-disclosure","data-testid":"project-gitlab-configuration-disclosure",children:[e.jsxs("summary",{children:[e.jsx("span",{className:"settings-gitlab-disclosure__title",children:d("settings.general.gitLabConfiguration","GitLab Configuration")}),e.jsxs("label",{className:"checkbox-label settings-gitlab-disclosure__toggle",htmlFor:"gitlabEnabled",onClick:i=>i.stopPropagation(),children:[e.jsx("input",{id:"gitlabEnabled",type:"checkbox",checked:t.gitlabEnabled!==!1,onChange:i=>s(u=>({...u,gitlabEnabled:i.target.checked}))}),d("settings.general.enableGitLabIntegration","Enable GitLab integration")]}),e.jsx("span",{onClick:i=>i.stopPropagation(),children:e.jsx(B,{settingKey:"project-gitlab-configuration",children:t.gitlabEnabled===!1?d("settings.general.gitLabDisabledHint","GitLab API imports, comments, close/reopen, and refresh operations are disabled. Saved URLs and tokens remain stored for re-enable."):d("settings.general.gitLabEnabledHint","Configure GitLab.com or self-managed GitLab URLs. Blank values inherit global fallbacks and then GitLab.com. No default — unset (unset behaves as enabled until explicitly disabled).")})})]}),e.jsxs("div",{className:"settings-gitlab-disclosure__body","aria-disabled":t.gitlabEnabled===!1,children:[e.jsx(de,{descriptor:{key:"gitlabInstanceUrl",label:d("settings.general.gitLabInstanceUrl","GitLab instance URL"),help:d("settings.general.gitLabInstanceUrlHint","Blank uses GitLab.com or the global default. Set an absolute http:// or https:// URL for self-managed GitLab, such as https://gitlab.example.com/gitlab."),type:"url",placeholder:"https://gitlab.com",disabled:t.gitlabEnabled===!1},value:t.gitlabInstanceUrl??"",onChange:i=>s(u=>({...u,gitlabInstanceUrl:i||void 0}))}),e.jsx(de,{descriptor:{key:"gitlabApiBaseUrl",label:d("settings.general.gitLabApiBaseUrlOptional","GitLab API base URL (optional / advanced)"),help:d("settings.general.gitLabApiBaseUrlHint","Blank derives <instance>/api/v4. Override only when a self-managed GitLab API is served from a different absolute http:// or https:// URL."),type:"url",placeholder:"https://gitlab.com/api/v4",disabled:t.gitlabEnabled===!1},value:t.gitlabApiBaseUrl??"",onChange:i=>s(u=>({...u,gitlabApiBaseUrl:i||void 0}))}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h5",{className:"settings-section-heading",children:d("settings.merge.gitLabAuthentication","GitLab Authentication")}),e.jsx(B,{settingKey:"project-gitlab-authentication",children:t.gitlabEnabled===!1?d("settings.merge.gitLabDisabledHint","GitLab comments, close/reopen, import fetches, and refresh operations are disabled. Saved tokens remain stored for re-enable."):d("settings.merge.gitLabAuthDetails","Fusion uses GitLab REST API token authentication with the PRIVATE-TOKEN header. Leave the token blank to clear the project override and fall back to a configured global GitLab token or GITLAB_TOKEN where available. No default — unset (unset behaves as enabled until explicitly disabled).")})]}),e.jsx(ke,{descriptor:{key:"gitlabAuthTokenType",label:d("settings.merge.gitLabTokenType","GitLab token type"),disabled:t.gitlabEnabled===!1,options:[{value:"personal",label:d("settings.merge.gitLabPersonalAccessToken","Personal access token (default)")},{value:"project",label:d("settings.merge.gitLabProjectAccessToken","Project access token")},{value:"group",label:d("settings.merge.gitLabGroupAccessToken","Group access token")}]},value:t.gitlabAuthTokenType??"personal",onChange:i=>s(u=>({...u,gitlabAuthTokenType:i}))}),e.jsx(de,{descriptor:{key:"gitlabAuthToken",label:d("settings.merge.gitLabAccessToken","GitLab access token"),help:d("settings.merge.gitLabAuthTokenHint","Read-only GitLab operations need read_api or api. Future write actions such as comments and auto-close need api. Project and group tokens are limited to their associated resource and role membership. No default — unset."),type:"password",disabled:t.gitlabEnabled===!1},value:t.gitlabAuthToken??"",onChange:i=>s(u=>({...u,gitlabAuthToken:i||void 0}))})]})]})]})}function tp({form:t,setForm:s,globalSettings:a,onGlobalGitlabSettingsChange:n,globalTrackingRepoOptions:c,globalTrackingRepoLoading:d,globalTrackingRepoError:i}){const{t:u}=te("app"),l=a??t;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"globalGithubTrackingDefaultRepo",children:u("settings.globalGeneral.globalDefaultTrackingRepo","Global default tracking repo")}),e.jsx(B,{settingKey:"globalGithubTrackingDefaultRepo",children:u("settings.globalGeneral.projectsInheritThisValueWhenTheyDoNot","Projects inherit this value when they do not set a project default tracking repo. No default — unset.")})]}),e.jsx(Ir,{id:"globalGithubTrackingDefaultRepo",ariaLabel:"Global default tracking repo",value:t.githubTrackingDefaultRepo??"",options:c,loading:d,error:i??void 0,placeholder:u("settings.globalGeneral.ownerRepo","owner/repo"),onChange:h=>s(p=>({...p,githubTrackingDefaultRepo:h||void 0}))})]}),e.jsxs("details",{className:"settings-gitlab-disclosure","data-testid":"global-gitlab-configuration-disclosure",children:[e.jsxs("summary",{children:[e.jsx("span",{className:"settings-gitlab-disclosure__title",children:u("settings.globalGeneral.gitLabConfiguration","GitLab Configuration")}),e.jsxs("label",{className:"checkbox-label settings-gitlab-disclosure__toggle",htmlFor:"globalGitlabEnabled",onClick:h=>h.stopPropagation(),children:[e.jsx("input",{id:"globalGitlabEnabled",type:"checkbox",checked:l.gitlabEnabled!==!1,onChange:h=>n({gitlabEnabled:h.target.checked})}),u("settings.globalGeneral.enableGitLabIntegration","Enable GitLab integration")]}),e.jsx("span",{onClick:h=>h.stopPropagation(),children:e.jsx(B,{settingKey:"global-gitlab-configuration",children:l.gitlabEnabled===!1?u("settings.globalGeneral.gitLabDisabledHint","GitLab API operations are disabled by global default. Saved URL and token fallbacks remain stored for re-enable."):u("settings.globalGeneral.gitLabEnabledHint","Global GitLab URL and token fallbacks apply to projects that do not set their own values. No default — unset (unset behaves as enabled until explicitly disabled).")})})]}),e.jsxs("div",{className:"settings-gitlab-disclosure__body","aria-disabled":l.gitlabEnabled===!1,children:[e.jsx(de,{descriptor:{key:"gitlabInstanceUrl",label:u("settings.globalGeneral.gitLabInstanceUrl","Global GitLab instance URL"),help:u("settings.globalGeneral.gitLabInstanceUrlHint","Blank defaults to GitLab.com. Projects inherit this self-managed GitLab URL unless they set their own project value. No default — unset."),type:"url",placeholder:"https://gitlab.com",disabled:l.gitlabEnabled===!1},value:l.gitlabInstanceUrl??"",onChange:h=>n({gitlabInstanceUrl:h||void 0})}),e.jsx(de,{descriptor:{key:"gitlabApiBaseUrl",label:u("settings.globalGeneral.gitLabApiBaseUrlOptional","Global GitLab API base URL (optional / advanced)"),help:u("settings.globalGeneral.gitLabApiBaseUrlHint","Blank derives <instance>/api/v4. Override only for self-managed GitLab API gateways that use a different absolute http:// or https:// URL. No default — unset."),type:"url",placeholder:"https://gitlab.com/api/v4",disabled:l.gitlabEnabled===!1},value:l.gitlabApiBaseUrl??"",onChange:h=>n({gitlabApiBaseUrl:h||void 0})}),e.jsx(ke,{descriptor:{key:"gitlabAuthTokenType",label:u("settings.globalGeneral.gitLabTokenType","Global GitLab token type"),help:u("settings.globalGeneral.gitLabTokenTypeHint","No default — unset (the selector falls back to personal access token until you choose otherwise)."),disabled:l.gitlabEnabled===!1,options:[{value:"personal",label:u("settings.globalGeneral.gitLabPersonalAccessToken","Personal access token")},{value:"project",label:u("settings.globalGeneral.gitLabProjectAccessToken","Project access token")},{value:"group",label:u("settings.globalGeneral.gitLabGroupAccessToken","Group access token")}]},value:l.gitlabAuthTokenType??"personal",onChange:h=>n({gitlabAuthTokenType:h})}),e.jsx(de,{descriptor:{key:"gitlabAuthToken",label:u("settings.globalGeneral.gitLabAccessToken","Global GitLab access token"),help:u("settings.globalGeneral.gitLabAuthTokenHint","Projects inherit this fallback only when they do not set a project GitLab token. Read-only operations need read_api or api; write actions need api; project/group tokens remain limited by resource membership. No default — unset."),type:"password",disabled:l.gitlabEnabled===!1},value:l.gitlabAuthToken??"",onChange:h=>n({gitlabAuthToken:h||void 0})})]})]})]})}function or(t){return Array.from(new Set(t.split(/[\n,]+/).map(s=>s.trim()).filter(s=>s.length>0)))}function sp({value:t,onChange:s,disabled:a=!1}){const{t:n}=te("app"),c=t?.approvalMode??"trusted-only",d=t?.alwaysApproveDelete??!0,i={always:{label:n("agentProvisioning.always","Always require approval"),description:n("agentProvisioning.alwaysDesc","All fn_agent_create/fn_agent_delete requests require approval unless caller is trusted.")},"trusted-only":{label:n("agentProvisioning.trustedOnly","Trusted-only"),description:n("agentProvisioning.trustedOnlyDesc","Trusted roles/agent IDs bypass approval; other callers require approval.")},never:{label:n("agentProvisioning.never","Never require approval"),description:n("agentProvisioning.neverDesc","Allow provisioning without approval for non-privileged callers.")}},u=l=>{s({...t??{},...l})};return e.jsxs("div",{className:"agent-provisioning-policy-editor card",children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"agent-provisioning-approval-mode",children:n("agentProvisioning.approvalMode","Approval mode")}),e.jsx("select",{id:"agent-provisioning-approval-mode",className:"select",value:c,onChange:l=>u({approvalMode:l.target.value}),disabled:a,children:td.map(l=>e.jsx("option",{value:l,children:i[l].label},l))}),e.jsx("small",{className:"agent-provisioning-policy-help",children:i[c].description})]}),e.jsx("div",{className:"form-group",children:e.jsxs("label",{className:"checkbox-label",htmlFor:"agent-provisioning-always-approve-delete",children:[e.jsx("input",{id:"agent-provisioning-always-approve-delete",type:"checkbox",checked:d,onChange:l=>u({alwaysApproveDelete:l.target.checked}),disabled:a}),n("agentProvisioning.alwaysApproveDelete","Always require approval for fn_agent_delete")]})}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"agent-provisioning-trusted-roles",children:n("agentProvisioning.trustedRoles","Trusted roles")}),e.jsx("textarea",{id:"agent-provisioning-trusted-roles",className:"input agent-provisioning-policy-textarea",value:(t?.trustedRoles??[]).join(", "),onChange:l=>u({trustedRoles:or(l.target.value)}),disabled:a,placeholder:n("agentProvisioning.trustedRolesPlaceholder","reviewer, ceo"),rows:2})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"agent-provisioning-trusted-agent-ids",children:n("agentProvisioning.trustedAgentIds","Trusted agent IDs")}),e.jsx("textarea",{id:"agent-provisioning-trusted-agent-ids",className:"input agent-provisioning-policy-textarea",value:(t?.trustedAgentIds??[]).join(", "),onChange:l=>u({trustedAgentIds:or(l.target.value)}),disabled:a,placeholder:n("agentProvisioning.trustedAgentIdsPlaceholder","agent-abc123"),rows:2})]}),e.jsx("p",{className:"agent-provisioning-policy-help",children:e.jsx(un,{i18nKey:"app:agentProvisioning.helpText",defaults:"These settings govern durable provisioning tools only: <code>fn_agent_create</code> and <code>fn_agent_delete</code>. Ephemeral <code2>fn_spawn_agent</code2> requests stay under the task/agent mutation approval gate (FN-3973).",components:{code:e.jsx("code",{}),code2:e.jsx("code",{})}})})]})}function en(t){return sd.reduce((s,a)=>(s[a]=t?.[a]??"allow",s),{})}function ap({form:t,setForm:s}){const{t:a}=te("app");return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.agentPermissions.agentPermissions","Agent Permissions")}),e.jsx(B,{settingKey:"defaultAgentPermissionPolicy",children:a("settings.agentPermissions.perAgentSettingsOverrideProjectDefaultsEachCategory","Project defaults apply to permanent agents, ephemeral task workers, and fallback executor workers unless a per-agent override is set. Exact tool rules compose with the legacy ephemeral create-task toggle. Default: unset — every action category defaults to allow until a category is explicitly restricted.")})]}),e.jsx(Yd,{mode:"project-default",value:t.defaultAgentPermissionPolicy?{presetId:"custom",rules:en(t.defaultAgentPermissionPolicy.rules),...t.defaultAgentPermissionPolicy.toolRules?{toolRules:t.defaultAgentPermissionPolicy.toolRules}:{}}:{presetId:"custom",rules:en()},onChange:n=>s(c=>({...c,defaultAgentPermissionPolicy:{rules:en(n?.rules),...n?.toolRules?{toolRules:n.toolRules}:{}}}))}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.agentPermissions.agentProvisioningApprovals","Agent Provisioning Approvals")}),e.jsx(B,{settingKey:"agentProvisioning",children:a("settings.agentPermissions.configureProjectLevelApprovalBehaviorForDurableProvisioning"," Configure project-level approval behavior for durable provisioning tools (fn_agent_create/fn_agent_delete). Default: no approval policy configured (empty). ")})]}),e.jsx(sp,{value:t.agentProvisioning,onChange:n=>s(c=>({...c,agentProvisioning:n}))})]})}const np=72;function lp(t,s){if(t.length<=s)return t;const a=Math.max(1,s-1),n=Math.ceil(a/2),c=Math.floor(a/2);return`${t.slice(0,n)}…${t.slice(t.length-c)}`}function rp(t){const s=`${t.label} — ${t.path}`;return lp(s,np)}function ip({form:t,setForm:s,memory:a}){const{t:n}=te("app"),{memoryCapabilities:c,memoryBackendStatus:d,memoryBackendLoading:i,memoryBackendError:u,memoryFiles:l,selectedMemoryPath:h,setSelectedMemoryPath:p,memoryContent:b,setMemoryContent:w,memoryLoading:x,memoryDirty:f,setMemoryDirty:D,memoryTestQuery:S,setMemoryTestQuery:C,memoryTestLoading:y,memoryTestResult:k,qmdInstallLoading:R,dreamRunning:P,memoryCompactLoading:N,onInstallQmd:U,onTestMemoryRetrieval:m,onDreamNow:Y,onCompactMemory:E,onSaveMemory:L}=a,G=t.memoryEnabled!==!1,K=!i&&d!==null,z=K?c?.writable??!0:!0,ne=G&&z,re=l.find(T=>T.path===h),ce={"long-term":"Long-term",daily:"Daily",dreams:"Dreams"};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.memory.memory","Memory")}),e.jsxs(B,{settingKey:"memory-section",children:[n("settings.memory.memoryLivesIn"," Memory lives in "),e.jsx("code",{children:".fusion/memory/"}),n("settings.memory.agentsSearchWithQmdFirstFallBackTo",". Agents search with qmd first, fall back to local files when qmd is missing, and open exact line windows only when needed. ")]})]}),e.jsx(se,{descriptor:{key:"memoryEnabled",label:n("settings.memory.enableMemoryTools"," Enable memory tools "),help:n("settings.memory.agentsGetMemorySearchMemoryGetAndMemory","Agents get memory_search, memory_get, and memory_append tools. Search defaults to qmd with a local file fallback. Default: enabled."),scope:"project"},value:t.memoryEnabled!==!1,onChange:T=>s($=>({...$,memoryEnabled:T===!0}))}),i?e.jsx("div",{className:"form-group",children:e.jsx("small",{className:"settings-muted",children:n("settings.memory.checkingMemoryWriteAccess","Checking memory write access...")})}):u?e.jsx("div",{className:"form-group",children:e.jsxs("small",{className:"field-error",children:[n("settings.memory.failedToLoadBackendStatus","Failed to load backend status: "),u]})}):null,K&&d.qmdAvailable===!1&&e.jsxs("div",{className:"settings-empty-state memory-status-message",children:[e.jsxs("span",{children:[n("settings.memory.qmdIsNotInstalledSearchWillUseLocal"," qmd is not installed. Search will use local files. Install indexed retrieval: "),e.jsx("code",{children:d.qmdInstallCommand||"bun install -g @tobilu/qmd"})]}),e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:U,disabled:R,children:R?n("settings.memory.installing","Installing…"):n("settings.memory.installQmd","Install qmd")})]}),e.jsx(se,{descriptor:{key:"memoryAutoSummarizeEnabled",label:n("settings.memory.autoSummarizeMemory"," Auto-Summarize Memory "),help:n("settings.memory.automaticallyCompactMemoryWhenItExceedsTheThreshold","Automatically compact memory when it exceeds the threshold on a schedule. Default: disabled."),scope:"project"},value:t.memoryAutoSummarizeEnabled||!1,onChange:T=>s($=>({...$,memoryAutoSummarizeEnabled:T===!0}))}),(t.memoryAutoSummarizeEnabled||!1)&&e.jsxs(e.Fragment,{children:[e.jsx(ye,{descriptor:{key:"memoryAutoSummarizeThresholdChars",label:n("settings.memory.compactionThresholdChars","Compaction Threshold (chars)"),help:n("settings.memory.memoryWillBeCompactedWhenItExceedsThis","Memory will be compacted when it exceeds this character count. Default: 50000."),scope:"project",min:1e3},value:t.memoryAutoSummarizeThresholdChars??5e4,onChange:T=>s($=>({...$,memoryAutoSummarizeThresholdChars:T||5e4}))}),e.jsx(de,{descriptor:{key:"memoryAutoSummarizeSchedule",label:n("settings.memory.scheduleCron","Schedule (cron)"),help:n("settings.memory.cronExpressionForAutoSummarizeScheduleDefaultDaily","Cron expression for auto-summarize schedule. Default: 0 3 * * * (daily at 3 AM)."),scope:"project",placeholder:n("settings.memory.03","0 3 * * *")},value:t.memoryAutoSummarizeSchedule??"0 3 * * *",onChange:T=>s($=>({...$,memoryAutoSummarizeSchedule:T??""}))})]}),e.jsx(se,{descriptor:{key:"insightExtractionEnabled",label:n("settings.memory.enableInsightExtraction"," Enable Insight Extraction "),help:n("settings.memory.periodicallyExtractDurableInsightsFromCompletedTasks","Periodically extract durable insights/learnings from completed tasks into memory"),scope:"project"},value:t.insightExtractionEnabled||!1,onChange:T=>s($=>({...$,insightExtractionEnabled:T===!0}))}),(t.insightExtractionEnabled||!1)&&e.jsx(de,{descriptor:{key:"insightExtractionSchedule",label:n("settings.memory.scheduleCron","Schedule (cron)"),help:n("settings.memory.cronExpressionForInsightExtractionScheduleDefaultDaily","Cron expression for insight extraction schedule (default: daily at 2 AM)"),scope:"project",placeholder:n("settings.memory.02","0 2 * * *")},value:t.insightExtractionSchedule??"0 2 * * *",onChange:T=>s($=>({...$,insightExtractionSchedule:T??""}))}),e.jsx("div",{style:{borderTop:"1px solid var(--border)",margin:"var(--space-lg) 0"}}),e.jsx(se,{descriptor:{key:"memoryDreamsEnabled",label:n("settings.memory.processDreamsFromDailyMemory"," Process dreams from daily memory "),help:n("settings.memory.turnsDailyNotesIntoDREAMSMdAndPromotes","Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md. Default: disabled."),scope:"project",disabled:!G},value:t.memoryDreamsEnabled===!0,onChange:T=>s($=>({...$,memoryDreamsEnabled:T===!0}))}),G&&t.memoryDreamsEnabled===!0&&e.jsxs(e.Fragment,{children:[e.jsx(de,{descriptor:{key:"memoryDreamsSchedule",label:n("settings.memory.dreamSchedule","Dream Schedule"),help:n("settings.memory.cronExpressionForDreamProcessing","Cron expression for dream processing. Default: 0 4 * * * (daily at 4 AM)."),scope:"project"},value:t.memoryDreamsSchedule??"0 4 * * *",onChange:T=>s($=>({...$,memoryDreamsSchedule:T??""}))}),e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:Y,disabled:P||t.memoryDreamsEnabled!==!0,children:P?e.jsxs(e.Fragment,{children:[e.jsx(Ze,{size:14,className:"animate-spin"}),n("settings.memory.dreaming"," Dreaming… ")]}):n("settings.memory.dreamNow","Dream Now")}),e.jsx(B,{settingKey:"memory-dream-now",children:n("settings.memory.manuallyTriggerDreamProcessingNow","Manually trigger dream processing now.")})]})]}),e.jsxs("div",{className:"memory-retrieval-test",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"memoryRetrievalQuery",children:n("settings.memory.testRetrieval","Test Retrieval")}),e.jsx(B,{settingKey:"memoryRetrievalQuery",children:n("settings.memory.runsTheSameQmdBackedMemorySearchPath","Runs the same qmd-backed memory_search path agents use.")})]}),e.jsx("input",{id:"memoryRetrievalQuery",type:"text",value:S,onChange:T=>C(T.target.value),placeholder:n("settings.memory.searchMemoryWithQmd","Search memory with qmd")})]}),e.jsx("div",{className:"form-group",children:e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:m,disabled:y,children:y?n("settings.memory.testing","Testing…"):n("settings.memory.testRetrieval","Test Retrieval")})}),k&&e.jsxs("div",{className:"memory-test-result",children:[e.jsxs("strong",{children:[k.results.length,n("settings.memory.result"," result"),k.results.length===1?"":"s"," ",n("settings.memory.for",'for "'),k.query,'"']}),e.jsxs("small",{children:[n("settings.memory.qmd"," qmd "),k.qmdAvailable?"available":"missing"," · ",k.usedFallback?"local fallback used":"qmd path used"]}),k.results.length>0?e.jsx("ul",{children:k.results.map((T,$)=>e.jsxs("li",{children:[e.jsxs("span",{children:[T.path,":",T.lineStart]}),e.jsx("p",{children:T.snippet})]},`${T.path}-${T.lineStart}-${$}`))}):e.jsx("small",{children:n("settings.memory.noMatchingMemoryFound","No matching memory found.")})]})]}),!G&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:n("settings.memory.memoryIsCurrentlyDisabledYouCanViewThe"," Memory is currently disabled. You can view the file, but editing is read-only until memory is re-enabled. ")}),G&&K&&!z&&e.jsx("div",{className:"settings-empty-state memory-status-message",children:n("settings.memory.memoryIsConfiguredWithAReadOnlyBackend"," Memory is configured with a read-only backend. You can view the file, but saving is disabled. ")}),x?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:n("settings.memory.loadingMemory","Loading memory…")})}):e.jsxs("div",{className:"memory-editor-section",children:[e.jsxs("div",{className:"form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"memoryFilePath",children:n("settings.memory.memoryFile","Memory File")}),e.jsx(B,{settingKey:"memoryFilePath",children:"Choose any project memory file to view or edit. Dreams is selected by default."})]}),e.jsx("select",{id:"memoryFilePath",value:h,onChange:T=>{p(T.target.value),D(!1)},disabled:f,children:l.map(T=>e.jsx("option",{value:T.path,title:`${T.label} — ${T.path}`,children:rp(T)},T.path))}),f&&e.jsx("small",{children:"Save or discard the current edits before switching files."})]}),re&&e.jsxs("div",{className:"memory-file-summary",children:[e.jsx("span",{children:ce[re.layer]}),e.jsx("strong",{children:re.path}),e.jsxs("small",{children:[re.size.toLocaleString(),n("settings.memory.bytesUpdated"," bytes · updated "),new Date(re.updatedAt).toLocaleString()]})]}),e.jsxs("div",{className:"form-group memory-editor-form-group",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{children:re?.label||"Memory Editor"}),e.jsxs(B,{settingKey:"memory-editor",children:[re?.layer==="long-term"&&"Curated durable decisions, conventions, constraints, and pitfalls promoted from dreams.",re?.layer==="daily"&&"Raw daily observations, open loops, and running context for dream processing.",re?.layer==="dreams"&&"Synthesized patterns and open loops promoted from daily memory.",!re&&"Edits the selected memory file."]})]}),e.jsx("div",{className:"memory-editor-frame",children:e.jsx(ad,{content:b,onChange:T=>{w(T),D(!0)},readOnly:!ne,filePath:h})})]})]}),!x&&e.jsxs("div",{className:"form-group",children:[e.jsx("button",{type:"button",className:"btn btn-secondary btn-sm",onClick:E,disabled:!ne||f||N,children:N?n("settings.memory.compacting","Compacting…"):n("settings.memory.compactSelectedFile","Compact Selected File")}),e.jsx(B,{settingKey:"memory-compact-file",children:`Compacts ${h} and writes the result back to the same file.`}),f&&e.jsx("small",{children:"Save or discard edits before compacting this file."})]}),f&&ne&&e.jsx("div",{className:"form-group",children:e.jsx("button",{type:"button",className:"btn btn-primary btn-sm",onClick:L,children:n("settings.memory.saveMemory","Save Memory")})}),f&&!ne&&e.jsx("div",{className:"form-group",children:e.jsxs("small",{className:"field-error",children:[n("settings.memory.cannotSave","Cannot save: "),G?"Backend is read-only":"Memory is disabled"]})})]})}function op({form:t,setForm:s,researchLimitError:a}){const{t:n}=te("app"),c=t.researchSettings?.limits,d=t.researchSettings?.enabledSources;return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:n("settings.researchProject.projectResearchSettings","Project Research Settings")}),e.jsx(se,{descriptor:{key:"researchSettings.enabled",label:n("settings.researchProject.enableResearchInThisProject"," Enable research in this project "),help:n("settings.researchProject.enableResearchInThisProjectHint","Default: enabled."),scope:"project"},value:t.researchSettings?.enabled??!0,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},enabled:i===!0}}))}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:n("settings.researchProject.enabledSources","Enabled Sources")}),e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"research-project-source-webSearch",className:"checkbox-label settings-research-source-locked",children:[e.jsx("input",{id:"research-project-source-webSearch",type:"checkbox",checked:!0,disabled:!0,readOnly:!0}),n("settings.researchProject.webSearch"," Web Search "),e.jsx("span",{className:"settings-muted",children:n("settings.researchProject.alwaysOn","Always on")})]}),e.jsx(B,{settingKey:"research-project-source-webSearch",children:n("settings.researchProject.webSearchIsAlwaysEnabledConfigureTheSearch"," Web search is always enabled. Configure the search provider under Research Defaults. ")})]}),e.jsx("div",{className:"settings-research-source-grid",children:[["pageFetch",n("settings.researchProject.pageFetch","Page Fetch"),"Default: enabled."],["github",n("settings.researchProject.github","GitHub"),"Default: disabled."],["localDocs",n("settings.researchProject.localDocs","Local Docs"),"Default: enabled."],["llmSynthesis",n("settings.researchProject.llmSynthesis","LLM Synthesis"),"Default: enabled."]].map(([i,u,l])=>e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:`research-project-source-${i}`,className:"checkbox-label",children:[e.jsx("input",{id:`research-project-source-${i}`,type:"checkbox",checked:d?.[i]??!1,onChange:h=>s(p=>({...p,researchSettings:{...p.researchSettings??{},enabledSources:{...p.researchSettings?.enabledSources??{},[i]:h.target.checked}}}))}),u]}),e.jsx(B,{settingKey:`research-project-source-${i}`,children:l})]},i))})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-research-limits-grid",children:[e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-max-concurrent",children:n("settings.researchProject.maxConcurrentRuns","Max Concurrent Runs")}),e.jsx(B,{settingKey:"research-project-max-concurrent",children:n("settings.researchProject.maxConcurrentRunsHint","Default: 3.")})]}),e.jsx("input",{id:"research-project-max-concurrent",className:"input",type:"number",min:1,value:c?.maxConcurrentRuns??3,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},maxConcurrentRuns:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-max-sources",children:n("settings.researchProject.maxSourcesPerRun","Max Sources Per Run")}),e.jsx(B,{settingKey:"research-project-max-sources",children:n("settings.researchProject.maxSourcesPerRunHint","Default: 20.")})]}),e.jsx("input",{id:"research-project-max-sources",className:"input",type:"number",min:1,value:c?.maxSourcesPerRun??20,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},maxSourcesPerRun:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-max-duration",children:n("settings.researchProject.maxDurationMs","Max Duration (ms)")}),e.jsx(B,{settingKey:"research-project-max-duration",children:n("settings.researchProject.maxDurationMsHint","Default: 300000 (5 minutes).")})]}),e.jsx("input",{id:"research-project-max-duration",className:"input",type:"number",min:1e3,value:c?.maxDurationMs??3e5,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},maxDurationMs:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),e.jsxs("div",{className:"settings-research-limit-field",children:[e.jsxs("div",{className:"settings-field-label-row",children:[e.jsx("label",{htmlFor:"research-project-request-timeout",children:n("settings.researchProject.requestTimeoutMs","Request Timeout (ms)")}),e.jsx(B,{settingKey:"research-project-request-timeout",children:n("settings.researchProject.requestTimeoutMsHint","Default: 30000 (30 seconds).")})]}),e.jsx("input",{id:"research-project-request-timeout",className:"input",type:"number",min:1e3,value:c?.requestTimeoutMs??3e4,onChange:i=>s(u=>({...u,researchSettings:{...u.researchSettings??{},limits:{...u.researchSettings?.limits??{},requestTimeoutMs:i.target.value===""?void 0:Number(i.target.value)}}}))})]}),a&&e.jsx("small",{className:"field-error settings-research-limits-error",children:a})]})})]})}function cp({form:t,setForm:s,globalSettings:a,projectId:n,addToast:c}){const{t:d}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:d("settings.nav.mcp","MCP Servers")}),e.jsx(Tr,{scope:"project",form:t,setForm:s,globalSettings:a,projectId:n,addToast:c})]})}function dp({form:t,setForm:s}){const{t:a}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.backups.memoryBackups","Memory Backups")}),e.jsx(se,{descriptor:{key:"memoryBackupEnabled",label:a("settings.backups.enableAutomaticMemoryBackups"," Enable automatic memory backups "),help:a("settings.backups.whenEnabledProjectAndAgentMemoryFilesAre","When enabled, project and agent memory files are backed up automatically on a schedule. Default: disabled."),scope:"project"},value:t.memoryBackupEnabled||!1,onChange:n=>s(c=>({...c,memoryBackupEnabled:n===!0}))}),e.jsx(de,{descriptor:{key:"memoryBackupSchedule",label:a("settings.backups.memoryBackupScheduleCron","Memory Backup Schedule (Cron)"),help:a("settings.backups.cronExpressionForMemoryBackupTimingDefault0","Cron expression for memory backup timing. Default: 0 3 * * * (daily at 3 AM)."),scope:"project",placeholder:a("settings.backups.03","0 3 * * *"),disabled:!t.memoryBackupEnabled},value:t.memoryBackupSchedule||"0 3 * * *",onChange:n=>s(c=>({...c,memoryBackupSchedule:n??""})),error:t.memoryBackupSchedule&&!/^[\s\d*,/-]+$/.test(t.memoryBackupSchedule)?a("settings.backups.invalidCronExpressionFormat","Invalid cron expression format"):void 0}),e.jsx(ye,{descriptor:{key:"memoryBackupRetention",label:a("settings.backups.memoryRetentionCount","Memory Retention Count"),help:a("settings.backups.numberOfMemoryBackupsToKeepOldestAre","Number of memory backups to keep (oldest are deleted first). Range: 1-100. Default: 14."),scope:"project",min:1,max:100,disabled:!t.memoryBackupEnabled},value:t.memoryBackupRetention??null,onChange:n=>s(c=>({...c,memoryBackupRetention:n??void 0})),error:t.memoryBackupRetention!==void 0&&(t.memoryBackupRetention<1||t.memoryBackupRetention>100)?a("settings.backups.mustBeBetween1And100","Must be between 1 and 100"):void 0}),e.jsx(de,{descriptor:{key:"memoryBackupDir",label:a("settings.backups.memoryBackupDirectory","Memory Backup Directory"),help:a("settings.backups.directoryForMemoryBackupsRelativeToProjectRoot","Directory for memory backups, relative to project root. Default: .fusion/backups/memory."),scope:"project",placeholder:a("settings.backups.fusionBackupsMemory",".fusion/backups/memory"),disabled:!t.memoryBackupEnabled},value:t.memoryBackupDir||".fusion/backups/memory",onChange:n=>s(c=>({...c,memoryBackupDir:n??""})),error:t.memoryBackupDir&&t.memoryBackupDir.includes("..")?a("settings.backups.pathCannotContainParentDirectoryTraversal","Path cannot contain parent directory traversal (..)"):void 0}),e.jsx(ke,{descriptor:{key:"memoryBackupScope",label:a("settings.backups.memoryBackupScope","Memory Backup Scope"),help:a("settings.backups.memoryBackupScopeHint","Default: all (project + agents)."),scope:"project",disabled:!t.memoryBackupEnabled,options:[{value:"all",label:a("settings.backups.allProjectAgents","All (project + agents)")},{value:"project",label:a("settings.backups.projectOnlyFusionMemory","Project only (.fusion/memory)")},{value:"agents",label:a("settings.backups.agentsOnlyFusionAgentMemory","Agents only (.fusion/agent-memory)")}]},value:t.memoryBackupScope||"all",onChange:n=>s(c=>({...c,memoryBackupScope:n??"all"}))})]})}function up({form:t,setForm:s,backupInfo:a,backupLoading:n,onBackupNow:c}){const{t:d}=te("app"),i=t.backupSettingsMigrationConflicts??[],u=(l,h)=>{s(p=>({...p,[l.key]:h.value,backupSettingsMigrationConflicts:i.filter(b=>b.key!==l.key)}))};return e.jsxs(e.Fragment,{children:[i.length>0&&e.jsxs("div",{className:"settings-notice settings-notice-warning",role:"status",children:[e.jsx("strong",{children:d("settings.backups.migrationConflict","Choose database backup settings")}),e.jsx("p",{children:d("settings.backups.migrationConflictHelp","Existing projects used different backup settings. Choose the value to use globally.")}),i.map(l=>e.jsxs("div",{children:[e.jsx("span",{children:l.key}),l.candidates.map((h,p)=>e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>u(l,h),children:h.source==="global"?d("settings.backups.existingGlobalValue","Existing global value"):`${d("settings.backups.projectValue","Project value")}: ${h.projectId}`},`${h.source}-${h.projectId??"global"}-${p}`))]},l.key))]}),e.jsx("h4",{className:"settings-section-heading",children:d("settings.backups.databaseBackups","Database Backups")}),e.jsx(se,{descriptor:{key:"autoBackupEnabled",label:d("settings.backups.enableAutomaticDatabaseBackups"," Enable automatic database backups "),help:d("settings.backups.whenEnabledTheDatabaseIsBackedUpAutomatically","When enabled, the database is backed up automatically on a schedule. Default: disabled."),scope:"global"},value:t.autoBackupEnabled||!1,onChange:l=>s(h=>({...h,autoBackupEnabled:l===!0}))}),e.jsx(de,{descriptor:{key:"autoBackupSchedule",label:d("settings.backups.backupScheduleCron","Backup Schedule (Cron)"),help:d("settings.backups.cronExpressionForBackupTimingDefault02"," Cron expression for backup timing. Default: 0 2 * * * (daily at 2 AM). Examples: 0 * * * * (hourly), 0 0 * * 0 (weekly), */15 * * * * (every 15 min) "),scope:"global",placeholder:d("settings.backups.02","0 2 * * *"),disabled:!t.autoBackupEnabled},value:t.autoBackupSchedule||"0 2 * * *",onChange:l=>s(h=>({...h,autoBackupSchedule:l??""})),error:t.autoBackupSchedule&&!/^[\s\d*,/-]+$/.test(t.autoBackupSchedule)?d("settings.backups.invalidCronExpressionFormat","Invalid cron expression format"):void 0}),e.jsx(ye,{descriptor:{key:"autoBackupRetention",label:d("settings.backups.retentionCount","Retention Count"),help:d("settings.backups.numberOfBackupFilesToKeepOldestAre","Number of backup files to keep (oldest are deleted first). Range: 1-100. Default: 7."),scope:"global",min:1,max:100,disabled:!t.autoBackupEnabled},value:t.autoBackupRetention??null,onChange:l=>s(h=>({...h,autoBackupRetention:l??void 0})),error:t.autoBackupRetention!==void 0&&(t.autoBackupRetention<1||t.autoBackupRetention>100)?d("settings.backups.mustBeBetween1And100","Must be between 1 and 100"):void 0}),e.jsx(de,{descriptor:{key:"autoBackupDir",label:d("settings.backups.backupDirectory","Backup Directory"),help:d("settings.backups.directoryForBackupFilesRelativeToProjectRoot","Directory for backup files, relative to the global Fusion directory. Default: .fusion/backups."),scope:"global",placeholder:d("settings.backups.fusionBackups",".fusion/backups"),disabled:!t.autoBackupEnabled},value:t.autoBackupDir||".fusion/backups",onChange:l=>s(h=>({...h,autoBackupDir:l??""})),error:t.autoBackupDir&&t.autoBackupDir.includes("..")?d("settings.backups.pathCannotContainParentDirectoryTraversal","Path cannot contain parent directory traversal (..)"):void 0}),n?e.jsx("div",{className:"settings-empty-state",children:e.jsx(kt,{label:d("settings.backups.loadingBackupInfo","Loading backup info…")})}):a?e.jsxs("div",{className:"form-group",children:[e.jsx("label",{children:d("settings.backups.currentBackups","Current Backups")}),e.jsxs("div",{className:"backup-stats",children:[e.jsxs("div",{className:"backup-stat",children:[e.jsx("span",{className:"backup-stat-value",children:a.count}),e.jsx("span",{className:"backup-stat-label",children:d("settings.backups.backups","backups")})]}),e.jsxs("div",{className:"backup-stat",children:[e.jsx("span",{className:"backup-stat-value",children:a.totalSize>1024*1024?`${(a.totalSize/(1024*1024)).toFixed(1)} MB`:`${(a.totalSize/1024).toFixed(1)} KB`}),e.jsx("span",{className:"backup-stat-label",children:d("settings.backups.totalSize","total size")})]})]}),a.backups.length>0&&e.jsxs("details",{className:"backup-list",children:[e.jsxs("summary",{children:[d("settings.backups.view","View "),a.backups.length,d("settings.backups.backupS"," backup(s)")]}),e.jsxs("ul",{children:[a.backups.slice(0,10).map(l=>e.jsxs("li",{children:[e.jsx("code",{children:l.filename}),e.jsx("span",{className:"backup-size",children:l.size>1024*1024?`${(l.size/(1024*1024)).toFixed(1)} MB`:`${(l.size/1024).toFixed(1)} KB`})]},l.filename)),a.backups.length>10&&e.jsx("li",{children:e.jsxs("em",{children:[d("settings.backups.and","...and "),a.backups.length-10,d("settings.backups.more"," more")]})})]})]})]}):null,e.jsx("div",{className:"form-group",children:e.jsx("button",{type:"button",className:"btn btn-sm",onClick:c,disabled:n,children:n?d("settings.backups.creating","Creating…"):d("settings.backups.backupNow","Backup Now")})})]})}const gp=o.lazy(()=>vr(()=>import("./PluginManager-H32X557C.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13])).then(t=>({default:t.PluginManager}))),pp=o.lazy(()=>vr(()=>import("./PiExtensionsManager-B7fl5l3O.js"),__vite__mapDeps([14,1,2,3,4,5,6,7,8,9,15,16,17,18])).then(t=>({default:t.PiExtensionsManager})));function hp({projectId:t,addToast:s,activePluginsSubsection:a,setActivePluginsSubsection:n}){const{t:c}=te("app");return e.jsxs(e.Fragment,{children:[e.jsx("h4",{className:"settings-section-heading",children:c("settings.plugins.plugins","Plugins")}),e.jsxs("div",{className:"settings-plugins-subsection-toggle",role:"tablist","aria-label":c("settings.plugins.pluginManagerType","Plugin manager type"),children:[e.jsx("button",{type:"button",id:"plugins-tab-fusion-plugins",role:"tab","aria-controls":"plugins-panel-fusion-plugins","aria-selected":a==="fusion-plugins",tabIndex:a==="fusion-plugins"?0:-1,className:`settings-plugins-subsection-btn${a==="fusion-plugins"?" active":""}`,onClick:()=>n("fusion-plugins"),children:c("settings.plugins.fusionPlugins"," Fusion Plugins ")}),e.jsx("button",{type:"button",id:"plugins-tab-pi-extensions",role:"tab","aria-controls":"plugins-panel-pi-extensions","aria-selected":a==="pi-extensions",tabIndex:a==="pi-extensions"?0:-1,className:`settings-plugins-subsection-btn${a==="pi-extensions"?" active":""}`,onClick:()=>n("pi-extensions"),children:c("settings.plugins.piExtensions"," Pi Extensions ")})]}),e.jsx("div",{id:"plugins-panel-fusion-plugins",role:"tabpanel","aria-labelledby":"plugins-tab-fusion-plugins",className:"settings-plugins-subsection-panel",hidden:a!=="fusion-plugins",children:a==="fusion-plugins"&&e.jsxs(e.Fragment,{children:[e.jsx(o.Suspense,{fallback:null,children:e.jsx(gp,{addToast:s,projectId:t})}),e.jsx(dn,{slotId:"settings-section",projectId:t})]})}),e.jsx("div",{id:"plugins-panel-pi-extensions",role:"tabpanel","aria-labelledby":"plugins-tab-pi-extensions",className:"settings-plugins-subsection-panel",hidden:a!=="pi-extensions",children:a==="pi-extensions"&&e.jsx(o.Suspense,{fallback:null,children:e.jsx(pp,{addToast:s,projectId:t})})})]})}function tn(t,s){if(!s)return t;const a=t.includes("?")?"&":"?";return`${t}${a}projectId=${encodeURIComponent(s)}`}async function cr(t,s){const a=await fetch(t,{credentials:"same-origin",...s,headers:{"Content-Type":"application/json",...s?.headers??{}}}),n=await a.json();if(!a.ok)throw new Error(n.error??`Request failed (${a.status})`);return n}function mp(t,s){const a=s?.enabled===!0,[n,c]=o.useState({status:"missing"}),[d,i]=o.useState(!1),u=o.useCallback(async()=>{try{const h=await cr(tn("/api/worktrunk/status",t));return c(h),h}catch(h){const p={status:"failed",error:h instanceof Error?h.message:"Failed to load worktrunk status"};return c(p),p}},[t]);o.useEffect(()=>{a&&u()},[a,u]),o.useEffect(()=>nd(tn("/api/events",t),{events:{"approval:updated":()=>{n.pendingApprovalId&&u()},"approval:decided":()=>{n.pendingApprovalId&&u()}}}),[t,u,n.pendingApprovalId]);const l=o.useCallback(async()=>{i(!0),c(h=>({...h,status:"installing",error:void 0}));try{const h=await cr(tn("/api/worktrunk/install-request",t),{method:"POST",body:JSON.stringify({})});c({status:h.status,version:h.version,installPath:h.installPath,pendingApprovalId:h.pendingApprovalId??h.approvalRequestId,error:h.error})}catch(h){c({status:"failed",error:h instanceof Error?h.message:"Failed to request install"})}finally{i(!1)}},[t]);return{...n,refresh:u,requestInstall:l,requesting:d}}const bp=[{sectionId:"appearance",key:"openTasksInRightSidebar",labelKey:"settings.appearance.openTasksInRightSidebar",labelFallback:"Open tasks in the right sidebar",helpKey:"settings.appearance.openTasksInRightSidebarHelp",helpFallback:"When enabled, board task cards open detail in the right sidebar when it is available; mobile and hidden-sidebar states keep the full task panel. Default: disabled.",keywords:["dock","right dock","side panel"]},{sectionId:"appearance",key:"openMobileTasksInPopup",labelKey:"settings.appearance.openMobileTasksInPopup",labelFallback:"Open tasks as popups",helpKey:"settings.appearance.openMobileTasksInPopupHelp",helpFallback:"When enabled, ordinary board task-card, List row/card, and right-dock Tasks-list clicks open the existing movable task popup so the board or list remains visible. Deep-tab and other task opens keep their current behavior. Default: disabled.",keywords:["mobile","floating window","modal"]},{sectionId:"appearance",key:"taskPopupsBoardListOnly",labelKey:"settings.appearance.taskPopupsBoardListOnly",labelFallback:"Keep task popups on the view where they were opened",helpKey:"settings.appearance.taskPopupsBoardListOnlyHelp",helpFallback:"When enabled, each open task-detail popup appears only on the view where it was opened. Switching views hides it without closing; returning restores it in the same position. Default: enabled.",keywords:["popup view attachment","pin popup"]},{sectionId:"appearance",key:"showCostBadgeOnCards",labelKey:"settings.appearance.showCostBadgeOnCards",labelFallback:"Show cost badges on task cards",helpKey:"settings.appearance.showCostBadgeOnCardsHelp",helpFallback:"Default: disabled. When enabled, board cards show derived model cost next to execution time; unavailable pricing displays — and tasks without token usage show no badge.",keywords:["spend","price","tokens","usage"]},{sectionId:"appearance",key:"taskDetailChatFirst",labelKey:"settings.appearance.taskDetailChatFirst",labelFallback:"Open task details with Chat first",helpKey:"settings.appearance.taskDetailChatFirstHelp",helpFallback:"Off by default: task details list Activity first and omitted non-done opens land on Activity. Turn on to restore Chat-first order/default; explicit Chat links still work either way.",keywords:["activity first","default tab"]},{sectionId:"appearance",key:"sessionBannersHidden",labelKey:"settings.appearance.hideAISessionNotificationBanners",labelFallback:"Hide AI session notification banners",helpKey:"settings.appearance.suppressTheLdquoNeedsYourInputRdquoBanner",helpFallback:"Suppress the “needs your input” banner that appears when AI sessions are awaiting input or have failed.",keywords:["needs your input","toast","alert"]}],fp=[{sectionId:"backups",key:"memoryBackupEnabled",labelKey:"settings.backups.enableAutomaticMemoryBackups",labelFallback:" Enable automatic memory backups ",helpKey:"settings.backups.whenEnabledProjectAndAgentMemoryFilesAre",helpFallback:"When enabled, project and agent memory files are backed up automatically on a schedule. Default: disabled.",keywords:["snapshot","restore"]},{sectionId:"backups",key:"memoryBackupSchedule",labelKey:"settings.backups.memoryBackupScheduleCron",labelFallback:"Memory Backup Schedule (Cron)",helpKey:"settings.backups.cronExpressionForMemoryBackupTimingDefault0",helpFallback:"Cron expression for memory backup timing. Default: 0 3 * * * (daily at 3 AM).",keywords:["timing","frequency"]},{sectionId:"backups",key:"memoryBackupRetention",labelKey:"settings.backups.memoryRetentionCount",labelFallback:"Memory Retention Count",helpKey:"settings.backups.numberOfMemoryBackupsToKeepOldestAre",helpFallback:"Number of memory backups to keep (oldest are deleted first). Range: 1-100. Default: 14.",keywords:["how many","prune","rotation"]},{sectionId:"backups",key:"memoryBackupDir",labelKey:"settings.backups.memoryBackupDirectory",labelFallback:"Memory Backup Directory",helpKey:"settings.backups.directoryForMemoryBackupsRelativeToProjectRoot",helpFallback:"Directory for memory backups, relative to project root. Default: .fusion/backups/memory.",keywords:["location","folder","destination"]},{sectionId:"backups",key:"memoryBackupScope",labelKey:"settings.backups.memoryBackupScope",labelFallback:"Memory Backup Scope",helpKey:"settings.backups.memoryBackupScopeHint",helpFallback:"Default: all (project + agents).",keywords:["agent memory",".fusion/memory",".fusion/agent-memory","what to back up"]}],yp=[{sectionId:"backups-global",key:"autoBackupEnabled",labelKey:"settings.backups.enableAutomaticDatabaseBackups",labelFallback:" Enable automatic database backups ",helpKey:"settings.backups.whenEnabledTheDatabaseIsBackedUpAutomatically",helpFallback:"When enabled, the database is backed up automatically on a schedule. Default: disabled.",keywords:["sqlite","snapshot","restore"]},{sectionId:"backups-global",key:"autoBackupSchedule",labelKey:"settings.backups.backupScheduleCron",labelFallback:"Backup Schedule (Cron)",helpKey:"settings.backups.cronExpressionForBackupTimingDefault02",helpFallback:" Cron expression for backup timing. Default: 0 2 * * * (daily at 2 AM). Examples: 0 * * * * (hourly), 0 0 * * 0 (weekly), */15 * * * * (every 15 min) ",keywords:["timing","frequency"]},{sectionId:"backups-global",key:"autoBackupRetention",labelKey:"settings.backups.retentionCount",labelFallback:"Retention Count",helpKey:"settings.backups.numberOfBackupFilesToKeepOldestAre",helpFallback:"Number of backup files to keep (oldest are deleted first). Range: 1-100. Default: 7.",keywords:["how many","prune","rotation"]},{sectionId:"backups-global",key:"autoBackupDir",labelKey:"settings.backups.backupDirectory",labelFallback:"Backup Directory",helpKey:"settings.backups.directoryForBackupFilesRelativeToProjectRoot",helpFallback:"Directory for backup files, relative to project root. Default: .fusion/backups.",keywords:["location","folder","destination"]}],kp=[{sectionId:"commands",key:"testCommand",labelKey:"settings.commands.testCommand",labelFallback:"Test Command",helpKey:"settings.commands.commandUsedToRunTestsInjectedIntoGenerated",helpFallback:"Command used to run tests — injected into generated task specs. No default — unset.",keywords:["verify","verification","vitest","pnpm test"]},{sectionId:"commands",key:"buildCommand",labelKey:"settings.commands.buildCommand",labelFallback:"Build Command",helpKey:"settings.commands.commandUsedToBuildTheProjectInjectedInto",helpFallback:"Command used to build the project — injected into generated task specs. No default — unset.",keywords:["compile","pnpm build"]}],vp=[{sectionId:"general",key:"taskPrefix",labelKey:"settings.general.taskPrefix",labelFallback:"Task Prefix",helpKey:"settings.general.prefixForNewTaskIDsEGKB",helpFallback:"Prefix for new task IDs (e.g. KB, PROJ). No default — unset.",keywords:["task id","identifier","naming"]},{sectionId:"general",key:"ephemeralAgentsCanCreateTasks",labelKey:"settings.general.allowEphemeralAgentsToCreateTasks",labelFallback:" Allow ephemeral agents to create tasks ",helpKey:"settings.general.allowEphemeralAgentsToCreateTasksHint",helpFallback:"When enabled (default), ephemeral task-worker agents can open follow-up tasks via fn_task_create. When disabled, only humans and permanent agents can create tasks; ephemeral callers are rejected.",keywords:["follow-up","permissions"]},{sectionId:"general",key:"workspaceMode",labelKey:"settings.general.workspaceMode",labelFallback:" Workspace mode (multi-repo) ",helpKey:"settings.general.workspaceModeHint",helpFallback:"When enabled, the project root is treated as a workspace containing multiple git sub-repos. Tasks run per-sub-repo and no git repo is created at the root. Disable for single-repo projects. No default — unset (disabled).",keywords:["monorepo","polyrepo"]},{sectionId:"general",key:"allowAbsoluteFileBrowserPaths",labelKey:"settings.general.allowAbsoluteFileBrowserPaths",labelFallback:" Allow absolute file-browser paths ",helpKey:"settings.general.allowAbsoluteFileBrowserPathsHint",helpFallback:"When enabled, slash-prefixed paths such as /tmp can be opened in the workspace file browser. Windows drive-letter paths remain blocked, and other path validators are unchanged. Default: disabled.",keywords:["outside workspace","root paths"]},{sectionId:"general",key:"mobileNavPrimaryItems",labelKey:"settings.general.mobileNavPrimaryItems",labelFallback:"Mobile footer quick actions",helpKey:"settings.general.mobileNavPrimaryItemsHint",helpFallback:"Default: Dashboard, Tasks, Agents, Missions, Chat, Mailbox. Unselected destinations remain in More.",keywords:["mobile","footer","navigation","planning","more"]},{sectionId:"general",key:"quickChatButtonMode",labelKey:"settings.general.quickChatLauncher",labelFallback:"Quick Chat launcher",helpKey:"settings.general.quickChatLauncherHint",helpFallback:"Choose whether Quick Chat opens from the draggable floating button, a footer button beside Terminal, or stays hidden. Default: off (hidden).",keywords:["FAB","floating action button"]},{sectionId:"general",key:"quickChatCloseOnOutsideClick",labelKey:"settings.general.quickChatCloseOnOutsideClick",labelFallback:"Close Quick Chat on outside click",helpKey:"settings.general.quickChatCloseOnOutsideClickHint",helpFallback:"When enabled, clicking outside the Quick Chat window closes it. Disable to keep it open until you close it explicitly. Default: enabled.",keywords:["dismiss","backdrop"]},{sectionId:"general",key:"showTaskChatsInCommonFeed",labelKey:"settings.general.showTaskChatsInCommonFeed",labelFallback:"Show task chats in common Chat feed",helpKey:"settings.general.showTaskChatsInCommonFeedHint",helpFallback:"When enabled, populated task-detail Chat conversations appear in the common Direct feed. Empty task chats stay hidden. Default: disabled.",keywords:["planner chats","inbox"]},{sectionId:"general",key:"chatAutoCleanupDays",labelKey:"settings.general.autoCleanupOldChats",labelFallback:"Auto-cleanup old chats",helpKey:"settings.general.deleteChatSessionsAndRoomsThatHaveBeen",helpFallback:"Delete chat sessions and rooms that have been idle for this many days. Default: Off.",keywords:["retention","prune","purge"]},{sectionId:"general",key:"mailAutoCleanupDays",labelKey:"settings.general.autoPruneOldMail",labelFallback:"Auto-prune old mail",helpKey:"settings.general.deleteInboxOutboxMessagesOlderThanThisMany",helpFallback:"Delete inbox/outbox messages older than this many days. Default: Off. 7 days is the suggested setting.",keywords:["retention","purge","mailbox"]},{sectionId:"general",key:"operationalLogRetentionDays",labelKey:"settings.general.operationalLogRetention",labelFallback:"Operational log retention",helpKey:"settings.general.loweringThisWindowMeansReliabilityMetricsChartsAnd",helpFallback:" Lowering this window means Reliability metrics/charts and the Activity feed will not show history older than the selected range. Per-task task detail history is unaffected. Default: 30 days. ",keywords:["run audit","database size","purge","disk"]},{sectionId:"general",key:"chatRoomRecentVerbatimMessages",labelKey:"settings.general.recentVerbatimRoomMessages",labelFallback:"Recent verbatim room messages",helpKey:"settings.general.numberOfMostRecentChatRoomMessagesKept",helpFallback:"Number of most-recent chat-room messages kept verbatim in the responder transcript. Older messages are compacted into a summary block. Default: 25.",keywords:["context window","history depth"]},{sectionId:"general",key:"chatRoomCompactionFetchLimit",labelKey:"settings.general.roomCompactionFetchLimit",labelFallback:"Room compaction fetch limit",helpKey:"settings.general.upperBoundOnMessagesFetchedFromTheRoom",helpFallback:"Upper bound on messages fetched from the room store for compaction consideration. Default: 200.",keywords:["summarization","context window"]},{sectionId:"general",key:"chatRoomSummaryMaxChars",labelKey:"settings.general.roomSummaryMaxCharacters",labelFallback:"Room summary max characters",helpKey:"settings.general.hardCapOnTheSynthesizedEarlierRoomContext",helpFallback:'Hard cap on the synthesized "Earlier room context" summary block. Default: 3000.',keywords:["compaction","length limit"]},{sectionId:"general",key:"capacityRiskBannerEnabled",labelKey:"settings.general.showCapacityRiskBanner",labelFallback:" Show capacity risk banner ",helpKey:"settings.general.warnOnTheBoardWhenTodoWorkExceeds",helpFallback:"Warn on the board when todo work exceeds the threshold and no idle agents are available. Default: disabled.",keywords:["backlog warning","overload","alert"]},{sectionId:"general",key:"capacityRiskTodoThreshold",labelKey:"settings.general.todoThreshold",labelFallback:"Todo threshold",helpKey:"settings.general.bannerFiresWhenTodoCountIsStrictlyGreater",helpFallback:"Banner fires when todo count is strictly greater than this value (default 20). Applies when the banner is enabled.",keywords:["capacity risk","backlog limit"]},{sectionId:"general",key:"sessionAdvisorEnabledByDefault",labelKey:"settings.general.defaultSessionAdvisorForNewTasks",labelFallback:"Default for new tasks",helpKey:"settings.general.sessionAdvisorHelp",helpFallback:"Controls whether newly created tasks enable the session advisor (live LLM overseer of the executor). Individual tasks can override this from Quick Add or task detail. Also set Session advisor model provider and model id under workflow settings before the advisor can run.",keywords:["session advisor","overseer","oversight","planner"]},{sectionId:"general",key:"githubImportAutoTranslate",labelKey:"settings.general.autoTranslateImportedIssues",labelFallback:"Auto-translate imported issues",helpKey:"settings.general.autoTranslateImportedIssuesHelp",helpFallback:"When enabled, the Import Tasks panel automatically translates foreign-language issue titles and bodies into the target language below and shows the translation by default. You can always switch back to the original text, and imported tasks carry the translated text. Default: disabled.",keywords:["localization","foreign language"]},{sectionId:"general",key:"importTranslateTargetLocale",labelKey:"settings.general.translationTargetLanguage",labelFallback:"Translation target language",helpKey:"settings.general.translationTargetLanguageHelp",helpFallback:"Language imported issues are translated into when auto-translation is enabled. No default — unset inherits the dashboard language.",keywords:["locale","localization"]}],xp=[{sectionId:"global-general",key:"dismissModalsOnOutsideClick",labelKey:"settings.globalGeneral.dismissModalsByClickingOutside",labelFallback:" Dismiss modals by clicking outside ",helpKey:"settings.globalGeneral.dismissModalsByClickingOutsideHint",helpFallback:" When enabled, clicking or tapping a modal backdrop closes the modal. Default: disabled, to prevent accidental dismissal. ",keywords:["dialog","backdrop","accidental close"]},{sectionId:"global-general",key:"skipConfirmationDialogs",labelKey:"settings.globalGeneral.skipConfirmationDialogs",labelFallback:" Skip confirmation dialogs for critical actions ",helpKey:"settings.globalGeneral.skipConfirmationDialogsHint",helpFallback:" When enabled, destructive actions such as deleting a task or resetting progress run immediately without a prompt. Default: disabled",keywords:["confirm","critical action","delete","reset","destructive"]},{sectionId:"global-general",key:"persistAgentToolOutput",labelKey:"settings.globalGeneral.saveToolOutputInAgentLogs",labelFallback:" Save tool output in agent logs ",helpKey:"settings.globalGeneral.whenDisabledToolRowsAreStillLoggedBut",helpFallback:" When disabled, tool rows are still logged but detailed tool payloads are omitted. Very large tool payloads may still be clipped even when this stays enabled. Default: disabled. ",keywords:["persist","transcript","disk usage"]},{sectionId:"global-general",key:"updateCheckFrequency",labelKey:"settings.globalGeneral.frequency",labelFallback:"Frequency",helpKey:"settings.globalGeneral.controlsHowOftenTheDashboardReFetchesThe",helpFallback:" Controls how often the dashboard re-fetches the npm registry. Use the version + refresh control in the header to trigger an immediate check at any time. Default: daily. ",keywords:["update check","cadence","how often","version check"]},{sectionId:"global-general",key:"autoReloadOnVersionChange",labelKey:"settings.globalGeneral.autoReloadDashboardOnVersionChange",labelFallback:" Auto-reload dashboard on version change ",helpKey:"settings.globalGeneral.whenEnabledDefaultTheDashboardAutomaticallyReloadsWhen",helpFallback:" When enabled (default), the dashboard automatically reloads when it detects a new build version — either from server rebuilds or service worker updates. Disable this to stay on the current version until you manually refresh. Default: enabled. ",keywords:["refresh","service worker","hot reload"]}],jp=[{sectionId:"global-models",key:"defaultThinkingLevel",labelKey:"settings.globalModels.thinkingEffort",labelFallback:"Thinking Effort",helpKey:"settings.globalModels.controlsHowMuchReasoningEffortTheAIModel",helpFallback:"Controls how much reasoning effort the AI model uses. Higher levels produce better results but cost more. No default — unset (model's own default effort applies).",keywords:["high","low","medium","xhigh","extended thinking"]},{sectionId:"global-models",key:"openrouterModelSync",labelKey:"settings.globalModels.syncOpenRouterModelListAtStartup",labelFallback:" Sync OpenRouter model list at startup ",helpKey:"settings.globalModels.whenEnabledStartupFetchesTheLatestAvailableModels",helpFallback:" When enabled, startup fetches the latest available models from the OpenRouter API so model pickers always include the newest catalog. Default: enabled. ",keywords:["refresh","boot"]},{sectionId:"global-models",key:"openrouterAppAttribution.referer",labelKey:"settings.globalModels.openRouterHTTPReferer",labelFallback:"OpenRouter HTTP-Referer",helpKey:"settings.globalModels.leaveEmptyToOmitThisHeaderDefaultHttps",helpFallback:"Leave empty to omit this header. No default — unset (Fusion falls back to https://runfusion.ai when unset).",keywords:["attribution","app ranking"]},{sectionId:"global-models",key:"openrouterAppAttribution.title",labelKey:"settings.globalModels.openRouterXTitle",labelFallback:"OpenRouter X-Title",helpKey:"settings.globalModels.leaveEmptyToOmitThisHeaderDefaultFusion",helpFallback:'Leave empty to omit this header. No default — unset (Fusion falls back to the title "Fusion" when unset).',keywords:["attribution","app ranking"]},{sectionId:"global-models",key:"openrouterModelFilters.supported_parameters",labelKey:"settings.globalModels.openRouterSupportedParametersFilter",labelFallback:"OpenRouter supported_parameters filter",helpKey:"settings.globalModels.commaSeparatedValuesSentToOpenRouterModelSync",helpFallback:"Comma-separated values sent to OpenRouter model sync. No default — unset (unfiltered).",keywords:["tools","structured outputs","catalog filter"]},{sectionId:"global-models",key:"openrouterModelFilters.output_modalities",labelKey:"settings.globalModels.openRouterOutputModalitiesFilter",labelFallback:"OpenRouter output_modalities filter",helpKey:"settings.globalModels.commaSeparatedValuesSentToOpenRouterModelSyncOutputModalities",helpFallback:"Comma-separated values sent to OpenRouter model sync. No default — unset (unfiltered).",keywords:["text","image","catalog filter"]},{sectionId:"global-models",key:"openrouterProviderPreferences.order",labelKey:"settings.globalModels.openRouterRoutingOrder",labelFallback:"OpenRouter routing order",helpKey:"settings.globalModels.openRouterRoutingOrderHint",helpFallback:"No default — unset (OpenRouter's own default routing order applies).",keywords:["provider preference","priority"]},{sectionId:"global-models",key:"openrouterProviderPreferences.ignore",labelKey:"settings.globalModels.openRouterRoutingIgnore",labelFallback:"OpenRouter routing ignore",helpKey:"settings.globalModels.openRouterRoutingIgnoreHint",helpFallback:"No default — unset (no providers ignored).",keywords:["exclude","block","deny provider"]},{sectionId:"global-models",key:"openrouterProviderPreferences.only",labelKey:"settings.globalModels.openRouterRoutingOnly",labelFallback:"OpenRouter routing only",helpKey:"settings.globalModels.openRouterRoutingOnlyHint",helpFallback:"No default — unset (no provider restriction).",keywords:["allowlist","restrict","pin provider"]},{sectionId:"global-models",key:"openrouterProviderPreferences.allow_fallbacks",labelKey:"settings.globalModels.openRouterAllowFallbacks",labelFallback:"OpenRouter allow fallbacks",helpKey:"settings.globalModels.openRouterAllowFallbacksHint",helpFallback:"No default — unset (OpenRouter's own default fallback behavior applies).",keywords:["backup provider","failover"]},{sectionId:"global-models",key:"openrouterProviderPreferences.sort",labelKey:"settings.globalModels.openRouterRoutingSort",labelFallback:"OpenRouter routing sort",helpKey:"settings.globalModels.openRouterRoutingSortHint",helpFallback:"No default — unset (OpenRouter's own default sort applies).",keywords:["price","throughput","latency","cheapest","fastest"]},{sectionId:"global-models",key:"openrouterProviderPreferences.require_parameters",labelKey:"settings.globalModels.requireParameters",labelFallback:" Require parameters ",helpKey:"settings.globalModels.requireParametersHint",helpFallback:"Default: disabled.",keywords:["strict routing","provider support"]}],wp=[{sectionId:"memory",key:"memoryEnabled",labelKey:"settings.memory.enableMemoryTools",labelFallback:" Enable memory tools ",helpKey:"settings.memory.agentsGetMemorySearchMemoryGetAndMemory",helpFallback:"Agents get memory_search, memory_get, and memory_append tools. Search defaults to qmd with a local file fallback. Default: enabled.",keywords:["recall","knowledge"]},{sectionId:"memory",key:"memoryAutoSummarizeEnabled",labelKey:"settings.memory.autoSummarizeMemory",labelFallback:" Auto-Summarize Memory ",helpKey:"settings.memory.automaticallyCompactMemoryWhenItExceedsTheThreshold",helpFallback:"Automatically compact memory when it exceeds the threshold on a schedule. Default: disabled.",keywords:["condense","prune","shrink"]},{sectionId:"memory",key:"memoryAutoSummarizeThresholdChars",labelKey:"settings.memory.compactionThresholdChars",labelFallback:"Compaction Threshold (chars)",helpKey:"settings.memory.memoryWillBeCompactedWhenItExceedsThis",helpFallback:"Memory will be compacted when it exceeds this character count. Default: 50000.",keywords:["size limit","trigger"]},{sectionId:"memory",key:"memoryAutoSummarizeSchedule",labelKey:"settings.memory.scheduleCron",labelFallback:"Schedule (cron)",helpKey:"settings.memory.cronExpressionForAutoSummarizeScheduleDefaultDaily",helpFallback:"Cron expression for auto-summarize schedule. Default: 0 3 * * * (daily at 3 AM).",keywords:["auto-summarize","compaction schedule","timing"]},{sectionId:"memory",key:"insightExtractionEnabled",labelKey:"settings.memory.enableInsightExtraction",labelFallback:" Enable Insight Extraction ",helpKey:"settings.memory.periodicallyExtractDurableInsightsFromCompletedTasks",helpFallback:"Periodically extract durable insights/learnings from completed tasks into memory",keywords:["lessons","retrospective"]},{sectionId:"memory",key:"insightExtractionSchedule",labelKey:"settings.memory.scheduleCron",labelFallback:"Schedule (cron)",helpKey:"settings.memory.cronExpressionForInsightExtractionScheduleDefaultDaily",helpFallback:"Cron expression for insight extraction schedule (default: daily at 2 AM)",keywords:["insight","timing"]},{sectionId:"memory",key:"memoryDreamsEnabled",labelKey:"settings.memory.processDreamsFromDailyMemory",labelFallback:" Process dreams from daily memory ",helpKey:"settings.memory.turnsDailyNotesIntoDREAMSMdAndPromotes",helpFallback:"Turns daily notes into DREAMS.md and promotes reusable lessons into MEMORY.md. Default: disabled.",keywords:["synthesis","consolidation"]},{sectionId:"memory",key:"memoryDreamsSchedule",labelKey:"settings.memory.dreamSchedule",labelFallback:"Dream Schedule",helpKey:"settings.memory.cronExpressionForDreamProcessing",helpFallback:"Cron expression for dream processing. Default: 0 4 * * * (daily at 4 AM).",keywords:["timing"]}],Cp=[{sectionId:"merge",key:"maxAutoMergeRetries",labelKey:"settings.merge.autoMergeConflictRetries",labelFallback:"Auto-merge conflict retries",helpKey:"settings.merge.positiveIntegerRetryCapForAutoMergeConflict",helpFallback:"Positive integer retry cap for auto-merge conflict resolution before a task parks for human recovery. Default 3.",keywords:["attempts","give up","parked","merge failure"]},{sectionId:"merge",key:"merger.maxReviewPasses",labelKey:"settings.merge.maxAIReviewPasses",labelFallback:"Max AI review passes",helpKey:"settings.merge.aICorrectiveRoundsBeforeLandingTheBestResult",helpFallback:"AI corrective rounds before landing the best result (advisory concern) or hard-failing (unfixable correctness concern). Default 3. The reviewer uses your project's reviewer/validator model.",keywords:["clean room","audit","retries","attempts"]},{sectionId:"merge",key:"mergeStrategyOverlapBehavior",labelKey:"settings.merge.smartPreferMainOverlapGuard",labelFallback:"Smart Prefer Main Overlap Guard",helpKey:"settings.merge.whenUsingSmartPreferMainAutomaticallyPreferThe",helpFallback:" When using smart-prefer-main, automatically prefer the branch side for files that main has recently modified to avoid silently discarding branch work. ",keywords:["ours","theirs","lost work","clobber"]}],Sp=[{sectionId:"node-routing",key:"unavailableNodePolicy",labelKey:"settings.nodeRouting.unavailableNodePolicy",labelFallback:"Unavailable Node Policy",helpKey:"settings.nodeRouting.unavailableNodePolicyHint",helpFallback:"Default: block execution.",keywords:["offline node","fallback","unreachable","local execution"]}],Np=[{sectionId:"node-sync",key:"settingsSyncEnabled",labelKey:"settings.nodeSync.enableAutomaticSettingsSync",labelFallback:" Enable automatic settings sync ",helpKey:"settings.nodeSync.automaticallySynchronizeSettingsBetweenThisNodeAndConnected",helpFallback:"Automatically synchronize settings between this node and connected remote nodes. Default: disabled."},{sectionId:"node-sync",key:"settingsSyncAuth",labelKey:"settings.nodeSync.syncModelAuthCredentials",labelFallback:" Sync model auth credentials ",helpKey:"settings.nodeSync.includeAPIKeysAndOAuthTokensInSync",helpFallback:"Include API keys and OAuth tokens in sync operations. Default: disabled.",keywords:["secrets","authentication"]},{sectionId:"node-sync",key:"settingsSyncInterval",labelKey:"settings.nodeSync.syncInterval",labelFallback:"Sync interval",helpKey:"settings.nodeSync.syncIntervalHint",helpFallback:"Default: every 15 minutes.",keywords:["frequency","how often","schedule"]},{sectionId:"node-sync",key:"settingsSyncConflictResolution",labelKey:"settings.nodeSync.conflictResolution",labelFallback:"Conflict resolution",helpKey:"settings.nodeSync.conflictResolutionHint",helpFallback:"Default: last write wins."}],Pp=[{sectionId:"notifications",key:"failureNotificationMode",labelKey:"settings.notifications.failureNotificationMode",labelFallback:"Failure notification mode",helpKey:"settings.notifications.stickyOnlySuppressesRecoveredFailuresTerminalOnlyWaits",helpFallback:"Sticky-only suppresses recovered failures; terminal-only waits for paused/in-review failed tasks; all restores legacy alerts.",keywords:["retry","noise","alerts"]},{sectionId:"notifications",key:"failureNotificationDelayMs",labelKey:"settings.notifications.failureNotificationDelayMs",labelFallback:"Failure notification delay (ms)",helpKey:"settings.notifications.howLongAFailureMustPersistBeforeA",helpFallback:" How long a failure must persist before a push notification is sent. 0 = notify immediately. Default: 30000 (30 seconds). ",keywords:["debounce","wait","throttle"]},{sectionId:"notifications",key:"ntfyDashboardHost",labelKey:"settings.notifications.dashboardHostname",labelFallback:"Dashboard Hostname",helpKey:"settings.notifications.baseURLForDeepLinksInNotificationsWhen",helpFallback:" Base URL for deep links in notifications. When set, clicking a notification opens the dashboard directly to the task. No default — unset. ",keywords:["ntfy","deep link","base url"]},{sectionId:"notifications",key:"webhookUrl",labelKey:"settings.notifications.webhookURL",labelFallback:"Webhook URL",helpKey:"settings.notifications.webhookUrlHint",helpFallback:"No default — unset.",keywords:["endpoint","hook","callback"]},{sectionId:"notifications",key:"webhookFormat",labelKey:"settings.notifications.format",labelFallback:"Format",helpKey:"settings.notifications.webhookFormatHint",helpFallback:"Default: generic.",keywords:["slack","discord","payload","webhook"]},{sectionId:"notifications",key:"ntfyBaseUrl",labelKey:"settings.notifications.customNtfyServerURLOptional",labelFallback:"Custom ntfy server URL (optional)",helpKey:"settings.notifications.leaveBlankToKeepTheDefaultServerHttps",helpFallback:" Leave blank to keep the default server: https://ntfy.sh. Custom servers must use http:// or https://. No default — unset. ",keywords:["self-hosted","custom server"]},{sectionId:"notifications",key:"ntfyAccessToken",labelKey:"settings.notifications.accessTokenOptional",labelFallback:"Access token (optional)",helpKey:"settings.notifications.leaveBlankToPublishWithoutAuthenticationWhenSet",helpFallback:" Leave blank to publish without authentication. When set, Fusion sends an Authorization Bearer header with ntfy requests. No default — unset. ",keywords:["auth","bearer","credential","secret"]}],Tp=[{sectionId:"project-models",key:"tokenCap",labelKey:"settings.projectModels.tokenCap",labelFallback:"Token Cap",helpKey:"settings.projectModels.automaticallyCompactContextWhenApproachingThisTokenCount",helpFallback:"Automatically compact context when approaching this token count. Leave empty for no cap (compact only on overflow errors). Set a number to proactively compact when reaching this token count. No default — unset (no cap).",keywords:["context window","limit","budget"]},{sectionId:"project-models",key:"chatNewSessionMode",labelKey:"settings.projectModels.chatNewSessionMode",labelFallback:"New Chat behavior",helpKey:"settings.projectModels.chatNewSessionModeHelp",helpFallback:"Prompt mode opens New Chat with this default preselected. Always-default mode skips the dialog when the configured default is complete.",keywords:["direct chat","skip dialog"]},{sectionId:"project-models",key:"autoSelectModelPreset",labelKey:"settings.projectModels.autoSelectPresetBasedOnTaskSize",labelFallback:" Auto-select preset based on task size ",helpKey:"settings.projectModels.autoSelectModelPresetHint",helpFallback:"Default: disabled.",keywords:["small","medium","large","S M L"]},{sectionId:"project-models",key:"taskDefinitionInInputLanguage",labelKey:"settings.projectModels.taskDefinitionInInputLanguage",labelFallback:"Write task definitions in the operator's input language",helpKey:"settings.projectModels.taskDefinitionInInputLanguageHelp",helpFallback:"When enabled, generated task-definition prose uses supported detectable input languages (Spanish, French, Korean, or Chinese as zh-CN). Headings, markers, and code stay English. Unsupported or undetectable input stays English. Default: disabled.",keywords:["task definition","prompt language","localized prose","Spanish","French","Korean","Chinese"]},{sectionId:"project-models",key:"autoSummarizeTitles",labelKey:"settings.projectModels.autoSummarizeLongDescriptionsAsTitles",labelFallback:" Auto-summarize long descriptions as titles ",helpKey:"settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut",helpFallback:" When enabled, tasks created without a title but with descriptions over 200 characters will automatically get an AI-generated title (max 60 characters). The same model is also used to generate fallback merge commit message bodies when the branch's commit log is empty (e.g. squash merges with no unique commits), and GitHub tracking issue titles when a tracked task has no title yet. Default: disabled. "},{sectionId:"project-models",key:"useAiMergeCommitSummary",labelKey:"settings.projectModels.aIMergeCommitSummaries",labelFallback:" AI merge commit summaries ",helpKey:"settings.projectModels.whenEnabledMergeCommitMessagesIncludeAnAI",helpFallback:" When enabled, merge commit messages include an AI-generated subject plus body summary (narrative + bullets + diff-stat) instead of just listing step commit subjects. Uses the title summarization model. Default: enabled. "},{sectionId:"project-models",key:"prTitlePromptInstructions",labelKey:"settings.projectModels.prTitlePromptInstructions",labelFallback:"PR title prompt guidance",helpKey:"settings.projectModels.prTitlePromptInstructionsHelp",helpFallback:"Guides the AI-generated Create PR title. Leave blank to use the default PR metadata prompt. No default — unset.",keywords:["pull request","conventional commit"]},{sectionId:"project-models",key:"prDescriptionPromptInstructions",labelKey:"settings.projectModels.prDescriptionPromptInstructions",labelFallback:"PR description prompt guidance",helpKey:"settings.projectModels.prDescriptionPromptInstructionsHelp",helpFallback:"Guides the AI-generated Create PR summary, changes, and testing sections. Leave blank to use the default PR metadata prompt. No default — unset.",keywords:["pull request","body"]}],Ap=[{sectionId:"remote",key:"remoteTailscaleAcceptRoutes",labelKey:"settings.remote.acceptRoutes",labelFallback:" Accept routes ",helpKey:"settings.remote.acceptRoutesHint",helpFallback:"Default: disabled.",keywords:["tailscale","subnet","tailnet","funnel"]},{sectionId:"remote",key:"remoteShortLivedEnabled",labelKey:"settings.remote.enableShortLivedTokens",labelFallback:" Enable short-lived tokens ",helpKey:"settings.remote.shortLivedEnabledHint",helpFallback:"Default: disabled.",keywords:["expiring token","temporary access","auth link"]},{sectionId:"remote",key:"remoteShortLivedTtlMs",labelKey:"settings.remote.shortLivedTTLMs",labelFallback:"Short-lived TTL (ms)",helpKey:"settings.remote.shortLivedTtlMsHint",helpFallback:"Default: 900000 (15 minutes).",keywords:["expiry","lifetime","time to live","token duration"]},{sectionId:"remote",key:"remoteRememberLastRunning",labelKey:"settings.remote.rememberLastRunningState",labelFallback:" Remember last running state ",helpKey:"settings.remote.automaticallyRestoreTunnelOnStartupIfItWas",helpFallback:"Automatically restore tunnel on startup if it was running when last stopped. Default: disabled.",keywords:["cloudflared","autostart","reconnect","persist tunnel"]},{sectionId:"remote",key:"remoteCloudflareTunnelName",labelKey:"settings.remote.tunnelName",labelFallback:"Tunnel name",keywords:["cloudflare","named tunnel","cloudflared"]},{sectionId:"remote",key:"remoteCloudflareTunnelToken",labelKey:"settings.remote.tunnelToken",labelFallback:"Tunnel token",keywords:["cloudflare","named tunnel","credential","secret"]},{sectionId:"remote",key:"remoteCloudflareIngressUrl",labelKey:"settings.remote.ingressURL",labelFallback:"Ingress URL",keywords:["cloudflare","named tunnel","hostname","domain"]}],Mp=[{sectionId:"research-global",key:"researchGlobalWebSearchProvider",labelKey:"settings.researchGlobal.searchProvider",labelFallback:"Search Provider",keywords:["SearXNG","Brave","Google Custom Search","Tavily","external search providers","built-in"]},{sectionId:"research-global",key:"researchGlobalSearxngUrl",labelKey:"settings.researchGlobal.searXNGURL",labelFallback:"SearXNG URL",helpKey:"settings.researchGlobal.searXNGURLHint",helpFallback:"No default — unset.",keywords:["endpoint","instance","self-hosted"]},{sectionId:"research-global",key:"researchGlobalGoogleSearchCx",labelKey:"settings.researchGlobal.googleSearchCX",labelFallback:"Google Search CX",helpKey:"settings.researchGlobal.googleSearchCXHint",helpFallback:"No default — unset.",keywords:["custom search engine id","programmable search"]}],Ip=[{sectionId:"research-project",key:"researchSettings.enabled",labelKey:"settings.researchProject.enableResearchInThisProject",labelFallback:" Enable research in this project ",helpKey:"settings.researchProject.enableResearchInThisProjectHint",helpFallback:"Default: enabled.",keywords:["research","web search","citations","sources","turn off research"]}],Rp=[{sectionId:"scheduled-evals",key:"evalSettings.enabled",labelKey:"settings.scheduledEvals.enableScheduledEvalRunsForThisProject",labelFallback:" Enable scheduled eval runs for this project ",helpKey:"settings.scheduledEvals.enabledHint",helpFallback:"Default: disabled.",keywords:["evaluation","benchmark","quality"]},{sectionId:"scheduled-evals",key:"evalSettings.intervalMs",labelKey:"settings.scheduledEvals.intervalMs",labelFallback:"Interval (ms)",helpKey:"settings.scheduledEvals.intervalMsHint",helpFallback:"Default: 86400000 (24 hours).",keywords:["frequency","how often","schedule"]},{sectionId:"scheduled-evals",key:"evalSettings.evaluatorProvider",labelKey:"settings.scheduledEvals.evaluatorProvider",labelFallback:"Evaluator Provider",helpKey:"settings.scheduledEvals.evaluatorProviderHint",helpFallback:"No default — unset (inherits the project validator lane provider)."},{sectionId:"scheduled-evals",key:"evalSettings.evaluatorModelId",labelKey:"settings.scheduledEvals.evaluatorModel",labelFallback:"Evaluator Model",helpKey:"settings.scheduledEvals.leaveProviderAndModelBlankToInheritThe",helpFallback:" Leave provider and model blank to inherit the project validator lane model settings. No default — unset. "},{sectionId:"scheduled-evals",key:"evalSettings.followUpPolicy",labelKey:"settings.scheduledEvals.followUpPolicy",labelFallback:"Follow-up Policy",helpKey:"settings.scheduledEvals.followUpPolicyHint",helpFallback:"Default: suggest only.",keywords:["auto-create tasks","suggestions"]},{sectionId:"scheduled-evals",key:"evalSettings.retentionDays",labelKey:"settings.scheduledEvals.retentionDays",labelFallback:"Retention (days)",helpKey:"settings.scheduledEvals.retentionDaysHint",helpFallback:"Default: 30.",keywords:["prune","cleanup","history"]}],Ep=[{sectionId:"scheduling-global",key:"globalMaxConcurrent",labelKey:"settings.scheduling.globalMaxConcurrent",labelFallback:"Global Max Concurrent",helpKey:"settings.scheduling.maximumConcurrentAgentsAcrossAllProjects",helpFallback:"Maximum concurrent agents across all projects. Default: 4.",keywords:["parallelism","capacity","machine wide","cap"]}],Fp=[{sectionId:"scheduling",key:"maxConcurrent",labelKey:"settings.scheduling.maxConcurrentTasks",labelFallback:"Max Concurrent Tasks",helpKey:"settings.scheduling.maxConcurrentTasksHint",helpFallback:"Default: 2.",keywords:["parallelism","capacity","how many tasks at once","agents","cap"]},{sectionId:"scheduling",key:"maxConcurrentVerifications",labelKey:"settings.scheduling.maxConcurrentVerifications",labelFallback:"Max Concurrent Verifications",helpKey:"settings.scheduling.maxConcurrentVerificationsHint",helpFallback:"Caps stacked typecheck/build verification across tasks. Default: 1. Range: 1–8.",keywords:["parallelism","tests","cpu","load"]},{sectionId:"scheduling",key:"maxTriageConcurrent",labelKey:"settings.scheduling.maxTriageConcurrent",labelFallback:"Max Triage Concurrent",helpKey:"settings.scheduling.maximumConcurrentPlanningAgents",helpFallback:"Maximum concurrent planning agents. Default: 2.",keywords:["parallelism","capacity","spec"]},{sectionId:"scheduling",key:"executorToolFailureRetryCount",labelKey:"settings.scheduling.executorToolFailureRetryCount",labelFallback:"Executor tool-failure retries",helpKey:"settings.scheduling.executorToolFailureRetryCountHelp",helpFallback:"Same-model retries after consecutive tool-call failures. Set 0 to disable. Default: 2.",keywords:["executor","tool error","auto retry","same model","failure"]},{sectionId:"scheduling",key:"executorToolFailureRetryBackoffMs",labelKey:"settings.scheduling.executorToolFailureRetryBackoffMs",labelFallback:"Tool-failure retry backoff (ms)",helpKey:"settings.scheduling.executorToolFailureRetryBackoffMsHelp",helpFallback:"Unref'd wait before retrying. Default: 2000.",keywords:["executor","delay","wait","auto retry","tool error"]},{sectionId:"scheduling",key:"executorToolFailureThreshold",labelKey:"settings.scheduling.executorToolFailureThreshold",labelFallback:"Consecutive tool failures",helpKey:"settings.scheduling.executorToolFailureThresholdHelp",helpFallback:"Terminal tool errors required before retrying. Default: 3.",keywords:["executor","tool error","threshold","auto retry"]},{sectionId:"scheduling",key:"executorModelEscalationEnabled",labelKey:"settings.scheduling.executorModelEscalationEnabled",labelFallback:"Escalate after tool-failure retries",helpKey:"settings.scheduling.executorModelEscalationEnabledHelp",helpFallback:"After same-model retries are exhausted, try one configured alternate model or node. Disabled by default.",keywords:["executor","model","node","escalation","tool error"]},{sectionId:"scheduling",key:"executorEscalationProvider",labelKey:"settings.scheduling.executorEscalationProvider",labelFallback:"Escalation provider",helpKey:"settings.scheduling.executorEscalationProviderHelp",helpFallback:"Provider for the alternate model. Requires an alternate model ID.",keywords:["executor","model","provider","escalation"]},{sectionId:"scheduling",key:"executorEscalationModelId",labelKey:"settings.scheduling.executorEscalationModelId",labelFallback:"Escalation model ID",helpKey:"settings.scheduling.executorEscalationModelIdHelp",helpFallback:"Alternate model ID. Requires an escalation provider.",keywords:["executor","model","escalation"]},{sectionId:"scheduling",key:"executorEscalationNodeId",labelKey:"settings.scheduling.executorEscalationNodeId",labelFallback:"Escalation node ID",helpKey:"settings.scheduling.executorEscalationNodeIdHelp",helpFallback:"Optional configured node; a node target re-enters scheduler routing.",keywords:["executor","node","routing","escalation"]},{sectionId:"scheduling",key:"pollIntervalMs",labelKey:"settings.scheduling.pollIntervalMs",labelFallback:"Poll Interval (ms)",helpKey:"settings.scheduling.pollIntervalMsHint",helpFallback:"Default: 15000 (15 seconds).",keywords:["tick","engine loop","frequency","refresh"]},{sectionId:"scheduling",key:"heartbeatScopeDiscipline",labelKey:"settings.scheduling.heartbeatScopeDiscipline",labelFallback:"Heartbeat Scope Discipline",helpKey:"settings.scheduling.strictCoordinationFocusedHigherPerTickTokensLite",helpFallback:"Strict — coordination-focused; higher per-tick tokens. Lite — pre-2026-05-11 behavior. Off — minimal procedure.",keywords:["agent prompt","token cost"]},{sectionId:"scheduling",key:"engineerBacklogAutoClaim",labelKey:"settings.scheduling.letEngineerAgentsAutoClaimBacklogTasks",labelFallback:" Let engineer agents auto-claim backlog tasks ",helpKey:"settings.scheduling.backlogNoTaskAutoClaimIsExecutorOnly",helpFallback:"Backlog/no-task auto-claim is executor-only by default. Enable to let engineer-role agents auto-claim unowned backlog tasks; explicit routing and delegation are unchanged. Default: off.",keywords:["pick up work","unassigned","todo"]},{sectionId:"scheduling",key:"taskStuckTimeoutMs",labelKey:"settings.scheduling.stuckTaskTimeoutMinutes",labelFallback:"Stuck Task Timeout (minutes)",helpKey:"settings.scheduling.timeoutInMinutesForDetectingStuckTasksWhen",helpFallback:"Timeout in minutes for detecting stuck tasks. When a task's agent session shows no activity for longer than this duration, the task is terminated and retried. Leave empty to disable. Suggested: 10. Default: 10 minutes (600000ms).",keywords:["hung","frozen","watchdog","kill"]},{sectionId:"scheduling",key:"buildTimeoutMs",labelKey:"settings.scheduling.buildTimeoutMinutes",labelFallback:"Build/Verification Timeout (minutes)",helpKey:"settings.scheduling.maximumTimeInMinutesForBuildVerificationCommands",helpFallback:"Maximum time in minutes for build/verification commands before they are killed. Raise for large monorepo or Docker builds. Default: 5.",keywords:["test timeout","compile","slow build"]},{sectionId:"scheduling",key:"staleHighFanoutBlockerAgeThresholdMs",labelKey:"settings.scheduling.staleHighFanOutEscalationHours",labelFallback:"Stale High Fan-out Escalation (hours)",helpKey:"settings.scheduling.escalateHighFanOutBlockersOnlyAfterThey",helpFallback:"Escalate high fan-out blockers only after they remain in in-progress or in-review for this many hours (age source: columnMovedAt, fallback updatedAt). Default: 2 hours.",keywords:["dependencies","alert","notify"]},{sectionId:"scheduling",key:"preserveProgressOnStuckRequeue",labelKey:"settings.scheduling.preserveStepProgressOnStuckTaskRequeue",labelFallback:" Preserve step progress on stuck-task requeue ",helpKey:"settings.scheduling.whenTheStuckDetectorKillsAndReQueues",helpFallback:"When the stuck detector kills and re-queues a task, keep completed step statuses so the agent can resume from where it left off. Disable to reset every step to pending on each stuck retry. Default: enabled.",keywords:["resume","restart","retry"]},{sectionId:"scheduling",key:"specStalenessEnabled",labelKey:"settings.scheduling.enablePlanStalenessEnforcement",labelFallback:" Enable plan staleness enforcement ",helpKey:"settings.scheduling.whenEnabledTasksWithStalePlansPROMPTMd",helpFallback:"When enabled, tasks with stale plans (PROMPT.md older than the threshold) are automatically sent back to planning for replanning. Default: disabled.",keywords:["spec","replan","outdated"]},{sectionId:"scheduling",key:"specStalenessMaxAgeMs",labelKey:"settings.scheduling.staleSpecThresholdHours",labelFallback:"Stale Spec Threshold (hours)",helpKey:"settings.scheduling.maximumAgeInHoursBeforeAPlanIs",helpFallback:"Maximum age in hours before a plan is considered stale. Default: 6 hours.",keywords:["PROMPT.md","replan","age"]},{sectionId:"scheduling",key:"autoArchiveDoneTasksEnabled",labelKey:"settings.scheduling.enableAutomaticTaskArchiving",labelFallback:" Enable automatic task archiving ",helpKey:"settings.scheduling.completedTasksOlderThanTheThresholdAreMoved",helpFallback:"Completed tasks older than the threshold are moved out of the active task database. Default: enabled.",keywords:["done column","cleanup","prune","board clutter"]},{sectionId:"scheduling",key:"autoArchiveDoneAfterMs",labelKey:"settings.scheduling.archiveCompletedTasksAfterDays",labelFallback:"Archive Completed Tasks After (days)",helpKey:"settings.scheduling.numberOfDaysATaskCanStayIn",helpFallback:"Number of days a task can stay in Done before it is archived. Default: 2 days (48 hours).",keywords:["retention","cleanup","age"]},{sectionId:"scheduling",key:"archiveAgentLogMode",labelKey:"settings.scheduling.archiveAgentLog",labelFallback:"Archive Agent Log",helpKey:"settings.scheduling.compactModeKeepsArchiveSizeLowWhilePreserving",helpFallback:"Compact mode keeps archive size low while preserving recent agent activity for context. Default: compact.",keywords:["history","transcript","disk space","retention"]},{sectionId:"scheduling",key:"autoArchiveDuplicateTasksEnabled",labelKey:"settings.scheduling.autoArchiveDuplicateTasks",labelFallback:" Automatically archive duplicate tasks ",helpKey:"settings.scheduling.autoArchiveDuplicateTasksHelp",helpFallback:"Automatically archive tasks detected as same-agent duplicates on creation (off by default). When disabled, duplicates are flagged in place with the yellow Duplicate chip and Keep/Archive actions instead of being archived automatically.",keywords:["near duplicate","dedupe","repeat"]},{sectionId:"scheduling",key:"triageDuplicateResolution",labelKey:"settings.scheduling.triageDuplicateResolution",labelFallback:"Triage duplicate resolution",helpKey:"settings.scheduling.triageDuplicateResolutionHelp",helpFallback:"Block triage-detected duplicates for a Keep/Delete decision with a link to the duplicate (default), keep automatically, or delete automatically.",keywords:["duplicate","triage","keep","delete","decision"]},{sectionId:"scheduling",key:"maxStuckKills",labelKey:"settings.scheduling.maxStuckRetries",labelFallback:"Max Stuck Retries",helpKey:"settings.scheduling.maximumStuckDetectorRetriesBeforeATaskIs",helpFallback:"Maximum stuck-detector retries before a task is marked failed. Default: 6.",keywords:["give up","attempts","hung"]},{sectionId:"scheduling",key:"groupOverlappingFiles",labelKey:"settings.scheduling.serializeTasksWithOverlappingFiles",labelFallback:" Serialize tasks with overlapping files ",helpKey:"settings.scheduling.whenEnabledTasksThatModifyTheSameFiles",helpFallback:"When enabled, tasks that modify the same files are queued serially to avoid merge conflicts. Default: enabled.",keywords:["file scope","collision","queue","lease"]},{sectionId:"scheduling",key:"ignoreHiddenOverlapPaths",labelKey:"settings.scheduling.ignoreHiddenDotPathsInOverlapChecks",labelFallback:" Ignore hidden dot paths in overlap checks ",helpKey:"settings.scheduling.ignoreHiddenDotPathsHelp",helpFallback:"When enabled, overlap checks ignore hidden path segments such as .fusion/, .changeset/, .github/, .env, and nested .cache/ directories. Uncheck to restore legacy counting for stricter serialization. Default: enabled.",keywords:["dotfiles","collision","file scope"]}],Dp=[{sectionId:"source-control-global",key:"gitlabInstanceUrl",labelKey:"settings.globalGeneral.gitLabInstanceUrl",labelFallback:"Global GitLab instance URL",helpKey:"settings.globalGeneral.gitLabInstanceUrlHint",helpFallback:"Blank defaults to GitLab.com. Projects inherit this self-managed GitLab URL unless they set their own project value. No default — unset.",keywords:["self managed","self-hosted","fallback","inherit"]},{sectionId:"source-control-global",key:"gitlabApiBaseUrl",labelKey:"settings.globalGeneral.gitLabApiBaseUrlOptional",labelFallback:"Global GitLab API base URL (optional / advanced)",helpKey:"settings.globalGeneral.gitLabApiBaseUrlHint",helpFallback:"Blank derives <instance>/api/v4. Override only for self-managed GitLab API gateways that use a different absolute http:// or https:// URL. No default — unset.",keywords:["api v4","gateway","fallback","self managed"]},{sectionId:"source-control-global",key:"gitlabAuthTokenType",labelKey:"settings.globalGeneral.gitLabTokenType",labelFallback:"Global GitLab token type",helpKey:"settings.globalGeneral.gitLabTokenTypeHint",helpFallback:"No default — unset (the selector falls back to personal access token until you choose otherwise).",keywords:["personal access token","project access token","group access token","pat"]},{sectionId:"source-control-global",key:"gitlabAuthToken",labelKey:"settings.globalGeneral.gitLabAccessToken",labelFallback:"Global GitLab access token",helpKey:"settings.globalGeneral.gitLabAuthTokenHint",helpFallback:"Projects inherit this fallback only when they do not set a project GitLab token. Read-only operations need read_api or api; write actions need api; project/group tokens remain limited by resource membership. No default — unset.",keywords:["glpat","private-token","credentials","secret","fallback"]}],Lp=[{sectionId:"source-control",key:"githubLinkImportedIssuesToTracking",labelKey:"settings.general.alwaysLinkImportedGitHubIssuesToTracking",labelFallback:" Always link imported GitHub issues to GitHub tracking ",helpKey:"settings.general.whenEnabledImportedGitHubIssuesUseTheirSource",helpFallback:"When enabled, GitHub issue imports become tracked tasks that adopt the source issue. This does not turn GitHub tracking on for ordinary new tasks. Default: disabled.",keywords:["adopt issue","import"]},{sectionId:"source-control",key:"githubTrackingDedupEnabled",labelKey:"settings.general.searchTheTrackingRepoForLikelyDuplicatesBefore",labelFallback:" Search the tracking repo for likely duplicates before opening a new issue ",helpKey:"settings.general.whenEnabledFusionChecksOpenAndClosedIssues",helpFallback:" When enabled, Fusion checks open and closed issues in the target repo for likely duplicates (using File Scope paths and key symptoms) before creating a new tracking issue. Uncheck to always create a new issue. Default: enabled. ",keywords:["dedupe","deduplication"]},{sectionId:"source-control",key:"githubAuthMode",labelKey:"settings.merge.gitHubAuthMode",labelFallback:"GitHub auth mode",keywords:["gh cli","personal access token","pat","credentials","login"]},{sectionId:"source-control",key:"githubAuthToken",labelKey:"settings.merge.gitHubPersonalAccessToken",labelFallback:"GitHub personal access token",helpKey:"settings.merge.githubAuthTokenHint",helpFallback:"No default — unset.",keywords:["pat","credentials","secret","ghp"]},{sectionId:"source-control",key:"gitlabInstanceUrl",labelKey:"settings.general.gitLabInstanceUrl",labelFallback:"GitLab instance URL",helpKey:"settings.general.gitLabInstanceUrlHint",helpFallback:"Blank uses GitLab.com or the global default. Set an absolute http:// or https:// URL for self-managed GitLab, such as https://gitlab.example.com/gitlab.",keywords:["self managed","self-hosted","on premise"]},{sectionId:"source-control",key:"gitlabApiBaseUrl",labelKey:"settings.general.gitLabApiBaseUrlOptional",labelFallback:"GitLab API base URL (optional / advanced)",helpKey:"settings.general.gitLabApiBaseUrlHint",helpFallback:"Blank derives <instance>/api/v4. Override only when a self-managed GitLab API is served from a different absolute http:// or https:// URL.",keywords:["api v4","gateway","self managed"]},{sectionId:"source-control",key:"gitlabAuthTokenType",labelKey:"settings.merge.gitLabTokenType",labelFallback:"GitLab token type",keywords:["personal access token","project access token","group access token","pat"]},{sectionId:"source-control",key:"gitlabAuthToken",labelKey:"settings.merge.gitLabAccessToken",labelFallback:"GitLab access token",helpKey:"settings.merge.gitLabAuthTokenHint",helpFallback:"Read-only GitLab operations need read_api or api. Future write actions such as comments and auto-close need api. Project and group tokens are limited to their associated resource and role membership. No default — unset.",keywords:["glpat","private-token","credentials","secret","read_api"]}],Op=[{sectionId:"worktrees",key:"maxWorktrees",labelKey:"settings.worktrees.maxWorktrees",labelFallback:"Max Worktrees",helpKey:"settings.worktrees.limitsTotalGitWorktreesIncludingInReviewTasks",helpFallback:"Limits total git worktrees including in-review tasks. Default: 4.",keywords:["concurrency","parallel tasks","capacity","limit"]},{sectionId:"worktrees",key:"worktreeInitCommand",labelKey:"settings.worktrees.worktreeInitCommand",labelFallback:"Worktree Init Command",helpKey:"settings.worktrees.shellCommandToRunInEachNewWorktree",helpFallback:"Shell command to run in each new worktree after creation. No default — unset.",keywords:["setup script","bootstrap","install dependencies","post-create"]},{sectionId:"worktrees",key:"recycleWorktrees",labelKey:"settings.worktrees.recycleWorktrees",labelFallback:" Recycle worktrees ",helpKey:"settings.worktrees.offByDefaultOptInWhenEnabledCompleted",helpFallback:"Off by default (opt-in). When enabled, completed task worktrees are returned to an idle pool instead of being deleted, preserving build caches for faster startup",keywords:["reuse","warm pool"]},{sectionId:"worktrees",key:"showWorktreeGrouping",labelKey:"settings.worktrees.showWorktreeGrouping",labelFallback:" Show worktree grouping on the board ",helpKey:"settings.worktrees.showWorktreeGroupingHelp",helpFallback:"Off by default. When enabled, WIP and processing columns always group tasks by worktree and show worktree names, including workflow-mode processing columns.",keywords:["group by","swimlane"]},{sectionId:"worktrees",key:"worktreeNaming",labelKey:"settings.worktrees.worktreeNamingStyle",labelFallback:"Worktree Naming Style",helpKey:"settings.worktrees.howToNameFreshWorktreeDirectories",helpFallback:"How to name fresh worktree directories. Only applies when recycling is off. Default: random.",keywords:["folder name","directory name","branch naming"]},{sectionId:"worktrees",key:"worktreeRebaseBeforeMerge",labelKey:"settings.worktrees.rebaseFromRemoteBeforeMerge",labelFallback:" Rebase from remote before merge ",helpKey:"settings.worktrees.whenEnabledTheMergerFetchesFromTheConfigured",helpFallback:"When enabled, the merger fetches from the configured remote and rebases the task branch onto the latest default-branch tip before merging — catching concurrent pushes from other collaborators or fusion workers. Any conflicts the rebase surfaces flow into the existing smart/AI resolve pipeline. Default: enabled.",keywords:["pull","up to date","prerebase"]},{sectionId:"worktrees",key:"worktreeRebaseLocalBase",labelKey:"settings.worktrees.alsoRebaseOntoLocalDefaultBranchHEAD",labelFallback:" Also rebase onto local default-branch HEAD ",helpKey:"settings.worktrees.inAdditionToTheRemoteRebaseAboveAlso",helpFallback:" In addition to the remote rebase above, also rebase the task branch onto the local default-branch HEAD (rootDir). This catches sibling tasks that merged locally but haven't been pushed yet — without it, two concurrent tasks where one deletes code can have the other silently re-introduce it via the fallback strategy. Enabled by default; only disable if it causes issues with your workflow. ",keywords:["main","unpushed","prerebase"]}],Kp=[...bp,...fp,...yp,...kp,...vp,...xp,...jp,...wp,...Cp,...Sp,...Np,...Pp,...Tp,...Ap,...Mp,...Ip,...Rp,...Ep,...Fp,...Dp,...Lp,...Op];function ls(t){return t.trim().toLocaleLowerCase()}const Bp=0,Gp=1,Hp=2,_p=3,Wp=4,Up=5;function $p(t,s,a,n){const c=ls(a);return c===s?Bp:c.startsWith(s)?Gp:c.includes(s)?Hp:t.keywords?.some(d=>ls(d).includes(s))?_p:ls(t.key).includes(s)?Wp:n&&ls(n).includes(s)?Up:null}function zp(t,s,a){const n=ls(s);if(!n)return[];const c=[];for(const d of t){const i=a(d.labelKey,d.labelFallback),u=d.helpKey&&d.helpFallback?a(d.helpKey,d.helpFallback):void 0,l=$p(d,n,i,u);l!==null&&c.push({...d,label:i,help:u,score:l})}return c.sort((d,i)=>d.score-i.score||d.label.localeCompare(i.label))}function qp(t){return new Set(t.map(s=>s.sectionId))}const Rr="fusion_github_star_count",Er=900*1e3,dr="fusion:github-star-clicked";function Gs(t){return t.startsWith("/")}function Vp({size:t=13}){return e.jsx("svg",{"data-testid":"discord-icon",width:t,height:t,viewBox:"0 0 24 24",role:"img","aria-hidden":"true",fill:"currentColor",children:e.jsx("path",{d:"M20.317 4.369A19.791 19.791 0 0 0 15.885 3a13.66 13.66 0 0 0-.696 1.412 18.27 18.27 0 0 0-6.378 0A13.627 13.627 0 0 0 8.115 3a19.736 19.736 0 0 0-4.432 1.369C.878 8.604.111 12.734.494 16.803a19.916 19.916 0 0 0 5.993 3.048 14.43 14.43 0 0 0 1.286-2.106 12.94 12.94 0 0 1-2.024-.977c.17-.122.337-.249.499-.381 3.908 1.838 8.149 1.838 12.01 0 .163.132.329.259.5.381a12.936 12.936 0 0 1-2.028.978 14.344 14.344 0 0 0 1.287 2.105 19.85 19.85 0 0 0 5.996-3.049c.449-4.713-.766-8.806-3.696-12.433zM8.02 14.335c-1.184 0-2.157-1.085-2.157-2.419 0-1.334.95-2.418 2.157-2.418 1.217 0 2.167 1.095 2.157 2.418 0 1.334-.95 2.419-2.157 2.419zm7.975 0c-1.184 0-2.157-1.085-2.157-2.419 0-1.334.95-2.418 2.157-2.418 1.217 0 2.167 1.095 2.157 2.418 0 1.334-.94 2.419-2.157 2.419z"})})}function Yp(t){const s=new Map;for(const a of t){const n=`${a.owner}/${a.repo}`;s.has(n)||s.set(n,{value:n,label:n})}return[...s.values()].sort((a,n)=>a.value.localeCompare(n.value))}function Qp(){const[t,s]=o.useState(()=>{try{return localStorage.getItem(dr)==="true"}catch{return!1}}),a=o.useCallback(()=>{s(!0);try{localStorage.setItem(dr,"true")}catch{}},[]);return[t,a]}function ur(){try{const t=localStorage.getItem(Rr);if(!t)return null;const s=JSON.parse(t);return Number.isFinite(s.count)&&Number.isFinite(s.fetchedAt)?s:null}catch{return null}}function Jp(t){return t!==null&&Date.now()-t.fetchedAt<Er}function Xp(){const[t,s]=o.useState(()=>ur()?.count??null),a=o.useRef(!1),n=o.useCallback(()=>{document.hidden||a.current||Jp(ur())||(a.current=!0,fetch("https://api.github.com/repos/Runfusion/Fusion",{cache:"no-store"}).then(async c=>{if(!c.ok)return null;const d=await c.json();return typeof d.stargazers_count=="number"&&Number.isFinite(d.stargazers_count)?d.stargazers_count:null}).then(c=>{if(c===null)return;const d={count:c,fetchedAt:Date.now()};try{localStorage.setItem(Rr,JSON.stringify(d))}catch{}s(c)}).catch(()=>{}).finally(()=>{a.current=!1}))},[]);return o.useEffect(()=>{n();const c=()=>{document.hidden||n()};document.addEventListener("visibilitychange",c);const d=window.setInterval(n,Er);return()=>{document.removeEventListener("visibilitychange",c),window.clearInterval(d)}},[n]),t}const gr="(max-width: 768px)",sn=".fusion/memory/DREAMS.md",Fr="fusion:settings:show-advanced",Zp=1600,an=8;function eh(){return typeof window>"u"||typeof window.matchMedia!="function"||window.matchMedia("(prefers-reduced-motion: reduce)").matches?"auto":"smooth"}const Dr="fusion:settings-nav-width",Lr=248,Or=200,Kr=420,pr=new Set(["node-sync","global-mcp","cli-agents","research-global","remote","experimental","hermes-runtime","openclaw-runtime","paperclip-runtime","scheduled-evals","node-routing","agent-permissions","memory","backups","research-project","secrets","mcp","prompts","plugins"]);function th(){try{return localStorage.getItem(Fr)==="true"}catch{return!1}}function Br(t){return Number.isFinite(t)?Math.min(Kr,Math.max(Or,Math.round(t))):Lr}function sh(){try{const t=Number.parseFloat(localStorage.getItem(Dr)??"");return Br(t)}catch{return Lr}}function ah(t){return t.filter((s,a)=>{if(!s.isGroupHeader)return!0;for(const n of t.slice(a+1))return!n.isGroupHeader;return!1})}function Gr(t){return t.trim().toLocaleLowerCase()}function nh(t,s,a,n,c){return!s||t.isGroupHeader||c?.has(t.id)?!0:[a,...t.searchableText??[],...(t.searchableKeys??[]).map(d=>n(d))].map(Gr).some(d=>d.includes(s))}function lh(t,s,a,n,c){if(!s)return t;const d=new Set(t.filter(i=>!i.isGroupHeader&&nh(i,s,a(i),n,c)).map(i=>i.id));return t.filter((i,u)=>{if(!i.isGroupHeader)return d.has(i.id);for(const l of t.slice(u+1)){if(l.isGroupHeader)return!1;if(d.has(l.id))return!0}return!1})}function hr(t,s){return t.find(a=>!a.isGroupHeader)?.id??s}const rh=/ · (Global|Project)$/,ih=new Set(["authentication"]);function oh(t,s){return rh.test(s)?s:t.scope==="global"||ih.has(t.id)?`${s} · Global`:t.scope==="project"?`${s} · Project`:s}function mr(t){const s=Number(t?.maxAutoMergeRetries);return Number.isFinite(s)&&s>0?Math.floor(s):3}function Hs(t,s){const a=Number(t);return Number.isFinite(a)&&a>=0?Math.floor(a):s}const nn=[{id:"__preferences_header",label:"Preferences",labelKey:"settings.nav.preferencesHeader",scope:void 0,isGroupHeader:!0},{id:"appearance",label:"Appearance",labelKey:"settings.nav.appearance",scope:"global",searchableText:["theme","color","sidebar","dock","task popup","task popups","board list popups","popup view attachment","open tasks as popups","quick chat"]},{id:"keyboard-shortcuts",label:"Keyboard Shortcuts",labelKey:"settings.nav.keyboardShortcuts",scope:"global",searchableText:["keyboard shortcuts","hotkeys","quick chat shortcut","terminal shortcut","open files","open settings","command center","new task shortcut","record shortcut"]},{id:"notifications",label:"Notifications",labelKey:"settings.nav.notifications",scope:"global",searchableText:["ntfy","webhook","events","failure notifications","sticky","toast"]},{id:"global-general",label:"General · Global",labelKey:"settings.nav.globalGeneral",scope:"global",searchableText:["global defaults","modal outside dismiss","agent logs","persist tool output","thinking logs"]},{id:"cli-binary",label:"CLI Binary",labelKey:"settings.nav.cliBinary",scope:"global",searchableText:["fn binary","cli","install","version","path","upgrade","homebrew","binary check"]},{id:"__project_header",label:"Project",labelKey:"settings.nav.projectHeader",scope:void 0,isGroupHeader:!0},{id:"general",label:"General · Project",labelKey:"settings.nav.projectGeneral",scope:"project",searchableText:["project general","Completion Documentation Automation","Quick Chat launcher","ephemeral task-worker agents","chat rooms","auto-cleanup old chats","translate","translation","auto translate","auto-translate","autotranslate","auto translate issues","translate issues","translate imported issues","githubImportAutoTranslate","importTranslateTargetLocale","target language","translation target language","translation language","language","foreign language issues","import language","localize","localization"],searchableKeys:["settings.general.autoTranslateImportedIssues","settings.general.autoTranslateImportedIssuesHelp","settings.general.translationTargetLanguage","settings.general.translationTargetLanguageHelp","settings.general.followDashboardLanguage"]},{id:"commands",label:"Commands & Scripts",labelKey:"settings.nav.commands",scope:"project",searchableText:["test command","build command","verification command","workflow scripts","commands"]},{id:"worktrees",label:"Worktrees",labelKey:"settings.nav.worktrees",scope:"project",searchableText:["worktree directory","copy files","recycle worktrees","branch naming","sibling branch rename"]},{id:"merge",label:"Merge",labelKey:"settings.nav.merge",scope:"project",searchableText:["auto merge","AI merge","merge strategy","plan approval","direct merge","integration branch","push after merge"]},{id:"__ai_header",label:"AI & Models",labelKey:"settings.nav.aiHeader",scope:void 0,isGroupHeader:!0},{id:"authentication",label:"Authentication",labelKey:"settings.nav.authentication",scope:void 0,icon:Us,searchableText:["login","OAuth","API key","custom providers","Anthropic","OpenAI","provider credentials"]},{id:"global-models",label:"Models · Global",labelKey:"settings.nav.globalModels",scope:"global",searchableText:["global models","model presets","favorite providers","model pricing overrides","LiteLLM pricing","token pricing","translate","translation model","import translation model","import auto-translation model"]},{id:"project-models",label:"Models · Project",labelKey:"settings.nav.projectModels",scope:"project",searchableText:["default provider","default model","workflow model lanes","Plan/Triage","Executor","Reviewer","summarization model","summarize","summarize titles","auto summarize","auto-summarize","auto summarize titles","auto-summarize titles","autoSummarizeTitles","task definition language","task definitions input language","taskDefinitionInInputLanguage","localized task prose","title summarization","title summarizer","AI title","AI merge commit summaries","merge commit summary","chat","new chat","new chat behavior","chat default","chat default model","chat default agent","chat model","chat agent","prompt for model","always use default","translate","translation","translation model","import translation model","import auto-translation model","auto-translate model"],searchableKeys:["settings.projectModels.chatHeading","settings.projectModels.chatDescription","settings.projectModels.chatNewSessionMode","settings.projectModels.chatNewSessionModePrompt","settings.projectModels.chatNewSessionModeAlwaysDefault","settings.projectModels.chatDefaultKind","settings.projectModels.chatDefaultModel","settings.projectModels.chatDefaultAgent","settings.projectModels.aITitleAndGitCommitMessageSummarization","settings.projectModels.autoSummarizeLongDescriptionsAsTitles","settings.projectModels.whenEnabledTasksCreatedWithoutATitleBut","settings.projectModels.aIMergeCommitSummaries","settings.projectModels.whenEnabledMergeCommitMessagesIncludeAnAI"]},{id:"cli-agents",label:"CLI Agents",labelKey:"settings.nav.cliAgents",scope:"global",searchableText:["Droid CLI","Cursor CLI","agent runtime","command line agents","Adapter","Command override","Path or name of the binary to launch","Extra arguments","Appended after the adapter's computed arguments","Environment variable additions","Comma-separated variable names forwarded","Autonomy mode","Elevated autonomy requires a per-project approval"],searchableKeys:["settings.cliAgents.adapterLabel","settings.cliAgents.commandLabel","settings.cliAgents.commandHelp","settings.cliAgents.extraArgsLabel","settings.cliAgents.extraArgsHelp","settings.cliAgents.envLabel","settings.cliAgents.envHelp","settings.cliAgents.autonomyLabel","settings.cliAgents.autonomyHelp","settings.cliAgents.approvedNote"]},{id:"agent-permissions",label:"Agents & Permissions",labelKey:"settings.nav.agentPermissions",scope:"project",searchableText:["agent provisioning","approval","permissions","policy","agent creation"]},{id:"prompts",label:"Prompts",labelKey:"settings.nav.prompts",scope:"project",searchableText:["prompt instructions","PR title prompt","PR description prompt","custom prompts"]},{id:"memory",label:"Memory",labelKey:"settings.nav.memory",scope:"project",searchableText:["memory backend","Dreams","long-term memory","qmd","memory file","retrieval"]},{id:"research-global",label:"Research · Global",labelKey:"settings.nav.researchGlobal",scope:"global",searchableText:["research providers","external search providers","fetch limits","global research defaults","citations"]},{id:"research-project",label:"Research · Project",labelKey:"settings.nav.researchProject",scope:"project",searchableText:["project research","research runs","citations","search limits","fetch synthesis"]},{id:"__automation_header",label:"Automation",labelKey:"settings.nav.automationHeader",scope:void 0,isGroupHeader:!0},{id:"scheduling-global",label:"Scheduling · Global",labelKey:"settings.nav.schedulingGlobal",scope:"global",searchableText:["global max concurrent","concurrency cap","all projects","machine wide","parallel agents","scheduler"]},{id:"scheduling",label:"Scheduling · Project",labelKey:"settings.nav.scheduling",scope:"project",searchableText:["max concurrent","capacity","stuck tasks","poll interval","parallel steps","scheduler"]},{id:"scheduled-evals",label:"Scheduled Evals",labelKey:"settings.nav.scheduledEvals",scope:"project",searchableText:["scheduled evals","evaluation schedule","eval runs","quality jobs"]},{id:"__integrations_header",label:"Integrations",labelKey:"settings.nav.integrationsHeader",scope:void 0,isGroupHeader:!0},{id:"source-control-global",label:"Source Control · Global",labelKey:"settings.nav.sourceControlGlobal",scope:"global",icon:Al,searchableText:["GitLab instance URL","global tracking repo","GitLab","GitHub","global GitLab token","GitLab fallback","source control","forge"]},{id:"source-control",label:"Source Control · Project",labelKey:"settings.nav.sourceControl",scope:"project",icon:Al,searchableText:["GitHub tracking","GitLab integration","GitHub auth mode","GitLab access token","GitHub personal access token","tracking repo","source control","forge","gh cli","issue tracking"]},{id:"global-mcp",label:"MCP Servers · Global",labelKey:"settings.nav.globalMcp",scope:"global",searchableText:["global MCP servers","shared MCP","user MCP","tool servers"]},{id:"mcp",label:"MCP Servers · Project",labelKey:"settings.nav.mcp",scope:"project",searchableText:["project MCP servers","workspace MCP","project tool servers","mcp config"]},{id:"plugins",label:"Plugins",labelKey:"settings.nav.plugins",scope:"project",searchableText:["Fusion plugins","Pi extensions","plugin manager","extension marketplace"]},{id:"hermes-runtime",label:"Hermes",labelKey:"settings.nav.hermesRuntime",scope:"global",searchableText:["Hermes runtime","plugin runtime","printer runtime"]},{id:"openclaw-runtime",label:"OpenClaw",labelKey:"settings.nav.openclawRuntime",scope:"global",searchableText:["OpenClaw runtime","plugin runtime","open claw"]},{id:"paperclip-runtime",label:"Paperclip",labelKey:"settings.nav.paperclipRuntime",scope:"global",searchableText:["Paperclip runtime","plugin runtime"]},{id:"secrets",label:"Secrets",labelKey:"settings.nav.secrets",scope:"project",searchableText:["secrets","secret storage","environment","credentials"]},{id:"__infrastructure_header",label:"Infrastructure",labelKey:"settings.nav.infrastructureHeader",scope:void 0,isGroupHeader:!0},{id:"node-sync",label:"Node Sync",labelKey:"settings.nav.nodeSync",scope:"global",searchableText:["sync","node","distributed","heartbeat","coordination"]},{id:"node-routing",label:"Node Routing",labelKey:"settings.nav.nodeRouting",scope:"project",searchableText:["node routing","routing rules","node selection","execution nodes"]},{id:"remote",label:"Remote Access",labelKey:"settings.nav.remote",scope:"global",searchableText:["cloudflared","tunnel","QR","persistent token","remote URL"]},{id:"backups-global",label:"Database Backups",labelKey:"settings.backups.databaseBackups",scope:"global",searchableText:["database backup","restore","shared cluster"]},{id:"backups",label:"Memory Backups",labelKey:"settings.backups.memoryBackups",scope:"project",searchableText:["memory backup","memory snapshot"]},{id:"__advanced_header",label:"Advanced",labelKey:"settings.nav.advancedHeader",scope:void 0,isGroupHeader:!0},{id:"experimental",label:"Experimental Features",labelKey:"settings.nav.experimental",scope:"global",searchableText:["feature flags","experiments","research view","evals view","sandbox","subtask breakdown"]}],ch={insights:"Insights",memoryView:"Memory Editor",skillsView:"Skills View",nodesView:"Nodes View",devServerView:"Dev Server",todoView:"Todo List",researchView:"Research View",evalsView:"Evals View",qualityPlugin:"Quality Plugin",goalsView:"Goals View",subtaskBreakdown:"Subtask Breakdown",leftSidebarNav:"Left Sidebar Navigation",sandbox:"Sandbox (command isolation)",chatRooms:"Chat Rooms",agentOnboarding:"Planning-style Agent Onboarding",workflowInterpreterDualObserve:"Workflow Graph Engine — dual-observe parity (diagnostic)"},dh=new Set(["chatRooms","goalsView","insights","memoryView","remoteAccess","roadmap","rightDock","skillsView","todoView","workflowColumns","workflowGraphExecutor","workflowInterpreterDualObserve"]),Hr=new Set(["leftSidebarNav"]),Qs={devServer:"devServerView"};function jn(t){return Qs[t]??t}function pn(t,s){return t[s]===!0?!0:t[s]===!1?!1:Object.entries(Qs).some(([a,n])=>n===s&&t[a]===!0)?!0:Hr.has(s)}function uh(t,s){const a=jn(s);return Hr.has(a)&&t[a]===void 0?!0:pn(t,a)}function gh(t){if(!t)return{};const s={};for(const[a,n]of Object.entries(t))s[jn(a)]=n;for(const[a,n]of Object.entries(Qs))s[n]!==void 0&&!(a in s)&&(s[a]=null);return s}function ph(t){const s=new Set,a=[];for(const n of t??[]){const c=n.trim();!c||s.has(c)||(s.add(c),a.push(c))}return a}const ln="appearance";function hh({projectId:t,addToast:s}){const{t:a}=te("app"),{confirm:n}=xr(),[c,d]=o.useState([]),[i,u]=o.useState({}),[l,h]=o.useState({}),[p,b]=o.useState("");o.useEffect(()=>{let S=!1;return(async()=>{try{const[C,y]=await Promise.all([fetch("/api/cli-agents"),fetch("/api/cli-agents/settings")]),k=C.ok?await C.json():{adapters:[]},R=y.ok?await y.json():{cliAgents:{}};if(S)return;const P=k.adapters??[];d(P),u(R.cliAgents??{}),P.length>0&&b(N=>N||P[0].id)}catch{}})(),()=>{S=!0}},[]),o.useEffect(()=>{if(!p)return;let S=!1;return fetch(`/api/cli-agents/${p}/autonomy`).then(C=>C.ok?C.json():null).then(C=>{S||!C||h(y=>({...y,[p]:!!C.approved}))}).catch(()=>{}),()=>{S=!0}},[p]);const w=i[p]??{},x=o.useCallback(async(S,C)=>{try{const y=await fetch("/api/cli-agents/settings",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({adapterId:S,config:C})});if(!y.ok)throw new Error(`HTTP ${y.status}`);const k=await y.json();u(k.cliAgents??{})}catch(y){s(xe(y)||a("settings.cliAgents.saveFailed"),"error")}},[s,a]),f=o.useCallback(S=>{if(!p)return;const C={...w,...S};u(y=>({...y,[p]:C})),x(p,C)},[p,w,x]),D=o.useCallback(async S=>{if(p){if(S==="elevated"){if(!await n({title:a("settings.cliAgents.elevatedConfirmTitle"),message:a("settings.cliAgents.elevatedConfirmBody"),confirmLabel:a("settings.cliAgents.elevatedConfirmAction"),danger:!0}))return;try{const y=await fetch(`/api/cli-agents/${p}/approve-autonomy`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({confirm:!0})});if(!y.ok)throw new Error(`HTTP ${y.status}`);h(k=>({...k,[p]:!0}))}catch(y){s(xe(y)||a("settings.cliAgents.approveFailed"),"error");return}}f({autonomyMode:S})}},[p,n,a,s,f]);return e.jsxs("div",{"data-testid":"cli-agents-settings",children:[e.jsx("h4",{className:"settings-section-heading",children:a("settings.cliAgents.heading")}),e.jsx("p",{className:"settings-section-description",children:a("settings.cliAgents.description")}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentAdapter",children:a("settings.cliAgents.adapterLabel")}),e.jsx("select",{id:"cliAgentAdapter",value:p,onChange:S=>b(S.target.value),children:c.map(S=>e.jsxs("option",{value:S.id,children:[S.name," (",a(`settings.cliAgents.tier.${S.tier}`),")"]},S.id))})]}),p&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentCommand",children:a("settings.cliAgents.commandLabel")}),e.jsx("input",{id:"cliAgentCommand",type:"text",placeholder:c.find(S=>S.id===p)?.defaultCommand??"",value:w.commandOverride??"",onChange:S=>f({commandOverride:S.target.value||void 0})}),e.jsx("p",{className:"settings-field-help",children:a("settings.cliAgents.commandHelp")})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentExtraArgs",children:a("settings.cliAgents.extraArgsLabel")}),e.jsx("input",{id:"cliAgentExtraArgs",type:"text",value:(w.extraArgs??[]).join(" "),onChange:S=>f({extraArgs:S.target.value.split(/\s+/).filter(C=>C.length>0)})}),e.jsx("p",{className:"settings-field-help",children:a("settings.cliAgents.extraArgsHelp")})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentEnv",children:a("settings.cliAgents.envLabel")}),e.jsx("input",{id:"cliAgentEnv",type:"text",value:(w.envAdditions??[]).join(", "),onChange:S=>f({envAdditions:S.target.value.split(",").map(C=>C.trim()).filter(C=>C.length>0)})}),e.jsx("p",{className:"settings-field-help",children:a("settings.cliAgents.envHelp")})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"cliAgentAutonomy",children:a("settings.cliAgents.autonomyLabel")}),e.jsxs("select",{id:"cliAgentAutonomy",value:w.autonomyMode??"default",onChange:S=>void D(S.target.value),children:[e.jsx("option",{value:"default",children:a("settings.cliAgents.autonomy.default")}),e.jsx("option",{value:"elevated",children:a("settings.cliAgents.autonomy.elevated")})]}),e.jsx("p",{className:"settings-field-help",children:l[p]?a("settings.cliAgents.approvedNote"):a("settings.cliAgents.autonomyHelp")})]})]})]})}function mh({onClose:t,addToast:s,projectId:a,initialSection:n,themeMode:c="system",colorTheme:d="shadcn-ember",onThemeModeChange:i,onColorThemeChange:u,dashboardFontScalePct:l=100,shadcnCustomColors:h={},resolvedThemeMode:p,onDashboardFontScaleChange:b,onShadcnCustomColorsChange:w,onQuickChatButtonModeChange:x,onMobileNavPrimaryItemsChange:f,onReopenOnboarding:D,onOpenApprovals:S,onOpenWorkflowSettings:C,presentation:y="modal"}){const{isEmbedded:k,scrollLockEnabled:R,resizePersistEnabled:P,escapeEnabled:N,overlayDismissEnabled:U}=Bd(y),{t:m}=te("app"),{confirm:Y}=xr(),E=ld();rd(R);const{keyboardOverlap:L,viewportHeight:G,viewportOffsetTop:K,keyboardOpen:z}=id({enabled:E==="mobile"}),ne=z?{"--keyboard-overlap":`${L}px`,"--vv-offset-top":`${K}px`,...G!==null?{"--vv-height":`${G}px`}:{}}:{},re=o.useRef(null),ce=o.useRef(null),T=o.useRef(null),$=o.useCallback(r=>{r&&(T.current=r)},[]);od(re,P,"fusion:settings-modal-size");const ge=cd(),[O,X]=o.useState({maxConcurrent:2,maxConcurrentVerifications:1,maxTriageConcurrent:2,maxWorktrees:4,pollIntervalMs:15e3,heartbeatMultiplier:1,groupOverlappingFiles:!0,ignoreHiddenOverlapPaths:!0,overlapIgnorePaths:[],allowAbsoluteFileBrowserPaths:!1,autoMerge:!0,planApprovalMode:"auto-approve-all",mergeStrategy:"direct",maxAutoMergeRetries:3,executorToolFailureRetryCount:2,executorToolFailureRetryBackoffMs:2e3,executorToolFailureThreshold:3,executorModelEscalationEnabled:!1,executorEscalationProvider:"",executorEscalationModelId:"",executorEscalationNodeId:"",mergeIntegrationWorktree:"reuse-task-worktree",mergeAdvanceAutoSync:"stash-and-ff",merger:{mode:"ai",maxReviewPasses:3,allowDirtyLocalCheckoutSync:!0},recycleWorktrees:!1,showWorktreeGrouping:!1,openTasksInRightSidebar:!1,openMobileTasksInPopup:!1,taskPopupsBoardListOnly:!0,showCostBadgeOnCards:!1,taskDetailChatFirst:!1,executorAllowSiblingBranchRename:!1,worktreeNaming:"random",worktreeCopyFiles:[],worktreesDir:"",worktrunk:{enabled:!1,binaryPath:"",onFailure:"fail"},includeTaskIdInCommit:!0,worktreeInitCommand:"",ntfyEnabled:!1,agentClarificationEnabled:!1,ntfyTopic:void 0,ntfyAccessToken:void 0,failureNotificationMode:"sticky-only",failureNotificationDelayMs:3e4,webhookEnabled:!1,webhookUrl:void 0,webhookFormat:"generic",webhookEvents:void 0,githubLinkImportedIssuesToTracking:!1,prTitlePromptInstructions:"",prDescriptionPromptInstructions:""}),[me,I]=o.useState(!0),[we,je]=o.useState(!1),[Ke,F]=o.useState(null),[_,ie]=o.useState(null),[be,ve]=o.useState(null),[le,V]=o.useState(null),pe=o.useCallback(r=>({...O,mcpServers:Lt(r,_)}),[O,_]),Ce=o.useCallback(r=>g=>{ie(j=>{if(!j)return j;const H={...O,mcpServers:Lt(r,j)},Q=typeof g=="function"?g(H):g;return r==="global"?{...j,global:{...j.global,mcpServers:Q.mcpServers}}:{...j,project:{...j.project,mcpServers:Q.mcpServers}}})},[O]),A=nn.find(r=>!r.isGroupHeader),[M,W]=o.useState(()=>n==="pi-extensions"?"plugins":n??ln),Z=mp(a,{enabled:M==="worktrees"||O.worktrunk?.enabled===!0}),oe=Z.status==="installed",[fe,he]=o.useState(()=>n==="pi-extensions"?"pi-extensions":"fusion-plugins"),[Pe,et]=o.useState(null),Fe=o.useRef(!1),[_e,is]=o.useState(()=>E==="mobile"||(typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia(gr)?.matches===!0:!1)),[Be,Js]=o.useState(()=>sh()),St=o.useRef(null),[Nt,tt]=o.useState(""),[ct,os]=o.useState(()=>{const r=n==="pi-extensions"?"plugins":n;return th()||r!==void 0&&pr.has(r)}),cs=o.useCallback(r=>{os(r);try{localStorage.setItem(Fr,String(r))}catch{}},[]),vt=o.useCallback(r=>{const g=Br(r);Js(g);try{localStorage.setItem(Dr,String(g))}catch{}return g},[]),[Xs,Zs]=o.useState(!1),[We,v]=o.useState(null),[q,J]=o.useState(!1),[ae,Ne]=o.useState(null),[De,Ge]=o.useState(!1),[st,dt]=o.useState(null),[Bt,ds]=o.useState(),[Gt,us]=o.useState(!1),[wn,ea]=o.useState(!1),[ta,Ht]=o.useState(null),_t=Xp(),[_r,Wr]=Qp(),[sa,Ur]=o.useState(null),[$r,Wt]=o.useState(null),[Ue,aa]=o.useState(null),[Cn,Sn]=o.useState(!1),[$e,na]=o.useState(null),[Ut,gs]=o.useState(!1),[at,ps]=o.useState(!1),{entries:zr,currentPath:nt,setPath:la,loading:qr,error:Vr,refresh:Yr}=_a("project",Ue!==null,a,{allowAbsolutePaths:!1}),{entries:Qr,currentPath:lt,setPath:ra,loading:Jr,error:Xr,refresh:Zr}=_a("project",Cn,a,{allowAbsolutePaths:!1}),{entries:ei,currentPath:ia,setPath:oa,loading:ti,error:si,refresh:ai}=_a("project",$e!==null,a,{allowAbsolutePaths:!1}),{nodes:ni}=dd(),Nn=O.experimentalFeatures??{},hs=pn(Nn,"researchView"),ms=pn(Nn,"evalsView"),ze=o.useMemo(()=>ah(nn.filter(r=>!ct&&pr.has(r.id)?!1:r.id==="research-global"||r.id==="research-project"?hs:r.id==="scheduled-evals"?ms:!0)),[hs,ms,ct]),$t=ze.some(r=>r.id===ln)?ln:hr(ze,A?.id??"general"),Pt=Gr(Nt),ut=o.useMemo(()=>{if(!Pt)return[];const r=new Set(ze.map(g=>g.id));return zp(Kp.filter(g=>r.has(g.sectionId)),Pt,(g,j)=>m(g,j))},[Pt,m,ze]),Pn=o.useMemo(()=>qp(ut),[ut]),gt=o.useMemo(()=>lh(ze,Pt,r=>m(r.labelKey,r.label),r=>m(r),Pn),[Pt,m,ze,Pn]),Tn=gt.filter(r=>!r.isGroupHeader),zt=Pt.length>0,qt=Tn.length>0,An=E==="mobile",bs=!An||Xs,Mn=hr(gt,$t),li=o.useCallback((r,g)=>{Fe.current=!0,W(r),et(g)},[]);o.useEffect(()=>{if(Fe.current){Fe.current=!1;return}ce.current&&(ce.current.scrollTop=0)},[M]),o.useEffect(()=>{if(!Pe)return;const r=ce.current;if(!r)return;const g=r.querySelector(`[data-settings-key="${CSS.escape(Pe)}"]`);if(!g)return;for(let H=g.parentElement;H;H=H.parentElement)H instanceof HTMLDetailsElement&&(H.open=!0);g.scrollIntoView({block:"center",behavior:eh()});const j=window.setTimeout(()=>et(null),Zp);return()=>window.clearTimeout(j)},[Pe,M]);const ca=ze.find(r=>r.id===M)?.scope;o.useEffect(()=>{if((M==="research-global"||M==="research-project")&&!hs){W($t);return}if(M==="scheduled-evals"&&!ms){W($t);return}if(!ze.some(r=>r.id===M)){W($t);return}zt&&qt&&!gt.some(r=>r.id===M)&&W(Mn)},[M,hs,ms,$t,Mn,zt,qt,gt,ze]);const[pt,da]=o.useState([]),[ri,In]=o.useState(!1),[ii,Le]=o.useState(null),[oi,ua]=o.useState({}),[ci,Rn]=o.useState({}),[ga,En]=o.useState({}),[pa,ha]=o.useState({}),[di,ma]=o.useState(null),[ba,fa]=o.useState({}),[ui,fs]=o.useState({}),[gi,Vt]=o.useState({}),Ie=o.useRef(null),Yt=o.useRef({}),[Fn,Dn]=o.useState([]),[Ln,On]=o.useState(!1),[Tt,ya]=o.useState([]),[At,ka]=o.useState([]),[pi,Kn]=o.useState({}),[hi,ys]=o.useState({}),[Qt,Bn]=o.useState(null),[rt,Gn]=o.useState(null),[mi,va]=o.useState(null),[bi,ks]=o.useState(!1),[qe,vs]=o.useState(null),[xa,ja]=o.useState(null),[fi,Hn]=o.useState(null),[yi,_n]=o.useState(!1),[ki,wa]=o.useState(null),[vi,xi]=o.useState("persistent"),[ji,wi]=o.useState(null),[Ci,Si]=o.useState(null),[Ni,Pi]=o.useState(null),[Ti,Mt]=o.useState(null),[Ca,xs]=o.useState(""),[Ai,Wn]=o.useState(!1),[Sa,js]=o.useState(!1),[Un,ws]=o.useState([]),[Mi,$n]=o.useState([]),[Ii,Ri]=o.useState(!1),[Ei,zn]=o.useState([]),[Fi,qn]=o.useState(!1),[Di,Vn]=o.useState(null),[Li,Yn]=o.useState([]),[Oi,Qn]=o.useState(!1),[Ki,Na]=o.useState(null),Pa=o.useRef(!1),[Bi,Jn]=o.useState([]),[Ve,Ta]=o.useState(sn),[Aa,Gi]=o.useState(""),[Hi,Xn]=o.useState(!1),[_i,Zn]=o.useState(null),[Wi,el]=o.useState(!1),[Ui,tl]=o.useState(!1),[$i,sl]=o.useState(!1),Ma=o.useRef(!1),[Cs,al]=o.useState(4),nl=o.useRef(4),ll=o.useRef(!1),Ss=o.useRef(!1),[rl,il]=o.useState(!1),[zi,Jt]=o.useState(!1),[,Ia]=o.useState(null),[Ye,ol]=o.useState(null),[Ns,Ps]=o.useState(!1),[Ra,qi]=o.useState("both"),[Ea,Vi]=o.useState(!0),cl=o.useRef(null),{status:Yi,capabilities:Qi,loading:Ji,error:Xi,refresh:dl}=Jd({projectId:a,enabled:M==="memory"}),ht=!_e,Zi=ht?{"--settings-nav-width":`${Be}px`}:void 0,Xt=o.useCallback((r,g)=>{const j=St.current;if(j&&(document.body.style.userSelect=j.previousUserSelect,St.current=null,typeof r=="number"&&g instanceof HTMLElement&&typeof g.releasePointerCapture=="function"))try{g.releasePointerCapture(r)}catch{}},[]),Fa=o.useCallback(r=>{const g=St.current;g&&(r.preventDefault(),vt(g.startWidth+r.clientX-g.startX))},[vt]),Zt=o.useCallback(r=>{Xt(r.pointerId,r.target)},[Xt]),eo=o.useCallback(r=>{ht&&(r.preventDefault(),r.stopPropagation(),typeof r.currentTarget.setPointerCapture=="function"&&r.currentTarget.setPointerCapture(r.pointerId),St.current={startX:r.clientX,startWidth:Be,previousUserSelect:document.body.style.userSelect},document.body.style.userSelect="none")},[ht,Be]),to=o.useCallback(r=>{ht&&(r.key!=="ArrowLeft"&&r.key!=="ArrowRight"||(r.preventDefault(),vt(Be+(r.key==="ArrowRight"?16:-16))))},[vt,ht,Be]);o.useEffect(()=>{if(!ht){Xt();return}return document.addEventListener("pointermove",Fa),document.addEventListener("pointerup",Zt),document.addEventListener("pointercancel",Zt),()=>{document.removeEventListener("pointermove",Fa),document.removeEventListener("pointerup",Zt),document.removeEventListener("pointercancel",Zt),Xt()}},[Xt,Fa,Zt,ht]),o.useEffect(()=>{if(typeof window>"u"||typeof window.matchMedia!="function")return;const r=window.matchMedia(gr);if(!r)return;const g=j=>{is(E==="mobile"||(j?j.matches:r.matches))};return g(),r.addEventListener("change",g),()=>r.removeEventListener("change",g)},[E]);const es=o.useCallback(r=>Promise.all([Ml(a),ud(a)]).then(([g,j])=>{const H={...g,ignoreHiddenOverlapPaths:g.ignoreHiddenOverlapPaths??!0,allowAbsoluteFileBrowserPaths:g.allowAbsoluteFileBrowserPaths===!0,showCostBadgeOnCards:g.showCostBadgeOnCards===!0,taskDetailChatFirst:g.taskDetailChatFirst===!0,githubLinkImportedIssuesToTracking:g.githubLinkImportedIssuesToTracking===!0,mergeIntegrationWorktree:zl(g.mergeIntegrationWorktree),mergeAdvanceAutoSync:ql(g.mergeAdvanceAutoSync),maxAutoMergeRetries:mr(g),executorToolFailureRetryCount:Hs(g.executorToolFailureRetryCount,2),executorToolFailureRetryBackoffMs:Hs(g.executorToolFailureRetryBackoffMs,2e3),executorToolFailureThreshold:Math.max(1,Math.floor(Number(g.executorToolFailureThreshold??3)||3)),executorModelEscalationEnabled:g.executorModelEscalationEnabled===!0,executorEscalationProvider:g.executorEscalationProvider??"",executorEscalationModelId:g.executorEscalationModelId??"",executorEscalationNodeId:g.executorEscalationNodeId??"",worktreeCopyFiles:Array.isArray(g.worktreeCopyFiles)?g.worktreeCopyFiles:[]};X(H),F(H),ie(j),ve({gitlabEnabled:j.global.gitlabEnabled,gitlabInstanceUrl:j.global.gitlabInstanceUrl,gitlabApiBaseUrl:j.global.gitlabApiBaseUrl,gitlabAuthToken:j.global.gitlabAuthToken,gitlabAuthTokenType:j.global.gitlabAuthTokenType}),V({...j,project:{...j.project,mergeIntegrationWorktree:j.project.mergeIntegrationWorktree===void 0?void 0:zl(j.project.mergeIntegrationWorktree),mergeAdvanceAutoSync:j.project.mergeAdvanceAutoSync===void 0?void 0:ql(j.project.mergeAdvanceAutoSync)}}),r&&I(!1)}).catch(g=>{s(xe(g),"error"),r&&I(!1)}),[s,a]);o.useEffect(()=>{es(!0)},[s,a]),o.useEffect(()=>{if(M!=="scheduling"&&M!=="scheduling-global"||ll.current)return;let r=!1;return gd().then(g=>{r||(Ss.current||al(g.globalMaxConcurrent),nl.current=g.globalMaxConcurrent,ll.current=!0,il(!0))}).catch(()=>{il(!0)}),()=>{r=!0}},[M]),o.useEffect(()=>{let r=!1;return pd().then(g=>{r||typeof g.version=="string"&&g.version.trim().length>0&&v(g.version)}).catch(()=>{}),()=>{r=!0}},[]);const so=o.useCallback(async()=>{J(!0),dt(null),ds(void 0),us(!1),ea(!1),Ht(null);try{const r=await hd();Ne(r),r.error&&s(r.error,"error")}catch(r){const g=xe(r)||m("settings.general.updateCheckFailed","Failed to check for updates");Ne({currentVersion:We??"unknown",latestVersion:null,updateAvailable:!1,error:g}),s(g,"error")}finally{J(!1)}},[s,We,m]),ul=o.useCallback(async()=>{Ge(!0),dt(null),us(!1),ea(!1),Ht(null);try{const r=await md(a);if(dt(r),r.error){s(r.error,"error");return}r.updated&&s(m("settings.general.updateSuccessToast","Update installed. Restart Fusion to apply it."),"success")}catch(r){const g=xe(r)||m("settings.general.updateFailed","Update failed");dt({currentVersion:ae?.currentVersion??We??"unknown",latestVersion:ae?.latestVersion??null,updated:!1,error:g}),s(g,"error")}finally{Ge(!1)}},[s,We,a,m,ae]);o.useEffect(()=>{if(!ae?.updateAvailable&&st?.updated!==!0)return;let r=!1;return ds(void 0),bd().then(g=>{r||ds(g.restartSupported)}).catch(()=>{r||ds(!1)}),()=>{r=!0}},[ae?.updateAvailable,st?.updated]);const gl=o.useCallback(async()=>{if(!(Gt||Bt!==!0)){us(!0),Ht(null);try{(await fd("settings-update")).scheduled?ea(!0):Ht(m("settings.general.restartFailed","Restart could not be scheduled. Try restarting Fusion manually."))}catch(r){Ht(xe(r)||m("settings.general.restartFailed","Restart could not be scheduled. Try restarting Fusion manually."))}finally{us(!1)}}},[Gt,Bt,m]),ao=o.useCallback(()=>{if(!ae)return null;if(ae.error)return ae.error;if(ae.updateAvailable&&ae.latestVersion){const r=st?.updated===!0,g=st?.error;return e.jsxs(e.Fragment,{children:[e.jsxs("span",{children:[m("settings.general.updateAvailablePrefix","v{{version}} available",{version:ae.latestVersion})," ·"," ",e.jsx("a",{href:"https://runfusion.ai",target:"_blank",rel:"noreferrer",className:"settings-update-result-link",children:m("settings.general.learnMore","Learn more")})]}),r?e.jsxs("span",{className:"settings-update-install-succeeded",children:[e.jsx("span",{className:"settings-update-install-status settings-update-install-status--success","aria-live":"polite",children:m("settings.general.updateSuccess","Updated to v{{version}} — restart Fusion to apply",{version:st.latestVersion??ae.latestVersion})}),wn?e.jsx("span",{className:"settings-update-install-status","aria-live":"polite",children:m("settings.general.restarting","Restarting… Your connection will close shortly.")}):e.jsx("button",{type:"button",className:"btn btn-sm settings-update-now-btn",onClick:()=>{gl()},disabled:Bt!==!0||Gt,children:Gt?e.jsxs(e.Fragment,{children:[e.jsx(rs,{size:12,className:"spinning","aria-hidden":"true"}),m("settings.general.restarting","Restarting…")]}):e.jsxs(e.Fragment,{children:[e.jsx(yd,{size:12,"aria-hidden":"true"}),m("settings.general.restartNow","Restart Fusion")]})}),Bt!==!0&&e.jsx("span",{className:"settings-update-install-status","aria-live":"polite",children:m("settings.general.restartUnavailable","Needs a supervising parent — restart Fusion manually without --no-supervise.")}),ta&&e.jsx("span",{className:"settings-update-install-status settings-update-install-status--error","aria-live":"polite",children:ta})]}):e.jsx("button",{type:"button",className:"btn btn-sm settings-update-now-btn",onClick:()=>{ul()},disabled:De,children:De?e.jsxs(e.Fragment,{children:[e.jsx(rs,{size:12,className:"spinning","aria-hidden":"true"}),m("settings.general.updating","Updating…")]}):m("settings.general.updateNow","Update now")}),g&&e.jsx("span",{className:"settings-update-install-status settings-update-install-status--error","aria-live":"polite",children:m("settings.general.updateFailedWithMessage","Update failed: {{message}}",{message:g})})]})}return m("settings.general.upToDate","You're up to date ✓")},[ul,gl,ta,Gt,wn,Bt,m,ae,De,st]),Te=o.useCallback(async()=>{try{const{providers:r}=await Il(),g=Rl(r);da(g),ua(j=>{const H={};for(const[Q,ee]of Object.entries(j)){const ue=g.find(Se=>Se.id===Q);ue&&!ue.authenticated&&(H[Q]=ee)}return Object.keys(H).length===Object.keys(j).length?j:H})}catch{}},[]);o.useEffect(()=>{(M==="global-models"||M==="project-models")&&(On(!0),kd().then(r=>{Dn(r.models),ya(r.favoriteProviders),ka(r.favoriteModels)}).catch(()=>Dn([])).finally(()=>On(!1)))},[M]),o.useEffect(()=>{M==="backups"&&(ks(!0),El(a).then(r=>va(r)).catch(()=>va(null)).finally(()=>ks(!1)))},[M,a]);const Ts=o.useCallback(async()=>{const[r,g]=await Promise.allSettled([bu(a),za(a)]);r.status==="fulfilled"&&X(j=>({...j,...r.value.settings})),g.status==="fulfilled"&&(vs(g.value),ja(g.value.externalTunnel??null))},[a]);o.useEffect(()=>{const r=qe?.state;(r==="running"||r==="starting")&&ja(null)},[qe?.state]),o.useEffect(()=>{M==="remote"&&Ts().catch(()=>{vs(null)})},[M,Ts]),o.useEffect(()=>{if(M!=="remote")return;const r=qe?.state;if(r!=="starting"&&r!=="stopping")return;const g=setInterval(()=>{za(a).then(j=>{vs(j),ja(j.externalTunnel??null)}).catch(()=>{})},1e3);return()=>clearInterval(g)},[M,a,qe?.state]),o.useEffect(()=>{if(M!=="remote")return;if(qe?.state!=="running"){Mt(null);return}let r=!1;return(async()=>{try{const g=await gn("image/svg",{projectId:a,tokenType:"persistent"});if(r)return;Mt({url:g.url,qrSvg:g.data??null})}catch{if(r)return;try{const g=await Cr({projectId:a,tokenType:"persistent"});if(r)return;Mt({url:g.url,qrSvg:null})}catch{r||Mt(null)}}})(),()=>{r=!0}},[M,a,qe?.state,qe?.url]),o.useEffect(()=>{if(M!=="remote")return;const r=xa?.url;if(qe?.state!=="stopped"||!r)return;let g=!1;return(async()=>{try{const j=await gn("image/svg",{projectId:a,tokenType:"persistent"});if(g)return;Mt({url:r,qrSvg:j.data??null})}catch{g||Mt({url:r,qrSvg:null})}})(),()=>{g=!0}},[M,xa?.url,a,qe?.state]),o.useEffect(()=>{M==="worktrees"&&Fl(a).then(r=>ws(r)).catch(()=>ws([]))},[M,a]),o.useEffect(()=>{M==="merge"&&(Fl(a).then(r=>ws(r)).catch(()=>ws([])),vd(a).then(r=>{const g=r.map(ee=>ee.name).filter(ee=>typeof ee=="string"&&ee.length>0),j=new Set,H=["main","master","trunk","develop"],Q=[];for(const ee of H)g.includes(ee)&&!j.has(ee)&&(Q.push(ee),j.add(ee));for(const ee of[...g].sort((ue,Se)=>ue.localeCompare(Se)))j.has(ee)||(j.add(ee),Q.push(ee));$n(Q)}).catch(()=>$n([])))},[M,a]),o.useEffect(()=>{if(M!=="source-control")return;let r=!1;return qn(!0),Vn(null),Dl(a).then(g=>{r||zn(Yp(g))}).catch(()=>{r||(zn([]),Vn("Could not load detected remotes. Enter a custom owner/repo value."))}).finally(()=>{r||qn(!1)}),()=>{r=!0}},[M,a]),o.useEffect(()=>{if(M!=="source-control-global"||Pa.current)return;let r=!1;return Qn(!0),Na(null),xd().then(async g=>{const j=await Promise.allSettled(g.map(async ue=>(await Dl(ue.id)).map(Ae=>({value:`${Ae.owner}/${Ae.repo}`,label:`${Ae.owner}/${Ae.repo}`,source:ue.name}))));if(r)return;const H=new Map;let Q=0;for(const ue of j)if(ue.status==="fulfilled"){Q+=1;for(const Se of ue.value)H.has(Se.value)||H.set(Se.value,Se)}const ee=[...H.values()].sort((ue,Se)=>ue.value.localeCompare(Se.value));Yn(ee),g.length>0&&Q===0&&Na("Could not load remotes from registered projects. Enter a custom owner/repo value."),Pa.current=!0}).catch(()=>{r||(Yn([]),Na("Could not load project list. Enter a custom owner/repo value."),Pa.current=!0)}).finally(()=>{r||Qn(!1)}),()=>{r=!0}},[M,a]),o.useEffect(()=>{if(M!=="memory"||Sa)return;if(Ma.current){Ma.current=!1;return}let r=!1;return Wn(!0),Ol(a).then(async({files:g})=>{if(r)return;Jn(g);const j=g.some(Q=>Q.path===Ve)?Ve:g.find(Q=>Q.path===sn)?.path??g.find(Q=>Q.layer==="dreams")?.path??g[0]?.path??sn;Ta(j);const{content:H}=await Xd(j,a);r||(xs(H),js(!1))}).catch(g=>{r||(s(xe(g)||"Failed to load project memory","error"),xs(""))}).finally(()=>{r||Wn(!1)}),()=>{r=!0}},[M,Sa,Ve,a,s]),o.useEffect(()=>((M==="authentication"||M==="research-global")&&(In(!0),Te().finally(()=>In(!1))),()=>{Ie.current&&(clearInterval(Ie.current),Ie.current=null)}),[M,Te]),o.useEffect(()=>{if(M!=="authentication"||!pt.some(j=>j.type!=="api_key"&&j.loginInProgress))return;const g=setInterval(()=>{Te()},2e3);return()=>clearInterval(g)},[M,pt,Te]);const As=o.useRef({});o.useEffect(()=>{for(const r of pt){const g=r.loginError;if(!g){r.id in As.current&&delete As.current[r.id];continue}As.current[r.id]!==g&&(As.current[r.id]=g,s(`${r.name} login failed: ${g}`,"error"))}},[pt,s]);const Ms=o.useCallback(()=>{ce.current?.scrollTo({top:0,behavior:"smooth"})},[]),xt=o.useCallback(r=>{if(r in Yt.current){const g={...Yt.current};delete g[r],Yt.current=g}ua(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j}),Rn(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j}),ha(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j}),En(g=>{if(!(r in g))return g;const j={...g};return delete j[r],j})},[]);o.useEffect(()=>{const r=ga["github-copilot"];r?.userCode&&Yt.current["github-copilot"]!==r.userCode&&(Yt.current["github-copilot"]=r.userCode,mn(r.userCode))},[ga]);const no=o.useCallback(async r=>{const g=pt.find(j=>j.id===r);if(!(g?.requiresManualCode===!0&&!await Y({title:m("settings.auth.manualPasteTitle","Heads up — manual paste-back required"),message:m("settings.auth.manualPasteMessage","After you sign in with {{name}}, the browser will try to redirect to a localhost address that this dashboard can't reach. The redirect tab will look like it failed. Before that happens, copy the full URL from the browser address bar — you'll paste it back here to finish login. Continue?",{name:g.name}),confirmLabel:m("settings.auth.continueToLogin","Continue to login"),cancelLabel:m("settings.actions.cancel","Cancel")}))){Le(r),xt(r);try{const{url:j,instructions:H,manualCode:Q,deviceCode:ee}=await jd(r);H?.trim()&&!(r==="github-copilot"&&ee)&&ua(ue=>({...ue,[r]:H})),Q&&Rn(ue=>({...ue,[r]:Q})),ee&&r==="github-copilot"&&En(ue=>({...ue,[r]:ee})),(r!=="github-copilot"||!ee)&&window.open(kr(ee?.verificationUri??j),"_blank"),Ie.current=setInterval(async()=>{try{const{providers:ue}=await Il(),Se=Rl(ue);da(Se);const Ae=Se.find(Ga=>Ga.id===r);if(Ae?.authenticated){Ie.current&&(clearInterval(Ie.current),Ie.current=null),Le(null),xt(r),s(m("settings.auth.loginSuccessful","Login successful"),"success"),window.dispatchEvent(new CustomEvent(wd,{detail:{providerId:r}})),Ms();return}Ae?.loginInProgress||(Ie.current&&(clearInterval(Ie.current),Ie.current=null),Le(null),xt(r),s(m("settings.auth.loginDidNotComplete","Login did not complete. Please try again."),"error"))}catch{}},2e3)}catch(j){const H=xe(j)||"Login failed";H.includes("already in progress")||typeof j=="object"&&j!==null&&"status"in j&&j.status===409?(s(m("settings.auth.loginAlreadyInProgress","Login already in progress. You can cancel it and retry."),"warning"),await Te()):s(H,"error"),Le(null),xt(r)}}},[s,pt,xt,Y,Te,Ms]),lo=o.useCallback(async r=>{const g=pa[r]?.trim();if(!g){s(m("settings.auth.pasteRedirectUrlFirst","Paste the full redirect URL or authorization code first."),"warning");return}ma(r);try{(await Cd(r,g)).submitted?(ha(H=>{if(!(r in H))return H;const Q={...H};return delete Q[r],Q}),s(m("settings.auth.authCodeReceived","Authorization code received. Finishing login…"),"success")):s(m("settings.auth.authCodeAlreadySubmitted","That authorization code was already submitted. Waiting for login…"),"warning")}catch(j){s(xe(j)||"Failed to submit authorization code","error")}finally{ma(null)}},[s,pa]),ro=o.useCallback(async r=>{Le(r),da(g=>g.map(j=>j.id===r?{...j,loginInProgress:!1}:j));try{await Sd(r),xt(r),await Te().catch(()=>{}),s(m("settings.auth.loginCancelled","Login cancelled"),"success")}catch(g){s(xe(g)||"Failed to cancel login","error")}finally{Le(null),ma(g=>g===r?null:g),Ie.current&&(clearInterval(Ie.current),Ie.current=null)}},[s,xt,Te]),io=o.useCallback(async r=>{Le(r);try{await Nd(r),await Te(),s(m("settings.auth.loggedOut","Logged out"),"success")}catch(g){s(xe(g)||"Logout failed","error")}finally{Le(null)}},[s,Te]),oo=o.useCallback(async r=>{const g=ba[r]?.trim();if(!g){fs(j=>({...j,[r]:"API key is required"}));return}Le(r),fs(j=>{const H={...j};return delete H[r],H});try{const j=await Pd(r,g);if(fa(H=>{const Q={...H};return delete Q[r],Q}),await Te(),r==="opencode"||r==="opencode-go"){const H=j.modelsRefreshed,Q=j.refreshReason,ee=j.refreshError;ee?Vt(ue=>({...ue,[r]:{tone:"error",message:`Saved, but model refresh failed: ${ee}. Make sure the \`opencode\` CLI is installed on PATH.`}})):Q==="no-models-from-cli"?Vt(ue=>({...ue,[r]:{tone:"error",message:"Saved. The local `opencode` CLI returned no models — run `opencode auth login` and `opencode models opencode --refresh`, then click Save again."}})):typeof H=="number"&&H>0?Vt(ue=>({...ue,[r]:{tone:"success",message:`Refreshed ${H} opencode-go models.`}})):Vt(ue=>{const Se={...ue};return delete Se[r],Se})}s(m("settings.auth.apiKeySaved","API key saved"),"success"),Ms()}catch(j){fs(H=>({...H,[r]:xe(j)||"Failed to save API key"})),(r==="opencode"||r==="opencode-go")&&Vt(H=>{const Q={...H};return delete Q[r],Q})}finally{Le(null)}},[ba,s,Te,Ms]),co=o.useCallback(async r=>{Le(r);try{await Td(r),fa(g=>{const j={...g};return delete j[r],j}),fs(g=>{const j={...g};return delete j[r],j}),await Te(),s(m("settings.auth.apiKeyCleared","API key cleared"),"success")}catch(g){s(xe(g)||"Failed to clear API key","error")}finally{Le(null)}},[s,Te]),uo=o.useCallback(async r=>{if(!((r==="ntfy"||r==="ntfy-message"||r==="ntfy-room")&&(!O.ntfyEnabled||!O.ntfyTopic||!/^[a-zA-Z0-9_-]{1,64}$/.test(O.ntfyTopic)))){if(r==="webhook"){if(!O.webhookEnabled||!O.webhookUrl?.trim())return;try{const g=new URL(O.webhookUrl.trim());if(g.protocol!=="http:"&&g.protocol!=="https:")return}catch{return}}Kn(g=>({...g,[r]:!0})),ys(g=>{const j={...g};return delete j[r],j});try{const g={ntfyEnabled:O.ntfyEnabled,ntfyTopic:O.ntfyTopic,...O.ntfyBaseUrl?.trim()?{ntfyBaseUrl:O.ntfyBaseUrl.trim()}:{},...O.ntfyAccessToken?.trim()?{ntfyAccessToken:O.ntfyAccessToken.trim()}:{}},j=r==="ntfy"?g:r==="ntfy-message"?{...g,messageEventType:"message:agent-to-user"}:r==="ntfy-room"?{...g,messageEventType:"message:room"}:{webhookUrl:O.webhookUrl,webhookFormat:O.webhookFormat||"generic"};if((await Ad(r==="ntfy-message"||r==="ntfy-room"?"ntfy":r,j,a)).success){const Q=r==="ntfy"?"Test notification sent — check your ntfy app!":r==="ntfy-message"?"Message inbox test sent — check your ntfy inbox for the agent-to-user message.":r==="ntfy-room"?"Room reply test sent — check your ntfy inbox for the room reply.":"Test notification sent — check your webhook endpoint!";ys(ee=>({...ee,[r]:{status:"success",message:Q}})),s(Q,"success")}else{const Q=r==="ntfy-message"?"Failed to send message inbox test":r==="ntfy-room"?"Failed to send room reply test":"Failed to send test notification";ys(ee=>({...ee,[r]:{status:"error",message:Q}})),s(Q,"error")}}catch(g){const j=xe(g)||"Failed to send test notification";ys(H=>({...H,[r]:{status:"error",message:j}})),s(j,"error")}finally{Kn(g=>({...g,[r]:!1}))}}},[s,O.ntfyAccessToken,O.ntfyBaseUrl,O.ntfyEnabled,O.ntfyTopic,O.webhookEnabled,O.webhookFormat,O.webhookUrl,a]),go=o.useCallback(async()=>{ks(!0);try{const r=await Md(a);if(r.success){s(m("settings.backups.backupCreated","Backup created successfully"),"success");const g=await El(a);va(g)}else s(r.error||m("settings.backups.createFailed","Failed to create backup"),"error")}catch(r){s(xe(r)||m("settings.backups.createFailed","Failed to create backup"),"error")}finally{ks(!1)}},[s,a]),po=o.useCallback(async()=>{try{const r=ca==="global"?"global":ca==="project"?"project":"both",g=await Id(r,a),j=new Blob([JSON.stringify(g,null,2)],{type:"application/json"}),H=URL.createObjectURL(j),Q=document.createElement("a"),ee=`fusion-settings-${new Date().toISOString().replace(/[:.]/g,"-").slice(0,19)}.json`;Q.href=H,Q.download=ee,document.body.appendChild(Q),Q.click(),document.body.removeChild(Q),URL.revokeObjectURL(H);const ue=r==="global"?m("settings.importExport.scopeLabel.global","global"):r==="project"?m("settings.importExport.scopeLabel.project","project"):m("settings.importExport.scopeLabel.all","all");s(m("settings.importExport.exported","Settings exported ({{scope}} scope)",{scope:ue}),"success")}catch(r){s(xe(r)||m("settings.importExport.exportFailed","Failed to export settings"),"error")}},[s,ca,a]),ho=o.useCallback(async r=>{const g=r.target.files?.[0];if(g){Ia(g),Ps(!0);try{const j=await g.text(),H=JSON.parse(j);ol(H),Jt(!0)}catch(j){s(m("settings.importExport.invalidJson","Invalid JSON file: {{error}}",{error:xe(j)}),"error"),Ia(null)}finally{Ps(!1)}}},[s]),mo=o.useCallback(async()=>{if(Ye){Ps(!0);try{const r=await Rd(Ye,{scope:Ra,merge:Ea},a);if(r.success){const g=[];r.globalCount>0&&g.push(m("settings.importExport.counts.global","{{count}} global",{count:r.globalCount})),r.projectCount>0&&g.push(m("settings.importExport.counts.project","{{count}} project",{count:r.projectCount})),r.workflowSettingsCount>0&&g.push(m("settings.importExport.counts.workflowSettings","{{count}} workflow setting value",{count:r.workflowSettingsCount})),s(m("settings.importExport.imported","Imported {{counts}} setting(s)",{counts:g.join(", ")}),"success"),Jt(!1),ol(null),Ia(null);const j=await Ml(a);X({...j,ignoreHiddenOverlapPaths:j.ignoreHiddenOverlapPaths??!0,allowAbsoluteFileBrowserPaths:j.allowAbsoluteFileBrowserPaths===!0})}else s(r.error||m("settings.importExport.importFailed","Import failed"),"error")}catch(r){s(xe(r)||m("settings.importExport.importFailedDetailed","Failed to import settings"),"error")}finally{Ps(!1)}}},[s,Ye,Ra,Ea,a]),pl=o.useCallback(async r=>{const g=Tt,H=g.includes(r)?g.filter(Q=>Q!==r):[r,...g];ya(H);try{await Dt({favoriteProviders:H,favoriteModels:At})}catch{ya(g)}},[Tt,At]),hl=o.useCallback(async r=>{const g=At,H=g.includes(r)?g.filter(Q=>Q!==r):[r,...g];ka(H);try{await Dt({favoriteProviders:Tt,favoriteModels:H})}catch{ka(g)}},[At,Tt]);o.useEffect(()=>{if(!N)return;const r=g=>{g.key==="Escape"&&!Ut&&t()};return document.addEventListener("keydown",r),()=>document.removeEventListener("keydown",r)},[t,N,Ut]);const bo=Ed(t),fo=U?bo:{},ml=[{laneId:"default",label:"Default Model",globalProviderKey:"defaultProvider",globalModelKey:"defaultModelId",projectProviderKey:"defaultProviderOverride",projectModelKey:"defaultModelIdOverride",projectThinkingKey:"defaultThinkingLevelOverride",helperText:"Default AI model used for task execution when no per-task override is set.",fallbackOrder:"Project override → Global default lane → Automatic resolution"},{laneId:"execution",label:"Execution Model",globalProviderKey:"executionGlobalProvider",globalModelKey:"executionGlobalModelId",globalThinkingKey:"executionGlobalThinkingLevel",projectProviderKey:"executionProvider",projectModelKey:"executionModelId",helperText:"AI model used for task implementation (executor agent).",fallbackOrder:"Project override → Global execution lane → Global default lane → Automatic resolution"},{laneId:"planning",label:"Planning Model",globalProviderKey:"planningGlobalProvider",globalModelKey:"planningGlobalModelId",globalThinkingKey:"planningGlobalThinkingLevel",projectProviderKey:"planningProvider",projectModelKey:"planningModelId",helperText:"AI model used for task planning.",fallbackOrder:"Project override → Global planning lane → Global default lane → Automatic resolution"},{laneId:"validator",label:"Reviewer Model",globalProviderKey:"validatorGlobalProvider",globalModelKey:"validatorGlobalModelId",globalThinkingKey:"validatorGlobalThinkingLevel",projectProviderKey:"validatorProvider",projectModelKey:"validatorModelId",helperText:"AI model used for code and specification review.",fallbackOrder:"Project override → Global reviewer lane → Global default lane → Automatic resolution"},{laneId:"merger",label:"Merger Model",globalProviderKey:"mergerGlobalProvider",globalModelKey:"mergerGlobalModelId",globalThinkingKey:"mergerGlobalThinkingLevel",projectProviderKey:"mergerProvider",projectModelKey:"mergerModelId",projectThinkingKey:"mergerThinkingLevel",helperText:"AI model used for merge conflict resolution, clean-room merge, stash-conflict recovery, and related merger agent sessions.",fallbackOrder:"Project override → Global merger lane → Project default lane → Global default lane → Automatic resolution"},{laneId:"summarization",label:"Title and Git Commit Message Summarization Model",globalProviderKey:"titleSummarizerGlobalProvider",globalModelKey:"titleSummarizerGlobalModelId",globalThinkingKey:"titleSummarizerGlobalThinkingLevel",projectProviderKey:"titleSummarizerProvider",projectModelKey:"titleSummarizerModelId",projectThinkingKey:"titleSummarizerThinkingLevel",helperText:"AI model used for auto-generating task titles and merge commit summaries.",fallbackOrder:"Project override → Global summarization lane → Project planning lane → Project default lane → Global default lane → Automatic resolution"},{laneId:"import-translate",label:"Import Auto-Translation Model",globalProviderKey:"importTranslateGlobalProvider",globalModelKey:"importTranslateGlobalModelId",globalThinkingKey:"importTranslateGlobalThinkingLevel",projectProviderKey:"importTranslateProvider",projectModelKey:"importTranslateModelId",projectThinkingKey:"importTranslateThinkingLevel",helperText:"AI model used to translate foreign-language GitHub/GitLab issue titles and bodies in the Import Tasks panel.",fallbackOrder:"Project override → Global import-translate lane → Summarization lane → Project default → Global default"}];function Da(r){if(!_?.project)return"inherited";const g=_.project[r.projectProviderKey],j=_.project[r.projectModelKey];return g!==void 0||j!==void 0?"overridden":"inherited"}function yo(r){const g=O[r.projectProviderKey],j=O[r.projectModelKey];return g&&j?`${g}/${j}`:""}function ko(r,g){if(g){const j=g.indexOf("/");X(H=>({...H,[r.projectProviderKey]:g.slice(0,j),[r.projectModelKey]:g.slice(j+1)}))}else{if(Da(r)==="inherited")return;X(H=>({...H,[r.projectProviderKey]:void 0,[r.projectModelKey]:void 0}))}}function vo(r){Da(r)!=="inherited"&&X(j=>({...j,[r.projectProviderKey]:void 0,[r.projectModelKey]:void 0}))}function bl(r,g="project"){const j=g==="project"?r.projectThinkingKey:r.globalThinkingKey;return j?O[j]??"":""}function La(r,g,j="project"){const H=j==="project"?r.projectThinkingKey:r.globalThinkingKey;H&&X(Q=>({...Q,[H]:g||void 0}))}function fl(r,g="project"){La(r,"",g)}const xo=o.useCallback(r=>{aa(r),la(".")},[la]),mt=o.useCallback(()=>{aa(null)},[]),Oa=o.useCallback(r=>{Ue!==null&&(Gs(r)||(X(g=>{const j=g.overlapIgnorePaths&&g.overlapIgnorePaths.length>0?[...g.overlapIgnorePaths]:[""];return j[Ue]=r,{...g,overlapIgnorePaths:j}}),mt()))},[Ue,mt]),jo=o.useCallback(()=>{if(nt===".")return;const r=nt.endsWith("/")?nt:`${nt}/`;Oa(r)},[nt,Oa]),wo=o.useCallback(r=>{r.target===r.currentTarget&&mt()},[mt]),Co=o.useCallback(()=>{ra("."),Sn(!0)},[ra]),bt=o.useCallback(()=>{Sn(!1)},[]),So=o.useCallback(r=>{if(Gs(r))return;const g=r.endsWith("/")?r:`${r}/`;X(j=>({...j,worktreesDir:g})),bt()},[bt]),No=o.useCallback(()=>{if(Gs(lt))return;const r=lt==="."?"./":lt.endsWith("/")?lt:`${lt}/`;X(g=>({...g,worktreesDir:r})),bt()},[lt,bt]),Po=o.useCallback(r=>{r.target===r.currentTarget&&bt()},[bt]),To=o.useCallback(r=>{na(r),oa(".")},[oa]),ft=o.useCallback(()=>{na(null)},[]),Ao=o.useCallback(r=>{$e!==null&&(Gs(r)||(X(g=>{const j=g.worktreeCopyFiles&&g.worktreeCopyFiles.length>0?[...g.worktreeCopyFiles]:[""];return j[$e]=r,{...g,worktreeCopyFiles:j}}),ft()))},[$e,ft]),Mo=o.useCallback(r=>{r.target===r.currentTarget&&ft()},[ft]),Io=o.useCallback((r,g)=>{X(j=>{const H=j.worktreeCopyFiles&&j.worktreeCopyFiles.length>0?[...j.worktreeCopyFiles]:[""];return H[r]=g,{...j,worktreeCopyFiles:H}})},[]),Ro=o.useCallback(r=>{if(X(g=>{const H=(g.worktreeCopyFiles&&g.worktreeCopyFiles.length>0?[...g.worktreeCopyFiles]:[""]).filter((Q,ee)=>ee!==r);return{...g,worktreeCopyFiles:H.length>0?H:[]}}),$e===r){ft();return}$e!==null&&$e>r&&na($e-1)},[$e,ft]),Eo=o.useCallback(()=>{X(r=>{const g=r.worktreeCopyFiles&&r.worktreeCopyFiles.length>0?r.worktreeCopyFiles:[""];return{...r,worktreeCopyFiles:[...g,""]}})},[]),Fo=o.useCallback((r,g)=>{X(j=>{const H=j.overlapIgnorePaths&&j.overlapIgnorePaths.length>0?[...j.overlapIgnorePaths]:[""];return H[r]=g,{...j,overlapIgnorePaths:H}})},[]),Do=o.useCallback(r=>{if(X(g=>{const H=(g.overlapIgnorePaths&&g.overlapIgnorePaths.length>0?[...g.overlapIgnorePaths]:[""]).filter((Q,ee)=>ee!==r);return{...g,overlapIgnorePaths:H.length>0?H:[]}}),Ue===r){mt();return}Ue!==null&&Ue>r&&aa(Ue-1)},[Ue,mt]),Lo=o.useCallback(()=>{X(r=>{const g=r.overlapIgnorePaths&&r.overlapIgnorePaths.length>0?r.overlapIgnorePaths:[""];return{...r,overlapIgnorePaths:[...g,""]}})},[]),Oo=o.useCallback(async()=>{if(we||sa||rt)return;const r=O.researchSettings?.limits;if(r?.maxConcurrentRuns!==void 0&&(!Number.isFinite(r.maxConcurrentRuns)||r.maxConcurrentRuns<1)){Wt("Research max concurrent runs must be at least 1.");return}if(r?.maxSourcesPerRun!==void 0&&(!Number.isFinite(r.maxSourcesPerRun)||r.maxSourcesPerRun<1)){Wt("Research max sources per run must be at least 1.");return}if(r?.maxDurationMs!==void 0&&(!Number.isFinite(r.maxDurationMs)||r.maxDurationMs<1e3)){Wt("Research max duration must be at least 1000 ms.");return}if(r?.requestTimeoutMs!==void 0&&(!Number.isFinite(r.requestTimeoutMs)||r.requestTimeoutMs<1e3)){Wt("Research request timeout must be at least 1000 ms.");return}Wt(null);const g=fr(O.dashboardKeyboardShortcuts??{});if(g){s(g,"error");return}je(!0);try{const j=ph(O.worktreeCopyFiles);let H=oe;O.worktrunk?.enabled===!0&&!H&&(H=(await Z.refresh()).status==="installed");const Q=M==="source-control-global"&&be?be:O,ee={...O,worktreeInitCommand:O.worktreeInitCommand?.trim()||void 0,worktreesDir:O.worktreesDir?.trim()||void 0,worktrunk:{enabled:H&&O.worktrunk?.enabled===!0,binaryPath:O.worktrunk?.binaryPath?.trim()||void 0,onFailure:O.worktrunk?.onFailure??"fail"},maxAutoMergeRetries:mr(O),executorToolFailureRetryCount:Hs(O.executorToolFailureRetryCount,2),executorToolFailureRetryBackoffMs:Hs(O.executorToolFailureRetryBackoffMs,2e3),executorToolFailureThreshold:Math.max(1,Math.floor(Number(O.executorToolFailureThreshold??3)||3)),executorModelEscalationEnabled:O.executorModelEscalationEnabled===!0,executorEscalationProvider:O.executorEscalationProvider?.trim()||void 0,executorEscalationModelId:O.executorEscalationModelId?.trim()||void 0,executorEscalationNodeId:O.executorEscalationNodeId?.trim()||void 0,taskPrefix:O.taskPrefix?.trim()||void 0,githubTrackingDefaultRepo:O.githubTrackingDefaultRepo?.trim()||void 0,dashboardKeyboardShortcuts:Object.fromEntries(Object.entries(on(O.dashboardKeyboardShortcuts)).map(([Ae,Ga])=>[Ae,hn(Ga).normalized])),gitlabEnabled:Q.gitlabEnabled,gitlabInstanceUrl:Q.gitlabInstanceUrl?.trim()||void 0,gitlabApiBaseUrl:Q.gitlabApiBaseUrl?.trim()||void 0,gitlabAuthToken:Q.gitlabAuthToken?.trim()||void 0,gitlabAuthTokenType:Q.gitlabAuthTokenType??"personal",githubAuthToken:O.githubAuthToken?.trim()||void 0,prTitlePromptInstructions:O.prTitlePromptInstructions?.trim()||void 0,prDescriptionPromptInstructions:O.prDescriptionPromptInstructions?.trim()||void 0,pushRemote:O.pushAfterMerge&&O.pushRemote?.trim()||void 0,overlapIgnorePaths:(O.overlapIgnorePaths??[]).map(Ae=>Ae.trim()).filter(Ae=>Ae.length>0),worktreeCopyFiles:j.length>0||le?.project?.worktreeCopyFiles!==void 0?j:void 0,experimentalFeatures:gh(O.experimentalFeatures)};M==="source-control"&&Ul({project:{gitlabInstanceUrl:ee.gitlabInstanceUrl,gitlabApiBaseUrl:ee.gitlabApiBaseUrl}}),M==="source-control-global"&&Ul({global:{gitlabInstanceUrl:ee.gitlabInstanceUrl,gitlabApiBaseUrl:ee.gitlabApiBaseUrl}});const{globalPatch:ue,projectPatch:Se}=Pu({payload:ee,initialValues:Ke,initialScopedValues:le,activeSection:M,scopedMcpValues:_?{global:Lt("global",_),project:Lt("project",_)}:void 0});await Promise.all([Object.keys(ue).length>0?Dt(ue):Promise.resolve(),Object.keys(Se).length>0?Wa(Se,a):Promise.resolve(),Cs!==nl.current?Fd({globalMaxConcurrent:Cs??4}):Promise.resolve()]),await T.current?.(),s(m("settings.general.settingsSaved","Settings saved"),"success"),t()}catch(j){if(j instanceof Mr)return;s(xe(j),"error")}finally{je(!1)}},[O,be,Cs,sa,rt,Ke,le,_,t,s,a,M,we,m]),It=o.useMemo(()=>Au(M),[M]),Ka=o.useMemo(()=>Mu(M),[M]),Ba=o.useMemo(()=>{const r=nn.find(g=>g.id===M);return r?m(r.labelKey,r.label):M},[M,m]),Ko=o.useCallback(async()=>{if(!(at||!It)){ps(!0);try{if(It.scope==="global"){const r={};for(const g of It.keys)r[g]=Dd[g];await Dt(r)}else{const r={};for(const g of It.keys)r[g]=null;await Wa(r,a)}await es(!1),s(m("settings.reset.menuResetSuccess","{{section}} settings reset to defaults",{section:Ba}),"success"),gs(!1)}catch(r){s(xe(r),"error")}finally{ps(!1)}}},[at,It,a,es,s,m,Ba]),Bo=o.useCallback(async()=>{if(!at){ps(!0);try{const r={};for(const g of Iu)r[g]=null;await Wa(r,a),await es(!1),s(m("settings.reset.allProjectResetSuccess","All project settings reset to defaults"),"success"),gs(!1)}catch(r){s(xe(r),"error")}finally{ps(!1)}}},[at,a,es,s,m]),Rt=o.useCallback(()=>{at||gs(!1)},[at]),Go=o.useCallback(r=>{r.target===r.currentTarget&&Rt()},[Rt]);o.useEffect(()=>{if(!Ut)return;const r=g=>{g.key==="Escape"&&(g.stopPropagation(),Rt())};return document.addEventListener("keydown",r,!0),()=>document.removeEventListener("keydown",r,!0)},[Ut,Rt]);const Ho=o.useCallback(async()=>{try{await Zd(Ve,Ca,a),js(!1),s(m("settings.memory.memorySaved","Memory saved"),"success")}catch(r){s(xe(r)||"Failed to save memory","error")}},[Ve,Ca,a,s]),_o=o.useCallback(async()=>{tl(!0);try{const{path:r,content:g}=await eu(Ve,a),j=r??Ve;Ve!==j&&(Ma.current=!0),Ta(j),xs(g),js(!1);const{files:H}=await Ol(a);Jn(H),s(m("settings.memory.memoryCompacted","Memory file compacted"),"success")}catch(r){s(xe(r)||"Failed to compact memory","error")}finally{tl(!1)}},[Ve,a,s]),Wo=o.useCallback(async()=>{Xn(!0),Zn(null);try{const r=await tu(Aa,a);Zn(r),s(r.qmdAvailable?"Memory retrieval test complete":"qmd is not installed; local fallback was used",r.qmdAvailable?"success":"warning")}catch(r){s(xe(r)||"Failed to test memory retrieval","error")}finally{Xn(!1)}},[Aa,a,s]),Uo=o.useCallback(async()=>{el(!0);try{await su(a),s(m("settings.memory.dreamCompleted","Dream processing completed"),"success")}catch(r){s(r instanceof Error?r.message:"Failed to run dream processing","error")}finally{el(!1)}},[a,s]),$o=o.useCallback(async()=>{sl(!0);try{const r=await au(a);await dl(),s(r.qmdAvailable?m("settings.memory.qmdInstalled","qmd installed successfully"):m("settings.memory.qmdInstallUnavailable","qmd install finished, but qmd is still unavailable"),r.qmdAvailable?"success":"warning")}catch(r){s(xe(r)||m("settings.memory.qmdInstallFailed","Failed to install qmd"),"error")}finally{sl(!1)}},[a,dl,s]),zo=()=>{if(!rt)return;const r=rt.name.trim();if(!r){s(m("settings.models.presetNameRequired","Preset name is required"),"error");return}const g=O.modelPresets||[];let j;Qt?j=Qt:j=Hd(r,g);const H={id:j,name:r,executorProvider:rt.executorProvider,executorModelId:rt.executorModelId,validatorProvider:rt.validatorProvider,validatorModelId:rt.validatorModelId};X(Q=>{const ee=Q.modelPresets||[],ue=Qt?ee.map(Se=>Se.id===Qt?H:Se):[...ee,H];return{...Q,modelPresets:ue}}),Bn(null),Gn(null)},qo=o.useCallback(async(r,g)=>{Hn(r);try{await g(),await Ts()}catch(j){s(xe(j)||`Failed to ${r}`,"error")}finally{Hn(null)}},[s,Ts]),Vo=o.useCallback(()=>{if(typeof navigator<"u"&&navigator.userAgent.includes("Windows"))return"winget install Cloudflare.cloudflared";const r=typeof navigator<"u"?navigator.platform:"",g=typeof navigator<"u"?navigator.userAgent:"",j=/(Mac|iPhone|iPad|iPod)/i.test(r),H=/(arm64|aarch64)/i.test(`${r} ${g}`);return j?"brew install cloudflared":`curl -L --output /tmp/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${H?"arm64":"amd64"} && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared # If sudo is unavailable, use: mkdir -p ~/.local/bin && mv /tmp/cloudflared ~/.local/bin/cloudflared`},[]),Yo=o.useCallback(()=>typeof navigator>"u"||!/(Mac|iPhone|iPad|iPod)/i.test(navigator.platform)?null:`curl -L --output /tmp/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-${/(arm64|aarch64)/i.test(`${navigator.platform} ${navigator.userAgent}`)?"arm64":"amd64"} && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared`,[]),Qo=o.useCallback(async()=>{_n(!0),wa(null);try{const r=await fu(a);if(!r.success){wa(r.error??m("settings.remote.installationFailed","Installation failed"));return}const g=await za(a);vs(g),s(m("settings.remote.cloudflaredInstalled","cloudflared installed successfully"),"success")}catch(r){wa(r instanceof Error?r.message:m("settings.remote.installationFailed","Installation failed"))}finally{_n(!1)}},[s,a]),Jo=()=>{switch(M){case"cli-agents":return e.jsx(hh,{projectId:a,addToast:s});case"general":return e.jsx(Eg,{form:O,setForm:X,projectId:a,addToast:s,prefixError:sa,setPrefixError:Ur,onQuickChatButtonModeChange:x,onMobileNavPrimaryItemsChange:f});case"source-control":return e.jsx(ep,{form:O,setForm:X,projectTrackingRepoOptions:Ei,projectTrackingRepoLoading:Fi,projectTrackingRepoError:Di});case"source-control-global":return e.jsx(tp,{form:O,setForm:X,globalSettings:be,onGlobalGitlabSettingsChange:r=>ve(g=>({gitlabEnabled:g?.gitlabEnabled,gitlabInstanceUrl:g?.gitlabInstanceUrl,gitlabApiBaseUrl:g?.gitlabApiBaseUrl,gitlabAuthToken:g?.gitlabAuthToken,gitlabAuthTokenType:g?.gitlabAuthTokenType,...r})),globalTrackingRepoOptions:Li,globalTrackingRepoLoading:Oi,globalTrackingRepoError:Ki});case"global-general":return e.jsx(Hu,{form:O,setForm:X});case"keyboard-shortcuts":return e.jsx(Wu,{form:O,setForm:X});case"global-models":return e.jsx(ag,{form:O,setForm:X,availableModels:Fn,modelsLoading:Ln,globalModelLanes:ml.filter(r=>r.laneId!=="default"),getLaneThinkingValue:r=>bl(r,"global"),updateLaneThinkingValue:(r,g)=>La(r,g,"global"),resetLaneThinkingValue:r=>fl(r,"global"),favoriteProviders:Tt,favoriteModels:At,onToggleFavorite:pl,onToggleModelFavorite:hl,addToast:s,projectId:a});case"secrets":return e.jsx(Pg,{addToast:s});case"global-mcp":return e.jsx(Xu,{form:pe("global"),setForm:Ce("global"),projectId:a,addToast:s});case"mcp":return e.jsx(cp,{form:pe("project"),setForm:Ce("project"),globalSettings:_?.global??null,projectId:a,addToast:s});case"project-models":return e.jsx(Kg,{form:O,setForm:X,projectId:a,addToast:s,onOpenWorkflowSettings:C,registerWorkflowLaneSaver:$,models:{modelLanes:ml,getLaneStatus:Da,getLaneValue:yo,updateLaneValue:ko,resetLaneValue:vo,getLaneThinkingValue:bl,updateLaneThinkingValue:La,resetLaneThinkingValue:fl,availableModels:Fn,modelsLoading:Ln,favoriteProviders:Tt,favoriteModels:At,onToggleFavorite:pl,onToggleModelFavorite:hl,editingPresetId:Qt,setEditingPresetId:Bn,presetDraft:rt,setPresetDraft:Gn,onSavePresetDraft:zo,confirmDelete:Y}});case"appearance":return e.jsx(Ou,{form:O,setForm:X,themeMode:c,colorTheme:d,dashboardFontScalePct:l,shadcnCustomColors:h,resolvedThemeMode:p,onThemeModeChange:i,onColorThemeChange:u,onDashboardFontScaleChange:b,onShadcnCustomColorsChange:w,sessionBannersHidden:ge,setSessionBannersHidden:Gd});case"scheduling-global":return e.jsx(Hg,{globalMaxConcurrent:Cs,concurrencyLoading:M==="scheduling-global"&&!rl&&!Ss.current,onGlobalMaxConcurrentChange:r=>{Ss.current=!0,al(r)}});case"scheduling":return e.jsx(Gg,{form:O,setForm:X,concurrencyLoading:M==="scheduling"&&!rl&&!Ss.current,onOverlapIgnorePathChange:Fo,onOpenOverlapPathPicker:xo,onRemoveOverlapIgnorePath:Do,onAddOverlapIgnorePath:Lo,onOpenWorkflowSettings:C});case"scheduled-evals":return e.jsx(Ug,{form:O,setForm:X});case"node-routing":return e.jsx(zg,{form:O,setForm:X,nodes:ni});case"worktrees":return e.jsx(qg,{form:O,setForm:X,gitRemotes:Un,worktrunkInstall:Z,worktrunkInstallVerified:oe,onOpenWorktreesDirPicker:Co,onWorktreeCopyFileChange:Io,onRemoveWorktreeCopyFile:Ro,onAddWorktreeCopyFile:Eo,onOpenWorktreeCopyFilePicker:To,onOpenApprovals:S});case"commands":return e.jsx(Vg,{form:O,setForm:X});case"merge":return e.jsx(Xg,{form:O,setForm:X,integrationBranchOptions:Mi,integrationBranchCustomMode:Ii,setIntegrationBranchCustomMode:Ri,onOpenWorkflowSettings:C,gitRemoteOptions:Un.map(r=>r.name),projectId:a});case"agent-permissions":return e.jsx(ap,{form:O,setForm:X});case"memory":return e.jsx(ip,{form:O,setForm:X,memory:{memoryCapabilities:Qi,memoryBackendStatus:Yi,memoryBackendLoading:Ji,memoryBackendError:Xi,memoryFiles:Bi,selectedMemoryPath:Ve,setSelectedMemoryPath:Ta,memoryContent:Ca,setMemoryContent:xs,memoryLoading:Ai,memoryDirty:Sa,setMemoryDirty:js,memoryTestQuery:Aa,setMemoryTestQuery:Gi,memoryTestLoading:Hi,memoryTestResult:_i,qmdInstallLoading:$i,dreamRunning:Wi,memoryCompactLoading:Ui,onInstallQmd:$o,onTestMemoryRetrieval:Wo,onDreamNow:Uo,onCompactMemory:_o,onSaveMemory:Ho}});case"research-global":return e.jsx(Uu,{form:O,setForm:X,authProviders:pt,onNavigateToSection:W});case"research-project":return e.jsx(op,{form:O,setForm:X,researchLimitError:$r});case"cli-binary":return e.jsx(Wg,{});case"experimental":return e.jsx(Ku,{form:O,setForm:X,knownFeatures:ch,legacyAliases:Qs,getCanonicalKey:jn,isFeatureEnabled:uh,hiddenFeatureKeys:dh});case"backups-global":return e.jsx(up,{form:O,setForm:X,backupInfo:mi,backupLoading:bi,onBackupNow:go});case"backups":return e.jsx(dp,{form:O,setForm:X});case"notifications":return e.jsx(Gu,{form:O,setForm:X,testNotificationLoading:pi,testNotificationResult:hi,onTestProviderNotification:uo});case"node-sync":return e.jsx(Bu,{form:O,setForm:X});case"remote":return e.jsx($u,{form:O,setForm:X,remote:{projectId:a,addToast:s,remoteStatus:qe,externalTunnel:xa,tunnelShareLink:Ti,remoteBusyAction:fi,cloudflaredInstalling:yi,cloudflaredInstallError:ki,cloudflaredManualInstallCommand:Vo,cloudflaredMacFallbackCommand:Yo,handleInstallCloudflared:Qo,runRemoteAction:qo,remoteShortLivedToken:Ni,setRemoteShortLivedToken:Pi,remoteAuthLinkTokenType:vi,setRemoteAuthLinkTokenType:xi,remoteUrlPreview:ji,setRemoteUrlPreview:wi,remoteQrSvg:Ci,setRemoteQrSvg:Si}});case"prompts":return e.jsx(Rg,{form:O,setForm:X,onOpenWorkflowSettings:C});case"plugins":return e.jsx(hp,{projectId:a,addToast:s,activePluginsSubsection:fe,setActivePluginsSubsection:he});case"authentication":return e.jsx(gg,{auth:{projectId:a,addToast:s,authProviders:pt,authLoading:ri,authActionInProgress:ii,apiKeyInputs:ba,setApiKeyInputs:fa,apiKeyErrors:ui,opencodeApiKeyRefreshStatus:gi,deviceCodes:ga,loginInstructions:oi,manualCodeConfigs:ci,manualCodeInputs:pa,setManualCodeInputs:ha,manualCodeSubmitInProgress:di,loadAuthStatus:Te,handleLogin:no,handleLogout:io,handleCancelLogin:ro,handleSaveApiKey:oo,handleClearApiKey:co,handleSubmitManualCode:lo,onReopenOnboarding:D}});case"hermes-runtime":return e.jsx(Cg,{});case"openclaw-runtime":return e.jsx(Sg,{});case"paperclip-runtime":return e.jsx(Ng,{})}};return e.jsxs("div",{className:k?"settings-embedded right-dock-embedded-view":"modal-overlay open settings-modal-overlay",...fo,"data-testid":k?"settings-view":void 0,role:k?"region":"dialog","aria-label":k?m("settings.title","Settings"):void 0,"aria-modal":k?void 0:"true",children:[e.jsxs("div",{className:k?"modal modal-lg settings-modal settings-modal--embedded":"modal modal-lg settings-modal",ref:re,style:k?void 0:ne,children:[e.jsxs("div",{className:k?"modal-header modal-header--embedded":"modal-header",children:[e.jsx("div",{className:"settings-modal-heading",children:e.jsxs("h3",{children:[k&&e.jsx(Ld,{size:20,"aria-hidden":"true"}),e.jsx("span",{children:m("settings.title","Settings")})]})}),e.jsxs("div",{className:"settings-header-actions",children:[e.jsxs("a",{href:"https://github.com/Runfusion/Fusion",target:"_blank",rel:"noopener noreferrer",className:"settings-github-star-btn","aria-label":m("settings.header.starFusion","Star Fusion on GitHub"),title:m("settings.header.starFusion","Star Fusion on GitHub"),onClick:Wr,"data-clicked":_r?"true":"false",children:[e.jsxs("span",{className:"settings-github-star-btn__action",children:[e.jsx(it,{provider:"github",size:"sm"}),e.jsx(Od,{size:11,"aria-hidden":"true"}),m("settings.header.star","Star")]}),_t!==null&&e.jsx("span",{className:"settings-github-star-btn__count","aria-label":`${_t.toLocaleString()} stars`,children:_t>=1e3?`${(_t/1e3).toFixed(1)}k`:_t.toLocaleString()})]}),e.jsxs("a",{href:"https://discord.gg/ksrfuy7WYR",target:"_blank",rel:"noopener noreferrer",className:"btn btn-sm settings-header-discord-btn","aria-label":m("settings.header.joinDiscord","Join our Discord"),title:m("settings.header.joinDiscord","Join our Discord"),children:[e.jsx(Vp,{size:13}),m("settings.header.discord","Discord")]})]}),!k&&e.jsx("button",{className:"modal-close",onClick:t,"aria-label":m("actions.close","Close"),children:"×"}),k&&E==="mobile"&&e.jsx("button",{className:"modal-close settings-embedded-mobile-close",onClick:t,"aria-label":m("actions.close","Close"),children:"×"})]}),me?e.jsx("div",{className:"settings-empty-state settings-loading",children:e.jsx(kt,{label:m("settings.loading","Loading…")})}):e.jsxs("div",{className:"settings-layout",children:[e.jsxs("aside",{className:"settings-navigation","aria-label":m("settings.search.navigationLabel","Settings navigation"),style:Zi,children:[_e&&e.jsx("div",{className:"settings-mobile-section-picker",children:e.jsxs("div",{className:"settings-mobile-section-picker-control-row",children:[qt?e.jsx("select",{id:"settings-mobile-section","aria-label":m("settings.mobileNav.label","Settings Section"),className:"select touch-target",value:M,onChange:r=>W(r.target.value),children:gt.map((r,g)=>{if(!r.isGroupHeader)return null;const j=gt.slice(g+1).filter(ee=>!ee.isGroupHeader),H=gt.slice(g+1).findIndex(ee=>ee.isGroupHeader),Q=H===-1?j:j.slice(0,H);return Q.length===0?null:e.jsx("optgroup",{label:m(r.labelKey,r.label),children:Q.map(ee=>{const ue=m(ee.labelKey,ee.label);return e.jsx("option",{value:ee.id,children:oh(ee,ue)},ee.id)})},r.id)})}):e.jsx("p",{className:"settings-search-empty-hint",children:m("settings.search.noMobileOptions","No sections match this search.")}),An&&e.jsx("button",{type:"button",className:"btn btn-sm btn-icon settings-search-toggle",onClick:()=>Zs(r=>!r),"aria-expanded":bs,"aria-controls":"settings-search-row-region","aria-label":bs?m("settings.search.toggleHide","Hide search"):m("settings.search.toggleShow","Show search"),children:bs?e.jsx(yr,{size:16}):e.jsx(cn,{size:16})})]})}),e.jsxs("label",{className:"settings-advanced-toggle",children:[e.jsx("input",{type:"checkbox",checked:ct,onChange:r=>cs(r.target.checked)}),e.jsx("span",{children:m("settings.advanced.toggle","Advanced settings")})]}),bs&&e.jsx("div",{className:"settings-search","data-testid":"settings-search",children:e.jsxs("div",{id:"settings-search-row-region",className:"settings-search-row",children:[e.jsx("label",{className:"settings-search-label",htmlFor:"settings-search-input",children:m("settings.search.label","Search settings")}),e.jsxs("div",{className:"settings-search-input-wrap",children:[e.jsx("input",{id:"settings-search-input","data-testid":"settings-search-input",className:"input settings-search-input",type:"search",value:Nt,onChange:r=>tt(r.target.value),onKeyDown:r=>{r.key==="Escape"&&zt&&(r.stopPropagation(),tt(""))},placeholder:m("settings.search.placeholder","Search by setting or section"),"aria-describedby":"settings-search-results"}),zt&&e.jsx("button",{type:"button",className:"btn btn-sm settings-search-clear",onClick:()=>tt(""),"aria-label":m("settings.search.clear","Clear settings search"),children:m("actions.clear","Clear")})]}),e.jsx("div",{id:"settings-search-results",className:"settings-search-results","aria-live":"polite",children:zt?ut.length>0?m("settings.search.settingResultCount",{count:ut.length}):m("settings.search.resultCount",{count:Tn.length}):m("settings.search.allSections","Showing all settings sections")}),ut.length>0&&e.jsxs("ul",{className:"settings-search-hits","data-testid":"settings-search-hits",children:[ut.slice(0,an).map(r=>{const g=ze.find(j=>j.id===r.sectionId);return e.jsx("li",{children:e.jsxs("button",{type:"button",className:"settings-search-hit","data-testid":`settings-search-hit-${r.key}`,onClick:()=>li(r.sectionId,r.key),children:[e.jsx("span",{className:"settings-search-hit-label",children:r.label}),g&&e.jsx("span",{className:"settings-search-hit-section",children:m(g.labelKey,g.label)})]})},`${r.sectionId}:${r.key}`)}),ut.length>an&&e.jsx("li",{className:"settings-search-hits-more",children:m("settings.search.moreResults","{{count}} more — keep typing to narrow",{count:ut.length-an})})]})]})}),e.jsx("nav",{className:"settings-sidebar",children:qt?gt.map(r=>r.isGroupHeader?e.jsx("div",{className:"settings-group-header",children:m(r.labelKey,r.label)},r.id):e.jsxs("button",{className:`settings-nav-item${M===r.id?" active":""}`,onClick:()=>W(r.id),title:r.scope==="global"?m("settings.nav.tooltip.global","Shared across all projects"):r.scope==="project"?m("settings.nav.tooltip.project","Specific to this project"):void 0,children:[r.icon?e.jsx(r.icon,{className:"settings-scope-icon","aria-label":r.scope==="project"?m("settings.nav.aria.project","Project setting"):m("settings.nav.aria.global","Global setting"),size:16}):e.jsxs(e.Fragment,{children:[r.scope==="global"&&e.jsx(Us,{className:"settings-scope-icon","aria-label":m("settings.nav.aria.global","Global setting"),size:16}),r.scope==="project"&&e.jsx(Kd,{className:"settings-scope-icon","aria-label":m("settings.nav.aria.project","Project setting"),size:16})]}),m(r.labelKey,r.label)]},r.id)):e.jsxs("div",{className:"settings-search-empty",role:"status",children:[e.jsx("p",{children:m("settings.search.noResults",'No settings sections match "{{query}}".',{query:Nt.trim()})}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>tt(""),children:m("settings.search.clear","Clear settings search")})]})})]}),ht&&e.jsx("div",{className:"settings-nav-resize-handle",role:"separator","aria-orientation":"vertical","aria-label":m("settings.nav.resize","Resize settings navigation"),"aria-valuemin":Or,"aria-valuemax":Kr,"aria-valuenow":Be,tabIndex:0,onPointerDown:eo,onKeyDown:to}),e.jsx("div",{className:"settings-content",ref:ce,"data-show-advanced":ct?"true":"false",children:qt?e.jsx(Wd,{highlightedKey:Pe,children:Jo()}):e.jsxs("div",{className:"settings-empty-state settings-search-content-empty",role:"status",children:[e.jsx("p",{children:m("settings.search.noResults",'No settings sections match "{{query}}".',{query:Nt.trim()})}),e.jsx("button",{type:"button",className:"btn",onClick:()=>tt(""),children:m("settings.search.clear","Clear settings search")})]})})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsxs("div",{className:"settings-modal-footer-version",children:[e.jsx("a",{href:"https://github.com/Runfusion/Fusion/discussions",target:"_blank",rel:"noopener noreferrer",className:"btn btn-sm settings-footer-help-btn","aria-label":m("settings.footer.helpDiscussions","Help and discussions"),title:m("settings.footer.helpDiscussions","Help and discussions"),children:m("settings.footer.help","Help")}),e.jsxs("div",{className:"settings-update-check",children:[We&&e.jsxs("button",{type:"button",className:"settings-version-check-btn",onClick:()=>{so()},disabled:q,"aria-label":m("settings.footer.checkUpdates","Check for updates"),title:m("settings.footer.checkUpdates","Check for updates"),children:[e.jsx("span",{className:"settings-modal-version",children:E==="mobile"?m("settings.footer.versionShort","v{{version}}",{version:We}):m("settings.footer.version","Version {{version}}",{version:We})}),e.jsx(rs,{size:12,className:q?"spinning":void 0})]}),ae&&e.jsx("span",{"aria-live":"polite",className:`settings-update-result ${ae.error?"settings-update-result--error":ae.updateAvailable?"settings-update-result--available":"settings-update-result--up-to-date"}`,children:ao()})]})]}),e.jsxs("div",{className:"modal-actions-left",children:[e.jsx("button",{type:"button",className:"btn btn-sm",onClick:po,title:m("settings.importExport.exportTitle","Export settings to JSON file"),children:m("settings.importExport.exportBtn","Export")}),e.jsx("input",{type:"file",ref:cl,accept:".json,application/json",style:{display:"none"},onChange:ho}),e.jsx("button",{type:"button",className:"btn btn-sm",onClick:()=>cl.current?.click(),disabled:Ns,title:m("settings.importExport.importTitleAttr","Import settings from JSON file"),children:Ns?m("settings.importExport.loadingFile","Loading…"):m("settings.importExport.importBtn","Import")}),e.jsx("button",{type:"button",className:"btn btn-sm","data-testid":"settings-reset",onClick:()=>gs(!0),disabled:me,title:m("settings.reset.buttonTitle","Reset settings to their defaults"),children:E==="mobile"?m("settings.reset.buttonShort","Reset"):m("settings.reset.button","Reset Settings")})]}),e.jsxs("div",{className:"modal-actions-right",children:[!k&&e.jsx("button",{className:"btn btn-sm",onClick:t,children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:Oo,disabled:me||we,children:m("settings.actions.save","Save")})]})]})]}),Ue!==null&&e.jsx("div",{className:"modal-overlay open",onClick:wo,role:"dialog","aria-modal":"true","aria-label":m("settings.scheduling.browseWorkspacePath","Browse workspace path"),children:e.jsxs("div",{className:"modal modal-lg settings-overlap-path-picker-modal",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.scheduling.selectIgnoredOverlapPath","Select ignored overlap path")}),e.jsx("button",{className:"modal-close",onClick:mt,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body settings-overlap-path-picker-body",children:[e.jsx("p",{className:"settings-overlap-path-picker-note",children:m("settings.scheduling.overlapPickerNote","Choose a file to ignore directly, or navigate into a folder and select the current directory.")}),e.jsx(Ua,{entries:zr,currentPath:nt,onSelectFile:Oa,onNavigate:la,loading:qr,error:Vr,onRetry:Yr,workspace:"project",projectId:a})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("div",{className:"modal-actions-left",children:e.jsxs("small",{children:[m("settings.fileBrowser.currentDirectory","Current directory:")," ",e.jsx("code",{children:nt==="."?m("settings.fileBrowser.projectRoot","(project root)"):nt})]})}),e.jsxs("div",{className:"modal-actions-right",children:[e.jsx("button",{className:"btn btn-sm",onClick:mt,children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:jo,disabled:nt===".",children:m("settings.scheduling.selectCurrentDir","Select current directory")})]})]})]})}),Cn&&e.jsx("div",{className:"modal-overlay open",onClick:Po,role:"dialog","aria-modal":"true","aria-label":m("settings.worktrees.browseWorktreesDirectory","Browse worktrees directory"),children:e.jsxs("div",{className:"modal modal-lg settings-overlap-path-picker-modal",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.worktrees.selectWorktreesDir","Select worktrees directory")}),e.jsx("button",{className:"modal-close",onClick:bt,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body settings-overlap-path-picker-body",children:[e.jsx("p",{className:"settings-overlap-path-picker-note",children:m("settings.worktrees.worktreesPickerNote","Navigate to the folder where Fusion should create task worktrees, then select the current directory.")}),e.jsx(Ua,{entries:Qr,currentPath:lt,onSelectFile:So,onNavigate:ra,loading:Jr,error:Xr,onRetry:Zr,workspace:"project",projectId:a})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("div",{className:"modal-actions-left",children:e.jsxs("small",{children:[m("settings.fileBrowser.currentDirectory","Current directory:")," ",e.jsx("code",{children:lt==="."?m("settings.fileBrowser.projectRoot","(project root)"):lt})]})}),e.jsxs("div",{className:"modal-actions-right",children:[e.jsx("button",{className:"btn btn-sm",onClick:bt,children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:No,children:m("settings.scheduling.selectCurrentDir","Select current directory")})]})]})]})}),$e!==null&&e.jsx("div",{className:"modal-overlay open",onClick:Mo,role:"dialog","aria-modal":"true","aria-label":m("settings.worktrees.browseCopyFile","Browse file to copy into new worktrees"),children:e.jsxs("div",{className:"modal modal-lg settings-overlap-path-picker-modal",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.worktrees.selectCopyFile","Select file to copy")}),e.jsx("button",{className:"modal-close",onClick:ft,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body settings-overlap-path-picker-body",children:[e.jsx("p",{className:"settings-overlap-path-picker-note",children:m("settings.worktrees.copyFilePickerNote","Choose a repository file to copy into each newly assigned task worktree. Directories are not selected from this picker.")}),e.jsx(Ua,{entries:ei,currentPath:ia,onSelectFile:Ao,onNavigate:oa,loading:ti,error:si,onRetry:ai,workspace:"project",projectId:a})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("div",{className:"modal-actions-left",children:e.jsxs("small",{children:[m("settings.fileBrowser.currentDirectory","Current directory:")," ",e.jsx("code",{children:ia==="."?m("settings.fileBrowser.projectRoot","(project root)"):ia})]})}),e.jsx("div",{className:"modal-actions-right",children:e.jsx("button",{className:"btn btn-sm",onClick:ft,children:m("settings.actions.cancel","Cancel")})})]})]})}),zi&&Ye&&e.jsx("div",{className:"modal-overlay open",onClick:r=>r.target===r.currentTarget&&Jt(!1),role:"dialog","aria-modal":"true",children:e.jsxs("div",{className:"modal modal-md",children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.importExport.importTitle","Import Settings")}),e.jsx("button",{className:"modal-close",onClick:()=>Jt(!1),"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("p",{children:m("settings.importExport.reviewPrompt","Review the settings to be imported:")}),Ye.global&&Object.keys(Ye.global).length>0&&e.jsxs("div",{className:"form-group",children:[e.jsx("strong",{children:m("settings.importExport.globalSettings","Global Settings:")}),e.jsx("ul",{className:"import-preview-list",children:Object.entries(Ye.global).filter(([,r])=>r!==void 0).map(([r])=>e.jsx("li",{children:r},r))})]}),Ye.project&&Object.keys(Ye.project).length>0&&e.jsxs("div",{className:"form-group",children:[e.jsx("strong",{children:m("settings.importExport.projectSettings","Project Settings:")}),e.jsx("ul",{className:"import-preview-list",children:Object.entries(Ye.project).filter(([,r])=>r!==void 0).map(([r])=>e.jsx("li",{children:r},r))})]}),e.jsxs("div",{className:"form-group",children:[e.jsx("label",{htmlFor:"import-scope",children:m("settings.importExport.importScope","Import Scope:")}),e.jsxs("select",{id:"import-scope",value:Ra,onChange:r=>qi(r.target.value),children:[e.jsx("option",{value:"both",children:m("settings.importExport.scopeBoth","Both global and project settings")}),e.jsx("option",{value:"global",children:m("settings.importExport.scopeGlobal","Global settings only")}),e.jsx("option",{value:"project",children:m("settings.importExport.scopeProject","Project settings only")})]})]}),e.jsx("div",{className:"form-group",children:e.jsxs("div",{className:"settings-field-label-row",children:[e.jsxs("label",{htmlFor:"import-merge",className:"checkbox-label",children:[e.jsx("input",{id:"import-merge",type:"checkbox",checked:Ea,onChange:r=>Vi(r.target.checked)}),m("settings.importExport.mergeExisting","Merge with existing settings (recommended)")]}),e.jsx(B,{settingKey:"import-merge",children:m("settings.importExport.replaceWarning","If unchecked, existing settings will be replaced with imported values.")})]})})]}),e.jsxs("div",{className:"modal-actions",children:[e.jsx("button",{className:"btn btn-sm",onClick:()=>Jt(!1),children:m("settings.actions.cancel","Cancel")}),e.jsx("button",{className:"btn btn-primary btn-sm",onClick:mo,disabled:Ns,children:Ns?m("settings.importExport.importing","Importing…"):m("settings.importExport.confirmImport","Confirm Import")})]})]})}),Ut&&e.jsx("div",{className:"modal-overlay open",onClick:Go,role:"dialog","aria-modal":"true","aria-label":m("settings.reset.dialogAriaLabel","Reset settings"),"data-testid":"settings-reset-dialog",children:e.jsxs("div",{className:"modal modal-md settings-reset-dialog",onClick:r=>r.stopPropagation(),children:[e.jsxs("div",{className:"modal-header",children:[e.jsx("h3",{children:m("settings.reset.dialogTitle","Reset Settings")}),e.jsx("button",{className:"modal-close",onClick:Rt,"aria-label":m("actions.close","Close"),children:"×"})]}),e.jsxs("div",{className:"modal-body",children:[e.jsx("p",{children:m("settings.reset.dialogBody","Choose what to reset to its defaults. This cannot be undone.")}),e.jsxs("div",{className:"settings-reset-dialog__choice",children:[e.jsx("button",{type:"button",className:"btn btn-danger settings-reset-dialog__choice-btn","data-testid":"settings-reset-menu",onClick:()=>void Ko(),disabled:at||!It,title:Ka,children:m("settings.reset.resetMenuAction","Reset this menu ({{section}})",{section:Ba})}),Ka&&e.jsx("small",{className:"settings-reset-dialog__ineligible-reason",children:Ka})]}),e.jsx("div",{className:"settings-reset-dialog__choice",children:e.jsx("button",{type:"button",className:"btn btn-danger settings-reset-dialog__choice-btn","data-testid":"settings-reset-all-project",onClick:()=>void Bo(),disabled:at,children:m("settings.reset.resetAllProjectAction","Reset all project settings")})})]}),e.jsx("div",{className:"modal-actions",children:e.jsx("div",{className:"modal-actions-right",children:e.jsx("button",{className:"btn btn-sm",onClick:Rt,disabled:at,children:m("settings.actions.cancel","Cancel")})})})]})})]})}function Ah(t){return e.jsx(mh,{presentation:"embedded",...t})}export{Rr as GITHUB_STAR_CACHE_KEY,Er as GITHUB_STAR_CACHE_TTL_MS,nn as SETTINGS_SECTIONS,mh as SettingsModal,Ah as SettingsView,lh as filterSettingsSectionsForSearch,Gr as normalizeSettingsSearchText,nh as sectionMatchesSettingsSearch,Xp as useGitHubStarCount};
|