@runfusion/fusion 0.43.1 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/dist/automation-store-EKXXEE2S.js +10 -0
  2. package/dist/automation-store-PLNG3X72.js +10 -0
  3. package/dist/automation-store-RDDYZFUJ.js +10 -0
  4. package/dist/bin.js +8097 -1796
  5. package/dist/chunk-2JI3F6MG.js +948 -0
  6. package/dist/chunk-4L6CLWJC.js +8345 -0
  7. package/dist/chunk-4VNS5WPM.js +42 -0
  8. package/dist/chunk-5RGECGQL.js +1139 -0
  9. package/dist/chunk-6JDLN7IL.js +409 -0
  10. package/dist/chunk-AICJATVW.js +948 -0
  11. package/dist/chunk-AWKNRUOR.js +1148 -0
  12. package/dist/chunk-BHM3UYWS.js +4651 -0
  13. package/dist/chunk-BMUXDSBF.js +4647 -0
  14. package/dist/chunk-GETECT6V.js +353 -0
  15. package/dist/chunk-GUV4QQT3.js +1143 -0
  16. package/dist/chunk-JKQO7YYZ.js +8369 -0
  17. package/dist/chunk-LYZVU6UV.js +409 -0
  18. package/dist/chunk-MAN4WYHO.js +353 -0
  19. package/dist/chunk-MCUG2Z7M.js +4651 -0
  20. package/dist/chunk-PSDYB45U.js +948 -0
  21. package/dist/chunk-RR2HM46R.js +8345 -0
  22. package/dist/chunk-RXMQ5OMY.js +9226 -0
  23. package/dist/chunk-S2EVJUY3.js +353 -0
  24. package/dist/chunk-UXR5XZFZ.js +409 -0
  25. package/dist/client/.vite/manifest.json +272 -261
  26. package/dist/client/assets/{AgentDetailView-BGN03dyz.css → AgentDetailView-CanIeYHg.css} +1 -1
  27. package/dist/client/assets/{AgentDetailView-DKMz3r04.js → AgentDetailView-DxV8pFHX.js} +3 -3
  28. package/dist/client/assets/{AgentPermissionPolicyEditor-BiY1a4KR.js → AgentPermissionPolicyEditor--YS4iMUY.js} +2 -2
  29. package/dist/client/assets/AgentsView-BVILQjdS.css +1 -0
  30. package/dist/client/assets/{AgentsView-Co-k4vjh.js → AgentsView-CTzbcvhK.js} +3 -3
  31. package/dist/client/assets/ChatView-COygcnyk.js +6 -0
  32. package/dist/client/assets/CommandCenter-CTaopaC0.css +1 -0
  33. package/dist/client/assets/CommandCenter-DoKX2HWm.js +56 -0
  34. package/dist/client/assets/DevServerView-Cyevyvqx.js +1 -0
  35. package/dist/client/assets/{DirectoryPicker-DTKtd8L2.css → DirectoryPicker-0rspvcMz.css} +1 -1
  36. package/dist/client/assets/{DirectoryPicker-CkcGjyv0.js → DirectoryPicker-DBdyXEhR.js} +1 -1
  37. package/dist/client/assets/DocumentsView-BzSMyrns.js +1 -0
  38. package/dist/client/assets/{EvalsView-CUfyj5GW.js → EvalsView-ikz00o9g.js} +1 -1
  39. package/dist/client/assets/ExperimentalAgentOnboardingModal-CZ_jbgep.css +1 -0
  40. package/dist/client/assets/{ExperimentalAgentOnboardingModal-Dau9RTU_.js → ExperimentalAgentOnboardingModal-D-rzCCET.js} +10 -10
  41. package/dist/client/assets/GoalsView-Bfu1Oy2-.js +2 -0
  42. package/dist/client/assets/GoalsView-rg9VSIza.css +1 -0
  43. package/dist/client/assets/{InsightsView-BQPxHxKI.js → InsightsView-Cgmf5nES.js} +1 -1
  44. package/dist/client/assets/InsightsView-LMv1M1dU.css +1 -0
  45. package/dist/client/assets/MemoryView-DkEuDKQs.js +2 -0
  46. package/dist/client/assets/{NodesView-CSMvGwDU.js → NodesView-B_KYfS4o.js} +3 -3
  47. package/dist/client/assets/{PiExtensionsManager-BtqXF3fl.js → PiExtensionsManager-Dz69kkKs.js} +2 -2
  48. package/dist/client/assets/PluginManager-DSiHizRD.css +1 -0
  49. package/dist/client/assets/{PluginManager-CSSDb3VO.js → PluginManager-LHCVcduP.js} +1 -1
  50. package/dist/client/assets/PullRequestView-3AdbS2a1.css +1 -0
  51. package/dist/client/assets/{PullRequestView-Bjyfffdu.js → PullRequestView-DBJutLLl.js} +2 -2
  52. package/dist/client/assets/{ResearchView-CRU_NPho.js → ResearchView-gpn1XcVy.js} +1 -1
  53. package/dist/client/assets/{SecretsView-Bs8ySyC5.js → SecretsView-B7YqIowt.js} +1 -1
  54. package/dist/client/assets/SessionTerminal-9l4bdKcn.js +2 -0
  55. package/dist/client/assets/SessionTerminal-BNgtmXb3.css +1 -0
  56. package/dist/client/assets/SettingsModal-BGEK9_9A.js +31 -0
  57. package/dist/client/assets/{SettingsModal-DpAxDq6M.css → SettingsModal-CKv0TJfM.css} +1 -1
  58. package/dist/client/assets/SettingsModal-CXogw-Er.css +1 -0
  59. package/dist/client/assets/{SettingsModal-Nw5cTKAK.js → SettingsModal-DIIoHGUH.js} +1 -1
  60. package/dist/client/assets/{SetupWizardModal-CE79myEy.js → SetupWizardModal-BcVeMxeX.js} +1 -1
  61. package/dist/client/assets/{SkillsView-Dc8YskAX.js → SkillsView-BxSJ4PHL.js} +1 -1
  62. package/dist/client/assets/{StashRecoveryView-CqKOFiXT.js → StashRecoveryView-BhFQ2FsP.js} +1 -1
  63. package/dist/client/assets/{TodoView-BqIRwcZw.js → TodoView-BZpewjy0.js} +2 -2
  64. package/dist/client/assets/WorkflowNodeEditor-Yn1FRF2v.css +1 -0
  65. package/dist/client/assets/WorkflowNodeEditor-tWsgCdVt.js +8 -0
  66. package/dist/client/assets/{addon-fit-B4jkcKk4.js → addon-fit-SnYDEvGm.js} +1 -1
  67. package/dist/client/assets/{addon-unicode11-Cdne2Sj4.js → addon-unicode11-s5GoZCpi.js} +1 -1
  68. package/dist/client/assets/{addon-web-links-CRNLzj7m.js → addon-web-links-jjt2f_oV.js} +1 -1
  69. package/dist/client/assets/{addon-webgl-CeCSULF1.js → addon-webgl-Icn-RnEx.js} +1 -1
  70. package/dist/client/assets/{app-sEkTyT-w.js → app-BmGA0Hiz.js} +3 -3
  71. package/dist/client/assets/{app-BffGU_HQ.js → app-CEVYlVuJ.js} +3 -3
  72. package/dist/client/assets/{app-C8AHhs5N.js → app-CbBFax2C.js} +3 -3
  73. package/dist/client/assets/{app-B2ZxMfJT.js → app-DORKrGAz.js} +3 -3
  74. package/dist/client/assets/{app-Ri9Te2Dv.js → app-DQibuQ9z.js} +3 -3
  75. package/dist/client/assets/app-k76GrQP0.js +13 -0
  76. package/dist/client/assets/{createLucideIcon-BYvOGRiO.js → createLucideIcon-DmVITl5d.js} +1 -1
  77. package/dist/client/assets/{dashboard-view-C3SsjXo1.js → dashboard-view-B4LXCv5H.js} +4 -4
  78. package/dist/client/assets/{dashboard-view-DlKsVySD.js → dashboard-view-BFoyhTYF.js} +1 -1
  79. package/dist/client/assets/{dashboard-view-BhbN8LPh.js → dashboard-view-Cxzm_eqc.js} +1 -1
  80. package/dist/client/assets/dashboard-view-_8yfNwju.css +1 -0
  81. package/dist/client/assets/{folder-open-Bw1mxVfa.js → folder-open-33WGVnbp.js} +1 -1
  82. package/dist/client/assets/index-Bglw05rM.js +791 -0
  83. package/dist/client/assets/index-FYgnflWD.css +1 -0
  84. package/dist/client/assets/shield-alert-CqeGWBUK.js +6 -0
  85. package/dist/client/assets/{upload-BCmd-1I0.js → upload-C11J2diI.js} +1 -1
  86. package/dist/client/assets/{users-DO_t3V1p.js → users-a-ELbyyZ.js} +1 -1
  87. package/dist/client/assets/{vendor-i18n-CV0mwX_-.js → vendor-i18n-DYlSUfot.js} +1 -1
  88. package/dist/client/assets/vendor-react-BTgM5bbZ.js +49 -0
  89. package/dist/client/assets/{vendor-reactflow-CRZcPCXF.js → vendor-reactflow-ZasuEfF9.js} +3 -3
  90. package/dist/client/assets/{vendor-xterm-tcedd2Jt.js → vendor-xterm-ea7-K05z.js} +1 -1
  91. package/dist/client/assets/{x-CqNX_9E2.js → x-PItWc-wQ.js} +1 -1
  92. package/dist/client/assets/{zoom-out-CSTHbJgD.js → zoom-out-CzlHv0Kj.js} +1 -1
  93. package/dist/client/icons/icon-192.png +0 -0
  94. package/dist/client/icons/icon-512.png +0 -0
  95. package/dist/client/index.html +6 -6
  96. package/dist/client/sw.js +1 -1
  97. package/dist/client/theme-data.css +288 -285
  98. package/dist/client/version.json +1 -1
  99. package/dist/droid-cli/package.json +1 -1
  100. package/dist/droid-cli/src/__tests__/execsync-guard.test.ts +17 -0
  101. package/dist/droid-cli/src/__tests__/process-manager.test.ts +1 -45
  102. package/dist/extension.js +4780 -793
  103. package/dist/extract-zip-WL55Z3AU.js +2497 -0
  104. package/dist/index.min-CHQ3ABYJ.js +2926 -0
  105. package/dist/memory-dreams-7USISKVE.js +32 -0
  106. package/dist/memory-dreams-PBPISUDD.js +32 -0
  107. package/dist/memory-dreams-XNO2B2QF.js +32 -0
  108. package/dist/migration-EH2YOCYQ.js +15 -0
  109. package/dist/migration-PLGTTKL5.js +15 -0
  110. package/dist/migration-WZEZK22R.js +15 -0
  111. package/dist/pi-claude-cli/index.ts +47 -8
  112. package/dist/pi-claude-cli/package.json +4 -1
  113. package/dist/pi-claude-cli/src/__tests__/acp-dispatch.test.ts +80 -0
  114. package/dist/pi-claude-cli/src/__tests__/acp-driver.test.ts +423 -0
  115. package/dist/pi-claude-cli/src/__tests__/execsync-guard.test.ts +14 -0
  116. package/dist/pi-claude-cli/src/__tests__/process-manager.test.ts +1 -45
  117. package/dist/pi-claude-cli/src/__tests__/provider.test.ts +0 -1
  118. package/dist/pi-claude-cli/src/acp-driver.ts +585 -0
  119. package/dist/pi-claude-cli/src/event-bridge.ts +7 -0
  120. package/dist/pi-claude-cli/src/mcp-config.ts +29 -0
  121. package/dist/pi-claude-cli/src/process-manager.ts +6 -38
  122. package/dist/plugin-sdk/index.d.ts +5179 -5144
  123. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +263 -19
  124. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  125. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  126. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +37 -7
  127. package/dist/plugins/fusion-plugin-compound-engineering/manifest.json +4 -4
  128. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  129. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  130. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  131. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +1 -1
  132. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  133. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  134. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  135. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  136. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  137. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  138. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  139. package/dist/plugins/fusion-plugin-whatsapp-chat/src/__tests__/index.test.ts +5 -1
  140. package/dist/routine-store-GIJ6MXWY.js +10 -0
  141. package/dist/routine-store-HTVC2PUQ.js +10 -0
  142. package/dist/routine-store-KGHZBPDF.js +10 -0
  143. package/package.json +1 -1
  144. package/skill/fusion/references/engine-tools.md +6 -4
  145. package/dist/client/assets/AgentsView-DfznJDek.css +0 -1
  146. package/dist/client/assets/ChatView-BkAG99bj.js +0 -6
  147. package/dist/client/assets/DevServerView-C6DC0URX.js +0 -1
  148. package/dist/client/assets/DocumentsView-OCK1Vsw_.js +0 -1
  149. package/dist/client/assets/ExperimentalAgentOnboardingModal-BNpveCEk.css +0 -1
  150. package/dist/client/assets/GoalsView-CNLTn0rX.js +0 -2
  151. package/dist/client/assets/GoalsView-DI66UsjT.css +0 -1
  152. package/dist/client/assets/InsightsView-C9-mqVvf.css +0 -1
  153. package/dist/client/assets/MemoryView-D3xQIFjj.js +0 -2
  154. package/dist/client/assets/PluginManager-UHVLvWWl.css +0 -1
  155. package/dist/client/assets/PullRequestView-WQIS0zUC.css +0 -1
  156. package/dist/client/assets/ReliabilityView-QKMUDebT.js +0 -1
  157. package/dist/client/assets/ReliabilityView-eoKBhBc4.css +0 -1
  158. package/dist/client/assets/SessionTerminal-BiigPP2l.css +0 -1
  159. package/dist/client/assets/SessionTerminal-Dk1NgmN2.js +0 -2
  160. package/dist/client/assets/SettingsModal-JCaNvdAb.js +0 -31
  161. package/dist/client/assets/SettingsModal-nF_GaeeK.css +0 -1
  162. package/dist/client/assets/WorkflowNodeEditor-2jDuk2FR.js +0 -8
  163. package/dist/client/assets/WorkflowNodeEditor-BokhW3de.css +0 -1
  164. package/dist/client/assets/app-CUu1sm3x.js +0 -13
  165. package/dist/client/assets/dashboard-view-Du53JbmQ.css +0 -1
  166. package/dist/client/assets/index-CpTBp1RG.js +0 -793
  167. package/dist/client/assets/index-DqhCiU35.css +0 -1
  168. package/dist/client/assets/vendor-react-D37HfzIf.js +0 -49
@@ -0,0 +1,1143 @@
1
+ // ../core/dist/settings-schema.js
2
+ var DEFAULT_GLOBAL_SETTINGS = {
3
+ themeMode: "dark",
4
+ colorTheme: "default",
5
+ dashboardFontScalePct: 100,
6
+ language: void 0,
7
+ defaultProvider: void 0,
8
+ defaultModelId: void 0,
9
+ testMode: void 0,
10
+ mergeRequestContractShadowEnabled: false,
11
+ fallbackProvider: void 0,
12
+ fallbackModelId: void 0,
13
+ defaultThinkingLevel: void 0,
14
+ ntfyEnabled: false,
15
+ ntfyTopic: void 0,
16
+ ntfyBaseUrl: void 0,
17
+ ntfyAccessToken: void 0,
18
+ ntfyEvents: [
19
+ "in-review",
20
+ "merged",
21
+ "failed",
22
+ "awaiting-approval",
23
+ "awaiting-user-review",
24
+ "planning-awaiting-input",
25
+ "message:agent-to-user",
26
+ "message:agent-to-agent",
27
+ "message:room",
28
+ "gridlock",
29
+ "board-stall-unrecovered",
30
+ "fallback-used",
31
+ "memory-dreams-processed",
32
+ "token-budget"
33
+ ],
34
+ ntfyDashboardHost: void 0,
35
+ taskTokenBudget: void 0,
36
+ failureNotificationDelayMs: 3e4,
37
+ failureNotificationMode: "sticky-only",
38
+ webhookEnabled: false,
39
+ webhookUrl: void 0,
40
+ webhookFormat: "generic",
41
+ webhookEvents: [],
42
+ notificationProviders: [],
43
+ customProviders: [],
44
+ defaultProjectId: void 0,
45
+ setupComplete: void 0,
46
+ cliOnboardingCompletedAt: void 0,
47
+ favoriteProviders: void 0,
48
+ favoriteModels: void 0,
49
+ openrouterModelSync: true,
50
+ openrouterAppAttribution: void 0,
51
+ openrouterModelFilters: void 0,
52
+ openrouterProviderPreferences: void 0,
53
+ opencodeGoModelSync: true,
54
+ updateCheckEnabled: true,
55
+ fnBinaryCheckEnabled: true,
56
+ updateCheckFrequency: "daily",
57
+ autoReloadOnVersionChange: true,
58
+ githubTrackingDefaultRepo: void 0,
59
+ modelOnboardingComplete: void 0,
60
+ useClaudeCli: void 0,
61
+ useDroidCli: void 0,
62
+ useLlamaCpp: void 0,
63
+ // Global baseline lanes for per-role model selection
64
+ executionGlobalProvider: void 0,
65
+ executionGlobalModelId: void 0,
66
+ planningGlobalProvider: void 0,
67
+ planningGlobalModelId: void 0,
68
+ validatorGlobalProvider: void 0,
69
+ validatorGlobalModelId: void 0,
70
+ titleSummarizerGlobalProvider: void 0,
71
+ titleSummarizerGlobalModelId: void 0,
72
+ // Daemon mode settings
73
+ daemonToken: void 0,
74
+ daemonPort: 4040,
75
+ daemonHost: "127.0.0.1",
76
+ // Node settings sync
77
+ settingsSyncEnabled: false,
78
+ settingsSyncAuth: false,
79
+ settingsSyncInterval: 9e5,
80
+ settingsSyncConflictResolution: "last-write-wins",
81
+ // Dashboard session state (persisted to global settings for PWA/offline restore)
82
+ dashboardCurrentNodeId: void 0,
83
+ dashboardCurrentProjectIdByNode: void 0,
84
+ // Dashboard TUI memory guard
85
+ vitestAutoKillEnabled: true,
86
+ vitestKillThresholdPct: 90,
87
+ // Agent log persistence controls
88
+ persistAgentToolOutput: true,
89
+ persistAgentThinkingLogPermanent: false,
90
+ persistAgentThinkingLogEphemeral: false,
91
+ persistAgentThinkingLog: false,
92
+ agentMemoryInclusionMode: "full",
93
+ secretsAccessPolicy: void 0,
94
+ secretsSyncPassphraseConfigured: false,
95
+ researchGlobalDefaults: {
96
+ searchProvider: void 0,
97
+ synthesisProvider: void 0,
98
+ synthesisModelId: void 0,
99
+ enabledSources: {
100
+ webSearch: true,
101
+ pageFetch: true,
102
+ github: false,
103
+ localDocs: true,
104
+ llmSynthesis: true
105
+ },
106
+ maxSourcesPerRun: 20,
107
+ defaultExportFormat: "markdown"
108
+ },
109
+ researchGlobalEnabled: true,
110
+ researchGlobalMaxConcurrentRuns: 3,
111
+ researchGlobalDefaultTimeout: 3e5,
112
+ researchGlobalMaxSourcesPerRun: 20,
113
+ researchGlobalMaxSynthesisRounds: 2,
114
+ researchGlobalWebSearchProvider: "builtin",
115
+ researchGlobalSearxngUrl: void 0,
116
+ researchGlobalBraveApiKey: void 0,
117
+ researchGlobalGoogleSearchApiKey: void 0,
118
+ researchGlobalGoogleSearchCx: void 0,
119
+ researchGlobalTavilyApiKey: void 0,
120
+ researchGlobalGitHubEnabled: false,
121
+ researchGlobalLocalDocsEnabled: true,
122
+ researchGlobalMaxSearchResults: 10,
123
+ researchGlobalFetchTimeoutMs: 3e4,
124
+ researchGlobalUserAgent: "FusionResearchBot/1.0",
125
+ remoteAccess: {
126
+ activeProvider: null,
127
+ providers: {
128
+ tailscale: {
129
+ enabled: false,
130
+ hostname: "",
131
+ targetPort: 0,
132
+ acceptRoutes: false
133
+ },
134
+ cloudflare: {
135
+ enabled: false,
136
+ quickTunnel: true,
137
+ tunnelName: "",
138
+ tunnelToken: null,
139
+ ingressUrl: ""
140
+ }
141
+ },
142
+ tokenStrategy: {
143
+ persistent: {
144
+ enabled: true,
145
+ token: null
146
+ },
147
+ shortLived: {
148
+ enabled: false,
149
+ ttlMs: 9e5,
150
+ maxTtlMs: 864e5
151
+ }
152
+ },
153
+ lifecycle: {
154
+ rememberLastRunning: false,
155
+ wasRunningOnShutdown: false,
156
+ lastRunningProvider: null
157
+ }
158
+ },
159
+ worktrunk: {
160
+ enabled: false,
161
+ binaryPath: void 0,
162
+ installedBinaryPath: void 0,
163
+ onFailure: "fail"
164
+ },
165
+ owningNodeHandoffPolicy: "reassign-to-local",
166
+ experimentalFeatures: {},
167
+ cliAgents: {}
168
+ };
169
+ var DEFAULT_PROJECT_SETTINGS = {
170
+ globalPause: false,
171
+ globalPauseReason: void 0,
172
+ defaultWorkflowId: void 0,
173
+ enabledBuiltinWorkflowIds: void 0,
174
+ approvedWorkflowCliCommands: void 0,
175
+ approvedCliAutonomyAdapters: void 0,
176
+ enginePaused: false,
177
+ maxConcurrent: 2,
178
+ maxTriageConcurrent: 2,
179
+ globalMaxConcurrent: 4,
180
+ maxWorktrees: 4,
181
+ pollIntervalMs: 15e3,
182
+ heartbeatMultiplier: 1,
183
+ autoClaimCandidatesInPrompt: 5,
184
+ tombstoneStickyWindowDays: 7,
185
+ heartbeatScopeDiscipline: "strict",
186
+ heartbeatPromptTemplate: "default",
187
+ groupOverlappingFiles: true,
188
+ overlapIgnorePaths: [],
189
+ autoMerge: true,
190
+ testMode: void 0,
191
+ mergeRequestContractShadowEnabled: false,
192
+ mergeStrategy: "direct",
193
+ directMergeCommitStrategy: "always-squash",
194
+ mergeIntegrationWorktree: "reuse-task-worktree",
195
+ mergeAdvanceAutoSync: "stash-and-ff",
196
+ integrationBranch: void 0,
197
+ // `requirePrApproval` MOVED to workflow settings (U4) — see MOVED_SETTINGS_KEYS.
198
+ pushAfterMerge: false,
199
+ pushRemote: "origin",
200
+ unavailableNodePolicy: "block",
201
+ owningNodeHandoffPolicy: "reassign-to-local",
202
+ defaultNodeId: void 0,
203
+ secretsEnv: void 0,
204
+ worktreeInitCommand: void 0,
205
+ testCommand: void 0,
206
+ buildCommand: void 0,
207
+ recycleWorktrees: false,
208
+ executorAllowSiblingBranchRename: false,
209
+ worktreeNaming: "random",
210
+ worktrunk: {
211
+ enabled: false,
212
+ binaryPath: void 0,
213
+ installedBinaryPath: void 0,
214
+ onFailure: "fail"
215
+ },
216
+ worktreesDir: void 0,
217
+ taskPrefix: "FN",
218
+ taskAttributionTrailerNames: ["Fusion-Task-Id"],
219
+ commitMsgHookEnabled: true,
220
+ includeTaskIdInCommit: true,
221
+ commitAuthorEnabled: true,
222
+ commitAuthorName: "Fusion",
223
+ commitAuthorEmail: "noreply@runfusion.ai",
224
+ // Per-phase model lanes (planning/execution/validator) MOVED to workflow
225
+ // settings (U4) — see MOVED_SETTINGS_KEYS. The GLOBAL baseline lanes
226
+ // (executionGlobalProvider etc.) stay global; project default overrides stay.
227
+ // Project-level default override (NOT moved — stays project-scoped)
228
+ defaultProviderOverride: void 0,
229
+ defaultModelIdOverride: void 0,
230
+ modelPresets: [],
231
+ autoSelectModelPreset: false,
232
+ completionDocumentationMode: "off",
233
+ defaultPresetBySize: {},
234
+ autoResolveConflicts: true,
235
+ smartConflictResolution: true,
236
+ mergerAutostashMaxAgeHours: 24,
237
+ worktreeRebaseBeforeMerge: true,
238
+ worktreeRebaseRemote: "",
239
+ worktreeRebaseLocalBase: true,
240
+ prerebaseAutoEnabled: true,
241
+ prerebaseHotFiles: [
242
+ "AGENTS.md",
243
+ "packages/core/src/store.ts",
244
+ "packages/core/src/db.ts",
245
+ "packages/engine/src/executor.ts",
246
+ "packages/engine/src/scheduler.ts",
247
+ "packages/engine/src/merger.ts",
248
+ "packages/dashboard/app/styles.css"
249
+ ],
250
+ prerebaseDivergenceThreshold: 50,
251
+ mergeConflictStrategy: "smart-prefer-main",
252
+ merger: { mode: "ai", maxReviewPasses: 3, allowDirtyLocalCheckoutSync: false },
253
+ mergeDiffVolumeMinLines: void 0,
254
+ mergeDiffVolumeThreshold: void 0,
255
+ mergeDiffVolumeAllowlist: void 0,
256
+ mergeStrategyOverlapBehavior: "flip-to-prefer-branch",
257
+ postMergeAuditMode: "warn",
258
+ mergeAuditAutoRecovery: "ai-assisted",
259
+ autoRecovery: {
260
+ mode: "deterministic-only",
261
+ maxRetries: 3
262
+ },
263
+ reliabilityStatsResetAt: void 0,
264
+ // Step-execution knobs (workflowStepTimeoutMs, workflowStepScopeEnforcement,
265
+ // planOnlyScopeLeakEnforcement, workflowRevisionForkOnScopeMismatch,
266
+ // strictScopeEnforcement, buildRetryCount, verificationFixRetries,
267
+ // requirePlanApproval) MOVED to workflow settings (U4) — see
268
+ // MOVED_SETTINGS_KEYS. `buildTimeoutMs` is NOT moved (no engine reader) and
269
+ // stays a plain project setting:
270
+ buildTimeoutMs: 3e5,
271
+ ephemeralAgentsEnabled: true,
272
+ agentProvisioning: {},
273
+ sandboxProvisioning: {},
274
+ defaultAgentPermissionPolicy: void 0,
275
+ specStalenessEnabled: false,
276
+ specStalenessMaxAgeMs: 6 * 60 * 60 * 1e3,
277
+ taskStuckTimeoutMs: 6e5,
278
+ /** Number of rapid todo↔in-progress cycles allowed before auto-pausing the task. */
279
+ dispatchOscillationThreshold: 5,
280
+ /** Sliding time window used to count rapid todo↔in-progress cycles. */
281
+ dispatchOscillationWindowMs: 6e4,
282
+ /** Delay before scheduler may re-dispatch an engine-requeued todo task. */
283
+ dispatchOscillationSettleMs: 5e3,
284
+ runtimeStopDrainMs: 2e3,
285
+ engineActiveSinceMs: void 0,
286
+ engineActivationGraceMs: 5 * 6e4,
287
+ inReviewStallDeadlockThreshold: 3,
288
+ stalePausedReviewThresholdMs: 24 * 60 * 6e4,
289
+ inReviewStalledThresholdMs: 24 * 60 * 6e4,
290
+ stalePausedTodoThresholdMs: 24 * 60 * 6e4,
291
+ pausedScopeDecayMs: 30 * 6e4,
292
+ metaTaskStallAutoCloseMs: 2 * 60 * 6e4,
293
+ metaTaskActiveExecutionGraceMs: 30 * 6e4,
294
+ boardStallSweepWindowMs: 2 * 60 * 6e4,
295
+ boardStallBlockedGrowthThreshold: 3,
296
+ // Capacity risk warning default: only warn once todo is meaningfully backlogged.
297
+ capacityRiskBannerEnabled: false,
298
+ capacityRiskTodoThreshold: 20,
299
+ backlogPressureAlertEnabled: true,
300
+ backlogPressureRatioThreshold: 10,
301
+ backlogPressureMinTodoCount: 5,
302
+ backlogPressureAlertCooldownMs: 24 * 60 * 6e4,
303
+ dependencyBlockedTodoReportEnabled: true,
304
+ dependencyBlockedTodoFreshAgeMs: 30 * 6e4,
305
+ dependencyBlockedTodoStaleAgeMs: 4 * 60 * 6e4,
306
+ dependencyBlockedTodoMinCount: 1,
307
+ dependencyBlockedTodoReportCooldownMs: 6 * 60 * 6e4,
308
+ staleHighFanoutBlockerAgeThresholdMs: 2 * 60 * 60 * 1e3,
309
+ staleInProgressWarningMs: 4 * 60 * 6e4,
310
+ staleInProgressCriticalMs: 24 * 60 * 6e4,
311
+ staleInReviewWarningMs: 24 * 60 * 6e4,
312
+ staleInReviewCriticalMs: 3 * 24 * 60 * 6e4,
313
+ aiSessionTtlMs: 7 * 24 * 60 * 60 * 1e3,
314
+ aiSessionCleanupIntervalMs: 60 * 60 * 1e3,
315
+ autoUnpauseEnabled: true,
316
+ autoUnpauseBaseDelayMs: 3e5,
317
+ autoUnpauseMaxDelayMs: 36e5,
318
+ maxStuckKills: 6,
319
+ maxBranchConflictRecoveries: 5,
320
+ // maxReviewerContextRetries / maxReviewerFallbackRetries MOVED to workflow
321
+ // settings (U4) — see MOVED_SETTINGS_KEYS.
322
+ maxTotalRetriesBeforeFail: 25,
323
+ preserveProgressOnStuckRequeue: true,
324
+ // maxPostReviewFixes MOVED to workflow settings (U4).
325
+ maxSpawnedAgentsPerParent: 5,
326
+ maxSpawnedAgentsGlobal: 20,
327
+ // Run maintenance (including WAL checkpointing) every 5 minutes by default.
328
+ maintenanceIntervalMs: 3e5,
329
+ autoArchiveDoneTasksEnabled: true,
330
+ autoArchiveDoneAfterMs: 48 * 60 * 60 * 1e3,
331
+ doneAutoArchiveDays: 0,
332
+ archiveAgentLogMode: "compact",
333
+ autoUpdatePrStatus: false,
334
+ githubCommentOnDone: false,
335
+ githubCommentTemplate: void 0,
336
+ githubCloseSourceIssueOnDone: false,
337
+ githubTrackingEnabledByDefault: false,
338
+ githubTrackingDefaultRepo: void 0,
339
+ githubTrackingDedupEnabled: true,
340
+ githubAuthMode: "gh-cli",
341
+ githubAuthToken: void 0,
342
+ autoBackupEnabled: false,
343
+ autoBackupSchedule: "0 2 * * *",
344
+ autoBackupRetention: 7,
345
+ autoBackupDir: ".fusion/backups",
346
+ memoryBackupEnabled: false,
347
+ memoryBackupSchedule: "0 3 * * *",
348
+ memoryBackupRetention: 14,
349
+ memoryBackupDir: ".fusion/backups/memory",
350
+ memoryBackupScope: "all",
351
+ autoSummarizeTitles: false,
352
+ useAiMergeCommitSummary: true,
353
+ // Title-summarizer model lanes stay project-scoped (not moved in U4).
354
+ titleSummarizerProvider: void 0,
355
+ titleSummarizerModelId: void 0,
356
+ titleSummarizerFallbackProvider: void 0,
357
+ titleSummarizerFallbackModelId: void 0,
358
+ scripts: void 0,
359
+ setupScript: void 0,
360
+ insightExtractionEnabled: false,
361
+ insightExtractionSchedule: "0 2 * * *",
362
+ insightExtractionMinIntervalMs: 864e5,
363
+ taskEvaluationEnabled: false,
364
+ taskEvaluationSchedule: "0 5 * * *",
365
+ taskEvaluationProvider: void 0,
366
+ taskEvaluationModelId: void 0,
367
+ taskEvaluationFollowUpPolicy: "off",
368
+ taskEvaluationRetention: void 0,
369
+ memoryEnabled: true,
370
+ memoryBackendType: "qmd",
371
+ memoryAutoSummarizeEnabled: false,
372
+ memoryAutoSummarizeThresholdChars: 5e4,
373
+ memoryAutoSummarizeSchedule: "0 3 * * *",
374
+ memoryDreamsEnabled: false,
375
+ memoryDreamsSchedule: "0 4 * * *",
376
+ tokenCap: void 0,
377
+ taskTokenBudget: void 0,
378
+ // runStepsInNewSessions / maxParallelSteps MOVED to workflow settings (U4) —
379
+ // see MOVED_SETTINGS_KEYS.
380
+ missionStaleThresholdMs: 6e5,
381
+ missionMaxTaskRetries: 3,
382
+ missionHealthCheckIntervalMs: 3e5,
383
+ agentPrompts: void 0,
384
+ promptOverrides: void 0,
385
+ // reflectionEnabled MOVED to workflow settings (U4). reflectionIntervalMs /
386
+ // reflectionAfterTask have no engine reader, so they STAY plain project
387
+ // settings (catalog-shrink rule) and are NOT in MOVED_SETTINGS_KEYS.
388
+ reflectionIntervalMs: 36e5,
389
+ reflectionAfterTask: true,
390
+ // reviewHandoffPolicy MOVED to workflow settings (U4) — see MOVED_SETTINGS_KEYS.
391
+ showQuickChatFAB: false,
392
+ chatAutoCleanupDays: 0,
393
+ mailAutoCleanupDays: 0,
394
+ operationalLogRetentionDays: 30,
395
+ agentLogFileRetentionDays: 0,
396
+ chatRoomRecentVerbatimMessages: 25,
397
+ chatRoomCompactionFetchLimit: 200,
398
+ chatRoomSummaryMaxChars: 3e3,
399
+ researchSettings: {
400
+ enabled: true,
401
+ searchProvider: void 0,
402
+ synthesisProvider: void 0,
403
+ synthesisModelId: void 0,
404
+ enabledSources: {
405
+ webSearch: true,
406
+ pageFetch: true,
407
+ github: false,
408
+ localDocs: true,
409
+ llmSynthesis: true
410
+ },
411
+ limits: {
412
+ maxConcurrentRuns: 3,
413
+ maxSourcesPerRun: 20,
414
+ maxDurationMs: 3e5,
415
+ requestTimeoutMs: 3e4
416
+ }
417
+ },
418
+ sandbox: {
419
+ backend: "native",
420
+ policy: {
421
+ allowNetwork: true,
422
+ allowedPaths: []
423
+ },
424
+ failureMode: "fail-hard"
425
+ },
426
+ evalSettings: {
427
+ enabled: false,
428
+ intervalMs: 864e5,
429
+ evaluatorProvider: void 0,
430
+ evaluatorModelId: void 0,
431
+ followUpPolicy: "suggest-only",
432
+ retentionDays: 30
433
+ },
434
+ researchEnabled: true,
435
+ researchMaxConcurrentRuns: 3,
436
+ researchDefaultTimeout: 3e5,
437
+ researchMaxSourcesPerRun: 20,
438
+ researchMaxSynthesisRounds: 2
439
+ };
440
+ var DEFAULT_SETTINGS = {
441
+ ...DEFAULT_GLOBAL_SETTINGS,
442
+ ...DEFAULT_PROJECT_SETTINGS
443
+ };
444
+ var GLOBAL_SETTINGS_KEYS = Object.freeze(Object.keys(DEFAULT_GLOBAL_SETTINGS));
445
+ var PROJECT_SETTINGS_KEYS = Object.freeze(Object.keys(DEFAULT_PROJECT_SETTINGS));
446
+ function isGlobalSettingsKey(key) {
447
+ return GLOBAL_SETTINGS_KEYS.includes(key);
448
+ }
449
+ function isProjectSettingsKey(key) {
450
+ return PROJECT_SETTINGS_KEYS.includes(key);
451
+ }
452
+ function isGlobalOnlySettingsKey(key) {
453
+ return isGlobalSettingsKey(key) && !isProjectSettingsKey(key);
454
+ }
455
+ var CLI_AGENT_ADAPTER_IDS = Object.freeze([
456
+ "claude-code",
457
+ "codex",
458
+ "droid",
459
+ "pi",
460
+ "generic"
461
+ ]);
462
+ var CLI_AGENT_AUTONOMY_MODES = Object.freeze(["default", "elevated"]);
463
+ function sanitizeStringArray(value) {
464
+ if (!Array.isArray(value))
465
+ return void 0;
466
+ const cleaned = value.filter((v) => typeof v === "string").map((v) => v.trim()).filter((v) => v.length > 0);
467
+ return cleaned.length > 0 ? cleaned : void 0;
468
+ }
469
+ function sanitizeCliAgentSettings(value) {
470
+ if (!value || typeof value !== "object" || Array.isArray(value))
471
+ return void 0;
472
+ const input = value;
473
+ const out = {};
474
+ if (typeof input.commandOverride === "string") {
475
+ const trimmed = input.commandOverride.trim();
476
+ if (trimmed.length > 0)
477
+ out.commandOverride = trimmed;
478
+ }
479
+ const extraArgs = sanitizeStringArray(input.extraArgs);
480
+ if (extraArgs)
481
+ out.extraArgs = extraArgs;
482
+ const envAdditions = sanitizeStringArray(input.envAdditions);
483
+ if (envAdditions)
484
+ out.envAdditions = envAdditions;
485
+ if (typeof input.autonomyMode === "string" && CLI_AGENT_AUTONOMY_MODES.includes(input.autonomyMode)) {
486
+ out.autonomyMode = input.autonomyMode;
487
+ }
488
+ return Object.keys(out).length > 0 ? out : void 0;
489
+ }
490
+ function sanitizeCliAgentsSettings(value) {
491
+ if (!value || typeof value !== "object" || Array.isArray(value))
492
+ return {};
493
+ const input = value;
494
+ const out = {};
495
+ for (const adapterId of CLI_AGENT_ADAPTER_IDS) {
496
+ if (!(adapterId in input))
497
+ continue;
498
+ const entry = sanitizeCliAgentSettings(input[adapterId]);
499
+ if (entry)
500
+ out[adapterId] = entry;
501
+ }
502
+ return out;
503
+ }
504
+
505
+ // ../core/dist/error-message.js
506
+ function getErrorMessage(err) {
507
+ if (err instanceof Error)
508
+ return err.message;
509
+ if (typeof err === "string")
510
+ return err;
511
+ try {
512
+ return JSON.stringify(err);
513
+ } catch {
514
+ return String(err);
515
+ }
516
+ }
517
+
518
+ // ../core/dist/model-resolution.js
519
+ var TEST_MODE_RESOLVED = { provider: "mock", modelId: "scripted" };
520
+ function isTestModeActive(settings) {
521
+ return settings?.testMode === true || settings?.defaultProvider?.trim().toLowerCase() === "mock";
522
+ }
523
+ function applyTestModeOverrides(resolved, settings) {
524
+ return isTestModeActive(settings) ? TEST_MODE_RESOLVED : resolved;
525
+ }
526
+ function hasCompleteModelPair(pair) {
527
+ return Boolean(pair?.provider && pair?.modelId);
528
+ }
529
+ function pickFirstModelPair(...pairs) {
530
+ for (const pair of pairs) {
531
+ if (hasCompleteModelPair(pair)) {
532
+ return { provider: pair.provider, modelId: pair.modelId };
533
+ }
534
+ }
535
+ return {};
536
+ }
537
+ function resolveProjectDefaultModel(settings) {
538
+ return applyTestModeOverrides(pickFirstModelPair({
539
+ provider: settings?.defaultProviderOverride,
540
+ modelId: settings?.defaultModelIdOverride
541
+ }, {
542
+ provider: settings?.defaultProvider,
543
+ modelId: settings?.defaultModelId
544
+ }), settings);
545
+ }
546
+ function resolveTitleSummarizerSettingsModel(settings) {
547
+ return applyTestModeOverrides(pickFirstModelPair({
548
+ provider: settings?.titleSummarizerProvider,
549
+ modelId: settings?.titleSummarizerModelId
550
+ }, {
551
+ provider: settings?.titleSummarizerGlobalProvider,
552
+ modelId: settings?.titleSummarizerGlobalModelId
553
+ }, {
554
+ provider: settings?.planningProvider,
555
+ modelId: settings?.planningModelId
556
+ }, resolveProjectDefaultModel(settings)), settings);
557
+ }
558
+
559
+ // ../core/dist/experimental-features.js
560
+ var LEGACY_EXPERIMENTAL_FEATURE_ALIASES = {
561
+ devServer: "devServerView"
562
+ };
563
+ function isExperimentalFeatureEnabled(settings, key) {
564
+ const features = settings?.experimentalFeatures;
565
+ if (!features)
566
+ return false;
567
+ const canonicalKey = LEGACY_EXPERIMENTAL_FEATURE_ALIASES[key] ?? key;
568
+ if (features[canonicalKey] === true)
569
+ return true;
570
+ for (const [legacyKey, aliasCanonical] of Object.entries(LEGACY_EXPERIMENTAL_FEATURE_ALIASES)) {
571
+ if (aliasCanonical === canonicalKey && features[legacyKey] === true) {
572
+ return true;
573
+ }
574
+ }
575
+ return false;
576
+ }
577
+
578
+ // ../core/dist/types.js
579
+ var COLUMNS = ["triage", "todo", "in-progress", "in-review", "done", "archived"];
580
+ var TASK_PRIORITIES = ["low", "normal", "high", "urgent"];
581
+ var DEFAULT_TASK_PRIORITY = "normal";
582
+ var STALE_HIGH_FANOUT_BLOCKER_AGE_THRESHOLD_MS = 2 * 60 * 60 * 1e3;
583
+ var SUPPORTED_LOCALES = ["en", "zh-CN", "zh-TW", "fr", "es", "ko"];
584
+ function isLocale(value) {
585
+ return typeof value === "string" && SUPPORTED_LOCALES.includes(value);
586
+ }
587
+ var WORKFLOW_STEP_TEMPLATES = [
588
+ {
589
+ id: "documentation-review",
590
+ name: "Documentation Review",
591
+ description: "Verify all public APIs, functions, and complex logic have appropriate documentation",
592
+ category: "Quality",
593
+ icon: "file-text",
594
+ toolMode: "readonly",
595
+ prompt: `You are a documentation reviewer. Review the completed task and verify documentation quality.
596
+
597
+ Review Criteria:
598
+ 1. All new public functions, classes, and modules have JSDoc comments or equivalent documentation
599
+ 2. Complex logic has inline comments explaining the "why" not just the "what"
600
+ 3. README files are updated if the task changes user-facing behavior
601
+ 4. CHANGELOG or release notes are considered for significant changes
602
+ 5. Type definitions are documented for public APIs
603
+
604
+ Files to Review:
605
+ - Review all files modified in the task worktree
606
+ - Focus on public API surface area
607
+ - Check test files for test documentation
608
+
609
+ Output Requirements:
610
+ - Fast-bail: if Diff Scope contains no documentation-relevant files, output {"verdict":"APPROVE","notes":"out of scope: documentation"} immediately.
611
+ - APPROVE: documentation is adequate; use empty or brief notes.
612
+ - APPROVE_WITH_NOTES: documentation is adequate with advisory improvements; include concise suggestions in notes.
613
+ - REVISE: documentation is missing or incorrect; include actionable file paths/functions in notes.
614
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
615
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}`
616
+ },
617
+ {
618
+ id: "qa-check",
619
+ name: "QA Check",
620
+ description: "Run lint, tests, and typecheck; verify they pass and check for obvious bugs",
621
+ category: "Quality",
622
+ icon: "check-circle",
623
+ toolMode: "coding",
624
+ prompt: `You are a QA tester. Verify the task implementation by running lint, tests, and typecheck, and checking for bugs.
625
+
626
+ Quality Gate Execution (all three must pass):
627
+ 1. Run the project's lint command (e.g. \`pnpm lint\`, \`npm run lint\`)
628
+ 2. Run the project's test suite (e.g. \`pnpm test\`, \`npm test\`, or the configured test command)
629
+ 3. Run the project's typecheck command if one exists (e.g. \`pnpm typecheck\`, \`tsc --noEmit\`)
630
+ 4. Verify lint, tests, and typecheck all pass
631
+ 5. If any gate fails, analyze whether failures are related to the task changes
632
+
633
+ Code Review:
634
+ 1. Review the changes for obvious bugs or edge cases
635
+ 2. Check error handling is appropriate
636
+ 3. Verify input validation is present where needed
637
+ 4. Look for common issues: null pointer risks, off-by-one errors, race conditions
638
+
639
+ Output Requirements:
640
+ - Fast-bail: if Diff Scope contains no QA-relevant files, output {"verdict":"APPROVE","notes":"out of scope: QA"} immediately.
641
+ - APPROVE: lint/tests/typecheck pass and no actionable bugs.
642
+ - APPROVE_WITH_NOTES: quality gates pass but include non-blocking advisories in notes.
643
+ - REVISE: any gate fails or actionable bugs are found; include failing commands and affected file paths in notes.
644
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
645
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}`
646
+ },
647
+ {
648
+ id: "security-audit",
649
+ name: "Security Audit",
650
+ description: "Check for common security vulnerabilities and anti-patterns",
651
+ category: "Security",
652
+ icon: "shield",
653
+ toolMode: "readonly",
654
+ prompt: `You are a security auditor. Review the task changes for common security vulnerabilities.
655
+
656
+ Security Checklist:
657
+ 1. **Injection vulnerabilities** \u2014 Check for SQL injection, command injection, XSS via unsanitized user input
658
+ 2. **Secrets and credentials** \u2014 Ensure no hardcoded passwords, API keys, tokens, or private keys
659
+ 3. **Unsafe eval** \u2014 Check for eval(), new Function(), or similar dangerous patterns
660
+ 4. **Path traversal** \u2014 Verify file path handling prevents directory traversal attacks
661
+ 5. **Insecure deserialization** \u2014 Check for unsafe parsing of untrusted data
662
+ 6. **Authentication/Authorization** \u2014 Verify access controls are properly implemented
663
+ 7. **Dependency risks** \u2014 Note any new dependencies that might have known vulnerabilities
664
+
665
+ Files to Review:
666
+ - All modified files in the task
667
+ - Configuration files that might contain secrets
668
+ - Areas handling user input or external data
669
+
670
+ Output Requirements:
671
+ - Fast-bail: if Diff Scope contains no security-relevant files, output {"verdict":"APPROVE","notes":"out of scope: security"} immediately.
672
+ - APPROVE: no security issues found.
673
+ - APPROVE_WITH_NOTES: no blocking issues, but include advisory hardening opportunities in notes.
674
+ - REVISE: vulnerabilities require changes; include file paths, severity, and remediation guidance in notes.
675
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
676
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}`
677
+ },
678
+ {
679
+ id: "performance-review",
680
+ name: "Performance Review",
681
+ description: "Check for performance anti-patterns and optimization opportunities",
682
+ category: "Quality",
683
+ icon: "zap",
684
+ toolMode: "readonly",
685
+ prompt: `You are a performance reviewer. Analyze the task changes for performance implications.
686
+
687
+ Performance Checklist:
688
+ 1. **Algorithmic complexity** \u2014 Check for O(n\xB2) or worse patterns that could bottleneck
689
+ 2. **N+1 queries** \u2014 Look for database queries in loops
690
+ 3. **Memory leaks** \u2014 Check for unclosed resources, event listeners, or accumulating caches
691
+ 4. **Unnecessary re-renders** \u2014 For UI code, check for inefficient React/Angular/Vue patterns
692
+ 5. **Bundle size** \u2014 Note if large dependencies are added unnecessarily
693
+ 6. **Async patterns** \u2014 Verify proper use of async/await, Promise.all for parallel work
694
+ 7. **Caching opportunities** \u2014 Identify where caching could improve performance
695
+
696
+ Files to Review:
697
+ - All modified files, focusing on hot paths and frequently executed code
698
+ - Database query files
699
+ - API endpoints and route handlers
700
+
701
+ Output Requirements:
702
+ - Fast-bail: if Diff Scope contains no performance-relevant files, output {"verdict":"APPROVE","notes":"out of scope: performance"} immediately.
703
+ - APPROVE: performance impact is acceptable.
704
+ - APPROVE_WITH_NOTES: acceptable overall, but include optimization advisories in notes.
705
+ - REVISE: performance risks require changes; include actionable file paths and optimization guidance in notes.
706
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
707
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}`
708
+ },
709
+ {
710
+ id: "accessibility-check",
711
+ name: "Accessibility Check",
712
+ description: "Verify UI changes meet accessibility standards (WCAG 2.1)",
713
+ category: "Quality",
714
+ icon: "eye",
715
+ toolMode: "readonly",
716
+ prompt: `You are an accessibility reviewer. Check UI changes for WCAG 2.1 compliance.
717
+
718
+ Accessibility Checklist:
719
+ 1. **Keyboard navigation** \u2014 Ensure all interactive elements are keyboard accessible
720
+ 2. **ARIA labels** \u2014 Check that screen reader announcements are appropriate
721
+ 3. **Color contrast** \u2014 Verify text meets minimum contrast ratios (4.5:1 for normal text)
722
+ 4. **Focus indicators** \u2014 Ensure visible focus states for keyboard navigation
723
+ 5. **Alt text** \u2014 Check that images have meaningful alternative text
724
+ 6. **Form labels** \u2014 Verify all inputs have associated labels
725
+ 7. **Semantic HTML** \u2014 Check that proper HTML elements are used (buttons not divs)
726
+
727
+ Files to Review:
728
+ - Modified UI components
729
+ - CSS/styling changes
730
+ - New HTML templates or JSX
731
+
732
+ Output Requirements:
733
+ - Fast-bail: if Diff Scope contains no accessibility-relevant UI files, output {"verdict":"APPROVE","notes":"out of scope: accessibility"} immediately.
734
+ - APPROVE: accessibility requirements are met.
735
+ - APPROVE_WITH_NOTES: compliant overall, with advisory improvements in notes.
736
+ - REVISE: accessibility issues require changes; include file paths, WCAG references, and remediation steps in notes.
737
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
738
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}`
739
+ },
740
+ {
741
+ id: "browser-verification",
742
+ name: "Browser Verification",
743
+ description: "Verify web application functionality using browser automation",
744
+ category: "Quality",
745
+ icon: "globe",
746
+ toolMode: "coding",
747
+ prompt: `You are a browser verification specialist. Verify web application functionality after task implementation using the agent-browser CLI tool.
748
+
749
+ ## Prerequisites
750
+ First, determine the URL to verify. Check the task PROMPT.md for any URLs mentioned, or look at the code changes to identify the local development server URL (typically http://localhost:3000, http://localhost:5173, http://localhost:8080, etc.).
751
+
752
+ ## Verification Commands
753
+ Use these agent-browser commands for verification:
754
+ - \`agent-browser open <url>\` \u2014 Navigate to the page
755
+ - \`agent-browser snapshot -i\` \u2014 Get interactive elements with refs (@e1, @e2, etc.)
756
+ - \`agent-browser click @e1\` \u2014 Click an element
757
+ - \`agent-browser fill @e1 "text"\` \u2014 Fill an input field
758
+ - \`agent-browser get text @e1\` \u2014 Get element text content
759
+ - \`agent-browser screenshot\` \u2014 Capture screenshot to file
760
+ - \`agent-browser wait --load networkidle\` \u2014 Wait for page to fully load
761
+
762
+ ## Verification Checklist
763
+ 1. Page loads without JavaScript errors or blank screens
764
+ 2. Navigation between pages/sections works
765
+ 3. Forms accept input and submit correctly
766
+ 4. Interactive elements (buttons, links) respond to clicks
767
+ 5. Error states are handled gracefully
768
+ 6. Screenshots capture expected content
769
+
770
+ ## Output Requirements
771
+ - Fast-bail: if Diff Scope contains no browser-verification-relevant UI files, output {"verdict":"APPROVE","notes":"out of scope: browser verification"} immediately.
772
+ - APPROVE: verification succeeds.
773
+ - APPROVE_WITH_NOTES: verification succeeds with non-blocking advisory findings; include evidence references in notes.
774
+ - REVISE: verification failures or regressions require changes; include failing behavior and actionable file paths in notes.
775
+ - Screenshots/artifacts referenced in notes are evidence only; verdict must be conveyed by the final JSON line.
776
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
777
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}
778
+
779
+ Note: Refs (@e1, @e2) are invalidated after page navigation. Re-snapshot after clicking links or form submissions.`
780
+ },
781
+ {
782
+ id: "frontend-ux-design",
783
+ name: "Frontend UX Design",
784
+ description: "Verify visual polish and consistency with existing UI patterns and design tokens",
785
+ category: "Quality",
786
+ icon: "layout-grid",
787
+ toolMode: "readonly",
788
+ prompt: `You are a UX design reviewer. Verify frontend changes maintain visual polish and consistency with existing UI patterns and design tokens.
789
+
790
+ ## Step 1: Scope Check (MANDATORY FIRST)
791
+
792
+ The task harness provides a "Diff Scope" listing files this task actually changed.
793
+
794
+ If the Diff Scope contains ZERO frontend/UI files (no .tsx/.jsx/.ts/.js component files, no .css/.scss/.sass/.styl, no .html/.vue/.svelte/.astro, no design-token/theme files), output ONLY:
795
+ {"verdict":"APPROVE","notes":"out of scope: frontend UX design"}
796
+ Then STOP. Do not browse the worktree. Do not read any files.
797
+
798
+ If there ARE frontend/UI files in scope, proceed to Step 2.
799
+
800
+ ## Step 2: Design Review
801
+
802
+ Restrict your review to ONLY the UI files in the diff scope.
803
+
804
+ Check:
805
+ 1. **Visual Hierarchy** \u2014 heading levels, content flow, information architecture
806
+ 2. **Spacing and Typography** \u2014 consistent margins, padding, gaps, type scale
807
+ 3. **Color and Token Consistency** \u2014 CSS custom properties and design tokens used; no hardcoded colors
808
+ 4. **Component Reuse** \u2014 existing components reused; no one-off styling or duplication
809
+ 5. **Responsive Behavior** \u2014 layouts adapt across viewports
810
+ 6. **Fit with Design Language** \u2014 border radius, shadows, transitions, icon style match patterns
811
+
812
+ ## Output Format
813
+
814
+ - APPROVE: visual quality is acceptable; use empty or brief notes.
815
+ - APPROVE_WITH_NOTES: acceptable with non-blocking polish advisories; include specific notes.
816
+ - REVISE: issues require code changes; include specific files and required changes in notes.
817
+ - Final output: output exactly one trailing JSON object on the final line (no markdown fences, no surrounding prose):
818
+ {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}
819
+
820
+ Prioritize: layout breaks > visual inconsistency > style preferences.
821
+ Do NOT spend time on nits when no real issues exist.`
822
+ }
823
+ ];
824
+ var DOCUMENT_KEY_RE = /^[a-zA-Z0-9_-]{1,64}$/;
825
+ function validateDocumentKey(key) {
826
+ if (!DOCUMENT_KEY_RE.test(key)) {
827
+ throw new Error(`Invalid document key: "${key}". Must be 1-64 characters: letters, digits, hyphens, or underscores.`);
828
+ }
829
+ }
830
+ var CheckoutConflictError = class extends Error {
831
+ taskId;
832
+ currentHolderId;
833
+ requestedById;
834
+ constructor(taskId, currentHolderId, requestedById) {
835
+ super(`Task ${taskId} is already checked out by agent ${currentHolderId}`);
836
+ this.taskId = taskId;
837
+ this.currentHolderId = currentHolderId;
838
+ this.requestedById = requestedById;
839
+ this.name = "CheckoutConflictError";
840
+ }
841
+ };
842
+ var SHARED_STATE_SNAPSHOT_VERSION = 1;
843
+ var VALID_TRANSITIONS = {
844
+ // FN-4892: intake-side heuristics may cold-archive tasks before execution starts.
845
+ triage: ["todo", "archived"],
846
+ // FN-4892: allow direct archival for newly specified intake tasks.
847
+ todo: ["in-progress", "triage", "archived"],
848
+ // NOTE: "in-progress" → "done" is enabled for mission validation tasks that complete directly.
849
+ // Regular implementation tasks should move through "in-review" before "done".
850
+ "in-progress": ["in-review", "todo", "triage", "done"],
851
+ "in-review": ["done", "in-progress", "todo", "triage"],
852
+ done: ["todo", "triage", "archived"],
853
+ archived: ["done"]
854
+ };
855
+ function validateDockerNodeConfig(config) {
856
+ const errors = [];
857
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
858
+ return { valid: false, errors: ["config must be an object"] };
859
+ }
860
+ const candidate = config;
861
+ if (typeof candidate.image !== "string" || !candidate.image.trim()) {
862
+ errors.push("image must be a non-empty string");
863
+ }
864
+ if (!Array.isArray(candidate.volumeMounts)) {
865
+ errors.push("volumeMounts must be an array");
866
+ } else {
867
+ candidate.volumeMounts.forEach((mount, index) => {
868
+ if (!mount || typeof mount !== "object" || Array.isArray(mount)) {
869
+ errors.push(`volumeMounts[${index}] must be an object`);
870
+ return;
871
+ }
872
+ const mountCandidate = mount;
873
+ if (typeof mountCandidate.hostPath !== "string") {
874
+ errors.push(`volumeMounts[${index}].hostPath must be a string`);
875
+ }
876
+ if (typeof mountCandidate.containerPath !== "string") {
877
+ errors.push(`volumeMounts[${index}].containerPath must be a string`);
878
+ }
879
+ if (mountCandidate.mode !== void 0 && mountCandidate.mode !== "rw" && mountCandidate.mode !== "ro") {
880
+ errors.push(`volumeMounts[${index}].mode must be "rw" or "ro"`);
881
+ }
882
+ if (mountCandidate.type !== void 0 && mountCandidate.type !== "volume" && mountCandidate.type !== "bind") {
883
+ errors.push(`volumeMounts[${index}].type must be "volume" or "bind"`);
884
+ }
885
+ });
886
+ }
887
+ if (!candidate.environment || typeof candidate.environment !== "object" || Array.isArray(candidate.environment)) {
888
+ errors.push("environment must be an object");
889
+ } else {
890
+ for (const [key, value] of Object.entries(candidate.environment)) {
891
+ if (typeof key !== "string" || typeof value !== "string") {
892
+ errors.push(`environment.${key} must be a string value`);
893
+ }
894
+ }
895
+ }
896
+ if (typeof candidate.configVersion !== "number" || !Number.isFinite(candidate.configVersion) || candidate.configVersion < 1) {
897
+ errors.push("configVersion must be a number >= 1");
898
+ }
899
+ const validateOptionalObject = (fieldName, value, validators) => {
900
+ if (value === void 0)
901
+ return;
902
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
903
+ errors.push(`${fieldName} must be an object`);
904
+ return;
905
+ }
906
+ const typed = value;
907
+ for (const [prop, test, message] of validators) {
908
+ if (typed[prop] !== void 0 && !test(typed[prop])) {
909
+ errors.push(`${fieldName}.${prop} ${message}`);
910
+ }
911
+ }
912
+ };
913
+ validateOptionalObject("resources", candidate.resources, [
914
+ ["memoryBytes", (value) => typeof value === "number" && Number.isFinite(value), "must be a number"],
915
+ ["cpuCount", (value) => typeof value === "number" && Number.isFinite(value), "must be a number"],
916
+ ["pidsLimit", (value) => typeof value === "number" && Number.isFinite(value), "must be a number"]
917
+ ]);
918
+ validateOptionalObject("host", candidate.host, [
919
+ ["contextName", (value) => typeof value === "string", "must be a string"],
920
+ ["dockerHost", (value) => typeof value === "string", "must be a string"],
921
+ ["tlsCaCert", (value) => typeof value === "string", "must be a string"],
922
+ ["tlsCert", (value) => typeof value === "string", "must be a string"],
923
+ ["tlsKey", (value) => typeof value === "string", "must be a string"],
924
+ ["tlsVerify", (value) => typeof value === "boolean", "must be a boolean"]
925
+ ]);
926
+ validateOptionalObject("persistence", candidate.persistence, [
927
+ ["volumeName", (value) => typeof value === "string", "must be a string"],
928
+ ["retainOnDelete", (value) => typeof value === "boolean", "must be a boolean"]
929
+ ]);
930
+ if (candidate.extraClis !== void 0) {
931
+ if (!Array.isArray(candidate.extraClis) || candidate.extraClis.some((item) => typeof item !== "string")) {
932
+ errors.push("extraClis must be an array of strings");
933
+ }
934
+ }
935
+ if (candidate.containerName !== void 0 && typeof candidate.containerName !== "string") {
936
+ errors.push("containerName must be a string");
937
+ }
938
+ if (candidate.lastUpdated !== void 0 && typeof candidate.lastUpdated !== "string") {
939
+ errors.push("lastUpdated must be a string");
940
+ }
941
+ if (errors.length > 0) {
942
+ return { valid: false, errors };
943
+ }
944
+ return { valid: true, config: candidate };
945
+ }
946
+ var AGENT_VALID_TRANSITIONS = {
947
+ idle: ["active"],
948
+ active: ["idle", "running", "paused", "error"],
949
+ running: ["idle", "active", "paused", "error"],
950
+ paused: ["idle", "active"],
951
+ error: ["idle", "active", "paused"]
952
+ };
953
+ function isEphemeralAgent(agent) {
954
+ const metadata = agent.metadata ?? {};
955
+ if (metadata.agentKind === "task-worker")
956
+ return true;
957
+ if (metadata.taskWorker === true)
958
+ return true;
959
+ if (metadata.managedBy === "task-executor")
960
+ return true;
961
+ if (metadata.type === "spawned")
962
+ return true;
963
+ if (metadata.internal === true)
964
+ return true;
965
+ if (agent.role === "executor" && typeof agent.name === "string" && agent.name.startsWith("executor-") && agent.reportsTo == null) {
966
+ return true;
967
+ }
968
+ if (agent.role === "executor" && agent.name === "verification-agent" && agent.reportsTo == null) {
969
+ return true;
970
+ }
971
+ return false;
972
+ }
973
+ var AGENT_PERMISSIONS = [
974
+ "tasks:assign",
975
+ // Assign tasks to agents
976
+ "tasks:create",
977
+ // Create new tasks
978
+ "tasks:execute",
979
+ // Execute/run tasks
980
+ "tasks:review",
981
+ // Review task output (code, specs)
982
+ "tasks:merge",
983
+ // Merge completed task branches
984
+ "tasks:delete",
985
+ // Delete tasks
986
+ "tasks:archive",
987
+ // Archive/unarchive tasks
988
+ "agents:create",
989
+ // Create new agents
990
+ "agents:update",
991
+ // Update agent configuration
992
+ "agents:delete",
993
+ // Delete agents
994
+ "agents:view",
995
+ // View agent details and logs
996
+ "settings:read",
997
+ // Read project settings
998
+ "settings:update",
999
+ // Modify project settings
1000
+ "workflows:manage",
1001
+ // Create/edit/delete workflow steps
1002
+ "missions:manage",
1003
+ // Create/edit/delete missions and slices
1004
+ "automations:manage",
1005
+ // Create/edit/delete scheduled automations
1006
+ "messages:send",
1007
+ // Send messages to agents/users
1008
+ "messages:read"
1009
+ // Read mailbox messages
1010
+ ];
1011
+ var AGENT_PERMISSION_POLICY_ACTION_CATEGORIES = [
1012
+ "git_write",
1013
+ "file_write_delete",
1014
+ "command_execution",
1015
+ "network_api",
1016
+ "task_agent_mutation"
1017
+ ];
1018
+ var AGENT_PERMISSION_POLICY_PRESET_IDS = ["unrestricted", "approval-required", "locked-down", "custom"];
1019
+ var DEFAULT_HEARTBEAT_PROCEDURE_PATH = ".fusion/HEARTBEAT.md";
1020
+ function slugifyAgentAssetSegment(value) {
1021
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1022
+ }
1023
+ function getSafeAgentAssetIdSegment(agentId) {
1024
+ const slug = slugifyAgentAssetSegment(agentId);
1025
+ return slug || "agent";
1026
+ }
1027
+ function getCanonicalAgentAssetDirectoryName(agentName, agentId) {
1028
+ if (!agentId || typeof agentId !== "string") {
1029
+ throw new Error("getCanonicalAgentAssetDirectoryName requires a non-empty agentId");
1030
+ }
1031
+ const safeId = getSafeAgentAssetIdSegment(agentId);
1032
+ const nameSlug = slugifyAgentAssetSegment(agentName ?? "");
1033
+ const prefix = nameSlug || safeId;
1034
+ return `${prefix}-${safeId}`;
1035
+ }
1036
+ function getLegacyAgentAssetDirectoryName(agentId) {
1037
+ if (!agentId || typeof agentId !== "string") {
1038
+ throw new Error("getLegacyAgentAssetDirectoryName requires a non-empty agentId");
1039
+ }
1040
+ return agentId;
1041
+ }
1042
+ function getCanonicalAgentInstructionsBundleDirName(agentName, agentId) {
1043
+ return `${getCanonicalAgentAssetDirectoryName(agentName, agentId)}-instructions`;
1044
+ }
1045
+ function getLegacyAgentInstructionsBundleDirName(agentId) {
1046
+ return `${getLegacyAgentAssetDirectoryName(agentId)}-instructions`;
1047
+ }
1048
+ function getDefaultHeartbeatProcedurePath(agentId, agentName) {
1049
+ if (!agentId || typeof agentId !== "string") {
1050
+ throw new Error("getDefaultHeartbeatProcedurePath requires a non-empty agentId");
1051
+ }
1052
+ const directory = agentName ? getCanonicalAgentAssetDirectoryName(agentName, agentId) : getLegacyAgentAssetDirectoryName(agentId);
1053
+ return `.fusion/agents/${directory}/HEARTBEAT.md`;
1054
+ }
1055
+ function agentToConfigSnapshot(agent) {
1056
+ return {
1057
+ name: agent.name,
1058
+ role: agent.role,
1059
+ title: agent.title,
1060
+ icon: agent.icon,
1061
+ imageUrl: agent.imageUrl,
1062
+ reportsTo: agent.reportsTo,
1063
+ runtimeConfig: agent.runtimeConfig ? { ...agent.runtimeConfig } : void 0,
1064
+ permissions: agent.permissions ? { ...agent.permissions } : void 0,
1065
+ permissionPolicy: agent.permissionPolicy ? {
1066
+ presetId: agent.permissionPolicy.presetId,
1067
+ rules: { ...agent.permissionPolicy.rules }
1068
+ } : void 0,
1069
+ instructionsPath: agent.instructionsPath,
1070
+ instructionsText: agent.instructionsText,
1071
+ soul: agent.soul,
1072
+ memory: agent.memory,
1073
+ bundleConfig: agent.bundleConfig ? {
1074
+ ...agent.bundleConfig,
1075
+ files: [...agent.bundleConfig.files]
1076
+ } : void 0,
1077
+ heartbeatProcedurePath: agent.heartbeatProcedurePath,
1078
+ metadata: { ...agent.metadata }
1079
+ };
1080
+ }
1081
+ function diffConfigSnapshots(before, after) {
1082
+ const trackedFields = [
1083
+ "name",
1084
+ "role",
1085
+ "title",
1086
+ "icon",
1087
+ "imageUrl",
1088
+ "reportsTo",
1089
+ "runtimeConfig",
1090
+ "permissions",
1091
+ "permissionPolicy",
1092
+ "instructionsPath",
1093
+ "instructionsText",
1094
+ "soul",
1095
+ "memory",
1096
+ "bundleConfig",
1097
+ "heartbeatProcedurePath",
1098
+ "metadata"
1099
+ ];
1100
+ const diffs = [];
1101
+ for (const field of trackedFields) {
1102
+ const oldVal = before[field];
1103
+ const newVal = after[field];
1104
+ if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
1105
+ diffs.push({ field, oldValue: oldVal, newValue: newVal });
1106
+ }
1107
+ }
1108
+ return diffs;
1109
+ }
1110
+
1111
+ export {
1112
+ DEFAULT_GLOBAL_SETTINGS,
1113
+ DEFAULT_PROJECT_SETTINGS,
1114
+ DEFAULT_SETTINGS,
1115
+ isGlobalOnlySettingsKey,
1116
+ sanitizeCliAgentsSettings,
1117
+ getErrorMessage,
1118
+ resolveTitleSummarizerSettingsModel,
1119
+ isExperimentalFeatureEnabled,
1120
+ COLUMNS,
1121
+ TASK_PRIORITIES,
1122
+ DEFAULT_TASK_PRIORITY,
1123
+ isLocale,
1124
+ WORKFLOW_STEP_TEMPLATES,
1125
+ validateDocumentKey,
1126
+ CheckoutConflictError,
1127
+ SHARED_STATE_SNAPSHOT_VERSION,
1128
+ VALID_TRANSITIONS,
1129
+ validateDockerNodeConfig,
1130
+ AGENT_VALID_TRANSITIONS,
1131
+ isEphemeralAgent,
1132
+ AGENT_PERMISSIONS,
1133
+ AGENT_PERMISSION_POLICY_ACTION_CATEGORIES,
1134
+ AGENT_PERMISSION_POLICY_PRESET_IDS,
1135
+ DEFAULT_HEARTBEAT_PROCEDURE_PATH,
1136
+ getSafeAgentAssetIdSegment,
1137
+ getLegacyAgentAssetDirectoryName,
1138
+ getCanonicalAgentInstructionsBundleDirName,
1139
+ getLegacyAgentInstructionsBundleDirName,
1140
+ getDefaultHeartbeatProcedurePath,
1141
+ agentToConfigSnapshot,
1142
+ diffConfigSnapshots
1143
+ };