@ai-agent-forge/agent-forge 0.88.2 → 0.88.4

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 (460) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  4. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  5. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  6. package/bundled-plugins/coding-tools/plugin.json +1 -1
  7. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  8. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  9. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  10. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  11. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  12. package/bundled-plugins/provider-failover/plugin.json +1 -1
  13. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  14. package/bundled-plugins/retry-policy/plugin.json +1 -1
  15. package/dist/artifacts/paged-read.d.ts +6 -1
  16. package/dist/artifacts/paged-read.d.ts.map +1 -1
  17. package/dist/artifacts/paged-read.js.map +1 -1
  18. package/dist/bundle/.build-manifest.json +244 -234
  19. package/dist/bundle/chunks/{anthropic-messages-PLAKXR73.js → anthropic-messages-3FJHRAJL.js} +2 -2
  20. package/dist/bundle/chunks/anthropic.js +1 -1
  21. package/dist/bundle/chunks/{azure-openai-responses-OUWQ2AZD.js → azure-openai-responses-GCL47IDS.js} +1 -1
  22. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  23. package/dist/bundle/chunks/{chunk-6F5JWGKE.js → chunk-32YDZI4J.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-LSP24WNH.js → chunk-755VNWIF.js} +12 -12
  25. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-BVVSHK6W.js} +1 -1
  26. package/dist/bundle/chunks/{chunk-HTC5K5SM.js → chunk-HEL6TAWE.js} +95 -90
  27. package/dist/bundle/chunks/{chunk-6R7UI4IY.js → chunk-QDLOMKF6.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-44I47ACN.js → chunk-V3ACW7VD.js} +1 -1
  29. package/dist/bundle/chunks/{google-generative-ai-DLII6DAT.js → google-generative-ai-6BMXWA44.js} +1 -1
  30. package/dist/bundle/chunks/{google-vertex-G7BZL7GM.js → google-vertex-6H7NLRTK.js} +1 -1
  31. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  32. package/dist/bundle/chunks/{mistral-conversations-JXUK24ID.js → mistral-conversations-IXUHSFSJ.js} +1 -1
  33. package/dist/bundle/chunks/{openai-codex-responses-5GSGFIPG.js → openai-codex-responses-YHUAEVCM.js} +1 -1
  34. package/dist/bundle/chunks/openai-codex.js +1 -1
  35. package/dist/bundle/chunks/{openai-completions-EI2I6DTG.js → openai-completions-ULQCFC72.js} +1 -1
  36. package/dist/bundle/chunks/openai-responses-NLLAJDPS.js +2 -0
  37. package/dist/bundle/chunks/{openrouter-images-G4GQRUSG.js → openrouter-images-GZZQZXMS.js} +1 -1
  38. package/dist/bundle/chunks/openrouter.js +1 -1
  39. package/dist/bundle/chunks/{pi-messages-PWU2VJMR.js → pi-messages-EJTI2EJ3.js} +1 -1
  40. package/dist/bundle/chunks/virtual-modules-TQWEGNNZ.js +5 -0
  41. package/dist/bundle/cli.js +1 -1
  42. package/dist/bundle/client.js +1 -1
  43. package/dist/bundle/index.js +1 -1
  44. package/dist/bundle/rpc-entry.js +1 -1
  45. package/dist/cli/args.d.ts +0 -1
  46. package/dist/cli/args.d.ts.map +1 -1
  47. package/dist/cli/args.js +1 -4
  48. package/dist/cli/args.js.map +1 -1
  49. package/dist/cli/config-selector.d.ts.map +1 -1
  50. package/dist/cli/config-selector.js +1 -1
  51. package/dist/cli/config-selector.js.map +1 -1
  52. package/dist/cli/experimental/cli.d.ts +3 -3
  53. package/dist/cli/experimental/cli.d.ts.map +1 -1
  54. package/dist/cli/experimental/cli.js +2 -2
  55. package/dist/cli/experimental/cli.js.map +1 -1
  56. package/dist/cli/experimental/commands/agent-forge.d.ts +15 -0
  57. package/dist/cli/experimental/commands/agent-forge.d.ts.map +1 -0
  58. package/dist/cli/experimental/commands/{pi.js → agent-forge.js} +4 -4
  59. package/dist/cli/experimental/commands/agent-forge.js.map +1 -0
  60. package/dist/cli/startup-ui.d.ts.map +1 -1
  61. package/dist/cli/startup-ui.js +1 -1
  62. package/dist/cli/startup-ui.js.map +1 -1
  63. package/dist/config.d.ts +4 -4
  64. package/dist/config.d.ts.map +1 -1
  65. package/dist/config.js +7 -7
  66. package/dist/config.js.map +1 -1
  67. package/dist/core/agent-forge-manifest.d.ts +7 -0
  68. package/dist/core/agent-forge-manifest.d.ts.map +1 -0
  69. package/dist/core/{pi-manifest.js → agent-forge-manifest.js} +4 -4
  70. package/dist/core/agent-forge-manifest.js.map +1 -0
  71. package/dist/core/agent-session-compaction.d.ts +1 -1
  72. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  73. package/dist/core/agent-session-compaction.js +3 -3
  74. package/dist/core/agent-session-compaction.js.map +1 -1
  75. package/dist/core/agent-session-lifecycle.d.ts.map +1 -1
  76. package/dist/core/agent-session-lifecycle.js +12 -1
  77. package/dist/core/agent-session-lifecycle.js.map +1 -1
  78. package/dist/core/agent-session-projection.d.ts.map +1 -1
  79. package/dist/core/agent-session-projection.js +3 -3
  80. package/dist/core/agent-session-projection.js.map +1 -1
  81. package/dist/core/agent-session-services.d.ts +1 -1
  82. package/dist/core/agent-session-services.d.ts.map +1 -1
  83. package/dist/core/agent-session-services.js +1 -1
  84. package/dist/core/agent-session-services.js.map +1 -1
  85. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  86. package/dist/core/compaction/branch-summarization.js +1 -1
  87. package/dist/core/compaction/branch-summarization.js.map +1 -1
  88. package/dist/core/experimental.d.ts.map +1 -1
  89. package/dist/core/experimental.js +1 -3
  90. package/dist/core/experimental.js.map +1 -1
  91. package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
  92. package/dist/core/extensions/capability-plugin.js +15 -8
  93. package/dist/core/extensions/capability-plugin.js.map +1 -1
  94. package/dist/core/extensions/capability-runtime-store.d.ts +20 -1
  95. package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
  96. package/dist/core/extensions/capability-runtime-store.js +67 -0
  97. package/dist/core/extensions/capability-runtime-store.js.map +1 -1
  98. package/dist/core/extensions/capability-runtime-types.d.ts +14 -0
  99. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  100. package/dist/core/extensions/capability-runtime-types.js +7 -1
  101. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  102. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  103. package/dist/core/extensions/capability-runtime.js +144 -42
  104. package/dist/core/extensions/capability-runtime.js.map +1 -1
  105. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  106. package/dist/core/extensions/virtual-modules.js +12 -4
  107. package/dist/core/extensions/virtual-modules.js.map +1 -1
  108. package/dist/core/facade/coding-agent-facade.d.ts +1 -1
  109. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  110. package/dist/core/facade/coding-agent-facade.js +1 -1
  111. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  112. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +1 -1
  113. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -1
  114. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +3 -3
  115. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -1
  116. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -1
  117. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +1 -1
  118. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -1
  119. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  120. package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -1
  121. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  122. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -1
  123. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +2 -0
  124. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -1
  125. package/dist/core/model-resolver.d.ts +2 -0
  126. package/dist/core/model-resolver.d.ts.map +1 -1
  127. package/dist/core/model-resolver.js +4 -1
  128. package/dist/core/model-resolver.js.map +1 -1
  129. package/dist/core/package-resource-collection.d.ts.map +1 -1
  130. package/dist/core/package-resource-collection.js +5 -5
  131. package/dist/core/package-resource-collection.js.map +1 -1
  132. package/dist/core/provider-composer.d.ts.map +1 -1
  133. package/dist/core/provider-composer.js +3 -3
  134. package/dist/core/provider-composer.js.map +1 -1
  135. package/dist/core/resource-loader.d.ts.map +1 -1
  136. package/dist/core/resource-loader.js +1 -1
  137. package/dist/core/resource-loader.js.map +1 -1
  138. package/dist/core/sdk.d.ts +1 -1
  139. package/dist/core/sdk.d.ts.map +1 -1
  140. package/dist/core/sdk.js +6 -7
  141. package/dist/core/sdk.js.map +1 -1
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +4 -4
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/settings-manager.d.ts.map +1 -1
  146. package/dist/core/settings-manager.js +5 -10
  147. package/dist/core/settings-manager.js.map +1 -1
  148. package/dist/core/timings.d.ts.map +1 -1
  149. package/dist/core/timings.js +1 -3
  150. package/dist/core/timings.js.map +1 -1
  151. package/dist/core/tools/render-utils.d.ts +1 -1
  152. package/dist/core/tools/render-utils.d.ts.map +1 -1
  153. package/dist/core/tools/render-utils.js.map +1 -1
  154. package/dist/core/tools/tool-definition.d.ts +1 -1
  155. package/dist/core/tools/tool-definition.d.ts.map +1 -1
  156. package/dist/core/tools/tool-definition.js.map +1 -1
  157. package/dist/core/trace-retention.d.ts +16 -1
  158. package/dist/core/trace-retention.d.ts.map +1 -1
  159. package/dist/core/trace-retention.js +43 -20
  160. package/dist/core/trace-retention.js.map +1 -1
  161. package/dist/export-html/ansi-to-html.d.ts.map +1 -0
  162. package/dist/export-html/ansi-to-html.js.map +1 -0
  163. package/dist/{core/export-html → export-html}/index.d.ts +1 -1
  164. package/dist/export-html/index.d.ts.map +1 -0
  165. package/dist/{core/export-html → export-html}/index.js +5 -5
  166. package/dist/export-html/index.js.map +1 -0
  167. package/dist/{core/export-html → export-html}/tool-renderer.d.ts +2 -2
  168. package/dist/export-html/tool-renderer.d.ts.map +1 -0
  169. package/dist/export-html/tool-renderer.js.map +1 -0
  170. package/dist/{modes/interactive → host}/model-catalog-refresh.d.ts +1 -1
  171. package/dist/host/model-catalog-refresh.d.ts.map +1 -0
  172. package/dist/{modes/interactive → host}/model-catalog-refresh.js +1 -1
  173. package/dist/host/model-catalog-refresh.js.map +1 -0
  174. package/dist/index.d.ts +5 -5
  175. package/dist/index.d.ts.map +1 -1
  176. package/dist/index.js +12 -12
  177. package/dist/index.js.map +1 -1
  178. package/dist/main.d.ts.map +1 -1
  179. package/dist/main.js +25 -14
  180. package/dist/main.js.map +1 -1
  181. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  182. package/dist/modes/interactive/components/agents-view.js +1 -1
  183. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  184. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  185. package/dist/modes/interactive/components/armin.js +1 -1
  186. package/dist/modes/interactive/components/armin.js.map +1 -1
  187. package/dist/modes/interactive/components/assistant-message.d.ts +3 -0
  188. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  189. package/dist/modes/interactive/components/assistant-message.js +83 -24
  190. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  191. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  192. package/dist/modes/interactive/components/bash-execution.js +1 -1
  193. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  194. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  195. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  197. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/branch-summary-message.js +1 -1
  199. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  200. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  201. package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  202. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  203. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/config-selector.js +1 -1
  205. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  206. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/custom-entry.js +1 -1
  208. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  209. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/custom-message.js +1 -1
  211. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  212. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/daxnuts.js +1 -1
  214. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  215. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  216. package/dist/modes/interactive/components/dialog-editor.js +1 -1
  217. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  218. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  219. package/dist/modes/interactive/components/dialog-input.js +1 -1
  220. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  221. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  222. package/dist/modes/interactive/components/dialog-selector.js +1 -1
  223. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  224. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  225. package/dist/modes/interactive/components/diff.js +1 -1
  226. package/dist/modes/interactive/components/diff.js.map +1 -1
  227. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  228. package/dist/modes/interactive/components/dynamic-border.js +1 -1
  229. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  230. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  231. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  232. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  233. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  234. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  235. package/dist/modes/interactive/components/footer.js +1 -1
  236. package/dist/modes/interactive/components/footer.js.map +1 -1
  237. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  238. package/dist/modes/interactive/components/keybinding-hints.js +1 -1
  239. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  240. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  241. package/dist/modes/interactive/components/login-dialog.js +1 -1
  242. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  243. package/dist/modes/interactive/components/mermaid.d.ts +1 -1
  244. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  245. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  246. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  247. package/dist/modes/interactive/components/model-selector.js +2 -2
  248. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  249. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  250. package/dist/modes/interactive/components/oauth-selector.js +1 -1
  251. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  252. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  253. package/dist/modes/interactive/components/plugin-manager-entry.js +1 -1
  254. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  255. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  256. package/dist/modes/interactive/components/plugin-selection-entry.js +1 -1
  257. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  258. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -1
  259. package/dist/modes/interactive/components/queue-manager-selector.js +1 -1
  260. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -1
  261. package/dist/modes/interactive/components/render-types.d.ts +1 -1
  262. package/dist/modes/interactive/components/render-types.d.ts.map +1 -1
  263. package/dist/modes/interactive/components/render-types.js.map +1 -1
  264. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  265. package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
  266. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  267. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  268. package/dist/modes/interactive/components/session-selector.js +2 -2
  269. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  270. package/dist/modes/interactive/components/settings-selector.d.ts +1 -1
  271. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  272. package/dist/modes/interactive/components/settings-selector.js +1 -1
  273. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  274. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  275. package/dist/modes/interactive/components/settings-submenu.js +1 -1
  276. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  277. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  278. package/dist/modes/interactive/components/show-images-selector.js +1 -1
  279. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  280. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
  282. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  283. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  284. package/dist/modes/interactive/components/status-indicator.js +1 -1
  285. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  286. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  287. package/dist/modes/interactive/components/theme-selector.js +1 -1
  288. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  289. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  290. package/dist/modes/interactive/components/thinking-selector.js +1 -1
  291. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  292. package/dist/modes/interactive/components/tool-execution.d.ts +2 -0
  293. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  294. package/dist/modes/interactive/components/tool-execution.js +96 -4
  295. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  296. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -1
  297. package/dist/modes/interactive/components/tool-run-group.js +1 -1
  298. package/dist/modes/interactive/components/tool-run-group.js.map +1 -1
  299. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  300. package/dist/modes/interactive/components/tree-list.js +1 -1
  301. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  302. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  303. package/dist/modes/interactive/components/tree-render.js +1 -1
  304. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  305. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  306. package/dist/modes/interactive/components/tree-selector.js +1 -1
  307. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  308. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  309. package/dist/modes/interactive/components/user-message-selector.js +1 -1
  310. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  311. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  312. package/dist/modes/interactive/components/user-message.js +1 -1
  313. package/dist/modes/interactive/components/user-message.js.map +1 -1
  314. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  315. package/dist/modes/interactive/components/workflow-view.js +1 -1
  316. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  317. package/dist/modes/interactive/interactive-auth.d.ts +1 -1
  318. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  319. package/dist/modes/interactive/interactive-auth.js +1 -1
  320. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  321. package/dist/modes/interactive/interactive-commands.d.ts +123 -6
  322. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  323. package/dist/modes/interactive/interactive-commands.js +691 -4
  324. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  325. package/dist/modes/interactive/interactive-events.d.ts +174 -0
  326. package/dist/modes/interactive/interactive-events.d.ts.map +1 -0
  327. package/dist/modes/interactive/interactive-events.js +704 -0
  328. package/dist/modes/interactive/interactive-events.js.map +1 -0
  329. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  330. package/dist/modes/interactive/interactive-format.js +1 -1
  331. package/dist/modes/interactive/interactive-format.js.map +1 -1
  332. package/dist/modes/interactive/interactive-lifecycle.d.ts +94 -0
  333. package/dist/modes/interactive/interactive-lifecycle.d.ts.map +1 -0
  334. package/dist/modes/interactive/interactive-lifecycle.js +177 -0
  335. package/dist/modes/interactive/interactive-lifecycle.js.map +1 -0
  336. package/dist/modes/interactive/interactive-mode.d.ts +240 -133
  337. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  338. package/dist/modes/interactive/interactive-mode.js +251 -2159
  339. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  340. package/dist/modes/interactive/interactive-queues.d.ts +96 -0
  341. package/dist/modes/interactive/interactive-queues.d.ts.map +1 -0
  342. package/dist/modes/interactive/interactive-queues.js +183 -0
  343. package/dist/modes/interactive/interactive-queues.js.map +1 -0
  344. package/dist/modes/interactive/interactive-selectors.d.ts +95 -5
  345. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  346. package/dist/modes/interactive/interactive-selectors.js +517 -6
  347. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  348. package/dist/modes/interactive/startup-services.d.ts +31 -0
  349. package/dist/modes/interactive/startup-services.d.ts.map +1 -0
  350. package/dist/modes/interactive/startup-services.js +123 -0
  351. package/dist/modes/interactive/startup-services.js.map +1 -0
  352. package/dist/modes/memory-preheat.d.ts +11 -0
  353. package/dist/modes/memory-preheat.d.ts.map +1 -0
  354. package/dist/modes/memory-preheat.js +20 -0
  355. package/dist/modes/memory-preheat.js.map +1 -0
  356. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  357. package/dist/modes/rpc/rpc-mode.js +3 -1
  358. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  359. package/dist/plugins/ecosystem/node-package-install-host.d.ts +9 -1
  360. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  361. package/dist/plugins/ecosystem/node-package-install-host.js +79 -0
  362. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  363. package/dist/remote/server-assembly.d.ts.map +1 -1
  364. package/dist/remote/server-assembly.js +7 -2
  365. package/dist/remote/server-assembly.js.map +1 -1
  366. package/dist/suites/builtin-suites.d.ts.map +1 -0
  367. package/dist/suites/builtin-suites.js.map +1 -0
  368. package/dist/suites/resolved-agent-profile.d.ts.map +1 -0
  369. package/dist/suites/resolved-agent-profile.js.map +1 -0
  370. package/dist/suites/suite-lifecycle.d.ts.map +1 -0
  371. package/dist/suites/suite-lifecycle.js.map +1 -0
  372. package/dist/suites/suite-loader.d.ts.map +1 -0
  373. package/dist/suites/suite-loader.js.map +1 -0
  374. package/dist/{modes/interactive/theme → theme}/dark.json +1 -1
  375. package/dist/{modes/interactive/theme → theme}/light.json +1 -1
  376. package/dist/{modes/interactive/theme → theme}/theme-controller.d.ts +1 -1
  377. package/dist/theme/theme-controller.d.ts.map +1 -0
  378. package/dist/{modes/interactive/theme → theme}/theme-controller.js +1 -1
  379. package/dist/theme/theme-controller.js.map +1 -0
  380. package/dist/{modes/interactive/theme → theme}/theme.d.ts +1 -1
  381. package/dist/theme/theme.d.ts.map +1 -0
  382. package/dist/{modes/interactive/theme → theme}/theme.js +5 -5
  383. package/dist/theme/theme.js.map +1 -0
  384. package/docs/compaction.md +7 -7
  385. package/docs/environment-variables.md +10 -4
  386. package/docs/keybindings.md +3 -3
  387. package/docs/models.md +17 -17
  388. package/docs/packages.md +1 -1
  389. package/docs/prompt-templates.md +1 -1
  390. package/docs/rpc.md +2 -2
  391. package/docs/sdk.md +5 -5
  392. package/docs/session-format.md +3 -3
  393. package/docs/settings.md +15 -1
  394. package/docs/shell-aliases.md +1 -1
  395. package/docs/skills.md +1 -1
  396. package/docs/terminal-setup.md +17 -17
  397. package/docs/themes.md +5 -5
  398. package/docs/tmux.md +4 -4
  399. package/docs/tui.md +1 -1
  400. package/docs/usage.md +292 -292
  401. package/docs/windows.md +1 -1
  402. package/examples/extensions/bash-spawn-hook/index.ts +1 -1
  403. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  404. package/examples/extensions/mcp-stdio/index.d.ts +64 -0
  405. package/examples/extensions/mcp-stdio/index.d.ts.map +1 -0
  406. package/examples/extensions/mcp-stdio/index.js +292 -0
  407. package/examples/extensions/mcp-stdio/index.js.map +1 -0
  408. package/examples/extensions/with-deps/package-lock.json +2 -2
  409. package/examples/extensions/with-deps/package.json +1 -6
  410. package/examples/extensions/with-deps/plugin.json +1 -1
  411. package/package.json +2 -2
  412. package/dist/bundle/chunks/openai-responses-AUJQ3NWT.js +0 -2
  413. package/dist/bundle/chunks/virtual-modules-MRXD3RWG.js +0 -5
  414. package/dist/cli/experimental/commands/pi.d.ts +0 -15
  415. package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
  416. package/dist/cli/experimental/commands/pi.js.map +0 -1
  417. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  418. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  419. package/dist/core/export-html/index.d.ts.map +0 -1
  420. package/dist/core/export-html/index.js.map +0 -1
  421. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  422. package/dist/core/export-html/tool-renderer.js.map +0 -1
  423. package/dist/core/pi-manifest.d.ts +0 -7
  424. package/dist/core/pi-manifest.d.ts.map +0 -1
  425. package/dist/core/pi-manifest.js.map +0 -1
  426. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +0 -1
  427. package/dist/modes/interactive/model-catalog-refresh.js.map +0 -1
  428. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  429. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  430. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  431. package/dist/modes/interactive/theme/theme.js.map +0 -1
  432. package/dist/profiles/builtin-suites.d.ts.map +0 -1
  433. package/dist/profiles/builtin-suites.js.map +0 -1
  434. package/dist/profiles/resolved-agent-profile.d.ts.map +0 -1
  435. package/dist/profiles/resolved-agent-profile.js.map +0 -1
  436. package/dist/profiles/suite-lifecycle.d.ts.map +0 -1
  437. package/dist/profiles/suite-lifecycle.js.map +0 -1
  438. package/dist/profiles/suite-loader.d.ts.map +0 -1
  439. package/dist/profiles/suite-loader.js.map +0 -1
  440. package/dist/utils/deprecation.d.ts +0 -4
  441. package/dist/utils/deprecation.d.ts.map +0 -1
  442. package/dist/utils/deprecation.js +0 -13
  443. package/dist/utils/deprecation.js.map +0 -1
  444. /package/dist/{core/export-html → export-html}/ansi-to-html.d.ts +0 -0
  445. /package/dist/{core/export-html → export-html}/ansi-to-html.js +0 -0
  446. /package/dist/{core/export-html → export-html}/template.css +0 -0
  447. /package/dist/{core/export-html → export-html}/template.html +0 -0
  448. /package/dist/{core/export-html → export-html}/template.js +0 -0
  449. /package/dist/{core/export-html → export-html}/tool-renderer.js +0 -0
  450. /package/dist/{core/export-html → export-html}/vendor/highlight.min.js +0 -0
  451. /package/dist/{core/export-html → export-html}/vendor/marked.min.js +0 -0
  452. /package/dist/{profiles → suites}/builtin-suites.d.ts +0 -0
  453. /package/dist/{profiles → suites}/builtin-suites.js +0 -0
  454. /package/dist/{profiles → suites}/resolved-agent-profile.d.ts +0 -0
  455. /package/dist/{profiles → suites}/resolved-agent-profile.js +0 -0
  456. /package/dist/{profiles → suites}/suite-lifecycle.d.ts +0 -0
  457. /package/dist/{profiles → suites}/suite-lifecycle.js +0 -0
  458. /package/dist/{profiles → suites}/suite-loader.d.ts +0 -0
  459. /package/dist/{profiles → suites}/suite-loader.js +0 -0
  460. /package/dist/{modes/interactive/theme → theme}/theme-schema.json +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite-loader.js","sourceRoot":"","sources":["../../src/suites/suite-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Suite workspace location, lazy provisioning, and assembly (方案系统设计.md v2\n * §4/§5/§8/§9/§11/§12, M1a).\n *\n * The loader is the assembler layer of the suite system: it resolves the\n * active suite id (explicit > AGENT_FORGE_SUITE > project settings > global\n * settings > \"assistant\"), provisions the builtin suite workspaces under\n * `<agentDir>/suites/<id>/`, assembles the agents.md three-level chain\n * (system -> suite -> project, 设计 §8), gates the global SYSTEM.md/\n * APPEND_SYSTEM.md system prompt channel by inheritSystemAgentsMd (设计 §4:\n * the project-level `<cwd>/.agent-forge/` layer always passes), and bridges\n * the assembled suite onto the existing ProfileIdentityV1/ProfileLock\n * mechanisms. The project level of the chain is delegated to the existing\n * resource loader — the ancestor chain logic itself is never reimplemented\n * here.\n */\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join, resolve, sep } from \"node:path\";\nimport type { JsonValue } from \"@agent-forge/ai\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport type { ResourceDiagnostic } from \"../core/diagnostics.ts\";\nimport { t } from \"../core/i18n/index.ts\";\nimport type { SettingsManager } from \"../core/settings-manager.ts\";\nimport type { Skill } from \"../core/skills.ts\";\nimport { loadSkills } from \"../core/skills.ts\";\nimport type { HostFactsV1 } from \"../plugins/ecosystem/types.ts\";\nimport type { ProfileIdentityV1 } from \"../profile/identity.ts\";\nimport { buildProfileIdentityV1, stableJsonDigest } from \"../profile/identity.ts\";\nimport type { ProfileLockV1, ProfileLockVerificationV1 } from \"../profile/lock.ts\";\nimport { createProfileLock, verifyProfileLock } from \"../profile/lock.ts\";\nimport type {\n\tBuiltinPluginManifestOverridesV1,\n\tBuiltinPluginProfileIdV1,\n\tBuiltinPluginProfileResolutionV1,\n} from \"../profile/plugin-profiles.ts\";\nimport { resolveBuiltinPluginProfileV1 } from \"../profile/plugin-profiles.ts\";\nimport type { VerifiedToolPluginV1 } from \"../profile/profile-assembly.ts\";\nimport type { RegistryProfileEntryV1, RegistrySourceV1 } from \"../profile/profile-registry.ts\";\nimport { createProfileRegistry } from \"../profile/profile-registry.ts\";\nimport { stripBom } from \"../utils/text.ts\";\nimport {\n\tBUILTIN_SUITES,\n\tDEFAULT_SUITE_ID,\n\tFACTORY_CONTENTS_VERSION,\n\tgetBuiltinSuite,\n\tisBuiltinSuiteId,\n\tisValidSuiteId,\n\tORIENTATION_PROMPTS,\n\tparseSuiteJson,\n\tSUITE_SCHEMA_VERSION,\n\ttype SuiteDefinition,\n\tserializeSuiteJson,\n} from \"./builtin-suites.ts\";\n\nexport { DEFAULT_SUITE_ID };\n\nexport const SUITES_DIR_NAME = \"suites\";\nexport const SUITE_MANIFEST_FILENAME = \"suite.json\";\nexport const SUITE_AGENTS_MD_FILENAME = \"agents.md\";\nexport const SUITE_PERSONA_MD_FILENAME = \"persona.md\";\nexport const SUITE_ENV_VAR = \"AGENT_FORGE_SUITE\";\n/** customType of the session custom entry recording the suite a session was created with (设计 §10.1). */\nexport const SUITE_SESSION_ENTRY_TYPE = \"suite\";\n/** Persisted suite profile lock inside the suite workspace (M4, 设计 §12). */\nexport const SUITE_LOCK_FILENAME = \".profile-lock.json\";\n\nexport function getSuitesRootDir(agentDir: string): string {\n\treturn join(agentDir, SUITES_DIR_NAME);\n}\n\nexport function getSuiteWorkspaceDir(agentDir: string, suiteId: string): string {\n\treturn join(getSuitesRootDir(agentDir), suiteId);\n}\n\n/** The suite-local skill layer directory (统一修复轮 B): `<suiteDir>/skills`. */\nexport function getSuiteLocalSkillsDir(agentDir: string, suiteId: string): string {\n\treturn join(getSuiteWorkspaceDir(agentDir, suiteId), \"skills\");\n}\n\n/** The suite-local capability-plugin layer directory (统一修复轮 B): `<suiteDir>/plugins`. */\nexport function getSuiteLocalPluginsDir(agentDir: string, suiteId: string): string {\n\treturn join(getSuiteWorkspaceDir(agentDir, suiteId), \"plugins\");\n}\n\n/** Structured error for unknown suite ids; lists the available ids (设计 §9). */\nexport class SuiteResolutionError extends Error {\n\treadonly requestedId: string;\n\treadonly availableSuiteIds: readonly string[];\n\n\tconstructor(requestedId: string, availableSuiteIds: readonly string[]) {\n\t\tsuper(`Unknown suite \"${requestedId}\". Available suites: ${availableSuiteIds.join(\", \")}`);\n\t\tthis.name = \"SuiteResolutionError\";\n\t\tthis.requestedId = requestedId;\n\t\tthis.availableSuiteIds = Object.freeze([...availableSuiteIds]);\n\t}\n}\n\n/** Structured error for resuming a session under a suite it is not bound to. */\nexport class SuiteRebindError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SuiteRebindError\";\n\t}\n}\n\n/**\n * Every suite id resolvable on this host: the builtin pair plus user\n * workspaces that already contain a suite.json.\n */\nexport function listSuiteIds(agentDir: string): string[] {\n\tconst ids = new Set(BUILTIN_SUITES.map((suite) => suite.id));\n\tconst rootDir = getSuitesRootDir(agentDir);\n\tif (existsSync(rootDir)) {\n\t\tfor (const entry of readdirSync(rootDir, { withFileTypes: true })) {\n\t\t\tif (!entry.isDirectory()) continue;\n\t\t\tif (!existsSync(join(rootDir, entry.name, SUITE_MANIFEST_FILENAME))) continue;\n\t\t\tids.add(entry.name);\n\t\t}\n\t}\n\treturn [...ids].sort();\n}\n\nexport interface ResolveSuiteIdOptions {\n\t/** Explicit suite id (SDK/CLI parameter); highest priority. */\n\texplicit?: string;\n\t/** Raw AGENT_FORGE_SUITE value; callers pass process.env[SUITE_ENV_VAR]. */\n\tenvSuite?: string;\n\t/** Settings source for the project/global `suite` keys. */\n\tsettings?: Pick<SettingsManager, \"getProjectSettings\" | \"getGlobalSettings\">;\n\t/** Agent dir used for workspace discovery and available-id listing. */\n\tagentDir: string;\n}\n\nfunction normalizeCandidate(value: unknown): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Resolves the active suite id: explicit > env AGENT_FORGE_SUITE > project\n * settings `suite` > global settings `suite` > \"coding\" (设计 §9). The\n * first configured value wins; an unknown or malformed value is a structured\n * error, never a silent fallback.\n */\nexport function resolveSuiteId(options: ResolveSuiteIdOptions): string {\n\tconst candidate =\n\t\tnormalizeCandidate(options.explicit) ??\n\t\tnormalizeCandidate(options.envSuite) ??\n\t\t(options.settings === undefined ? undefined : normalizeCandidate(options.settings.getProjectSettings().suite)) ??\n\t\t(options.settings === undefined ? undefined : normalizeCandidate(options.settings.getGlobalSettings().suite));\n\tif (candidate === undefined) return DEFAULT_SUITE_ID;\n\tif (!isValidSuiteId(candidate)) throw new SuiteResolutionError(candidate, listSuiteIds(options.agentDir));\n\tif (!isBuiltinSuiteId(candidate)) {\n\t\tconst workspaceManifest = join(getSuiteWorkspaceDir(options.agentDir, candidate), SUITE_MANIFEST_FILENAME);\n\t\tif (!existsSync(workspaceManifest)) throw new SuiteResolutionError(candidate, listSuiteIds(options.agentDir));\n\t}\n\treturn candidate;\n}\n\nexport interface SuiteWorkspace {\n\treadonly suite: SuiteDefinition;\n\treadonly suiteDir: string;\n\treadonly suiteJsonPath: string;\n\treadonly agentsMdPath: string;\n\t/**\n\t * The resolved orientation persona text (设计 §6.2/§6.3): the compiled\n\t * ORIENTATION_PROMPTS text for assistant/coding, the workspace persona.md\n\t * content for custom; a missing or unreadable file degrades to \"\" with a\n\t * diagnostic.\n\t */\n\treadonly orientationPersona: string;\n\treadonly diagnostics: readonly string[];\n\t/** Persisted lock file path inside the workspace (M4). */\n\treadonly lockPath: string;\n\t/**\n\t * The suite profile lock (设计 §12): the persisted lock when one existed, a\n\t * fresh lock frozen over the current identity otherwise.\n\t */\n\treadonly lock: ProfileLockV1;\n\t/** Current resolved identity, including any selected optional domain Profile. */\n\treadonly identity: ProfileIdentityV1;\n\t/** Verify result against the persisted lock; absent when none existed. */\n\treadonly lockVerification?: ProfileLockVerificationV1;\n}\n\n/**\n * Serializes a ProfileLockV1 to the canonical `.profile-lock.json` text\n * (stable field order, trailing newline). Round-trips through\n * parseSuiteProfileLockFile.\n */\nexport function serializeSuiteProfileLockFile(lock: ProfileLockV1): string {\n\tconst ordered = {\n\t\tidentity: {\n\t\t\tprofileId: lock.identity.profileId,\n\t\t\tprofileVersion: lock.identity.profileVersion,\n\t\t\tmanifestDigest: lock.identity.manifestDigest,\n\t\t\tcapabilityVersions: lock.identity.capabilityVersions.map((ref) => ({ id: ref.id, version: ref.version })),\n\t\t},\n\t\tlockedAt: lock.lockedAt,\n\t\tlockedBy: lock.lockedBy,\n\t\tgeneration: lock.generation,\n\t};\n\treturn `${JSON.stringify(ordered, null, 2)}\\n`;\n}\n\n/**\n * Parses `.profile-lock.json` text back into a ProfileLockV1. Throws on any\n * structural mismatch so callers can apply their corruption policy.\n */\nexport function parseSuiteProfileLockFile(text: string): ProfileLockV1 {\n\tconst value: unknown = JSON.parse(text);\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(t(\".profile-lock.json must be a JSON object\"));\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst identityRecord = record.identity;\n\tif (identityRecord === null || typeof identityRecord !== \"object\" || Array.isArray(identityRecord)) {\n\t\tthrow new Error(t(\".profile-lock.json identity must be a JSON object\"));\n\t}\n\tconst identity = identityRecord as Record<string, unknown>;\n\tif (\n\t\ttypeof identity.profileId !== \"string\" ||\n\t\ttypeof identity.profileVersion !== \"string\" ||\n\t\ttypeof identity.manifestDigest !== \"string\" ||\n\t\t!Array.isArray(identity.capabilityVersions)\n\t) {\n\t\tthrow new Error(\n\t\t\tt(\".profile-lock.json identity must carry profileId/profileVersion/manifestDigest/capabilityVersions\"),\n\t\t);\n\t}\n\tconst capabilityVersions = identity.capabilityVersions.map((entry) => {\n\t\tif (entry === null || typeof entry !== \"object\" || Array.isArray(entry)) {\n\t\t\tthrow new Error(t(\".profile-lock.json identity.capabilityVersions entries must be objects\"));\n\t\t}\n\t\tconst capability = entry as Record<string, unknown>;\n\t\tif (typeof capability.id !== \"string\" || typeof capability.version !== \"number\") {\n\t\t\tthrow new Error(t(\".profile-lock.json identity.capabilityVersions entries must carry id/version\"));\n\t\t}\n\t\treturn { id: capability.id, version: capability.version };\n\t});\n\tif (\n\t\ttypeof record.lockedAt !== \"number\" ||\n\t\ttypeof record.lockedBy !== \"string\" ||\n\t\ttypeof record.generation !== \"number\"\n\t) {\n\t\tthrow new Error(t(\".profile-lock.json must carry lockedAt/lockedBy/generation\"));\n\t}\n\treturn Object.freeze({\n\t\tidentity: Object.freeze({\n\t\t\tprofileId: identity.profileId,\n\t\t\tprofileVersion: identity.profileVersion,\n\t\t\tmanifestDigest: identity.manifestDigest,\n\t\t\tcapabilityVersions: Object.freeze(capabilityVersions.map((ref) => Object.freeze({ ...ref }))),\n\t\t}),\n\t\tlockedAt: record.lockedAt,\n\t\tlockedBy: record.lockedBy,\n\t\tgeneration: record.generation,\n\t});\n}\n\n/**\n * Locates and lazily provisions `<agentDir>/suites/<id>/`: the builtin pair\n * gets its factory suite.json plus an empty agents.md skeleton on first start\n * (设计 §5). Corruption policy (设计 §9): builtin suites fall back to factory\n * content with diagnostics; user suites fail fast with the file path.\n */\nexport function loadSuiteWorkspace(options: {\n\tagentDir: string;\n\tsuiteId: string;\n\tpluginProfile?: BuiltinPluginProfileResolutionV1;\n}): SuiteWorkspace {\n\tconst { agentDir, suiteId } = options;\n\tconst suiteDir = getSuiteWorkspaceDir(agentDir, suiteId);\n\tconst suiteJsonPath = join(suiteDir, SUITE_MANIFEST_FILENAME);\n\tconst agentsMdPath = join(suiteDir, SUITE_AGENTS_MD_FILENAME);\n\tconst diagnostics: string[] = [];\n\n\tlet suite: SuiteDefinition;\n\tif (!existsSync(suiteJsonPath)) {\n\t\tconst builtin = getBuiltinSuite(suiteId);\n\t\tif (builtin === undefined) throw new SuiteResolutionError(suiteId, listSuiteIds(agentDir));\n\t\tmkdirSync(suiteDir, { recursive: true });\n\t\twriteFileSync(suiteJsonPath, serializeSuiteJson(builtin), \"utf8\");\n\t\t// D-075 S4 第三批:首启不再预种角色文件——种子移到 subagent-delegate 插件\n\t\t// 注册期(entry 的幂等 seedFactoryRoleCatalog 补缺),插件安装并注册时\n\t\t// `<agentDir>/roles/{explore,reviewer}.json` 自然到位。\n\t\tsuite = builtin;\n\t} else {\n\t\tconst parsed = parseSuiteJson(readFileSync(suiteJsonPath, \"utf8\"), {\n\t\t\texpectedBuiltin: getBuiltinSuite(suiteId) !== undefined,\n\t\t\texpectedId: suiteId,\n\t\t});\n\t\tconst builtin = getBuiltinSuite(suiteId);\n\t\tif (parsed.valid && parsed.suite) {\n\t\t\tsuite = parsed.suite;\n\t\t} else if (builtin !== undefined) {\n\t\t\t// Builtin corruption policy (设计 §9): fall back to factory content\n\t\t\t// with diagnostics instead of locking the user out. The file on disk\n\t\t\t// is left untouched; recovery (reset) is an explicit M4 flow.\n\t\t\tsuite = builtin;\n\t\t\tdiagnostics.push(\n\t\t\t\t`suite.json at ${suiteJsonPath} is invalid; falling back to the factory content for builtin suite \"${suiteId}\". Errors: ${parsed.errors.join(\"; \")}`,\n\t\t\t);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\tt(\n\t\t\t\t\t\"Invalid suite.json at {path}: {errors}. Fix the file, or delete the suite workspace directory {dir} and recreate it.\",\n\t\t\t\t\t{ path: suiteJsonPath, errors: parsed.errors.join(\"; \"), dir: suiteDir },\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (!existsSync(agentsMdPath)) {\n\t\twriteFileSync(agentsMdPath, \"\", \"utf8\");\n\t}\n\n\t// Suite profile lock persistence (M4, 设计 §12): an existing lock file is\n\t// verified against the current identity (drift/migration recorded, never\n\t// blocking and never silently replaced); without one a fresh lock is frozen\n\t// and persisted. A lock file that cannot be parsed is recreated with a\n\t// diagnostic — it carries no openable identity, so nothing is silently\n\t// replaced.\n\tconst lockPath = join(suiteDir, SUITE_LOCK_FILENAME);\n\tlet previousLock: ProfileLockV1 | undefined;\n\tif (existsSync(lockPath)) {\n\t\ttry {\n\t\t\tpreviousLock = parseSuiteProfileLockFile(readFileSync(lockPath, \"utf8\"));\n\t\t} catch (error) {\n\t\t\tdiagnostics.push(\n\t\t\t\t`Profile lock at ${lockPath} is unreadable; recreating it over the current suite identity. Errors: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t}\n\tconst bridge = bridgeSuiteProfileLock({\n\t\tsuite,\n\t\t...(options.pluginProfile === undefined ? {} : { pluginProfile: options.pluginProfile }),\n\t\t...(previousLock === undefined ? {} : { previousLock }),\n\t\tlockedBy: \"suite-loader\",\n\t});\n\tdiagnostics.push(...bridge.diagnostics);\n\tif (previousLock === undefined) {\n\t\ttry {\n\t\t\twriteFileSync(lockPath, serializeSuiteProfileLockFile(bridge.lock), \"utf8\");\n\t\t} catch (error) {\n\t\t\tdiagnostics.push(\n\t\t\t\t`Failed to persist the suite profile lock at ${lockPath}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Orientation persona resolution (设计 §6.3): assistant/coding use the\n\t// compiled persona texts; custom reads the workspace persona.md verbatim\n\t// (BOM stripped, never trimmed), degrading to an empty persona with a\n\t// diagnostic instead of silently falling back to a builtin persona.\n\tconst personaPath = join(suiteDir, SUITE_PERSONA_MD_FILENAME);\n\tlet orientationPersona: string;\n\tif (suite.orientation !== \"custom\") {\n\t\torientationPersona = ORIENTATION_PROMPTS[suite.orientation];\n\t} else if (!existsSync(personaPath)) {\n\t\torientationPersona = \"\";\n\t\tdiagnostics.push(\n\t\t\t`Suite \"${suiteId}\" orientation is \"custom\" but ${personaPath} is missing; the orientation prompt stays empty until the file is created`,\n\t\t);\n\t} else {\n\t\ttry {\n\t\t\torientationPersona = stripBom(readFileSync(personaPath, \"utf8\"));\n\t\t} catch (error) {\n\t\t\torientationPersona = \"\";\n\t\t\tdiagnostics.push(\n\t\t\t\t`Persona file at ${personaPath} is unreadable; the orientation prompt stays empty. Errors: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tsuite,\n\t\tsuiteDir,\n\t\tsuiteJsonPath,\n\t\tagentsMdPath,\n\t\torientationPersona,\n\t\tdiagnostics: Object.freeze(diagnostics),\n\t\tlockPath,\n\t\tlock: bridge.lock,\n\t\tidentity: bridge.identity,\n\t\t...(bridge.verification === undefined ? {} : { lockVerification: bridge.verification }),\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// agents.md three-level chain (设计 §8)\n// ---------------------------------------------------------------------------\n\nexport type SuiteAgentsMdSource = \"system\" | \"suite\" | \"project\";\n\nexport interface SuiteAgentsMdEntry {\n\treadonly source: SuiteAgentsMdSource;\n\treadonly path: string;\n\treadonly content: string;\n}\n\nexport interface SuiteAgentsMdAssembly {\n\treadonly chain: readonly SuiteAgentsMdEntry[];\n\treadonly diagnostics: readonly string[];\n}\n\nexport interface AssembleSuiteAgentsMdChainOptions {\n\treadonly suite: SuiteDefinition;\n\treadonly agentDir: string;\n\treadonly suiteJsonPath: string;\n\treadonly suiteAgentsMdPath: string;\n\t/**\n\t * Project-level context files exactly as produced by the existing resource\n\t * loader (`ResourceLoader.getAgentsFiles()`: agentDir global entry first,\n\t * then the AGENTS.md/CLAUDE.md ancestor chain). The ancestor chain logic is\n\t * delegated, never reimplemented; entries under agentDir are classified as\n\t * system-layer candidates.\n\t */\n\treadonly projectAgentsFiles: ReadonlyArray<{ path: string; content: string }>;\n}\n\nfunction readContextFile(path: string): string {\n\ttry {\n\t\treturn stripBom(readFileSync(path, \"utf8\"));\n\t} catch {\n\t\treturn \"\";\n\t}\n}\n\nfunction isUnderDir(path: string, dir: string): boolean {\n\tconst resolvedPath = resolve(path);\n\tconst resolvedDir = resolve(dir);\n\tconst prefix = resolvedDir.endsWith(sep) ? resolvedDir : `${resolvedDir}${sep}`;\n\treturn resolvedPath.startsWith(prefix);\n}\n\n/**\n * Assembles the agents.md three-level chain (设计 §8): system layer (the\n * agentDir context file the resource loader's agentsFiles already carries,\n * e.g. AGENTS.md, gated by inheritSystemAgentsMd) -> suite layer\n * (`suites/<id>/agents.md`) -> project layer (existing ancestor chain, passed\n * in unchanged). The global SYSTEM.md/APPEND_SYSTEM.md never ride the chain:\n * they keep their native system prompt channel and are gated there by\n * createSuiteSystemPromptGate, so both channels stay single-sourced. Every\n * entry carries its source label; missing layers are skipped. Diagnostics\n * record a blocked system layer (one-time migration hint) and the empty\n * association counts (设计 §11.3: 惰性 + 可观测).\n */\nexport function assembleSuiteAgentsMdChain(options: AssembleSuiteAgentsMdChainOptions): SuiteAgentsMdAssembly {\n\tconst { suite, agentDir, suiteJsonPath, suiteAgentsMdPath, projectAgentsFiles } = options;\n\tconst diagnostics: string[] = [];\n\n\t// System-layer candidates are the agentDir entries already present in the\n\t// loader's agentsFiles; they are never read from disk here again.\n\tconst systemCandidates = projectAgentsFiles\n\t\t.filter((entry) => isUnderDir(entry.path, agentDir))\n\t\t.map((entry) => ({ path: entry.path, content: entry.content }));\n\tconst projectEntries = projectAgentsFiles.filter((entry) => !isUnderDir(entry.path, agentDir));\n\n\tconst chain: SuiteAgentsMdEntry[] = [];\n\tif (suite.inheritSystemAgentsMd) {\n\t\tfor (const candidate of systemCandidates) {\n\t\t\tchain.push({ source: \"system\", path: candidate.path, content: candidate.content });\n\t\t}\n\t} else if (systemCandidates.length > 0) {\n\t\tdiagnostics.push(\n\t\t\t`Suite \"${suite.id}\" does not inherit the system agents.md layer (inheritSystemAgentsMd=false); system-layer file(s) kept out of the suite chain: ${systemCandidates\n\t\t\t\t.map((candidate) => candidate.path)\n\t\t\t\t.join(\n\t\t\t\t\t\", \",\n\t\t\t\t)}. Migrate them into ${suiteAgentsMdPath} or set \"inheritSystemAgentsMd\": true in ${suiteJsonPath}.`,\n\t\t);\n\t}\n\n\tchain.push({ source: \"suite\", path: suiteAgentsMdPath, content: readContextFile(suiteAgentsMdPath) });\n\tfor (const entry of projectEntries) {\n\t\tchain.push({ source: \"project\", path: entry.path, content: entry.content });\n\t}\n\n\t// Plugin associations are wired since M3 (the sdk filters the external\n\t// capability plugin pool by associations.plugins); mcp stays\n\t// declaration-only until M4.\n\tdiagnostics.push(\n\t\t`Suite \"${suite.id}\" mcp associations are declaration-only until M4; MCP association filtering is unwired.`,\n\t);\n\n\treturn { chain: Object.freeze(chain), diagnostics: Object.freeze(diagnostics) };\n}\n\n/**\n * Merges the assembled chain with the resource loader's own agentsFiles for\n * the contextFiles injection channel: chain entries are prepended unless they\n * are empty or already present in the base. Entries with empty content inject\n * nothing, so a fresh factory skeleton changes no prompt bytes. Base entries\n * under agentDir are dropped unconditionally (设计 §8): with\n * inheritSystemAgentsMd=false the switch blocks the system layer, with true\n * the chain already carries it at the head — keeping it in the base too would\n * duplicate it and pin it after the suite layer, breaking the\n * system -> suite -> project order.\n */\nexport function mergeSuiteAgentsFiles(\n\tchain: readonly SuiteAgentsMdEntry[],\n\tbase: ReadonlyArray<{ path: string; content: string }>,\n\toptions: { agentDir: string },\n): Array<{ path: string; content: string }> {\n\tconst retainedBase = base.filter((entry) => !isUnderDir(entry.path, options.agentDir));\n\tconst basePathSet = new Set(retainedBase.map((entry) => resolve(entry.path)));\n\tconst merged: Array<{ path: string; content: string }> = [];\n\tfor (const entry of chain) {\n\t\tif (entry.content.trim().length === 0) continue;\n\t\tif (basePathSet.has(resolve(entry.path))) continue;\n\t\tmerged.push({ path: entry.path, content: entry.content });\n\t}\n\tmerged.push(...retainedBase.map((entry) => ({ path: entry.path, content: entry.content })));\n\treturn merged;\n}\n\nexport interface SuiteSystemPromptGate {\n\t/** Gates the loader's main system prompt: the discovered file's content, or undefined. */\n\treadonly systemPromptOverride: (base: string | undefined) => string | undefined;\n\t/** Gates the loader's append system prompt: the discovered file's content array. */\n\treadonly appendSystemPromptOverride: (base: string[]) => string[];\n\t/** Blocked global system-layer files; filled as the overrides run, deduplicated. */\n\treadonly diagnostics: readonly string[];\n}\n\n/**\n * Gates the global SYSTEM.md/APPEND_SYSTEM.md system prompt channel by\n * inheritSystemAgentsMd (设计 §8: the switch governs the whole system layer,\n * not just the agents.md chain). The resource loader feeds both overrides with\n * the resolved content of exactly one discovered file — project-level\n * `<cwd>/.agent-forge/<name>` first, else global `<agentDir>/<name>` — with no\n * path attached, so project-level existence identifies the base origin:\n * present means the project layer, which per 设计 §4 is the third level and\n * always passes the switch; absent means a global source, which passes only\n * when the suite inherits the system layer. Blocked global files are recorded\n * in diagnostics with their paths (one-time migration hint, 设计 §11.3).\n */\nexport function createSuiteSystemPromptGate(\n\tsuite: SuiteDefinition,\n\toptions: { cwd: string; agentDir: string },\n): SuiteSystemPromptGate {\n\tconst diagnostics: string[] = [];\n\tconst passes = (filename: string): boolean => {\n\t\tconst projectPath = join(options.cwd, CONFIG_DIR_NAME, filename);\n\t\tif (existsSync(projectPath)) return true;\n\t\tif (suite.inheritSystemAgentsMd) return true;\n\t\tconst message =\n\t\t\t`Suite \"${suite.id}\" does not inherit the global system layer (inheritSystemAgentsMd=false); ` +\n\t\t\t`global file kept out of the model context: ${join(options.agentDir, filename)}. Move it to the ` +\n\t\t\t`project level (${projectPath}) or set \"inheritSystemAgentsMd\": true in the suite.json.`;\n\t\tif (!diagnostics.includes(message)) diagnostics.push(message);\n\t\treturn false;\n\t};\n\treturn {\n\t\tsystemPromptOverride: (base) => (base === undefined || passes(\"SYSTEM.md\") ? base : undefined),\n\t\tappendSystemPromptOverride: (base) => (base.length === 0 || passes(\"APPEND_SYSTEM.md\") ? base : []),\n\t\tdiagnostics,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Association filtering (设计 §3/§4/§11.3, M1b)\n// ---------------------------------------------------------------------------\n\nexport type SuiteAssociationKind = \"skills\" | \"plugins\" | \"capabilities\";\n\nexport interface SuiteAssociationFilterResult<T> {\n\t/** Entries that pass the filter, in input order. */\n\treadonly kept: T[];\n\t/** Association names that matched no discovered entry (设计 §11.3 dangling). */\n\treadonly dangling: readonly string[];\n}\n\n/**\n * Single-sourced dangling-association diagnostic text (设计 §11.3): reported\n * through the suiteDiagnostics channel, never thrown.\n */\nexport function suiteDanglingAssociationDiagnostic(suiteId: string, kind: SuiteAssociationKind, name: string): string {\n\treturn `Suite \"${suiteId}\" dangling association \"${name}\" (${kind}): not found in the discovered registry; ignored.`;\n}\n\n/**\n * Filters the discovered skills down to the suite's skill associations (设计\n * §3: the filter lives in the assembler; discovery stays untouched). Project\n * scope (`<cwd>/.agent-forge/`) is the third layer (设计 §4) and always passes;\n * every other entry is kept only when its `Skill.name` exactly matches an\n * `associations.skills` entry. Association names that match no discovered\n * skill — including case mismatches — are reported as dangling.\n *\n * `options.localSkillsDir` is the suite-local skill layer (统一修复轮 B:\n * `<agentDir>/suites/<id>/skills`): its entries live inside the active suite\n * workspace, so suite activation is their association and they pass the filter\n * by path — the suite-local layer exemption — instead of requiring an\n * association entry.\n */\nexport function filterSuiteSkills(\n\tsuite: SuiteDefinition,\n\tskills: ReadonlyArray<Skill>,\n\toptions?: { localSkillsDir?: string },\n): SuiteAssociationFilterResult<Skill> {\n\tconst associated = new Set(suite.associations.skills);\n\tconst discovered = new Set(skills.map((skill) => skill.name));\n\tconst dangling = suite.associations.skills.filter((name) => !discovered.has(name));\n\tconst localSkillsDir = options?.localSkillsDir;\n\tconst kept = skills.filter(\n\t\t(skill) =>\n\t\t\tskill.sourceInfo.scope === \"project\" ||\n\t\t\t(localSkillsDir !== undefined && isUnderDir(skill.filePath, localSkillsDir)) ||\n\t\t\tassociated.has(skill.name),\n\t);\n\treturn { kept, dangling: Object.freeze(dangling) };\n}\n\n// ---------------------------------------------------------------------------\n// Capability plugin pool filtering (设计 §10.4, M3)\n// ---------------------------------------------------------------------------\n\n/** One external capability plugin manifest discovered below a plugin pool root. */\nexport interface SuiteCapabilityPluginCandidate {\n\t/** Exact manifest id (`PluginManifest.id`). */\n\treadonly manifestId: string;\n\t/** Resolved manifest path, as it will be reported in diagnostics. */\n\treadonly manifestPath: string;\n}\n\nexport interface SuiteCapabilityPluginDecision {\n\treadonly keep: boolean;\n\t/** Diagnostic for a filtered-out plugin; absent when the plugin passes. */\n\treadonly diagnostic?: string;\n}\n\n/**\n * Decides one external capability plugin manifest against the suite's\n * `associations.plugins` (方案设计 §10.4, M3 双键语义: associations.plugins\n * governs only the external capability plugin pool; suite.capabilities governs\n * the compiled builtin ids). The project-level pool\n * (`<cwd>/.agent-forge/plugins`) is the third layer (设计 §4) and always\n * passes; every other manifest is kept only when its id matches an\n * association exactly. Filtered plugins surface as diagnostics, never as\n * errors.\n */\nexport function decideSuiteCapabilityPlugin(\n\tsuite: SuiteDefinition,\n\tcandidate: SuiteCapabilityPluginCandidate,\n\toptions: { cwd: string },\n): SuiteCapabilityPluginDecision {\n\tif (isUnderDir(candidate.manifestPath, join(options.cwd, CONFIG_DIR_NAME, \"plugins\"))) return { keep: true };\n\tif (suite.associations.plugins.includes(candidate.manifestId)) return { keep: true };\n\treturn {\n\t\tkeep: false,\n\t\tdiagnostic: `Suite \"${suite.id}\" capability plugin \"${candidate.manifestId}\" at ${candidate.manifestPath} is not associated; not loaded.`,\n\t};\n}\n\n/**\n * Dangling `associations.plugins` entries: association ids that matched no\n * candidate capability plugin manifest (设计 §11.3), single-sourced through\n * the shared dangling diagnostic text. The caller decides what counts as a\n * candidate: the sdk assembler passes every manifest id it loads, so explicit\n * capabilityPluginPaths count toward satisfying an association even though\n * they bypass the keep filter; only manifests absent from the passed ids\n * surface as dangling.\n */\nexport function suiteDanglingPluginAssociations(\n\tsuite: SuiteDefinition,\n\tdiscoveredManifestIds: readonly string[],\n): readonly string[] {\n\tconst discovered = new Set(discoveredManifestIds);\n\treturn suite.associations.plugins\n\t\t.filter((id) => !discovered.has(id))\n\t\t.map((id) => suiteDanglingAssociationDiagnostic(suite.id, \"plugins\", id));\n}\n\n// ---------------------------------------------------------------------------\n// Shared suite loader assembly (设计 §3/§4/§8, M2)\n// ---------------------------------------------------------------------------\n\n/**\n * The DefaultResourceLoader override subset that wires a resolved suite into a\n * loader: the agents.md three-level chain, the skill/extension association\n * filters, and the inheritSystemAgentsMd gate on the global SYSTEM.md/\n * APPEND_SYSTEM.md prompt channel. Structurally compatible with the matching\n * DefaultResourceLoaderOptions fields.\n */\nexport interface SuiteLoaderOverrides {\n\tagentsFilesOverride: (base: { agentsFiles: Array<{ path: string; content: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content: string }>;\n\t};\n\tskillsOverride: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tsystemPromptOverride: (base: string | undefined) => string | undefined;\n\tappendSystemPromptOverride: (base: string[]) => string[];\n}\n\nexport interface SuiteAssembly {\n\treadonly workspace: SuiteWorkspace;\n\t/** Optional domain plugin profile selected for this suite. */\n\treadonly pluginProfile?: BuiltinPluginProfileResolutionV1;\n\t/** Spread into DefaultResourceLoader options to wire the suite in. */\n\treadonly loaderOverrides: SuiteLoaderOverrides;\n\t/**\n\t * The suite-local skill layer directory (统一修复轮 B) when it exists on\n\t * disk; inject it into the loader's skill paths so suites/<id>/skills load\n\t * with the suite itself. Undefined when the directory is absent, so empty\n\t * and missing directories both contribute nothing.\n\t */\n\treadonly localSkillsDir?: string;\n\t/**\n\t * The suite-local capability-plugin layer directory (统一修复轮 B) when it\n\t * exists on disk; discover its manifests into the session's capability\n\t * plugin candidates. Undefined when the directory is absent.\n\t */\n\treadonly localPluginsDir?: string;\n\t/**\n\t * Snapshot of every suite assembly diagnostic collected so far — workspace\n\t * provisioning, agents.md chain, extension/skill filters, system prompt\n\t * gate, context budget — in the canonical suiteDiagnostics order. Overrides\n\t * that have not run yet contribute nothing (the budget line needs the\n\t * assembled agents.md chain).\n\t */\n\tcollectDiagnostics(): readonly string[];\n}\n\n/**\n * Single-sourced assembly-layer context budget estimate (统一修复轮 B): pure\n * chars/4 arithmetic over the assembled agents.md chain (per source layer),\n * the orientation persona text, plus the count of suite-local workspace\n * skills. Diagnostic-only: it never blocks, gates, or degrades anything.\n */\nexport function suiteContextBudgetDiagnostic(\n\tsuiteId: string,\n\tchain: ReadonlyArray<SuiteAgentsMdEntry>,\n\toptions: { personaChars: number; workspaceSkillCount: number },\n): string {\n\tconst layerChars: Record<SuiteAgentsMdSource, number> = { system: 0, suite: 0, project: 0 };\n\tfor (const entry of chain) {\n\t\tlayerChars[entry.source] += entry.content.length;\n\t}\n\tconst tokens = (chars: number): number => Math.round(chars / 4);\n\tconst system = tokens(layerChars.system);\n\tconst suiteLayer = tokens(layerChars.suite);\n\tconst project = tokens(layerChars.project);\n\treturn `Suite \"${suiteId}\" context budget: agents.md ~${system + suiteLayer + project} tok (system ${system}/suite ${suiteLayer}/project ${project}), persona ~${tokens(options.personaChars)} tok, workspace skills ${options.workspaceSkillCount}`;\n}\n\n/**\n * Plugin-profile diagnostics in the canonical suiteDiagnostics order.\n *\n * D-075 S2 soft degradation: a resolved Profile renders structured per-plugin\n * misses (e.g. `manifest_missing` for a package-distributed plugin without an\n * installed active version) as readable diagnostics, so the session keeps\n * starting without the missing plugin's tools and the miss stays visible.\n * Blocked resolutions already render every plugin diagnostic through\n * `resolution.diagnostics`; the per-plugin lines are additive for the\n * non-blocked branches only.\n */\nfunction pluginProfileDiagnosticsV1(profile: BuiltinPluginProfileResolutionV1): readonly string[] {\n\tif (profile.status === \"not_found\") return [`Plugin profile unavailable: ${profile.profileId}`];\n\tif (profile.status === \"host_facts_required\") return [`Plugin profile host facts required: ${profile.profileId}`];\n\tif (profile.status === \"invalid_selection\")\n\t\treturn [\n\t\t\t`Plugin profile invalid selection: ${profile.profileId} (unknown: ${profile.unknownPluginIds.join(\", \") || \"none\"}; duplicates: ${profile.duplicatePluginIds.join(\", \") || \"none\"})`,\n\t\t];\n\tconst pluginMisses =\n\t\tprofile.resolution.status === \"blocked\"\n\t\t\t? []\n\t\t\t: profile.resolution.plugins\n\t\t\t\t\t.filter((plugin) => plugin.status !== \"installed-ready\")\n\t\t\t\t\t.flatMap((plugin) =>\n\t\t\t\t\t\tplugin.diagnostics.map(\n\t\t\t\t\t\t\t(diagnostic) =>\n\t\t\t\t\t\t\t\t`Plugin profile plugin unavailable: ${plugin.pluginId} (${diagnostic.code}): ${diagnostic.message}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\tif (profile.resolution.status === \"blocked\")\n\t\treturn profile.resolution.diagnostics.map((diagnostic) => `Plugin profile blocked: ${diagnostic.message}`);\n\tif (profile.assembly?.status === \"unverified\")\n\t\treturn [\n\t\t\t...profile.assembly.unverified.map(\n\t\t\t\t(plugin) => `Plugin profile unverified: ${plugin.pluginId}@${plugin.pluginVersion}`,\n\t\t\t),\n\t\t\t...pluginMisses,\n\t\t];\n\treturn pluginMisses;\n}\n\n/**\n * The single suite assembly used by both first-party entry paths (sdk.ts\n * self-built loader and agent-session-services `suiteAssembly`), so the two\n * cannot drift. Loads the suite workspace, builds the system prompt gate, and\n * returns the loader overrides plus a diagnostics collection channel.\n */\nexport function createSuiteAssembly(options: {\n\tcwd: string;\n\tagentDir: string;\n\tsuiteId: string;\n\tpluginProfileId?: BuiltinPluginProfileIdV1;\n\tselectedPluginIds?: readonly string[];\n\tdisabledPluginIds?: readonly string[];\n\tpluginHost?: HostFactsV1;\n\tverifiedPlugins?: readonly VerifiedToolPluginV1[];\n\t/** Explicit host-owned active installed manifests; never discovered implicitly. */\n\tmanifestOverrides?: BuiltinPluginManifestOverridesV1;\n\tpluginProfile?: BuiltinPluginProfileResolutionV1;\n}): SuiteAssembly {\n\tconst { cwd, agentDir, suiteId } = options;\n\tlet pluginProfile = options.pluginProfile;\n\tif (pluginProfile === undefined && options.pluginProfileId !== undefined) {\n\t\tpluginProfile =\n\t\t\toptions.pluginHost === undefined\n\t\t\t\t? ({ status: \"host_facts_required\", profileId: options.pluginProfileId } as const)\n\t\t\t\t: resolveBuiltinPluginProfileV1({\n\t\t\t\t\t\tprofileId: options.pluginProfileId,\n\t\t\t\t\t\tselectedPluginIds: options.selectedPluginIds,\n\t\t\t\t\t\tdisabledPluginIds: options.disabledPluginIds,\n\t\t\t\t\t\thost: options.pluginHost,\n\t\t\t\t\t\tverifiedPlugins: options.verifiedPlugins,\n\t\t\t\t\t\tmanifestOverrides: options.manifestOverrides,\n\t\t\t\t\t});\n\t}\n\tconst workspace = loadSuiteWorkspace({\n\t\tagentDir,\n\t\tsuiteId,\n\t\t...(pluginProfile === undefined ? {} : { pluginProfile }),\n\t});\n\tconst gate = createSuiteSystemPromptGate(workspace.suite, { cwd, agentDir });\n\t// Suite-local asset layer (统一修复轮 B): present directories only, so\n\t// missing and empty directories both contribute nothing.\n\tconst localSkillsDir = getSuiteLocalSkillsDir(agentDir, suiteId);\n\tconst localPluginsDir = getSuiteLocalPluginsDir(agentDir, suiteId);\n\tconst hasLocalSkillsDir = existsSync(localSkillsDir);\n\tconst hasLocalPluginsDir = existsSync(localPluginsDir);\n\tconst workspaceSkillCount = hasLocalSkillsDir\n\t\t? loadSkills({ cwd, agentDir, skillPaths: [localSkillsDir], includeDefaults: false }).skills.length\n\t\t: 0;\n\tlet chainDiagnostics: readonly string[] = [];\n\tlet skillDiagnostics: readonly string[] = [];\n\t// The assembled chain as far as the agentsFilesOverride has run; the budget\n\t// line is only honest once the real chain is known.\n\tlet assembledChain: readonly SuiteAgentsMdEntry[] | undefined;\n\t// Factory upgrade proposal (M4, 设计 §9 升级合并): an unbounded registry\n\t// resolve only proposes when the factory source wins, i.e. its revision is\n\t// strictly greater than the disk revision. Daily assembly keeps the disk\n\t// contents; adoption is an explicit --suite-reset.\n\tconst upgrade = detectSuiteFactoryUpgrade(workspace.suite);\n\tconst proposalDiagnostics = upgrade === undefined ? [] : [suiteFactoryUpgradeDiagnostic(suiteId, upgrade)];\n\tconst budgetDiagnostics = (): readonly string[] => {\n\t\tif (assembledChain === undefined) return [];\n\t\treturn [\n\t\t\tsuiteContextBudgetDiagnostic(suiteId, assembledChain, {\n\t\t\t\tpersonaChars: workspace.orientationPersona.length,\n\t\t\t\tworkspaceSkillCount,\n\t\t\t}),\n\t\t];\n\t};\n\treturn {\n\t\tworkspace,\n\t\t...(pluginProfile === undefined ? {} : { pluginProfile }),\n\t\t...(hasLocalSkillsDir ? { localSkillsDir } : {}),\n\t\t...(hasLocalPluginsDir ? { localPluginsDir } : {}),\n\t\tloaderOverrides: {\n\t\t\tagentsFilesOverride: (base) => {\n\t\t\t\tconst assembly = assembleSuiteAgentsMdChain({\n\t\t\t\t\tsuite: workspace.suite,\n\t\t\t\t\tagentDir,\n\t\t\t\t\tsuiteJsonPath: workspace.suiteJsonPath,\n\t\t\t\t\tsuiteAgentsMdPath: workspace.agentsMdPath,\n\t\t\t\t\tprojectAgentsFiles: base.agentsFiles,\n\t\t\t\t});\n\t\t\t\tchainDiagnostics = assembly.diagnostics;\n\t\t\t\tassembledChain = assembly.chain;\n\t\t\t\treturn { agentsFiles: mergeSuiteAgentsFiles(assembly.chain, base.agentsFiles, { agentDir }) };\n\t\t\t},\n\t\t\tskillsOverride: (base) => {\n\t\t\t\tconst filtered = filterSuiteSkills(workspace.suite, base.skills, { localSkillsDir });\n\t\t\t\tskillDiagnostics = filtered.dangling.map((name) =>\n\t\t\t\t\tsuiteDanglingAssociationDiagnostic(suiteId, \"skills\", name),\n\t\t\t\t);\n\t\t\t\treturn { skills: filtered.kept, diagnostics: base.diagnostics };\n\t\t\t},\n\t\t\tsystemPromptOverride: gate.systemPromptOverride,\n\t\t\tappendSystemPromptOverride: gate.appendSystemPromptOverride,\n\t\t},\n\t\tcollectDiagnostics: () =>\n\t\t\tObject.freeze([\n\t\t\t\t...workspace.diagnostics,\n\t\t\t\t...(pluginProfile === undefined ? [] : pluginProfileDiagnosticsV1(pluginProfile)),\n\t\t\t\t...proposalDiagnostics,\n\t\t\t\t...chainDiagnostics,\n\t\t\t\t...skillDiagnostics,\n\t\t\t\t...budgetDiagnostics(),\n\t\t\t\t...gate.diagnostics,\n\t\t\t]),\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Session suite binding reader (设计 §10.1, 统一修复轮 B)\n// ---------------------------------------------------------------------------\n\n/**\n * Reads the suite binding recorded as session protocol data (设计 §10.1): the\n * suiteId of the latest `SUITE_SESSION_ENTRY_TYPE` custom entry. Undefined\n * when the session carries no binding — pre-suite sessions, entries without a\n * data payload, or payloads without a non-empty string suiteId.\n */\nexport function readSessionSuiteId(\n\tentries: ReadonlyArray<{ type: string; customType?: string; data?: unknown }>,\n): string | undefined {\n\treturn readSessionSuiteBinding(entries)?.suiteId;\n}\n\nexport interface SessionSuiteBindingV1 {\n\treadonly suiteId: string;\n\treadonly profileIdentity?: ProfileIdentityV1;\n}\n\nfunction sessionProfileIdentity(value: unknown): ProfileIdentityV1 | undefined {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n\tconst record = value as Record<string, unknown>;\n\tif (\n\t\ttypeof record.profileId !== \"string\" ||\n\t\trecord.profileId.trim() === \"\" ||\n\t\ttypeof record.profileVersion !== \"string\" ||\n\t\trecord.profileVersion.trim() === \"\" ||\n\t\ttypeof record.manifestDigest !== \"string\" ||\n\t\trecord.manifestDigest.trim() === \"\" ||\n\t\t!Array.isArray(record.capabilityVersions)\n\t) {\n\t\treturn undefined;\n\t}\n\tconst capabilityVersions: { id: string; version: number }[] = [];\n\tfor (const entry of record.capabilityVersions) {\n\t\tif (entry === null || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\n\t\tconst capability = entry as Record<string, unknown>;\n\t\tif (\n\t\t\ttypeof capability.id !== \"string\" ||\n\t\t\tcapability.id.trim() === \"\" ||\n\t\t\ttypeof capability.version !== \"number\" ||\n\t\t\t!Number.isSafeInteger(capability.version) ||\n\t\t\tcapability.version < 1\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\tcapabilityVersions.push({ id: capability.id, version: capability.version });\n\t}\n\treturn Object.freeze({\n\t\tprofileId: record.profileId,\n\t\tprofileVersion: record.profileVersion,\n\t\tmanifestDigest: record.manifestDigest,\n\t\tcapabilityVersions: Object.freeze(capabilityVersions) as readonly {\n\t\t\treadonly id: string;\n\t\t\treadonly version: number;\n\t\t}[],\n\t});\n}\n\n/** Reads the latest suite and optional Profile identity bound to a session. */\nexport function readSessionSuiteBinding(\n\tentries: ReadonlyArray<{ type: string; customType?: string; data?: unknown }>,\n): SessionSuiteBindingV1 | undefined {\n\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\tconst entry = entries[index];\n\t\tif (entry.type !== \"custom\" || entry.customType !== SUITE_SESSION_ENTRY_TYPE) continue;\n\t\tconst data = entry.data;\n\t\tif (data !== null && typeof data === \"object\" && !Array.isArray(data)) {\n\t\t\tconst suiteId = (data as { suiteId?: unknown }).suiteId;\n\t\t\tif (typeof suiteId === \"string\" && suiteId.length > 0) {\n\t\t\t\tconst profileIdentity = sessionProfileIdentity((data as { profileIdentity?: unknown }).profileIdentity);\n\t\t\t\treturn Object.freeze({\n\t\t\t\t\tsuiteId,\n\t\t\t\t\t...(profileIdentity === undefined ? {} : { profileIdentity }),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\treturn undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Suite -> ProfileIdentityV1 -> lock bridge (设计 §12)\n// ---------------------------------------------------------------------------\n\nfunction suiteToJsonValue(suite: SuiteDefinition): JsonValue {\n\treturn {\n\t\tschemaVersion: suite.schemaVersion,\n\t\tid: suite.id,\n\t\tname: suite.name,\n\t\tbuiltin: suite.builtin,\n\t\ttools: [...suite.tools],\n\t\tcapabilities: [...suite.capabilities],\n\t\tassociations: {\n\t\t\tskills: [...suite.associations.skills],\n\t\t\tmcp: [...suite.associations.mcp],\n\t\t\tplugins: [...suite.associations.plugins],\n\t\t},\n\t\tinheritSystemAgentsMd: suite.inheritSystemAgentsMd,\n\t\tmemory: suite.memory,\n\t\torientation: suite.orientation,\n\t\tmodel: suite.model,\n\t\tthinking: suite.thinking,\n\t\tclonedFrom: suite.clonedFrom\n\t\t\t? { id: suite.clonedFrom.id, digest: suite.clonedFrom.digest, at: suite.clonedFrom.at }\n\t\t\t: null,\n\t\t...(suite.factoryRevision === undefined ? {} : { factoryRevision: suite.factoryRevision }),\n\t};\n}\n\n/** The stable suite.json digest that rides as the suite profile manifest digest. */\nexport function suiteManifestDigest(suite: SuiteDefinition): string {\n\treturn stableJsonDigest(suiteToJsonValue(suite));\n}\n\n/**\n * Builds the ProfileIdentityV1 for an assembled suite. The identity is a pure\n * function of suite.json: the stable suite.json digest rides as the single\n * resolved \"manifest\", and the declared capabilities map to capability\n * references at version 1. No new identity/lock mechanism is introduced.\n */\nexport function buildSuiteProfileIdentity(\n\tsuite: SuiteDefinition,\n\tpluginProfile?: BuiltinPluginProfileResolutionV1,\n): ProfileIdentityV1 {\n\tconst fingerprint = suiteManifestDigest(suite);\n\tconst suiteCapabilityRefs = suite.capabilities.map((id) => ({ id, version: 1 }));\n\tconst pluginRefs =\n\t\tpluginProfile?.status === \"resolved\" && pluginProfile.resolution.status === \"ready\"\n\t\t\t? pluginProfile.resolution.resolvedManifest.plugins\n\t\t\t: [];\n\tconst capabilityRefs = [...suiteCapabilityRefs, ...pluginRefs.flatMap((plugin) => plugin.capabilityRefs)].sort(\n\t\t(left, right) => left.id.localeCompare(right.id) || left.version - right.version,\n\t);\n\treturn buildProfileIdentityV1({\n\t\tprofileId: suiteProfileId(suite.id),\n\t\tprofileVersion: `${SUITE_SCHEMA_VERSION}`,\n\t\tresolvedPlugins: [\n\t\t\t{\n\t\t\t\tpluginId: `${suite.id}/suite.json`,\n\t\t\t\tpluginVersion: fingerprint,\n\t\t\t\tcapabilityRefs: suiteCapabilityRefs,\n\t\t\t},\n\t\t\t...(pluginProfile?.status === \"resolved\" && pluginProfile.resolution.status === \"ready\"\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpluginId: `profile:${pluginProfile.profile.id}`,\n\t\t\t\t\t\t\tpluginVersion: pluginProfile.profile.version,\n\t\t\t\t\t\t\tcapabilityRefs: [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...pluginRefs,\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t],\n\t\tcapabilityVersions: capabilityRefs,\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// ProfileRegistryV1 hookup: factory/disk sources and upgrade proposals (M4)\n// ---------------------------------------------------------------------------\n\n/** Registry profileId namespace for suites (设计 §12). */\nexport function suiteProfileId(suiteId: string): string {\n\treturn `suite:${suiteId}`;\n}\n\nexport const SUITE_FACTORY_REGISTRY_SOURCE_ID = \"suite-factory\";\nexport const SUITE_DISK_REGISTRY_SOURCE_ID = \"suite-disk\";\n/** Lower priority wins same-version ties: the disk contents beat the factory. */\nconst SUITE_FACTORY_REGISTRY_PRIORITY = 10;\nconst SUITE_DISK_REGISTRY_PRIORITY = 0;\n\n/** The effective on-disk revision: absent key means FACTORY_CONTENTS_VERSION. */\nfunction suiteDiskRevision(suite: SuiteDefinition): number {\n\treturn suite.factoryRevision ?? FACTORY_CONTENTS_VERSION;\n}\n\n/** Builds the registry entry of one suite definition (version = factoryRevision). */\nexport function buildSuiteRegistryEntry(suite: SuiteDefinition): RegistryProfileEntryV1 {\n\treturn {\n\t\tprofileId: suiteProfileId(suite.id),\n\t\tprofileVersion: String(suiteDiskRevision(suite)),\n\t\tmanifestDigest: suiteManifestDigest(suite),\n\t};\n}\n\n/** Factory source over the builtin declarations (priority 10). */\nexport function buildSuiteFactoryRegistrySource(): RegistrySourceV1 {\n\treturn {\n\t\tsourceId: SUITE_FACTORY_REGISTRY_SOURCE_ID,\n\t\tpriority: SUITE_FACTORY_REGISTRY_PRIORITY,\n\t\tprofiles: BUILTIN_SUITES.map(buildSuiteRegistryEntry),\n\t};\n}\n\n/** Disk source over workspace-effective definitions (priority 0; wins ties). */\nexport function buildSuiteDiskRegistrySource(suites: readonly SuiteDefinition[]): RegistrySourceV1 {\n\treturn {\n\t\tsourceId: SUITE_DISK_REGISTRY_SOURCE_ID,\n\t\tpriority: SUITE_DISK_REGISTRY_PRIORITY,\n\t\tprofiles: suites.map(buildSuiteRegistryEntry),\n\t};\n}\n\nexport interface SuiteFactoryUpgrade {\n\t/** Revision the factory builtin declaration carries. */\n\treadonly factoryRevision: number;\n\t/** Revision effective on disk. */\n\treadonly diskRevision: number;\n}\n\n/** Single-sourced upgrade-proposal diagnostic text (设计 §9 升级合并). */\nexport function suiteFactoryUpgradeDiagnostic(suiteId: string, upgrade: SuiteFactoryUpgrade): string {\n\treturn `Suite \"${suiteId}\": factory revision ${upgrade.factoryRevision} available (disk has ${upgrade.diskRevision}); run \"--suite-reset ${suiteId}\" to review and adopt.`;\n}\n\n/**\n * Detects a factory upgrade proposal for one disk-effective suite: an\n * unbounded registry resolve over the factory source (all builtins) plus a\n * disk source carrying exactly the effective definition. The factory source\n * wins only when its revision is strictly greater — same-version resolves\n * keep the disk contents (priority 0), so no proposal is emitted for\n * unchanged suites, and user suites (no factory entry) never resolve to the\n * factory. Pure function; the caller decides what to do with the proposal.\n */\nexport function detectSuiteFactoryUpgrade(diskSuite: SuiteDefinition): SuiteFactoryUpgrade | undefined {\n\tconst registry = createProfileRegistry();\n\tregistry.registerSource(buildSuiteFactoryRegistrySource());\n\tregistry.registerSource(buildSuiteDiskRegistrySource([diskSuite]));\n\tconst resolution = registry.resolve({ profileId: suiteProfileId(diskSuite.id) });\n\tif (resolution.status !== \"resolved\" || resolution.sourceId !== SUITE_FACTORY_REGISTRY_SOURCE_ID) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tfactoryRevision: Number.parseInt(resolution.profileVersion, 10),\n\t\tdiskRevision: suiteDiskRevision(diskSuite),\n\t};\n}\n\nexport interface SuiteProfileLockBridge {\n\treadonly identity: ProfileIdentityV1;\n\t/**\n\t * The lock for this assembly. When a previous lock exists it is kept as-is\n\t * (a lock is never silently replaced); without one, a fresh lock freezes\n\t * the current identity.\n\t */\n\treadonly lock: ProfileLockV1;\n\treadonly verification?: ProfileLockVerificationV1;\n\t/** Drift/migration findings; recorded, never blocking in M1a (设计 §12). */\n\treadonly diagnostics: readonly string[];\n}\n\n/** Bridges an assembled suite onto the existing lock create/verify trio. */\nexport function bridgeSuiteProfileLock(options: {\n\treadonly suite: SuiteDefinition;\n\treadonly pluginProfile?: BuiltinPluginProfileResolutionV1;\n\treadonly previousLock?: ProfileLockV1;\n\treadonly lockedBy?: string;\n\treadonly now?: () => number;\n}): SuiteProfileLockBridge {\n\tconst identity = buildSuiteProfileIdentity(options.suite, options.pluginProfile);\n\tconst diagnostics: string[] = [];\n\tlet verification: ProfileLockVerificationV1 | undefined;\n\tif (options.previousLock !== undefined) {\n\t\tverification = verifyProfileLock(options.previousLock, identity);\n\t\tif (verification.status === \"drift\") {\n\t\t\t// 2026-10-01 dogfood finding: the bare drift reason left no recovery\n\t\t\t// path. Deleting the lock file and restarting rebuilds it from the\n\t\t\t// resolved manifest (loadSuiteWorkspace re-freezes a fresh lock).\n\t\t\tdiagnostics.push(\n\t\t\t\t`Suite \"${options.suite.id}\" profile lock drift: ${verification.reason}; to recover, delete <agentDir>/suites/${options.suite.id}/${SUITE_LOCK_FILENAME} and restart (the lock rebuilds from the resolved manifest)`,\n\t\t\t);\n\t\t} else if (verification.status === \"migration_required\") {\n\t\t\tdiagnostics.push(`Suite \"${options.suite.id}\" profile lock migration required: ${verification.reason}`);\n\t\t}\n\t}\n\tconst lock =\n\t\toptions.previousLock ??\n\t\tcreateProfileLock(identity, {\n\t\t\tlockedBy: options.lockedBy ?? \"suite-loader\",\n\t\t\t...(options.now === undefined ? {} : { now: options.now }),\n\t\t});\n\treturn {\n\t\tidentity,\n\t\tlock,\n\t\t...(verification === undefined ? {} : { verification }),\n\t\tdiagnostics: Object.freeze(diagnostics),\n\t};\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://raw.githubusercontent.com/agent-forge/agent-forge/main/packages/agent-forge/src/modes/interactive/theme/theme-schema.json",
2
+ "$schema": "https://raw.githubusercontent.com/agent-forge/agent-forge/main/packages/agent-forge/src/theme/theme-schema.json",
3
3
  "name": "dark",
4
4
  "vars": {
5
5
  "cyan": "#00d7ff",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://raw.githubusercontent.com/agent-forge/agent-forge/main/packages/agent-forge/src/modes/interactive/theme/theme-schema.json",
2
+ "$schema": "https://raw.githubusercontent.com/agent-forge/agent-forge/main/packages/agent-forge/src/theme/theme-schema.json",
3
3
  "name": "light",
4
4
  "vars": {
5
5
  "teal": "#5a8080",
@@ -1,5 +1,5 @@
1
1
  import type { TUI } from "@agent-forge/tui";
2
- import type { SettingsManager } from "../../../core/settings-manager.ts";
2
+ import type { SettingsManager } from "../core/settings-manager.ts";
3
3
  import { type TerminalTheme, type Theme } from "./theme.ts";
4
4
  type ThemeResult = {
5
5
  success: boolean;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-controller.d.ts","sourceRoot":"","sources":["../../src/theme/theme-controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EASN,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,MAAM,YAAY,CAAC;AAEpB,KAAK,WAAW,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,qBAAa,0BAA0B;IACtC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAwB;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IACvC,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,aAAa,CAA0D;IAC/E,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,8BAA8B,CAA2B;IAEjE,YACC,EAAE,EAAE,GAAG,EACP,OAAO,EAAE;QACR,kBAAkB,EAAE,MAAM,eAAe,CAAC;QAC1C,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;QACrC,SAAS,EAAE,MAAM,IAAI,CAAC;QACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC7B,EAaD;IAED,SAAS,IAAI,IAAI,CAIhB;IAEK,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAwBvC;IAED,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAEtC;IAED,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,WAAW,CAO9D;IAEK,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGzD;IAED,gBAAgB,CAAC,aAAa,EAAE,KAAK,GAAG,WAAW,CAMlD;IAED,OAAO,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAOxC;IAED,eAAe,IAAI,IAAI,CAEtB;IAED,gBAAgB,IAAI,aAAa,CAEhC;IAED,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,+BAA+B;IAMvC,OAAO,CAAC,kBAAkB;CAc1B","sourcesContent":["import type { TUI } from \"@agent-forge/tui\";\nimport { t } from \"../core/i18n/index.ts\";\nimport type { SettingsManager } from \"../core/settings-manager.ts\";\nimport {\n\tdetectTerminalBackgroundFromEnv,\n\tdetectTerminalBackgroundTheme,\n\tdetectTerminalThemeForAuto,\n\tinitTheme,\n\tparseAutoThemeSetting,\n\tresolveThemeSetting,\n\tsetTheme,\n\tsetThemeInstance,\n\ttype TerminalTheme,\n\ttype Theme,\n} from \"./theme.ts\";\n\ntype ThemeResult = { success: boolean; error?: string };\n\nexport class InteractiveThemeController {\n\tprivate readonly ui: TUI;\n\tprivate readonly getSettingsManager: () => SettingsManager;\n\tprivate readonly showError: (message: string) => void;\n\tprivate readonly onChanged: () => void;\n\tprivate currentThemeSetting: string | undefined;\n\tprivate terminalTheme: TerminalTheme = detectTerminalBackgroundFromEnv().theme;\n\tprivate activeThemeName: string | undefined;\n\tprivate autoSyncEnabled = false;\n\tprivate terminalColorSchemeUnsubscribe: (() => void) | undefined;\n\n\tconstructor(\n\t\tui: TUI,\n\t\toptions: {\n\t\t\tgetSettingsManager: () => SettingsManager;\n\t\t\tshowError: (message: string) => void;\n\t\t\tonChanged: () => void;\n\t\t\tinitialThemeSetting?: string;\n\t\t},\n\t) {\n\t\tthis.ui = ui;\n\t\tthis.getSettingsManager = options.getSettingsManager;\n\t\tthis.showError = options.showError;\n\t\tthis.onChanged = options.onChanged;\n\t\tthis.currentThemeSetting = options.initialThemeSetting;\n\t\tthis.activeThemeName = resolveThemeSetting(\n\t\t\tthis.currentThemeSetting ?? this.getSettingsManager().getThemeSetting(),\n\t\t\tthis.terminalTheme,\n\t\t);\n\t\tinitTheme(this.activeThemeName, true);\n\t\tthis.bindTerminalColorSchemeListener();\n\t}\n\n\trebindTui(): void {\n\t\tthis.terminalColorSchemeUnsubscribe?.();\n\t\tthis.bindTerminalColorSchemeListener();\n\t\tthis.ui.setTerminalColorSchemeNotifications(this.autoSyncEnabled);\n\t}\n\n\tasync applyFromSettings(): Promise<void> {\n\t\tconst settingsManager = this.getSettingsManager();\n\t\tconst themeSetting = this.currentThemeSetting ?? settingsManager.getThemeSetting();\n\t\tconst autoTheme = parseAutoThemeSetting(themeSetting);\n\t\tif (autoTheme) {\n\t\t\tthis.terminalTheme = await detectTerminalThemeForAuto({ ui: this.ui, timeoutMs: 100 });\n\t\t\tthis.setAutoSync(true);\n\t\t\tthis.applyThemeName(this.terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme, true);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setAutoSync(false);\n\t\tif (themeSetting !== undefined) {\n\t\t\tthis.applyThemeName(themeSetting, true);\n\t\t\treturn;\n\t\t}\n\n\t\tconst detection = await detectTerminalBackgroundTheme({ ui: this.ui, timeoutMs: 100 });\n\t\tthis.terminalTheme = detection.theme;\n\t\tif (!this.applyThemeName(detection.theme).success) return;\n\t\tif (detection.confidence === \"high\") {\n\t\t\tsettingsManager.setTheme(detection.theme);\n\t\t\tawait settingsManager.flush();\n\t\t}\n\t}\n\n\tgetThemeSelection(): string | undefined {\n\t\treturn this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting() ?? this.activeThemeName;\n\t}\n\n\tsetThemeName(themeName: string, showError = false): ThemeResult {\n\t\tthis.setAutoSync(false);\n\t\tconst result = this.applyThemeName(themeName, showError);\n\t\tif (result.success) {\n\t\t\tthis.currentThemeSetting = themeName;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync setThemeSetting(themeSetting: string): Promise<void> {\n\t\tthis.currentThemeSetting = themeSetting;\n\t\tawait this.applyFromSettings();\n\t}\n\n\tsetThemeInstance(themeInstance: Theme): ThemeResult {\n\t\tthis.setAutoSync(false);\n\t\tsetThemeInstance(themeInstance);\n\t\tthis.activeThemeName = \"<in-memory>\";\n\t\tthis.notifyChanged();\n\t\treturn { success: true };\n\t}\n\n\tpreview(themeSettingOrName: string): void {\n\t\tconst themeName = resolveThemeSetting(themeSettingOrName, this.terminalTheme) ?? this.activeThemeName;\n\t\tif (!themeName) return;\n\t\tif (setTheme(themeName, true).success) {\n\t\t\tthis.ui.invalidate();\n\t\t\tthis.ui.requestRender();\n\t\t}\n\t}\n\n\tdisableAutoSync(): void {\n\t\tthis.setAutoSync(false);\n\t}\n\n\tgetTerminalTheme(): TerminalTheme {\n\t\treturn this.terminalTheme;\n\t}\n\n\tprivate applyThemeName(themeName: string, showError = false): ThemeResult {\n\t\tconst result = setTheme(themeName, true);\n\t\tthis.activeThemeName = result.success ? themeName : \"dark\";\n\t\tthis.notifyChanged();\n\t\tif (!result.success && showError) {\n\t\t\tthis.showError(\n\t\t\t\t`${t('Failed to load theme \"{name}\": {error}', {\n\t\t\t\t\tname: themeName,\n\t\t\t\t\terror: result.error ?? \"unknown\",\n\t\t\t\t})}\\n${t(\"Fell back to dark theme.\")}`,\n\t\t\t);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate notifyChanged(): void {\n\t\tthis.ui.invalidate();\n\t\tthis.onChanged();\n\t}\n\n\tprivate setAutoSync(enabled: boolean): void {\n\t\tif (this.autoSyncEnabled === enabled) return;\n\t\tthis.autoSyncEnabled = enabled;\n\t\tthis.ui.setTerminalColorSchemeNotifications(enabled);\n\t}\n\n\tprivate bindTerminalColorSchemeListener(): void {\n\t\tthis.terminalColorSchemeUnsubscribe = this.ui.onTerminalColorSchemeChange((terminalTheme) =>\n\t\t\tthis.applyTerminalTheme(terminalTheme),\n\t\t);\n\t}\n\n\tprivate applyTerminalTheme(terminalTheme: TerminalTheme): void {\n\t\tif (!this.autoSyncEnabled) return;\n\t\tthis.terminalTheme = terminalTheme;\n\t\tconst autoTheme = parseAutoThemeSetting(this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting());\n\t\t// v8 ignore next -- auto sync is only enabled for an auto theme setting, which always parses\n\t\tif (!autoTheme) {\n\t\t\tthis.setAutoSync(false);\n\t\t\treturn;\n\t\t}\n\t\tconst themeName = terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme;\n\t\tif (themeName !== this.activeThemeName) {\n\t\t\tthis.applyThemeName(themeName);\n\t\t}\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { t } from "../../../core/i18n/index.js";
1
+ import { t } from "../core/i18n/index.js";
2
2
  import { detectTerminalBackgroundFromEnv, detectTerminalBackgroundTheme, detectTerminalThemeForAuto, initTheme, parseAutoThemeSetting, resolveThemeSetting, setTheme, setThemeInstance, } from "./theme.js";
3
3
  export class InteractiveThemeController {
4
4
  ui;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-controller.js","sourceRoot":"","sources":["../../src/theme/theme-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TUI } from \"@agent-forge/tui\";\nimport { t } from \"../core/i18n/index.ts\";\nimport type { SettingsManager } from \"../core/settings-manager.ts\";\nimport {\n\tdetectTerminalBackgroundFromEnv,\n\tdetectTerminalBackgroundTheme,\n\tdetectTerminalThemeForAuto,\n\tinitTheme,\n\tparseAutoThemeSetting,\n\tresolveThemeSetting,\n\tsetTheme,\n\tsetThemeInstance,\n\ttype TerminalTheme,\n\ttype Theme,\n} from \"./theme.ts\";\n\ntype ThemeResult = { success: boolean; error?: string };\n\nexport class InteractiveThemeController {\n\tprivate readonly ui: TUI;\n\tprivate readonly getSettingsManager: () => SettingsManager;\n\tprivate readonly showError: (message: string) => void;\n\tprivate readonly onChanged: () => void;\n\tprivate currentThemeSetting: string | undefined;\n\tprivate terminalTheme: TerminalTheme = detectTerminalBackgroundFromEnv().theme;\n\tprivate activeThemeName: string | undefined;\n\tprivate autoSyncEnabled = false;\n\tprivate terminalColorSchemeUnsubscribe: (() => void) | undefined;\n\n\tconstructor(\n\t\tui: TUI,\n\t\toptions: {\n\t\t\tgetSettingsManager: () => SettingsManager;\n\t\t\tshowError: (message: string) => void;\n\t\t\tonChanged: () => void;\n\t\t\tinitialThemeSetting?: string;\n\t\t},\n\t) {\n\t\tthis.ui = ui;\n\t\tthis.getSettingsManager = options.getSettingsManager;\n\t\tthis.showError = options.showError;\n\t\tthis.onChanged = options.onChanged;\n\t\tthis.currentThemeSetting = options.initialThemeSetting;\n\t\tthis.activeThemeName = resolveThemeSetting(\n\t\t\tthis.currentThemeSetting ?? this.getSettingsManager().getThemeSetting(),\n\t\t\tthis.terminalTheme,\n\t\t);\n\t\tinitTheme(this.activeThemeName, true);\n\t\tthis.bindTerminalColorSchemeListener();\n\t}\n\n\trebindTui(): void {\n\t\tthis.terminalColorSchemeUnsubscribe?.();\n\t\tthis.bindTerminalColorSchemeListener();\n\t\tthis.ui.setTerminalColorSchemeNotifications(this.autoSyncEnabled);\n\t}\n\n\tasync applyFromSettings(): Promise<void> {\n\t\tconst settingsManager = this.getSettingsManager();\n\t\tconst themeSetting = this.currentThemeSetting ?? settingsManager.getThemeSetting();\n\t\tconst autoTheme = parseAutoThemeSetting(themeSetting);\n\t\tif (autoTheme) {\n\t\t\tthis.terminalTheme = await detectTerminalThemeForAuto({ ui: this.ui, timeoutMs: 100 });\n\t\t\tthis.setAutoSync(true);\n\t\t\tthis.applyThemeName(this.terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme, true);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setAutoSync(false);\n\t\tif (themeSetting !== undefined) {\n\t\t\tthis.applyThemeName(themeSetting, true);\n\t\t\treturn;\n\t\t}\n\n\t\tconst detection = await detectTerminalBackgroundTheme({ ui: this.ui, timeoutMs: 100 });\n\t\tthis.terminalTheme = detection.theme;\n\t\tif (!this.applyThemeName(detection.theme).success) return;\n\t\tif (detection.confidence === \"high\") {\n\t\t\tsettingsManager.setTheme(detection.theme);\n\t\t\tawait settingsManager.flush();\n\t\t}\n\t}\n\n\tgetThemeSelection(): string | undefined {\n\t\treturn this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting() ?? this.activeThemeName;\n\t}\n\n\tsetThemeName(themeName: string, showError = false): ThemeResult {\n\t\tthis.setAutoSync(false);\n\t\tconst result = this.applyThemeName(themeName, showError);\n\t\tif (result.success) {\n\t\t\tthis.currentThemeSetting = themeName;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync setThemeSetting(themeSetting: string): Promise<void> {\n\t\tthis.currentThemeSetting = themeSetting;\n\t\tawait this.applyFromSettings();\n\t}\n\n\tsetThemeInstance(themeInstance: Theme): ThemeResult {\n\t\tthis.setAutoSync(false);\n\t\tsetThemeInstance(themeInstance);\n\t\tthis.activeThemeName = \"<in-memory>\";\n\t\tthis.notifyChanged();\n\t\treturn { success: true };\n\t}\n\n\tpreview(themeSettingOrName: string): void {\n\t\tconst themeName = resolveThemeSetting(themeSettingOrName, this.terminalTheme) ?? this.activeThemeName;\n\t\tif (!themeName) return;\n\t\tif (setTheme(themeName, true).success) {\n\t\t\tthis.ui.invalidate();\n\t\t\tthis.ui.requestRender();\n\t\t}\n\t}\n\n\tdisableAutoSync(): void {\n\t\tthis.setAutoSync(false);\n\t}\n\n\tgetTerminalTheme(): TerminalTheme {\n\t\treturn this.terminalTheme;\n\t}\n\n\tprivate applyThemeName(themeName: string, showError = false): ThemeResult {\n\t\tconst result = setTheme(themeName, true);\n\t\tthis.activeThemeName = result.success ? themeName : \"dark\";\n\t\tthis.notifyChanged();\n\t\tif (!result.success && showError) {\n\t\t\tthis.showError(\n\t\t\t\t`${t('Failed to load theme \"{name}\": {error}', {\n\t\t\t\t\tname: themeName,\n\t\t\t\t\terror: result.error ?? \"unknown\",\n\t\t\t\t})}\\n${t(\"Fell back to dark theme.\")}`,\n\t\t\t);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate notifyChanged(): void {\n\t\tthis.ui.invalidate();\n\t\tthis.onChanged();\n\t}\n\n\tprivate setAutoSync(enabled: boolean): void {\n\t\tif (this.autoSyncEnabled === enabled) return;\n\t\tthis.autoSyncEnabled = enabled;\n\t\tthis.ui.setTerminalColorSchemeNotifications(enabled);\n\t}\n\n\tprivate bindTerminalColorSchemeListener(): void {\n\t\tthis.terminalColorSchemeUnsubscribe = this.ui.onTerminalColorSchemeChange((terminalTheme) =>\n\t\t\tthis.applyTerminalTheme(terminalTheme),\n\t\t);\n\t}\n\n\tprivate applyTerminalTheme(terminalTheme: TerminalTheme): void {\n\t\tif (!this.autoSyncEnabled) return;\n\t\tthis.terminalTheme = terminalTheme;\n\t\tconst autoTheme = parseAutoThemeSetting(this.currentThemeSetting ?? this.getSettingsManager().getThemeSetting());\n\t\t// v8 ignore next -- auto sync is only enabled for an auto theme setting, which always parses\n\t\tif (!autoTheme) {\n\t\t\tthis.setAutoSync(false);\n\t\t\treturn;\n\t\t}\n\t\tconst themeName = terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme;\n\t\tif (themeName !== this.activeThemeName) {\n\t\t\tthis.applyThemeName(themeName);\n\t\t}\n\t}\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { ThinkingLevel } from "@agent-forge/agent-core";
2
2
  import { type EditorTheme, type MarkdownTheme, type RgbColor, type SelectListTheme, type SettingsListTheme } from "@agent-forge/tui";
3
- import type { SourceInfo } from "../../../core/source-info.ts";
3
+ import type { SourceInfo } from "../core/source-info.ts";
4
4
  export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "searchMatchText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "thinkingMax" | "bashMode";
5
5
  export type ThemeBg = "selectedBg" | "scrollbarThumb" | "searchMatchBg" | "userMessageBg" | "customMessageBg" | "toolPendingBg" | "toolSuccessBg" | "toolErrorBg";
6
6
  type OptionalThemeColor = "thinkingMax" | "searchMatchText";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/theme/theme.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { ThinkingLevel } from \"@agent-forge/agent-core\";\nimport {\n\ttype EditorTheme,\n\tgetCapabilities,\n\ttype MarkdownTheme,\n\ttype RgbColor,\n\ttype SelectListTheme,\n\ttype SettingsListTheme,\n} from \"@agent-forge/tui\";\nimport chalk from \"chalk\";\nimport { type Static, Type } from \"typebox\";\nimport { Compile } from \"typebox/compile\";\nimport { getCustomThemesDir, getThemesDir } from \"../config.ts\";\nimport { t } from \"../core/i18n/index.ts\";\nimport type { SourceInfo } from \"../core/source-info.ts\";\nimport { closeWatcher, watchWithErrorHandler } from \"../utils/fs-watch.ts\";\nimport { highlight, supportsLanguage } from \"../utils/syntax-highlight.ts\";\nimport { stripBom } from \"../utils/text.ts\";\n\n// ============================================================================\n// Types & Schema\n// ============================================================================\n\nconst ColorValueSchema = Type.Union([\n\tType.String(), // hex \"#ff0000\", var ref \"primary\", or empty \"\"\n\tType.Integer({ minimum: 0, maximum: 255 }), // 256-color index\n]);\n\ntype ColorValue = Static<typeof ColorValueSchema>;\n\nconst ThemeJsonSchema = Type.Object({\n\t$schema: Type.Optional(Type.String()),\n\tname: Type.String(),\n\tvars: Type.Optional(Type.Record(Type.String(), ColorValueSchema)),\n\tcolors: Type.Object({\n\t\t// Core UI (10 colors)\n\t\taccent: ColorValueSchema,\n\t\tborder: ColorValueSchema,\n\t\tborderAccent: ColorValueSchema,\n\t\tborderMuted: ColorValueSchema,\n\t\tsuccess: ColorValueSchema,\n\t\terror: ColorValueSchema,\n\t\twarning: ColorValueSchema,\n\t\tmuted: ColorValueSchema,\n\t\tdim: ColorValueSchema,\n\t\ttext: ColorValueSchema,\n\t\tthinkingText: ColorValueSchema,\n\t\t// Backgrounds & Content Text (11 required, 3 optional)\n\t\tselectedBg: ColorValueSchema,\n\t\tscrollbarThumb: Type.Optional(ColorValueSchema),\n\t\tsearchMatchBg: Type.Optional(ColorValueSchema),\n\t\tsearchMatchText: Type.Optional(ColorValueSchema),\n\t\tuserMessageBg: ColorValueSchema,\n\t\tuserMessageText: ColorValueSchema,\n\t\tcustomMessageBg: ColorValueSchema,\n\t\tcustomMessageText: ColorValueSchema,\n\t\tcustomMessageLabel: ColorValueSchema,\n\t\ttoolPendingBg: ColorValueSchema,\n\t\ttoolSuccessBg: ColorValueSchema,\n\t\ttoolErrorBg: ColorValueSchema,\n\t\ttoolTitle: ColorValueSchema,\n\t\ttoolOutput: ColorValueSchema,\n\t\t// Markdown (10 colors)\n\t\tmdHeading: ColorValueSchema,\n\t\tmdLink: ColorValueSchema,\n\t\tmdLinkUrl: ColorValueSchema,\n\t\tmdCode: ColorValueSchema,\n\t\tmdCodeBlock: ColorValueSchema,\n\t\tmdCodeBlockBorder: ColorValueSchema,\n\t\tmdQuote: ColorValueSchema,\n\t\tmdQuoteBorder: ColorValueSchema,\n\t\tmdHr: ColorValueSchema,\n\t\tmdListBullet: ColorValueSchema,\n\t\t// Tool Diffs (3 colors)\n\t\ttoolDiffAdded: ColorValueSchema,\n\t\ttoolDiffRemoved: ColorValueSchema,\n\t\ttoolDiffContext: ColorValueSchema,\n\t\t// Syntax Highlighting (9 colors)\n\t\tsyntaxComment: ColorValueSchema,\n\t\tsyntaxKeyword: ColorValueSchema,\n\t\tsyntaxFunction: ColorValueSchema,\n\t\tsyntaxVariable: ColorValueSchema,\n\t\tsyntaxString: ColorValueSchema,\n\t\tsyntaxNumber: ColorValueSchema,\n\t\tsyntaxType: ColorValueSchema,\n\t\tsyntaxOperator: ColorValueSchema,\n\t\tsyntaxPunctuation: ColorValueSchema,\n\t\t// Thinking Level Borders (6 colors)\n\t\tthinkingOff: ColorValueSchema,\n\t\tthinkingMinimal: ColorValueSchema,\n\t\tthinkingLow: ColorValueSchema,\n\t\tthinkingMedium: ColorValueSchema,\n\t\tthinkingHigh: ColorValueSchema,\n\t\tthinkingXhigh: ColorValueSchema,\n\t\tthinkingMax: Type.Optional(ColorValueSchema),\n\t\t// Bash Mode (1 color)\n\t\tbashMode: ColorValueSchema,\n\t}),\n\texport: Type.Optional(\n\t\tType.Object({\n\t\t\tpageBg: Type.Optional(ColorValueSchema),\n\t\t\tcardBg: Type.Optional(ColorValueSchema),\n\t\t\tinfoBg: Type.Optional(ColorValueSchema),\n\t\t}),\n\t),\n});\n\ntype ThemeJson = Static<typeof ThemeJsonSchema>;\n\nconst validateThemeJson = Compile(ThemeJsonSchema);\n\nexport type ThemeColor =\n\t| \"accent\"\n\t| \"border\"\n\t| \"borderAccent\"\n\t| \"borderMuted\"\n\t| \"success\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"muted\"\n\t| \"dim\"\n\t| \"text\"\n\t| \"thinkingText\"\n\t| \"searchMatchText\"\n\t| \"userMessageText\"\n\t| \"customMessageText\"\n\t| \"customMessageLabel\"\n\t| \"toolTitle\"\n\t| \"toolOutput\"\n\t| \"mdHeading\"\n\t| \"mdLink\"\n\t| \"mdLinkUrl\"\n\t| \"mdCode\"\n\t| \"mdCodeBlock\"\n\t| \"mdCodeBlockBorder\"\n\t| \"mdQuote\"\n\t| \"mdQuoteBorder\"\n\t| \"mdHr\"\n\t| \"mdListBullet\"\n\t| \"toolDiffAdded\"\n\t| \"toolDiffRemoved\"\n\t| \"toolDiffContext\"\n\t| \"syntaxComment\"\n\t| \"syntaxKeyword\"\n\t| \"syntaxFunction\"\n\t| \"syntaxVariable\"\n\t| \"syntaxString\"\n\t| \"syntaxNumber\"\n\t| \"syntaxType\"\n\t| \"syntaxOperator\"\n\t| \"syntaxPunctuation\"\n\t| \"thinkingOff\"\n\t| \"thinkingMinimal\"\n\t| \"thinkingLow\"\n\t| \"thinkingMedium\"\n\t| \"thinkingHigh\"\n\t| \"thinkingXhigh\"\n\t| \"thinkingMax\"\n\t| \"bashMode\";\n\nexport type ThemeBg =\n\t| \"selectedBg\"\n\t| \"scrollbarThumb\"\n\t| \"searchMatchBg\"\n\t| \"userMessageBg\"\n\t| \"customMessageBg\"\n\t| \"toolPendingBg\"\n\t| \"toolSuccessBg\"\n\t| \"toolErrorBg\";\n\ntype OptionalThemeColor = \"thinkingMax\" | \"searchMatchText\";\ntype OptionalThemeBg = \"scrollbarThumb\" | \"searchMatchBg\";\n\ntype ColorMode = \"truecolor\" | \"256color\";\n\n// ============================================================================\n// Color Utilities\n// ============================================================================\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n\tconst cleaned = hex.replace(\"#\", \"\");\n\tif (cleaned.length !== 6) {\n\t\tthrow new Error(t(\"Invalid hex color: {hex}\", { hex }));\n\t}\n\tconst r = parseInt(cleaned.substring(0, 2), 16);\n\tconst g = parseInt(cleaned.substring(2, 4), 16);\n\tconst b = parseInt(cleaned.substring(4, 6), 16);\n\tif (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {\n\t\tthrow new Error(t(\"Invalid hex color: {hex}\", { hex }));\n\t}\n\treturn { r, g, b };\n}\n\n// The 6x6x6 color cube channel values (indices 0-5)\nconst CUBE_VALUES = [0, 95, 135, 175, 215, 255];\n\n// Grayscale ramp values (indices 232-255, 24 grays from 8 to 238)\nconst GRAY_VALUES = Array.from({ length: 24 }, (_, i) => 8 + i * 10);\n\nfunction findClosestCubeIndex(value: number): number {\n\tlet minDist = Infinity;\n\tlet minIdx = 0;\n\tfor (let i = 0; i < CUBE_VALUES.length; i++) {\n\t\tconst dist = Math.abs(value - CUBE_VALUES[i]);\n\t\tif (dist < minDist) {\n\t\t\tminDist = dist;\n\t\t\tminIdx = i;\n\t\t}\n\t}\n\treturn minIdx;\n}\n\nfunction findClosestGrayIndex(gray: number): number {\n\tlet minDist = Infinity;\n\tlet minIdx = 0;\n\tfor (let i = 0; i < GRAY_VALUES.length; i++) {\n\t\tconst dist = Math.abs(gray - GRAY_VALUES[i]);\n\t\tif (dist < minDist) {\n\t\t\tminDist = dist;\n\t\t\tminIdx = i;\n\t\t}\n\t}\n\treturn minIdx;\n}\n\nfunction colorDistance(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number {\n\t// Weighted Euclidean distance (human eye is more sensitive to green)\n\tconst dr = r1 - r2;\n\tconst dg = g1 - g2;\n\tconst db = b1 - b2;\n\treturn dr * dr * 0.299 + dg * dg * 0.587 + db * db * 0.114;\n}\n\nfunction rgbTo256(r: number, g: number, b: number): number {\n\t// Find closest color in the 6x6x6 cube\n\tconst rIdx = findClosestCubeIndex(r);\n\tconst gIdx = findClosestCubeIndex(g);\n\tconst bIdx = findClosestCubeIndex(b);\n\tconst cubeR = CUBE_VALUES[rIdx];\n\tconst cubeG = CUBE_VALUES[gIdx];\n\tconst cubeB = CUBE_VALUES[bIdx];\n\tconst cubeIndex = 16 + 36 * rIdx + 6 * gIdx + bIdx;\n\tconst cubeDist = colorDistance(r, g, b, cubeR, cubeG, cubeB);\n\n\t// Find closest grayscale\n\tconst gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);\n\tconst grayIdx = findClosestGrayIndex(gray);\n\tconst grayValue = GRAY_VALUES[grayIdx];\n\tconst grayIndex = 232 + grayIdx;\n\tconst grayDist = colorDistance(r, g, b, grayValue, grayValue, grayValue);\n\n\t// Check if color has noticeable saturation (hue matters)\n\t// If max-min spread is significant, prefer cube to preserve tint\n\tconst maxC = Math.max(r, g, b);\n\tconst minC = Math.min(r, g, b);\n\tconst spread = maxC - minC;\n\n\t// Only consider grayscale if color is nearly neutral (spread < 10)\n\t// AND grayscale is actually closer\n\tif (spread < 10 && grayDist < cubeDist) {\n\t\treturn grayIndex;\n\t}\n\n\treturn cubeIndex;\n}\n\nfunction hexTo256(hex: string): number {\n\tconst { r, g, b } = hexToRgb(hex);\n\treturn rgbTo256(r, g, b);\n}\n\nfunction fgAnsi(color: string | number, mode: ColorMode): string {\n\tif (color === \"\") return \"\\x1b[39m\";\n\tif (typeof color === \"number\") return `\\x1b[38;5;${color}m`;\n\tif (color.startsWith(\"#\")) {\n\t\tif (mode === \"truecolor\") {\n\t\t\tconst { r, g, b } = hexToRgb(color);\n\t\t\treturn `\\x1b[38;2;${r};${g};${b}m`;\n\t\t} else {\n\t\t\tconst index = hexTo256(color);\n\t\t\treturn `\\x1b[38;5;${index}m`;\n\t\t}\n\t}\n\tthrow new Error(t(\"Invalid color value: {color}\", { color }));\n}\n\nfunction bgAnsi(color: string | number, mode: ColorMode): string {\n\tif (color === \"\") return \"\\x1b[49m\";\n\tif (typeof color === \"number\") return `\\x1b[48;5;${color}m`;\n\tif (color.startsWith(\"#\")) {\n\t\tif (mode === \"truecolor\") {\n\t\t\tconst { r, g, b } = hexToRgb(color);\n\t\t\treturn `\\x1b[48;2;${r};${g};${b}m`;\n\t\t} else {\n\t\t\tconst index = hexTo256(color);\n\t\t\treturn `\\x1b[48;5;${index}m`;\n\t\t}\n\t}\n\tthrow new Error(t(\"Invalid color value: {color}\", { color }));\n}\n\nfunction resolveVarRefs(\n\tvalue: ColorValue,\n\tvars: Record<string, ColorValue>,\n\tvisited = new Set<string>(),\n): string | number {\n\tif (typeof value === \"number\" || value === \"\" || value.startsWith(\"#\")) {\n\t\treturn value;\n\t}\n\tif (visited.has(value)) {\n\t\tthrow new Error(t(\"Circular variable reference detected: {value}\", { value }));\n\t}\n\tif (!(value in vars)) {\n\t\tthrow new Error(t(\"Variable reference not found: {value}\", { value }));\n\t}\n\tvisited.add(value);\n\treturn resolveVarRefs(vars[value], vars, visited);\n}\n\nfunction resolveThemeColors<T extends Record<string, ColorValue>>(\n\tcolors: T,\n\tvars: Record<string, ColorValue> = {},\n): Record<keyof T, string | number> {\n\tconst resolved: Record<string, string | number> = {};\n\tfor (const [key, value] of Object.entries(colors)) {\n\t\tresolved[key] = resolveVarRefs(value, vars);\n\t}\n\treturn resolved as Record<keyof T, string | number>;\n}\n\nfunction withThemeColorFallbacks(colors: ThemeJson[\"colors\"]): ThemeJson[\"colors\"] & {\n\tthinkingMax: ColorValue;\n\tscrollbarThumb: ColorValue;\n\tsearchMatchBg: ColorValue;\n\tsearchMatchText: ColorValue;\n} {\n\treturn {\n\t\t...colors,\n\t\tthinkingMax: colors.thinkingMax ?? colors.thinkingXhigh,\n\t\tscrollbarThumb: colors.scrollbarThumb ?? colors.selectedBg,\n\t\tsearchMatchBg: colors.searchMatchBg ?? colors.selectedBg,\n\t\tsearchMatchText: colors.searchMatchText ?? colors.text,\n\t};\n}\n\n// ============================================================================\n// Theme Class\n// ============================================================================\n\nexport class Theme {\n\treadonly name?: string;\n\treadonly sourcePath?: string;\n\tsourceInfo?: SourceInfo;\n\tprivate fgColors: Map<ThemeColor, string>;\n\tprivate bgColors: Map<ThemeBg, string>;\n\tprivate mode: ColorMode;\n\n\tconstructor(\n\t\tfgColors: Record<Exclude<ThemeColor, OptionalThemeColor>, string | number> &\n\t\t\tPartial<Record<OptionalThemeColor, string | number>>,\n\t\tbgColors: Record<Exclude<ThemeBg, OptionalThemeBg>, string | number> &\n\t\t\tPartial<Record<OptionalThemeBg, string | number>>,\n\t\tmode: ColorMode,\n\t\toptions: { name?: string; sourcePath?: string; sourceInfo?: SourceInfo } = {},\n\t) {\n\t\tthis.name = options.name;\n\t\tthis.sourcePath = options.sourcePath;\n\t\tthis.sourceInfo = options.sourceInfo;\n\t\tthis.mode = mode;\n\t\tthis.fgColors = new Map();\n\t\tconst colors = {\n\t\t\t...fgColors,\n\t\t\tthinkingMax: fgColors.thinkingMax ?? fgColors.thinkingXhigh,\n\t\t\tsearchMatchText: fgColors.searchMatchText ?? fgColors.text,\n\t\t};\n\t\tfor (const [key, value] of Object.entries(colors) as [ThemeColor, string | number][]) {\n\t\t\tthis.fgColors.set(key, fgAnsi(value, mode));\n\t\t}\n\t\tthis.bgColors = new Map();\n\t\tconst backgrounds = {\n\t\t\t...bgColors,\n\t\t\tscrollbarThumb: bgColors.scrollbarThumb ?? bgColors.selectedBg,\n\t\t\tsearchMatchBg: bgColors.searchMatchBg ?? bgColors.selectedBg,\n\t\t};\n\t\tfor (const [key, value] of Object.entries(backgrounds) as [ThemeBg, string | number][]) {\n\t\t\tthis.bgColors.set(key, bgAnsi(value, mode));\n\t\t}\n\t}\n\n\tfg(color: ThemeColor, text: string): string {\n\t\tconst ansi = this.fgColors.get(color);\n\t\tif (!ansi) throw new Error(t(\"Unknown theme color: {color}\", { color }));\n\t\treturn `${ansi}${text}\\x1b[39m`; // Reset only foreground color\n\t}\n\n\tbg(color: ThemeBg, text: string): string {\n\t\tconst ansi = this.bgColors.get(color);\n\t\tif (!ansi) throw new Error(t(\"Unknown theme background color: {color}\", { color }));\n\t\treturn `${ansi}${text}\\x1b[49m`; // Reset only background color\n\t}\n\n\tbold(text: string): string {\n\t\treturn chalk.bold(text);\n\t}\n\n\titalic(text: string): string {\n\t\treturn chalk.italic(text);\n\t}\n\n\tunderline(text: string): string {\n\t\treturn chalk.underline(text);\n\t}\n\n\tinverse(text: string): string {\n\t\treturn chalk.inverse(text);\n\t}\n\n\tstrikethrough(text: string): string {\n\t\treturn chalk.strikethrough(text);\n\t}\n\n\tgetFgAnsi(color: ThemeColor): string {\n\t\tconst ansi = this.fgColors.get(color);\n\t\tif (!ansi) throw new Error(t(\"Unknown theme color: {color}\", { color }));\n\t\treturn ansi;\n\t}\n\n\tgetBgAnsi(color: ThemeBg): string {\n\t\tconst ansi = this.bgColors.get(color);\n\t\tif (!ansi) throw new Error(t(\"Unknown theme background color: {color}\", { color }));\n\t\treturn ansi;\n\t}\n\n\tgetColorMode(): ColorMode {\n\t\treturn this.mode;\n\t}\n\n\tgetThinkingBorderColor(level: ThinkingLevel): (str: string) => string {\n\t\t// Map thinking levels to dedicated theme colors\n\t\tswitch (level) {\n\t\t\tcase \"off\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingOff\", str);\n\t\t\tcase \"minimal\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMinimal\", str);\n\t\t\tcase \"low\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingLow\", str);\n\t\t\tcase \"medium\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMedium\", str);\n\t\t\tcase \"high\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingHigh\", str);\n\t\t\tcase \"xhigh\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingXhigh\", str);\n\t\t\tcase \"max\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMax\", str);\n\t\t\tdefault:\n\t\t\t\treturn (str: string) => this.fg(\"thinkingOff\", str);\n\t\t}\n\t}\n\n\tgetBashModeBorderColor(): (str: string) => string {\n\t\treturn (str: string) => this.fg(\"bashMode\", str);\n\t}\n}\n\n// ============================================================================\n// Theme Loading\n// ============================================================================\n\nlet BUILTIN_THEMES: Record<string, ThemeJson> | undefined;\n\nfunction getBuiltinThemes(): Record<string, ThemeJson> {\n\tif (!BUILTIN_THEMES) {\n\t\tconst themesDir = getThemesDir();\n\t\tconst darkPath = path.join(themesDir, \"dark.json\");\n\t\tconst lightPath = path.join(themesDir, \"light.json\");\n\t\tBUILTIN_THEMES = {\n\t\t\tdark: JSON.parse(stripBom(fs.readFileSync(darkPath, \"utf-8\"))) as ThemeJson,\n\t\t\tlight: JSON.parse(stripBom(fs.readFileSync(lightPath, \"utf-8\"))) as ThemeJson,\n\t\t};\n\t}\n\treturn BUILTIN_THEMES;\n}\n\nexport function getAvailableThemes(): string[] {\n\treturn getAvailableThemesWithPaths().map(({ name }) => name);\n}\n\nexport interface ThemeInfo {\n\tname: string;\n\tpath: string | undefined;\n}\n\nexport function getAvailableThemesWithPaths(): ThemeInfo[] {\n\tconst themesDir = getThemesDir();\n\tconst result: ThemeInfo[] = [];\n\tconst seen = new Set<string>();\n\tconst addTheme = (themeInfo: ThemeInfo) => {\n\t\tif (seen.has(themeInfo.name)) {\n\t\t\treturn;\n\t\t}\n\t\tseen.add(themeInfo.name);\n\t\tresult.push(themeInfo);\n\t};\n\n\t// Built-in themes\n\tfor (const name of Object.keys(getBuiltinThemes())) {\n\t\taddTheme({ name, path: path.join(themesDir, `${name}.json`) });\n\t}\n\n\t// Custom themes\n\tfor (const themeInfo of getCustomThemeInfos()) {\n\t\taddTheme(themeInfo);\n\t}\n\n\tfor (const [name, theme] of registeredThemes.entries()) {\n\t\taddTheme({ name, path: theme.sourcePath });\n\t}\n\n\treturn result.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction getCustomThemeInfos(): ThemeInfo[] {\n\tconst customThemesDir = getCustomThemesDir();\n\tconst result: ThemeInfo[] = [];\n\tif (!fs.existsSync(customThemesDir)) {\n\t\treturn result;\n\t}\n\n\tfor (const file of fs.readdirSync(customThemesDir)) {\n\t\tif (!file.endsWith(\".json\")) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst themePath = path.join(customThemesDir, file);\n\t\ttry {\n\t\t\tconst customTheme = loadThemeFromPath(themePath);\n\t\t\tif (customTheme.name) {\n\t\t\t\tresult.push({ name: customTheme.name, path: themePath });\n\t\t\t}\n\t\t} catch {\n\t\t\t// Invalid themes are ignored here; the resource loader reports them\n\t\t\t// during normal startup/reload.\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction assertThemeNameIsValid(name: string): void {\n\tif (name.includes(\"/\")) {\n\t\tthrow new Error(\n\t\t\tt(\n\t\t\t\t'Invalid theme name \"{name}\": theme names cannot contain \"/\" because it is reserved for automatic light/dark theme settings.',\n\t\t\t\t{\n\t\t\t\t\tname,\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\t}\n}\n\nfunction parseThemeJson(label: string, json: unknown): ThemeJson {\n\tif (!validateThemeJson.Check(json)) {\n\t\tconst errors = Array.from(validateThemeJson.Errors(json));\n\t\tconst missingColors = new Set<string>();\n\t\tconst otherErrors: string[] = [];\n\n\t\tfor (const error of errors) {\n\t\t\tif (error.keyword === \"required\" && error.instancePath === \"/colors\") {\n\t\t\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\t\t\tfor (const requiredProperty of requiredProperties ?? []) {\n\t\t\t\t\tmissingColors.add(requiredProperty);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst path = error.instancePath || \"/\";\n\t\t\totherErrors.push(` - ${path}: ${error.message}`);\n\t\t}\n\n\t\tlet errorMessage = `${t('Invalid theme \"{label}\":', { label })}\\n`;\n\t\tif (missingColors.size > 0) {\n\t\t\terrorMessage += `\\n${t(\"Missing required color tokens:\")}\\n`;\n\t\t\terrorMessage += Array.from(missingColors)\n\t\t\t\t.sort()\n\t\t\t\t.map((color) => ` - ${color}`)\n\t\t\t\t.join(\"\\n\");\n\t\t\terrorMessage += `\\n\\n${t('Please add these colors to your theme\\'s \"colors\" object.')}`;\n\t\t\terrorMessage += `\\n${t(\"See the built-in themes (dark.json, light.json) for reference values.\")}`;\n\t\t}\n\t\tif (otherErrors.length > 0) {\n\t\t\terrorMessage += `\\n\\n${t(\"Other errors:\")}\\n${otherErrors.join(\"\\n\")}`;\n\t\t}\n\n\t\tthrow new Error(errorMessage);\n\t}\n\n\tconst themeJson = json as ThemeJson;\n\tassertThemeNameIsValid(themeJson.name);\n\treturn themeJson;\n}\n\nfunction parseThemeJsonContent(label: string, content: string): ThemeJson {\n\tlet json: unknown;\n\ttry {\n\t\tjson = JSON.parse(stripBom(content));\n\t} catch (error) {\n\t\tthrow new Error(t(\"Failed to parse theme {label}: {error}\", { label, error: String(error) }));\n\t}\n\treturn parseThemeJson(label, json);\n}\n\nfunction loadThemeJson(name: string): ThemeJson {\n\tconst builtinThemes = getBuiltinThemes();\n\tif (name in builtinThemes) {\n\t\treturn builtinThemes[name];\n\t}\n\tconst registeredTheme = registeredThemes.get(name);\n\tif (registeredTheme?.sourcePath) {\n\t\tconst content = fs.readFileSync(registeredTheme.sourcePath, \"utf-8\");\n\t\treturn parseThemeJsonContent(registeredTheme.sourcePath, content);\n\t}\n\tif (registeredTheme) {\n\t\tthrow new Error(t('Theme \"{name}\" does not have a source path for export', { name }));\n\t}\n\tconst customThemesDir = getCustomThemesDir();\n\tconst themePath = path.join(customThemesDir, `${name}.json`);\n\tif (!fs.existsSync(themePath)) {\n\t\tthrow new Error(t(\"Theme not found: {name}\", { name }));\n\t}\n\tconst content = fs.readFileSync(themePath, \"utf-8\");\n\treturn parseThemeJsonContent(name, content);\n}\n\nfunction createTheme(themeJson: ThemeJson, mode?: ColorMode, sourcePath?: string): Theme {\n\tconst colorMode = mode ?? (getCapabilities().trueColor ? \"truecolor\" : \"256color\");\n\tconst resolvedColors = resolveThemeColors(withThemeColorFallbacks(themeJson.colors), themeJson.vars);\n\tconst fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;\n\tconst bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;\n\tconst bgColorKeys: Set<string> = new Set([\n\t\t\"selectedBg\",\n\t\t\"scrollbarThumb\",\n\t\t\"searchMatchBg\",\n\t\t\"userMessageBg\",\n\t\t\"customMessageBg\",\n\t\t\"toolPendingBg\",\n\t\t\"toolSuccessBg\",\n\t\t\"toolErrorBg\",\n\t]);\n\tfor (const [key, value] of Object.entries(resolvedColors)) {\n\t\tif (bgColorKeys.has(key)) {\n\t\t\tbgColors[key as ThemeBg] = value;\n\t\t} else {\n\t\t\tfgColors[key as ThemeColor] = value;\n\t\t}\n\t}\n\treturn new Theme(fgColors, bgColors, colorMode, {\n\t\tname: themeJson.name,\n\t\tsourcePath,\n\t});\n}\n\nexport function loadThemeFromPath(themePath: string, mode?: ColorMode): Theme {\n\tconst content = fs.readFileSync(themePath, \"utf-8\");\n\tconst themeJson = parseThemeJsonContent(themePath, content);\n\treturn createTheme(themeJson, mode, themePath);\n}\n\nfunction loadTheme(name: string, mode?: ColorMode): Theme {\n\tconst registeredTheme = registeredThemes.get(name);\n\tif (registeredTheme) {\n\t\treturn registeredTheme;\n\t}\n\tconst themeJson = loadThemeJson(name);\n\treturn createTheme(themeJson, mode);\n}\n\nexport function getThemeByName(name: string): Theme | undefined {\n\ttry {\n\t\treturn loadTheme(name);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport type TerminalTheme = \"dark\" | \"light\";\n\nexport function parseAutoThemeSetting(\n\tthemeSetting: string | undefined,\n): { lightTheme: string; darkTheme: string } | undefined {\n\tif (!themeSetting) return undefined;\n\tconst slashIndex = themeSetting.indexOf(\"/\");\n\tif (slashIndex === -1 || themeSetting.indexOf(\"/\", slashIndex + 1) !== -1) {\n\t\treturn undefined;\n\t}\n\n\tconst lightTheme = themeSetting.slice(0, slashIndex).trim();\n\tconst darkTheme = themeSetting.slice(slashIndex + 1).trim();\n\tif (!lightTheme || !darkTheme) {\n\t\treturn undefined;\n\t}\n\treturn { lightTheme, darkTheme };\n}\n\nexport function resolveThemeSetting(\n\tthemeSetting: string | undefined,\n\tterminalTheme: TerminalTheme,\n): string | undefined {\n\tconst autoTheme = parseAutoThemeSetting(themeSetting);\n\tif (autoTheme) {\n\t\treturn terminalTheme === \"light\" ? autoTheme.lightTheme : autoTheme.darkTheme;\n\t}\n\tif (themeSetting?.includes(\"/\")) return undefined;\n\tif (typeof themeSetting === \"string\") return themeSetting;\n\treturn undefined;\n}\n\nexport interface TerminalThemeDetection {\n\ttheme: TerminalTheme;\n\tsource: \"terminal background\" | \"COLORFGBG\" | \"fallback\";\n\tdetail: string;\n\tconfidence: \"high\" | \"low\";\n}\n\nexport interface TerminalThemeDetectionOptions {\n\tenv?: NodeJS.ProcessEnv;\n}\n\nexport interface TerminalBackgroundThemeDetector {\n\tqueryTerminalBackgroundColor({ timeoutMs }: { timeoutMs: number }): Promise<RgbColor | undefined>;\n}\n\nexport interface TerminalAutoThemeDetector extends TerminalBackgroundThemeDetector {\n\tqueryTerminalColorScheme?({ timeoutMs }: { timeoutMs: number }): Promise<TerminalTheme | undefined>;\n}\n\nexport interface TerminalBackgroundThemeDetectionOptions extends TerminalThemeDetectionOptions {\n\tui: TerminalBackgroundThemeDetector;\n\ttimeoutMs: number;\n}\n\nexport interface TerminalAutoThemeDetectionOptions extends TerminalThemeDetectionOptions {\n\tui: TerminalAutoThemeDetector;\n\ttimeoutMs: number;\n}\n\nfunction getColorFgBgBackgroundIndex(colorfgbg: string): number | undefined {\n\tconst parts = colorfgbg.split(\";\");\n\tfor (let i = parts.length - 1; i >= 0; i--) {\n\t\tconst bg = parseInt(parts[i].trim(), 10);\n\t\tif (Number.isInteger(bg) && bg >= 0 && bg <= 255) {\n\t\t\treturn bg;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction getRgbColorLuminance({ r, g, b }: RgbColor): number {\n\tconst toLinear = (channel: number) => {\n\t\tconst value = channel / 255;\n\t\treturn value <= 0.03928 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n\t};\n\treturn 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\n\nfunction getAnsiColorLuminance(index: number): number {\n\treturn getRgbColorLuminance(hexToRgb(ansi256ToHex(index)));\n}\n\nexport function getThemeForRgbColor(rgb: RgbColor): TerminalTheme {\n\treturn getRgbColorLuminance(rgb) >= 0.5 ? \"light\" : \"dark\";\n}\n\nexport function detectTerminalBackgroundFromEnv(options: TerminalThemeDetectionOptions = {}): TerminalThemeDetection {\n\tconst env = options.env ?? process.env;\n\tconst colorfgbg = env.COLORFGBG || \"\";\n\tconst bg = getColorFgBgBackgroundIndex(colorfgbg);\n\tif (bg !== undefined) {\n\t\treturn {\n\t\t\ttheme: getAnsiColorLuminance(bg) >= 0.5 ? \"light\" : \"dark\",\n\t\t\tsource: \"COLORFGBG\",\n\t\t\tdetail: `background color index ${bg}`,\n\t\t\tconfidence: \"high\",\n\t\t};\n\t}\n\n\treturn {\n\t\ttheme: \"dark\",\n\t\tsource: \"fallback\",\n\t\tdetail: \"no terminal background hint found\",\n\t\tconfidence: \"low\",\n\t};\n}\n\nexport async function detectTerminalBackgroundTheme({\n\tui,\n\ttimeoutMs,\n\tenv,\n}: TerminalBackgroundThemeDetectionOptions): Promise<TerminalThemeDetection> {\n\ttry {\n\t\tconst rgb = await ui.queryTerminalBackgroundColor({ timeoutMs });\n\t\tif (rgb) {\n\t\t\treturn {\n\t\t\t\ttheme: getThemeForRgbColor(rgb),\n\t\t\t\tsource: \"terminal background\",\n\t\t\t\tdetail: `OSC 11 background rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`,\n\t\t\t\tconfidence: \"high\",\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// Fall back to environment-based detection when the terminal query fails.\n\t}\n\n\treturn detectTerminalBackgroundFromEnv({ env });\n}\n\nexport async function detectTerminalThemeForAuto({\n\tui,\n\ttimeoutMs,\n\tenv,\n}: TerminalAutoThemeDetectionOptions): Promise<TerminalTheme> {\n\tlet colorSchemePromise: Promise<TerminalTheme | undefined> | undefined;\n\ttry {\n\t\tcolorSchemePromise = ui.queryTerminalColorScheme?.({ timeoutMs });\n\t} catch {\n\t\t// Fall back to OSC 11 / COLORFGBG detection when starting the color-scheme query fails.\n\t}\n\tconst backgroundThemePromise = detectTerminalBackgroundTheme({ ui, timeoutMs, env });\n\n\ttry {\n\t\tconst colorScheme = await colorSchemePromise;\n\t\tif (colorScheme) return colorScheme;\n\t} catch {\n\t\t// Fall back to the concurrently queried OSC 11 / COLORFGBG detection.\n\t}\n\treturn (await backgroundThemePromise).theme;\n}\n\nexport function getDefaultTheme(): string {\n\treturn detectTerminalBackgroundFromEnv().theme;\n}\n\n// ============================================================================\n// Global Theme Instance\n// ============================================================================\n\n// Use globalThis to share theme across module loaders (tsx + jiti in dev mode)\nconst THEME_KEY = Symbol.for(\"@agent-forge/agent-forge:theme\");\nconst THEME_KEY_OLD = Symbol.for(\"@mariozechner/pi-coding-agent:theme\");\n\n// Export theme as a getter that reads from globalThis\n// This ensures all module instances (tsx, jiti) see the same theme\nexport const theme: Theme = new Proxy({} as Theme, {\n\tget(_target, prop) {\n\t\tconst active = (globalThis as Record<symbol, Theme>)[THEME_KEY];\n\t\tif (!active) throw new Error(t(\"Theme not initialized. Call initTheme() first.\"));\n\t\treturn (active as unknown as Record<string | symbol, unknown>)[prop];\n\t},\n});\n\nfunction setGlobalTheme(t: Theme): void {\n\t(globalThis as Record<symbol, Theme>)[THEME_KEY] = t;\n\t(globalThis as Record<symbol, Theme>)[THEME_KEY_OLD] = t;\n}\n\nlet currentThemeName: string | undefined;\nlet themeWatcher: fs.FSWatcher | undefined;\nlet themeReloadTimer: NodeJS.Timeout | undefined;\nlet onThemeChangeCallback: (() => void) | undefined;\nconst registeredThemes = new Map<string, Theme>();\n\nexport function setRegisteredThemes(themes: Theme[]): void {\n\tregisteredThemes.clear();\n\tfor (const theme of themes) {\n\t\tif (theme.name) {\n\t\t\tassertThemeNameIsValid(theme.name);\n\t\t\tregisteredThemes.set(theme.name, theme);\n\t\t}\n\t}\n}\n\nexport function initTheme(themeName?: string, enableWatcher: boolean = false): void {\n\tconst name = themeName ?? getDefaultTheme();\n\tcurrentThemeName = name;\n\ttry {\n\t\tsetGlobalTheme(loadTheme(name));\n\t\tif (enableWatcher) {\n\t\t\tstartThemeWatcher();\n\t\t}\n\t} catch (_error) {\n\t\t// Theme is invalid - fall back to dark theme silently\n\t\tcurrentThemeName = \"dark\";\n\t\tsetGlobalTheme(loadTheme(\"dark\"));\n\t\t// Don't start watcher for fallback theme\n\t}\n}\n\nexport function setTheme(name: string, enableWatcher: boolean = false): { success: boolean; error?: string } {\n\tcurrentThemeName = name;\n\ttry {\n\t\tsetGlobalTheme(loadTheme(name));\n\t\tif (enableWatcher) {\n\t\t\tstartThemeWatcher();\n\t\t}\n\t\tif (onThemeChangeCallback) {\n\t\t\tonThemeChangeCallback();\n\t\t}\n\t\treturn { success: true };\n\t} catch (error) {\n\t\t// Theme is invalid - fall back to dark theme\n\t\tcurrentThemeName = \"dark\";\n\t\tsetGlobalTheme(loadTheme(\"dark\"));\n\t\t// Don't start watcher for fallback theme\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\t// v8 ignore next -- loadTheme rejections are always Error instances\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function setThemeInstance(themeInstance: Theme): void {\n\tsetGlobalTheme(themeInstance);\n\tcurrentThemeName = \"<in-memory>\";\n\tstopThemeWatcher(); // Can't watch a direct instance\n\tif (onThemeChangeCallback) {\n\t\tonThemeChangeCallback();\n\t}\n}\n\nexport function onThemeChange(callback: () => void): void {\n\tonThemeChangeCallback = callback;\n}\n\nfunction startThemeWatcher(): void {\n\tstopThemeWatcher();\n\n\t// Only watch if it's a custom theme (not built-in)\n\tif (!currentThemeName || currentThemeName === \"dark\" || currentThemeName === \"light\") {\n\t\treturn;\n\t}\n\n\tconst customThemesDir = getCustomThemesDir();\n\tconst watchedThemeName = currentThemeName;\n\tconst watchedFileName = `${watchedThemeName}.json`;\n\tconst themeFile = path.join(customThemesDir, watchedFileName);\n\n\t// Only watch if the file exists\n\tif (!fs.existsSync(themeFile)) {\n\t\treturn;\n\t}\n\n\tconst scheduleReload = () => {\n\t\tif (themeReloadTimer) {\n\t\t\tclearTimeout(themeReloadTimer);\n\t\t}\n\t\tthemeReloadTimer = setTimeout(() => {\n\t\t\tthemeReloadTimer = undefined;\n\n\t\t\t// Ignore stale timers after switching themes or stopping the watcher\n\t\t\tif (currentThemeName !== watchedThemeName) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Keep the last successfully loaded theme active if the file is temporarily missing\n\t\t\tif (!fs.existsSync(themeFile)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// Reload the theme from disk and refresh the registry cache\n\t\t\t\tconst reloadedTheme = loadThemeFromPath(themeFile);\n\t\t\t\tregisteredThemes.set(watchedThemeName, reloadedTheme);\n\t\t\t\tsetGlobalTheme(reloadedTheme);\n\t\t\t\t// Notify callback (to invalidate UI)\n\t\t\t\tif (onThemeChangeCallback) {\n\t\t\t\t\tonThemeChangeCallback();\n\t\t\t\t}\n\t\t\t} catch (_error) {\n\t\t\t\t// Ignore errors (file might be in invalid state while being edited)\n\t\t\t}\n\t\t}, 100);\n\t};\n\n\tthemeWatcher =\n\t\twatchWithErrorHandler(\n\t\t\tcustomThemesDir,\n\t\t\t(_eventType, filename) => {\n\t\t\t\tif (currentThemeName !== watchedThemeName) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!filename) {\n\t\t\t\t\tscheduleReload();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (filename !== watchedFileName) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tscheduleReload();\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tcloseWatcher(themeWatcher);\n\t\t\t\tthemeWatcher = undefined;\n\t\t\t},\n\t\t) ?? undefined;\n}\n\nexport function stopThemeWatcher(): void {\n\tif (themeReloadTimer) {\n\t\tclearTimeout(themeReloadTimer);\n\t\tthemeReloadTimer = undefined;\n\t}\n\tcloseWatcher(themeWatcher);\n\tthemeWatcher = undefined;\n}\n\n// ============================================================================\n// HTML Export Helpers\n// ============================================================================\n\n/**\n * Convert a 256-color index to hex string.\n * Indices 0-15: basic colors (approximate)\n * Indices 16-231: 6x6x6 color cube\n * Indices 232-255: grayscale ramp\n */\nfunction ansi256ToHex(index: number): string {\n\t// Basic colors (0-15) - approximate common terminal values\n\tconst basicColors = [\n\t\t\"#000000\",\n\t\t\"#800000\",\n\t\t\"#008000\",\n\t\t\"#808000\",\n\t\t\"#000080\",\n\t\t\"#800080\",\n\t\t\"#008080\",\n\t\t\"#c0c0c0\",\n\t\t\"#808080\",\n\t\t\"#ff0000\",\n\t\t\"#00ff00\",\n\t\t\"#ffff00\",\n\t\t\"#0000ff\",\n\t\t\"#ff00ff\",\n\t\t\"#00ffff\",\n\t\t\"#ffffff\",\n\t];\n\tif (index < 16) {\n\t\treturn basicColors[index];\n\t}\n\n\t// Color cube (16-231): 6x6x6 = 216 colors\n\tif (index < 232) {\n\t\tconst cubeIndex = index - 16;\n\t\tconst r = Math.floor(cubeIndex / 36);\n\t\tconst g = Math.floor((cubeIndex % 36) / 6);\n\t\tconst b = cubeIndex % 6;\n\t\tconst toHex = (n: number) => (n === 0 ? 0 : 55 + n * 40).toString(16).padStart(2, \"0\");\n\t\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n\t}\n\n\t// Grayscale (232-255): 24 shades\n\tconst gray = 8 + (index - 232) * 10;\n\tconst grayHex = gray.toString(16).padStart(2, \"0\");\n\treturn `#${grayHex}${grayHex}${grayHex}`;\n}\n\n/**\n * Get resolved theme colors as CSS-compatible hex strings.\n * Used by HTML export to generate CSS custom properties.\n */\nexport function getResolvedThemeColors(themeName?: string): Record<string, string> {\n\tconst name = themeName ?? currentThemeName ?? getDefaultTheme();\n\tconst isLight = name === \"light\";\n\tconst themeJson = loadThemeJson(name);\n\tconst resolved = resolveThemeColors(withThemeColorFallbacks(themeJson.colors), themeJson.vars);\n\n\t// Default text color for empty values (terminal uses default fg color)\n\tconst defaultText = isLight ? \"#000000\" : \"#e5e5e7\";\n\n\tconst cssColors: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(resolved)) {\n\t\tif (typeof value === \"number\") {\n\t\t\tcssColors[key] = ansi256ToHex(value);\n\t\t} else if (value === \"\") {\n\t\t\t// Empty means default terminal color - use sensible fallback for HTML\n\t\t\tcssColors[key] = defaultText;\n\t\t} else {\n\t\t\tcssColors[key] = value;\n\t\t}\n\t}\n\treturn cssColors;\n}\n\n/**\n * Check if a theme is a \"light\" theme (for CSS that needs light/dark variants).\n */\nexport function isLightTheme(themeName?: string): boolean {\n\t// Currently just check the name - could be extended to analyze colors\n\treturn themeName === \"light\";\n}\n\n/**\n * Get explicit export colors from theme JSON, if specified.\n * Returns undefined for each color that isn't explicitly set.\n */\nexport function getThemeExportColors(themeName?: string): {\n\tpageBg?: string;\n\tcardBg?: string;\n\tinfoBg?: string;\n} {\n\tconst name = themeName ?? currentThemeName ?? getDefaultTheme();\n\ttry {\n\t\tconst themeJson = loadThemeJson(name);\n\t\tconst exportSection = themeJson.export;\n\t\tif (!exportSection) return {};\n\n\t\tconst vars = themeJson.vars ?? {};\n\t\tconst resolve = (value: ColorValue | undefined): string | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tconst resolved = resolveVarRefs(value, vars);\n\t\t\tif (typeof resolved === \"number\") return ansi256ToHex(resolved);\n\t\t\tif (resolved === \"\") return undefined;\n\t\t\treturn resolved;\n\t\t};\n\n\t\treturn {\n\t\t\tpageBg: resolve(exportSection.pageBg),\n\t\t\tcardBg: resolve(exportSection.cardBg),\n\t\t\tinfoBg: resolve(exportSection.infoBg),\n\t\t};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n// ============================================================================\n// TUI Helpers\n// ============================================================================\n\ntype CliHighlightTheme = Record<string, (s: string) => string>;\n\nlet cachedHighlightThemeFor: Theme | undefined;\nlet cachedCliHighlightTheme: CliHighlightTheme | undefined;\n\nfunction buildCliHighlightTheme(t: Theme): CliHighlightTheme {\n\treturn {\n\t\tkeyword: (s: string) => t.fg(\"syntaxKeyword\", s),\n\t\tbuilt_in: (s: string) => t.fg(\"syntaxType\", s),\n\t\tliteral: (s: string) => t.fg(\"syntaxNumber\", s),\n\t\tnumber: (s: string) => t.fg(\"syntaxNumber\", s),\n\t\tregexp: (s: string) => t.fg(\"syntaxString\", s),\n\t\tstring: (s: string) => t.fg(\"syntaxString\", s),\n\t\tcomment: (s: string) => t.fg(\"syntaxComment\", s),\n\t\tdoctag: (s: string) => t.fg(\"syntaxComment\", s),\n\t\tmeta: (s: string) => t.fg(\"muted\", s),\n\t\tfunction: (s: string) => t.fg(\"syntaxFunction\", s),\n\t\ttitle: (s: string) => t.fg(\"syntaxFunction\", s),\n\t\tclass: (s: string) => t.fg(\"syntaxType\", s),\n\t\ttype: (s: string) => t.fg(\"syntaxType\", s),\n\t\ttag: (s: string) => t.fg(\"syntaxPunctuation\", s),\n\t\tname: (s: string) => t.fg(\"syntaxKeyword\", s),\n\t\tattr: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\tvariable: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\tparams: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\toperator: (s: string) => t.fg(\"syntaxOperator\", s),\n\t\tpunctuation: (s: string) => t.fg(\"syntaxPunctuation\", s),\n\t\temphasis: (s: string) => t.italic(s),\n\t\tstrong: (s: string) => t.bold(s),\n\t\tlink: (s: string) => t.underline(s),\n\t\taddition: (s: string) => t.fg(\"toolDiffAdded\", s),\n\t\tdeletion: (s: string) => t.fg(\"toolDiffRemoved\", s),\n\t};\n}\n\nfunction getCliHighlightTheme(t: Theme): CliHighlightTheme {\n\tif (cachedHighlightThemeFor !== t || !cachedCliHighlightTheme) {\n\t\tcachedHighlightThemeFor = t;\n\t\tcachedCliHighlightTheme = buildCliHighlightTheme(t);\n\t}\n\treturn cachedCliHighlightTheme;\n}\n\n/**\n * Highlight code with syntax coloring based on file extension or language.\n * Returns array of highlighted lines.\n */\nexport function highlightCode(code: string, lang?: string): string[] {\n\t// Validate language before highlighting to avoid stderr spam from cli-highlight\n\tconst validLang = lang && supportsLanguage(lang) ? lang : undefined;\n\t// Skip highlighting when no valid language is specified. cli-highlight's\n\t// auto-detection is unreliable and can misidentify prose as AppleScript,\n\t// LiveCodeServer, etc., coloring random English words as keywords.\n\tif (!validLang) {\n\t\treturn code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n\t}\n\tconst opts = {\n\t\tlanguage: validLang,\n\t\tignoreIllegals: true,\n\t\ttheme: getCliHighlightTheme(theme),\n\t};\n\ttry {\n\t\treturn highlight(code, opts).split(\"\\n\");\n\t} catch {\n\t\treturn code.split(\"\\n\");\n\t}\n}\n\n/**\n * Get language identifier from file path extension.\n */\nexport function getLanguageFromPath(filePath: string): string | undefined {\n\tconst ext = filePath.split(\".\").pop()?.toLowerCase();\n\tif (!ext) return undefined;\n\n\tconst extToLang: Record<string, string> = {\n\t\tts: \"typescript\",\n\t\ttsx: \"typescript\",\n\t\tjs: \"javascript\",\n\t\tjsx: \"javascript\",\n\t\tmjs: \"javascript\",\n\t\tcjs: \"javascript\",\n\t\tpy: \"python\",\n\t\trb: \"ruby\",\n\t\trs: \"rust\",\n\t\tgo: \"go\",\n\t\tjava: \"java\",\n\t\tkt: \"kotlin\",\n\t\tswift: \"swift\",\n\t\tc: \"c\",\n\t\th: \"c\",\n\t\tcpp: \"cpp\",\n\t\tcc: \"cpp\",\n\t\tcxx: \"cpp\",\n\t\thpp: \"cpp\",\n\t\tcs: \"csharp\",\n\t\tphp: \"php\",\n\t\tsh: \"bash\",\n\t\tbash: \"bash\",\n\t\tzsh: \"bash\",\n\t\tfish: \"fish\",\n\t\tps1: \"powershell\",\n\t\tsql: \"sql\",\n\t\thtml: \"html\",\n\t\thtm: \"html\",\n\t\tcss: \"css\",\n\t\tscss: \"scss\",\n\t\tsass: \"sass\",\n\t\tless: \"less\",\n\t\tjson: \"json\",\n\t\tyaml: \"yaml\",\n\t\tyml: \"yaml\",\n\t\ttoml: \"toml\",\n\t\txml: \"xml\",\n\t\tmd: \"markdown\",\n\t\tmarkdown: \"markdown\",\n\t\tdockerfile: \"dockerfile\",\n\t\tmakefile: \"makefile\",\n\t\tcmake: \"cmake\",\n\t\tlua: \"lua\",\n\t\tperl: \"perl\",\n\t\tr: \"r\",\n\t\tscala: \"scala\",\n\t\tclj: \"clojure\",\n\t\tex: \"elixir\",\n\t\texs: \"elixir\",\n\t\terl: \"erlang\",\n\t\ths: \"haskell\",\n\t\tml: \"ocaml\",\n\t\tvim: \"vim\",\n\t\tgraphql: \"graphql\",\n\t\tproto: \"protobuf\",\n\t\ttf: \"hcl\",\n\t\thcl: \"hcl\",\n\t};\n\n\treturn extToLang[ext];\n}\n\nexport function getMarkdownTheme(): MarkdownTheme {\n\treturn {\n\t\theading: (text: string) => theme.fg(\"mdHeading\", text),\n\t\tlink: (text: string) => theme.fg(\"mdLink\", text),\n\t\tlinkUrl: (text: string) => theme.fg(\"mdLinkUrl\", text),\n\t\tcode: (text: string) => theme.fg(\"mdCode\", text),\n\t\tcodeBlock: (text: string) => theme.fg(\"mdCodeBlock\", text),\n\t\tcodeBlockBorder: (text: string) => theme.fg(\"mdCodeBlockBorder\", text),\n\t\tquote: (text: string) => theme.fg(\"mdQuote\", text),\n\t\tquoteBorder: (text: string) => theme.fg(\"mdQuoteBorder\", text),\n\t\thr: (text: string) => theme.fg(\"mdHr\", text),\n\t\tlistBullet: (text: string) => theme.fg(\"mdListBullet\", text),\n\t\tbold: (text: string) => theme.bold(text),\n\t\titalic: (text: string) => theme.italic(text),\n\t\tunderline: (text: string) => theme.underline(text),\n\t\tstrikethrough: (text: string) => chalk.strikethrough(text),\n\t\thighlightCode: (code: string, lang?: string): string[] => {\n\t\t\t// Validate language before highlighting to avoid stderr spam from cli-highlight\n\t\t\tconst validLang = lang && supportsLanguage(lang) ? lang : undefined;\n\t\t\t// Skip highlighting when no valid language is specified. cli-highlight's\n\t\t\t// auto-detection is unreliable and can misidentify prose as AppleScript,\n\t\t\t// LiveCodeServer, etc., coloring random English words as keywords.\n\t\t\tif (!validLang) {\n\t\t\t\treturn code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n\t\t\t}\n\t\t\tconst opts = {\n\t\t\t\tlanguage: validLang,\n\t\t\t\tignoreIllegals: true,\n\t\t\t\ttheme: getCliHighlightTheme(theme),\n\t\t\t};\n\t\t\ttry {\n\t\t\t\treturn highlight(code, opts).split(\"\\n\");\n\t\t\t} catch {\n\t\t\t\treturn code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function getSelectListTheme(): SelectListTheme {\n\treturn {\n\t\tselectedPrefix: (text: string) => theme.fg(\"accent\", text),\n\t\tselectedText: (text: string) => theme.fg(\"accent\", text),\n\t\tdescription: (text: string) => theme.fg(\"muted\", text),\n\t\tscrollInfo: (text: string) => theme.fg(\"muted\", text),\n\t\tnoMatch: (text: string) => theme.fg(\"muted\", text),\n\t};\n}\n\nexport function getEditorTheme(): EditorTheme {\n\treturn {\n\t\tborderColor: (text: string) => theme.fg(\"borderMuted\", text),\n\t\tselectList: getSelectListTheme(),\n\t};\n}\n\nexport function getSettingsListTheme(): SettingsListTheme {\n\treturn {\n\t\tlabel: (text: string, selected: boolean) => (selected ? theme.fg(\"accent\", text) : text),\n\t\tvalue: (text: string, selected: boolean) => (selected ? theme.fg(\"accent\", text) : theme.fg(\"muted\", text)),\n\t\tdescription: (text: string) => theme.fg(\"dim\", text),\n\t\tcursor: theme.fg(\"accent\", \"→ \"),\n\t\thint: (text: string) => theme.fg(\"dim\", text),\n\t};\n}\n"]}
@@ -4,11 +4,11 @@ import { getCapabilities, } from "@agent-forge/tui";
4
4
  import chalk from "chalk";
5
5
  import { Type } from "typebox";
6
6
  import { Compile } from "typebox/compile";
7
- import { getCustomThemesDir, getThemesDir } from "../../../config.js";
8
- import { t } from "../../../core/i18n/index.js";
9
- import { closeWatcher, watchWithErrorHandler } from "../../../utils/fs-watch.js";
10
- import { highlight, supportsLanguage } from "../../../utils/syntax-highlight.js";
11
- import { stripBom } from "../../../utils/text.js";
7
+ import { getCustomThemesDir, getThemesDir } from "../config.js";
8
+ import { t } from "../core/i18n/index.js";
9
+ import { closeWatcher, watchWithErrorHandler } from "../utils/fs-watch.js";
10
+ import { highlight, supportsLanguage } from "../utils/syntax-highlight.js";
11
+ import { stripBom } from "../utils/text.js";
12
12
  // ============================================================================
13
13
  // Types & Schema
14
14
  // ============================================================================