@xagent-ai/cli 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/workflows/ci.yml +72 -0
  4. package/.github/workflows/release.yml +109 -0
  5. package/.gitmodules +3 -3
  6. package/README.md +326 -280
  7. package/README_CN.md +325 -279
  8. package/dist/ai-client/factory.d.ts +52 -0
  9. package/dist/ai-client/factory.d.ts.map +1 -0
  10. package/dist/ai-client/factory.js +132 -0
  11. package/dist/ai-client/factory.js.map +1 -0
  12. package/dist/ai-client/index.d.ts +20 -0
  13. package/dist/ai-client/index.d.ts.map +1 -0
  14. package/dist/ai-client/index.js +49 -0
  15. package/dist/ai-client/index.js.map +1 -0
  16. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  17. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  18. package/dist/ai-client/providers/anthropic.js +400 -0
  19. package/dist/ai-client/providers/anthropic.js.map +1 -0
  20. package/dist/ai-client/providers/openai.d.ts +57 -0
  21. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  22. package/dist/ai-client/providers/openai.js +286 -0
  23. package/dist/ai-client/providers/openai.js.map +1 -0
  24. package/dist/ai-client/providers/remote.d.ts +111 -0
  25. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  26. package/dist/ai-client/providers/remote.js +351 -0
  27. package/dist/ai-client/providers/remote.js.map +1 -0
  28. package/dist/ai-client/registry.d.ts +51 -0
  29. package/dist/ai-client/registry.d.ts.map +1 -0
  30. package/dist/ai-client/registry.js +81 -0
  31. package/dist/ai-client/registry.js.map +1 -0
  32. package/dist/ai-client/types.d.ts +260 -0
  33. package/dist/ai-client/types.d.ts.map +1 -0
  34. package/dist/ai-client/types.js +73 -0
  35. package/dist/ai-client/types.js.map +1 -0
  36. package/dist/ai-client-factory.d.ts +62 -0
  37. package/dist/ai-client-factory.d.ts.map +1 -0
  38. package/dist/ai-client-factory.js +157 -0
  39. package/dist/ai-client-factory.js.map +1 -0
  40. package/dist/auth.d.ts +23 -1
  41. package/dist/auth.d.ts.map +1 -1
  42. package/dist/auth.js +160 -168
  43. package/dist/auth.js.map +1 -1
  44. package/dist/cancellation.d.ts +5 -4
  45. package/dist/cancellation.d.ts.map +1 -1
  46. package/dist/cancellation.js +55 -32
  47. package/dist/cancellation.js.map +1 -1
  48. package/dist/checkpoint.d.ts +1 -1
  49. package/dist/checkpoint.d.ts.map +1 -1
  50. package/dist/checkpoint.js +2 -2
  51. package/dist/checkpoint.js.map +1 -1
  52. package/dist/cli.js +626 -13
  53. package/dist/cli.js.map +1 -1
  54. package/dist/config.d.ts +10 -4
  55. package/dist/config.d.ts.map +1 -1
  56. package/dist/config.js +62 -25
  57. package/dist/config.js.map +1 -1
  58. package/dist/context-compressor.d.ts +81 -16
  59. package/dist/context-compressor.d.ts.map +1 -1
  60. package/dist/context-compressor.js +712 -153
  61. package/dist/context-compressor.js.map +1 -1
  62. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  63. package/dist/gui-subagent/action-parser/actionParser.js +4 -2
  64. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  65. package/dist/gui-subagent/agent/gui-agent.d.ts +29 -2
  66. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  67. package/dist/gui-subagent/agent/gui-agent.js +87 -45
  68. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  69. package/dist/gui-subagent/index.d.ts +16 -1
  70. package/dist/gui-subagent/index.d.ts.map +1 -1
  71. package/dist/gui-subagent/index.js +4 -0
  72. package/dist/gui-subagent/index.js.map +1 -1
  73. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  74. package/dist/gui-subagent/operator/base-operator.js +0 -1
  75. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  76. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  77. package/dist/gui-subagent/operator/computer-operator.js +29 -8
  78. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  79. package/dist/gui-subagent/types/actions.d.ts +1 -1
  80. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  81. package/dist/gui-subagent/types/actions.js +0 -1
  82. package/dist/gui-subagent/types/actions.js.map +1 -1
  83. package/dist/gui-subagent/types/operator.d.ts +1 -1
  84. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  85. package/dist/index.d.ts +1 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1 -2
  88. package/dist/index.js.map +1 -1
  89. package/dist/input-processor.d.ts.map +1 -1
  90. package/dist/input-processor.js +6 -3
  91. package/dist/input-processor.js.map +1 -1
  92. package/dist/mcp.d.ts +5 -0
  93. package/dist/mcp.d.ts.map +1 -1
  94. package/dist/mcp.js +81 -35
  95. package/dist/mcp.js.map +1 -1
  96. package/dist/ripgrep.d.ts +29 -0
  97. package/dist/ripgrep.d.ts.map +1 -0
  98. package/dist/ripgrep.js +292 -0
  99. package/dist/ripgrep.js.map +1 -0
  100. package/dist/session.d.ts +23 -7
  101. package/dist/session.d.ts.map +1 -1
  102. package/dist/session.js +624 -243
  103. package/dist/session.js.map +1 -1
  104. package/dist/shell.d.ts +33 -0
  105. package/dist/shell.d.ts.map +1 -0
  106. package/dist/shell.js +125 -0
  107. package/dist/shell.js.map +1 -0
  108. package/dist/skill-installer.d.ts +38 -0
  109. package/dist/skill-installer.d.ts.map +1 -0
  110. package/dist/skill-installer.js +447 -0
  111. package/dist/skill-installer.js.map +1 -0
  112. package/dist/skill-invoker.d.ts +7 -1
  113. package/dist/skill-invoker.d.ts.map +1 -1
  114. package/dist/skill-invoker.js +34 -13
  115. package/dist/skill-invoker.js.map +1 -1
  116. package/dist/skill-loader.d.ts +8 -3
  117. package/dist/skill-loader.d.ts.map +1 -1
  118. package/dist/skill-loader.js +46 -44
  119. package/dist/skill-loader.js.map +1 -1
  120. package/dist/skill-manager.d.ts +85 -0
  121. package/dist/skill-manager.d.ts.map +1 -0
  122. package/dist/skill-manager.js +340 -0
  123. package/dist/skill-manager.js.map +1 -0
  124. package/dist/slash-commands.d.ts +38 -1
  125. package/dist/slash-commands.d.ts.map +1 -1
  126. package/dist/slash-commands.js +912 -296
  127. package/dist/slash-commands.js.map +1 -1
  128. package/dist/smart-approval.d.ts.map +1 -1
  129. package/dist/smart-approval.js +67 -55
  130. package/dist/smart-approval.js.map +1 -1
  131. package/dist/system-prompt-generator.d.ts +6 -0
  132. package/dist/system-prompt-generator.d.ts.map +1 -1
  133. package/dist/system-prompt-generator.js +84 -34
  134. package/dist/system-prompt-generator.js.map +1 -1
  135. package/dist/terminal.d.ts +28 -0
  136. package/dist/terminal.d.ts.map +1 -0
  137. package/dist/terminal.js +82 -0
  138. package/dist/terminal.js.map +1 -0
  139. package/dist/tools.d.ts +23 -7
  140. package/dist/tools.d.ts.map +1 -1
  141. package/dist/tools.js +797 -437
  142. package/dist/tools.js.map +1 -1
  143. package/dist/truncate.d.ts +55 -0
  144. package/dist/truncate.d.ts.map +1 -0
  145. package/dist/truncate.js +130 -0
  146. package/dist/truncate.js.map +1 -0
  147. package/dist/types.d.ts +27 -9
  148. package/dist/types.d.ts.map +1 -1
  149. package/dist/update.d.ts.map +1 -1
  150. package/dist/update.js +17 -28
  151. package/dist/update.js.map +1 -1
  152. package/dist/workflow.d.ts +5 -1
  153. package/dist/workflow.d.ts.map +1 -1
  154. package/dist/workflow.js +60 -47
  155. package/dist/workflow.js.map +1 -1
  156. package/docs/architecture/mcp-integration-guide.md +304 -194
  157. package/docs/architecture/overview.md +169 -169
  158. package/docs/architecture/tool-system-design.md +134 -134
  159. package/docs/cli/commands.md +349 -238
  160. package/docs/smart-mode.md +281 -281
  161. package/docs/third-party-models.md +439 -439
  162. package/find-skills/SKILL.md +133 -0
  163. package/package.json +89 -90
  164. package/scripts/install-ripgrep.js +241 -0
  165. package/src/ai-client/factory.ts +151 -0
  166. package/src/ai-client/index.ts +61 -0
  167. package/src/ai-client/providers/anthropic.ts +466 -0
  168. package/src/ai-client/providers/openai.ts +342 -0
  169. package/src/ai-client/providers/remote.ts +436 -0
  170. package/src/ai-client/registry.ts +97 -0
  171. package/src/ai-client/types.ts +345 -0
  172. package/src/ai-client-factory.ts +204 -0
  173. package/src/auth.ts +663 -614
  174. package/src/cancellation.ts +205 -176
  175. package/src/checkpoint.ts +219 -219
  176. package/src/cli.ts +1406 -743
  177. package/src/config.ts +341 -297
  178. package/src/context-compressor.ts +982 -290
  179. package/src/conversation.ts +288 -288
  180. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  181. package/src/gui-subagent/action-parser/constants.ts +14 -14
  182. package/src/gui-subagent/action-parser/index.ts +8 -8
  183. package/src/gui-subagent/action-parser/types.ts +31 -31
  184. package/src/gui-subagent/agent/gui-agent.ts +1151 -1089
  185. package/src/gui-subagent/agent/index.ts +5 -5
  186. package/src/gui-subagent/index.ts +177 -163
  187. package/src/gui-subagent/operator/base-operator.ts +244 -245
  188. package/src/gui-subagent/operator/computer-operator.ts +540 -520
  189. package/src/gui-subagent/operator/index.ts +6 -6
  190. package/src/gui-subagent/types/actions.ts +260 -262
  191. package/src/gui-subagent/types/index.ts +6 -6
  192. package/src/gui-subagent/types/operator.ts +106 -106
  193. package/src/gui-subagent/utils.ts +51 -51
  194. package/src/index.ts +17 -18
  195. package/src/input-processor.ts +6 -3
  196. package/src/logger.ts +438 -438
  197. package/src/mcp.ts +730 -682
  198. package/src/memory.ts +344 -344
  199. package/src/ripgrep.ts +368 -0
  200. package/src/session-manager.ts +308 -308
  201. package/src/session.ts +948 -386
  202. package/src/shell.ts +133 -0
  203. package/src/skill-installer.ts +518 -0
  204. package/src/skill-invoker.ts +960 -935
  205. package/src/skill-loader.ts +501 -496
  206. package/src/skill-manager.ts +384 -0
  207. package/src/slash-commands.ts +2181 -1389
  208. package/src/smart-approval.ts +117 -73
  209. package/src/system-prompt-generator.ts +89 -34
  210. package/src/terminal.ts +96 -0
  211. package/src/theme.ts +738 -738
  212. package/src/tools.ts +1336 -773
  213. package/src/truncate.ts +173 -0
  214. package/src/types.ts +219 -198
  215. package/src/update.ts +22 -32
  216. package/src/workflow.ts +523 -508
  217. package/tsconfig.json +22 -22
  218. package/vitest.config.ts +19 -19
  219. package/dist/ai-client.d.ts +0 -86
  220. package/dist/ai-client.d.ts.map +0 -1
  221. package/dist/ai-client.js +0 -1372
  222. package/dist/ai-client.js.map +0 -1
  223. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  224. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  225. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  226. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  227. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  228. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  229. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  230. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  231. package/dist/hook.d.ts +0 -73
  232. package/dist/hook.d.ts.map +0 -1
  233. package/dist/hook.js +0 -156
  234. package/dist/hook.js.map +0 -1
  235. package/dist/input-history.d.ts +0 -24
  236. package/dist/input-history.d.ts.map +0 -1
  237. package/dist/input-history.js +0 -94
  238. package/dist/input-history.js.map +0 -1
  239. package/dist/keyboard-manager.d.ts +0 -151
  240. package/dist/keyboard-manager.d.ts.map +0 -1
  241. package/dist/keyboard-manager.js +0 -396
  242. package/dist/keyboard-manager.js.map +0 -1
  243. package/dist/print-system-prompt.d.ts +0 -2
  244. package/dist/print-system-prompt.d.ts.map +0 -1
  245. package/dist/print-system-prompt.js +0 -40
  246. package/dist/print-system-prompt.js.map +0 -1
  247. package/dist/remote-ai-client.d.ts +0 -104
  248. package/dist/remote-ai-client.d.ts.map +0 -1
  249. package/dist/remote-ai-client.js +0 -552
  250. package/dist/remote-ai-client.js.map +0 -1
  251. package/dist/sdk-output-adapter.d.ts +0 -232
  252. package/dist/sdk-output-adapter.d.ts.map +0 -1
  253. package/dist/sdk-output-adapter.js +0 -636
  254. package/dist/sdk-output-adapter.js.map +0 -1
  255. package/dist/sdk-session-v2.d.ts +0 -13
  256. package/dist/sdk-session-v2.d.ts.map +0 -1
  257. package/dist/sdk-session-v2.js +0 -46
  258. package/dist/sdk-session-v2.js.map +0 -1
  259. package/dist/sdk-session.d.ts +0 -13
  260. package/dist/sdk-session.d.ts.map +0 -1
  261. package/dist/sdk-session.js +0 -48
  262. package/dist/sdk-session.js.map +0 -1
  263. package/dist/test-boundary-conditions.d.ts.map +0 -1
  264. package/dist/test-boundary-conditions.js.map +0 -1
  265. package/dist/test-cancellation-fix.d.ts.map +0 -1
  266. package/dist/test-cancellation-fix.js.map +0 -1
  267. package/dist/test-input-history.d.ts.map +0 -1
  268. package/dist/test-input-history.js.map +0 -1
  269. package/dist/test-interaction-flow.d.ts.map +0 -1
  270. package/dist/test-interaction-flow.js.map +0 -1
  271. package/dist/test-quick.d.ts.map +0 -1
  272. package/dist/test-quick.js.map +0 -1
  273. package/dist/test-user-interaction.d.ts.map +0 -1
  274. package/dist/test-user-interaction.js.map +0 -1
  275. package/dist/tools/edit-diff.d.ts +0 -32
  276. package/dist/tools/edit-diff.d.ts.map +0 -1
  277. package/dist/tools/edit-diff.js +0 -185
  278. package/dist/tools/edit-diff.js.map +0 -1
  279. package/dist/tools/edit.d.ts +0 -11
  280. package/dist/tools/edit.d.ts.map +0 -1
  281. package/dist/tools/edit.js +0 -129
  282. package/dist/tools/edit.js.map +0 -1
  283. package/dist/unified-session.d.ts +0 -42
  284. package/dist/unified-session.d.ts.map +0 -1
  285. package/dist/unified-session.js +0 -271
  286. package/dist/unified-session.js.map +0 -1
  287. package/skills/.claude-plugin/marketplace.json +0 -45
  288. package/skills/README.md +0 -94
  289. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  290. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  291. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  292. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  293. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  294. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  295. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  296. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  297. package/skills/skills/canvas-design/SKILL.md +0 -130
  298. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  299. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  300. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  301. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  302. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  303. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  304. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  305. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  306. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  307. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  308. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  309. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  310. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  311. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  312. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  313. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  314. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  315. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  316. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  317. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  318. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  319. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  320. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  321. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  322. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  323. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  324. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  325. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  326. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  327. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  328. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  329. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  330. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  331. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  335. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  336. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  337. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  339. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  340. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  343. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  346. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  348. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  349. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  351. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  352. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  353. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  354. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  356. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  357. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  360. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  361. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  364. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  365. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  366. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  371. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  372. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  377. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  378. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  379. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  380. package/skills/skills/docx/LICENSE.txt +0 -30
  381. package/skills/skills/docx/SKILL.md +0 -197
  382. package/skills/skills/docx/docx-js.md +0 -350
  383. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  384. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  385. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  386. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  387. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  388. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  389. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  390. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  391. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  392. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  393. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  394. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  395. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  396. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  397. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  398. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  399. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  400. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  401. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  402. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  403. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  404. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  405. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  406. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  407. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  408. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  409. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  410. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  411. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  412. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  413. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  414. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  415. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  416. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  417. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  418. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  419. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  420. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  421. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  422. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  423. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  424. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  425. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  426. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  427. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  428. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  429. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  430. package/skills/skills/docx/ooxml.md +0 -610
  431. package/skills/skills/docx/scripts/__init__.py +0 -1
  432. package/skills/skills/docx/scripts/document.py +0 -1276
  433. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  434. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  435. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  436. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  437. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  438. package/skills/skills/docx/scripts/utilities.py +0 -374
  439. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  440. package/skills/skills/frontend-design/SKILL.md +0 -42
  441. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  442. package/skills/skills/internal-comms/SKILL.md +0 -32
  443. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  444. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  445. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  446. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  447. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  448. package/skills/skills/mcp-builder/SKILL.md +0 -236
  449. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  450. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  451. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  452. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  453. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  454. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  455. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  456. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  457. package/skills/skills/pdf/LICENSE.txt +0 -30
  458. package/skills/skills/pdf/SKILL.md +0 -294
  459. package/skills/skills/pdf/forms.md +0 -205
  460. package/skills/skills/pdf/reference.md +0 -612
  461. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  462. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  463. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  464. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  465. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  466. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  467. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  468. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  469. package/skills/skills/pptx/LICENSE.txt +0 -30
  470. package/skills/skills/pptx/SKILL.md +0 -484
  471. package/skills/skills/pptx/html2pptx.md +0 -625
  472. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  473. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  474. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  475. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  476. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  477. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  478. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  479. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  480. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  481. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  482. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  483. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  484. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  485. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  486. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  487. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  488. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  489. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  490. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  491. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  492. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  493. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  494. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  495. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  496. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  497. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  498. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  499. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  500. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  501. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  502. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  503. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  504. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  505. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  506. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  507. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  508. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  509. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  510. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  511. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  512. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  513. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  514. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  515. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  516. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  517. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  518. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  519. package/skills/skills/pptx/ooxml.md +0 -427
  520. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  521. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  522. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  523. package/skills/skills/pptx/scripts/replace.py +0 -385
  524. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  525. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  526. package/skills/skills/skill-creator/SKILL.md +0 -356
  527. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  528. package/skills/skills/skill-creator/references/workflows.md +0 -28
  529. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  530. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  531. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  532. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  533. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  534. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  535. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  536. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  537. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  538. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  539. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  540. package/skills/skills/theme-factory/SKILL.md +0 -59
  541. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  542. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  543. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  544. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  545. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  546. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  547. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  548. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  549. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  550. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  551. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  552. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  553. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  554. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  555. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  556. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  557. package/skills/skills/webapp-testing/SKILL.md +0 -96
  558. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  559. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  560. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  561. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  562. package/skills/skills/xlsx/LICENSE.txt +0 -30
  563. package/skills/skills/xlsx/SKILL.md +0 -289
  564. package/skills/skills/xlsx/recalc.py +0 -178
  565. package/skills/spec/agent-skills-spec.md +0 -3
  566. package/skills/template/SKILL.md +0 -6
  567. package/src/ai-client.ts +0 -1560
  568. package/src/remote-ai-client.ts +0 -664
package/src/theme.ts CHANGED
@@ -1,739 +1,739 @@
1
- import chalk from 'chalk';
2
-
3
- /**
4
- * Detect if terminal has dark or light background
5
- * Returns 'dark' for dark backgrounds (default), 'light' for light backgrounds
6
- */
7
- function getTerminalBackground(): 'dark' | 'light' {
8
- // Check common environment variables
9
- const colorfgbg = process.env.COLORFGBG; // e.g., "15;0" (light fg, dark bg)
10
- const termProgram = process.env.TERM_PROGRAM;
11
- const termProgramVersion = process.env.TERM_PROGRAM_VERSION;
12
-
13
- // Try to parse COLORFGBG (format: "fg;bg" or "fg;color;bg")
14
- if (colorfgbg) {
15
- const parts = colorfgbg.split(';');
16
- const bg = parts[parts.length - 1];
17
- // 0-6 are typically dark colors, 7-15 are light
18
- const bgNum = parseInt(bg, 10);
19
- if (!isNaN(bgNum)) {
20
- // Most terminal colors: 0=black, 1=red, 2=green, ... 7=white, 8-15=bright variants
21
- // For background: 0-6 = dark, 7 = light
22
- if (bgNum >= 0 && bgNum <= 6) return 'dark';
23
- if (bgNum >= 7) return 'light';
24
- }
25
- }
26
-
27
- // iTerm2 on macOS can indicate background brightness
28
- if (termProgram === 'Apple_Terminal' || termProgram === 'iTerm.app') {
29
- // Apple Terminal and iTerm2 default to dark
30
- return 'dark';
31
- }
32
-
33
- // Windows Terminal and VS Code Terminal typically dark
34
- if (termProgram?.includes('WindowsTerminal') || termProgram?.includes('Code')) {
35
- return 'dark';
36
- }
37
-
38
- // Default to dark background (most common for developers)
39
- return 'dark';
40
- }
41
-
42
- /**
43
- * Mix a color with background to create a transparent effect
44
- * @param hexColor - The base color in hex format
45
- * @param opacity - Opacity from 0 (background) to 1 (full color)
46
- * @param background - Terminal background color ('dark' or 'light')
47
- */
48
- function mixWithBackground(hexColor: string, opacity: number, background: 'dark' | 'light' = 'dark'): string {
49
- const hex = hexColor.replace('#', '');
50
- const r = parseInt(hex.substring(0, 2), 16);
51
- const g = parseInt(hex.substring(2, 4), 16);
52
- const b = parseInt(hex.substring(4, 6), 16);
53
-
54
- // Background colors
55
- const bg = background === 'dark'
56
- ? { r: 0, g: 0, b: 0 } // Black for dark terminals
57
- : { r: 255, g: 255, b: 255 }; // White for light terminals
58
-
59
- const mr = Math.round(bg.r + (r - bg.r) * opacity);
60
- const mg = Math.round(bg.g + (g - bg.g) * opacity);
61
- const mb = Math.round(bg.b + (b - bg.b) * opacity);
62
-
63
- return `#${mr.toString(16).padStart(2, '0')}${mg.toString(16).padStart(2, '0')}${mb.toString(16).padStart(2, '0')}`;
64
- }
65
-
66
- // Get terminal background once at module load
67
- const TERMINAL_BG = getTerminalBackground();
68
- export { TERMINAL_BG, getTerminalBackground, mixWithBackground };
69
-
70
- type ColorFunction = (text: string) => string;
71
-
72
- interface BoxOptions {
73
- width?: number;
74
- indent?: string;
75
- title?: string;
76
- titleAlign?: 'left' | 'center' | 'right';
77
- borderColor?: ColorFunction;
78
- }
79
-
80
- interface SubAgentBoxOptions {
81
- indentLevel?: number;
82
- accentColor?: ColorFunction;
83
- }
84
-
85
- interface BoxFunctions {
86
- single: (content: string, options?: BoxOptions) => string;
87
- double: (content: string, options?: BoxOptions) => string;
88
- minimal: (content: string, options?: Omit<BoxOptions, 'title' | 'titleAlign'>) => string;
89
- subAgent: (agentName: string, description: string, content: string, options?: SubAgentBoxOptions) => string;
90
- }
91
-
92
- /**
93
- * Modern color scheme - using coordinated HSL colors
94
- */
95
- export const colors = {
96
- // Primary colors - modern cyan-blue series
97
- primary: chalk.hex('#06b6d4'), // Cyan-500
98
- primaryBright: chalk.hex('#22d3ee'), // Cyan-400
99
- primaryDark: chalk.hex('#0891b2'), // Cyan-600
100
-
101
- // Success colors - soft green
102
- success: chalk.hex('#10b981'), // Emerald-500
103
- successBright: chalk.hex('#34d399'), // Emerald-400
104
-
105
- // Warning colors - warm amber
106
- warning: chalk.hex('#f59e0b'), // Amber-500
107
- warningBright: chalk.hex('#fbbf24'), // Amber-400
108
-
109
- // Error colors - soft red
110
- error: chalk.hex('#ef4444'), // Red-500
111
- errorBright: chalk.hex('#f87171'), // Red-400
112
-
113
- // Info colors - indigo blue
114
- info: chalk.hex('#6366f1'), // Indigo-500
115
- infoBright: chalk.hex('#818cf8'), // Indigo-400
116
-
117
- // Debug colors - neutral gray
118
- debug: chalk.hex('#6b7280'), // Gray-500
119
- debugBright: chalk.hex('#9ca3af'), // Gray-400
120
-
121
- // Accent colors
122
- accent: chalk.hex('#8b5cf6'), // Violet-500
123
- highlight: chalk.hex('#ec4899'), // Pink-500
124
-
125
- // Neutral colors
126
- text: chalk.hex('#f3f4f6'), // Gray-100
127
- textMuted: chalk.hex('#9ca3af'), // Gray-400
128
- textDim: chalk.hex('#6b7280'), // Gray-500
129
- border: chalk.hex('#374151'), // Gray-700
130
- borderLight: chalk.hex('#4b5563'), // Gray-600
131
-
132
- // Code block colors
133
- codeBackground: chalk.hex('#1f2937'), // Gray-800
134
- codeText: chalk.hex('#e5e7eb'), // Gray-200
135
-
136
- // Diff colors - git-style diff highlighting with transparent backgrounds
137
- diffAdded: chalk.hex('#10b981'), // Green - added lines
138
- diffRemoved: chalk.hex('#ef4444'), // Red - removed lines
139
- diffContext: chalk.hex('#6b7280'), // Gray - context lines
140
- diffAddedInverse: (text: string) => chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937')(text), // Adaptive green bg
141
- diffRemovedInverse: (text: string) => chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937')(text), // Adaptive red bg
142
-
143
- // Gradient colors
144
- gradient: (text: string) => {
145
- const gradientColors = ['#06b6d4', '#8b5cf6', '#ec4899'];
146
- let result = '';
147
- for (let i = 0; i < text.length; i++) {
148
- const colorIndex = Math.floor((i / text.length) * gradientColors.length);
149
- const color = gradientColors[Math.min(colorIndex, gradientColors.length - 1)];
150
- result += chalk.hex(color)(text[i]);
151
- }
152
- return result;
153
- }
154
- };
155
-
156
- /**
157
- * Icon system - using emoji and Unicode symbols
158
- */
159
- export const icons = {
160
- // Status icons
161
- success: '✓',
162
- error: '✗',
163
- warning: '⚠',
164
- info: 'ℹ',
165
- debug: '◦',
166
- loading: '⟳',
167
- processing: '⏳',
168
-
169
- // Feature icons
170
- robot: '🤖',
171
- brain: '🧠',
172
- tool: '🔧',
173
- code: '💻',
174
- file: '📄',
175
- folder: '📁',
176
- lock: '🔐',
177
- unlock: '🔓',
178
- star: '⭐',
179
- sparkles: '✨',
180
- fire: '🔥',
181
- bolt: '⚡',
182
- rocket: '🚀',
183
- check: '✔',
184
- cross: '✖',
185
- arrow: '→',
186
- arrowRight: '→',
187
- arrowLeft: '←',
188
- arrowUp: '↑',
189
- arrowDown: '↓',
190
- dots: '⋯',
191
- plus: '+',
192
- minus: '−',
193
- bullet: '•',
194
- diamond: '◆',
195
- square: '■',
196
- circle: '●',
197
- triangle: '▲',
198
-
199
- // Separators
200
- separator: '─',
201
- separatorDouble: '═',
202
- separatorDashed: '┄',
203
- separatorDotted: '┈',
204
- cornerTopLeft: '┌',
205
- cornerTopRight: '┐',
206
- cornerBottomLeft: '└',
207
- cornerBottomRight: '┘',
208
- teeLeft: '├',
209
- teeRight: '┤',
210
- teeTop: '┬',
211
- teeBottom: '┴',
212
- crossChar: '┼'
213
- };
214
-
215
- /**
216
- * Style configuration
217
- */
218
- export const styleHelpers = {
219
- // Border styles
220
- border: {
221
- single: {
222
- topLeft: '┌',
223
- topRight: '┐',
224
- bottomLeft: '└',
225
- bottomRight: '┘',
226
- horizontal: '─',
227
- vertical: '│',
228
- leftT: '├',
229
- rightT: '┤',
230
- topT: '┬',
231
- bottomT: '┴',
232
- cross: '┼'
233
- },
234
- double: {
235
- topLeft: '╔',
236
- topRight: '╗',
237
- bottomLeft: '╚',
238
- bottomRight: '╝',
239
- horizontal: '═',
240
- vertical: '║',
241
- leftT: '╠',
242
- rightT: '╣',
243
- topT: '╦',
244
- bottomT: '╩',
245
- cross: '╬'
246
- },
247
- rounded: {
248
- topLeft: '╭',
249
- topRight: '╮',
250
- bottomLeft: '╰',
251
- bottomRight: '╯',
252
- horizontal: '─',
253
- vertical: '│',
254
- leftT: '├',
255
- rightT: '┤',
256
- topT: '┬',
257
- bottomT: '┴',
258
- cross: '┼'
259
- }
260
- },
261
-
262
- // Text styles
263
- text: {
264
- bold: chalk.bold,
265
- dim: chalk.dim,
266
- italic: chalk.italic,
267
- underline: chalk.underline,
268
- strikethrough: chalk.strikethrough,
269
- inverse: chalk.inverse
270
- },
271
-
272
- // Animation effects
273
- animation: {
274
- spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
275
- dots: ['⠁', '⠂', '⠄', '⡀', '⡈', '⡐', '⡠', '⣀', '⣁', '⣂', '⣄', '⣌', '⣔', '⣤', '⣥', '�'],
276
- bars: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'],
277
- arrows: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙']
278
- },
279
-
280
- // Box rendering for sub-agents
281
- box: {
282
- single: (content: string, options: { width?: number; indent?: string; title?: string; titleAlign?: 'left' | 'center' | 'right' } = {}) => {
283
- const { width = 60, indent = '', title, titleAlign = 'left' } = options;
284
- const chars = styleHelpers.border.single;
285
- const availableWidth = width - 4;
286
-
287
- let lines: string[] = [];
288
-
289
- if (title) {
290
- const titleContent = ` ${title} `;
291
- const paddingNeeded = availableWidth - titleContent.length;
292
- let leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
293
- let rightPad = titleAlign === 'center' ? Math.ceil(paddingNeeded / 2) : (titleAlign === 'right' ? 0 : paddingNeeded);
294
-
295
- lines.push(`${indent}${chars.topLeft}${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)}${chars.topRight}`);
296
- } else {
297
- lines.push(`${indent}${chars.topLeft}${chars.horizontal.repeat(availableWidth)}${chars.topRight}`);
298
- }
299
-
300
- const contentLines = content.split('\n');
301
- for (const line of contentLines) {
302
- const lineContent = line.length > availableWidth ? line.substring(0, availableWidth - 3) + '...' : line;
303
- const padding = availableWidth - lineContent.length;
304
- lines.push(`${indent}${chars.vertical} ${lineContent}${' '.repeat(padding - 1)} ${chars.vertical}`);
305
- }
306
-
307
- lines.push(`${indent}${chars.bottomLeft}${chars.horizontal.repeat(availableWidth)}${chars.bottomRight}`);
308
-
309
- return lines.join('\n');
310
- },
311
-
312
- double: (content: string, options: { width?: number; indent?: string; title?: string; titleAlign?: 'left' | 'center' | 'right' } = {}) => {
313
- const { width = 60, indent = '', title, titleAlign = 'left' } = options;
314
- const chars = styleHelpers.border.double;
315
- const availableWidth = width - 4;
316
-
317
- let lines: string[] = [];
318
-
319
- if (title) {
320
- const titleContent = ` ${title} `;
321
- const paddingNeeded = availableWidth - titleContent.length;
322
- let leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
323
- let rightPad = titleAlign === 'center' ? Math.ceil(paddingNeeded / 2) : (titleAlign === 'right' ? 0 : paddingNeeded);
324
-
325
- lines.push(`${indent}${chars.topLeft}${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)}${chars.topRight}`);
326
- } else {
327
- lines.push(`${indent}${chars.topLeft}${chars.horizontal.repeat(availableWidth)}${chars.topRight}`);
328
- }
329
-
330
- const contentLines = content.split('\n');
331
- for (const line of contentLines) {
332
- const lineContent = line.length > availableWidth ? line.substring(0, availableWidth - 3) + '...' : line;
333
- const padding = availableWidth - lineContent.length;
334
- lines.push(`${indent}${chars.vertical} ${lineContent}${' '.repeat(padding - 1)} ${chars.vertical}`);
335
- }
336
-
337
- lines.push(`${indent}${chars.bottomLeft}${chars.horizontal.repeat(availableWidth)}${chars.bottomRight}`);
338
-
339
- return lines.join('\n');
340
- },
341
-
342
- minimal: (content: string, options: { width?: number; indent?: string; borderColor?: (text: string) => string } = {}) => {
343
- const { width = 60, indent = '', borderColor = colors.border } = options;
344
- const chars = styleHelpers.border.single;
345
- const availableWidth = width - 2;
346
-
347
- const lines = [
348
- borderColor(`${indent}${chars.topLeft}${chars.horizontal.repeat(availableWidth)}${chars.topRight}`),
349
- ...content.split('\n').map(line => {
350
- const lineContent = line.length > availableWidth ? line.substring(0, availableWidth - 3) + '...' : line;
351
- return `${indent}${chars.vertical} ${lineContent}${' '.repeat(availableWidth - lineContent.length - 2)}${chars.vertical}`;
352
- }),
353
- borderColor(`${indent}${chars.bottomLeft}${chars.horizontal.repeat(availableWidth)}${chars.bottomRight}`)
354
- ];
355
-
356
- return lines.join('\n');
357
- },
358
-
359
- subAgent: (agentName: string, description: string, content: string, options: { indentLevel?: number; accentColor?: (text: string) => string; contentColor?: (text: string) => string } = {}) => {
360
- const { indentLevel = 1, accentColor = colors.accent, contentColor = colors.text } = options;
361
- const indent = ' '.repeat(indentLevel);
362
- const chars = styleHelpers.border.single;
363
- const width = Math.min(70, (process.stdout.columns || 80) - indentLevel * 2);
364
- const availableWidth = width - 2;
365
-
366
- const headerContent = `${colors.primaryBright(agentName)}: ${description}`;
367
- const headerContentLength = headerContent.replace(/\x1b\[[0-9;]*m/g, '').length;
368
- const headerFillLength = Math.max(0, availableWidth - 3 - headerContentLength);
369
- const headerLine = `${indent}${accentColor(chars.topLeft)}${accentColor('─── ')}${headerContent} ${accentColor('─'.repeat(headerFillLength))}${accentColor(chars.topRight)}`;
370
-
371
- const contentLines = content.split('\n');
372
- const maxContentWidth = width - 4;
373
- const middleLines = contentLines.map(line => {
374
- const lineLength = line.length;
375
- if (lineLength <= maxContentWidth) {
376
- const paddingLength = Math.max(0, width - lineLength - 4);
377
- return `${indent}${chars.vertical} ${contentColor(line)}${' '.repeat(paddingLength)}${chars.vertical}`;
378
- }
379
- const wrappedLines: string[] = [];
380
- let remaining = line;
381
- while (remaining.length > maxContentWidth) {
382
- wrappedLines.push(`${indent}${chars.vertical} ${contentColor(remaining.substring(0, maxContentWidth - 3))}...${chars.vertical}`);
383
- remaining = '... ' + remaining.substring(maxContentWidth - 3);
384
- }
385
- const remainingLength = remaining.length;
386
- const remainingPadding = Math.max(0, width - remainingLength - 4);
387
- wrappedLines.push(`${indent}${chars.vertical} ${contentColor(remaining)}${' '.repeat(remainingPadding)}${chars.vertical}`);
388
- return wrappedLines.join('\n');
389
- });
390
-
391
- const bottomLine = `${indent}${accentColor(chars.bottomLeft)}${accentColor('─'.repeat(width - 2))}${accentColor(chars.bottomRight)}`;
392
-
393
- return [headerLine, ...middleLines, bottomLine].join('\n');
394
- }
395
- }
396
- };
397
-
398
- /**
399
- * Theme configuration
400
- */
401
- export const theme = {
402
- colors,
403
- icons,
404
- styles: styleHelpers,
405
-
406
- // Predefined style combinations
407
- predefinedStyles: {
408
- // Title styles
409
- title: (text: string) => styleHelpers.text.bold(colors.primary(text)),
410
- subtitle: (text: string) => colors.infoBright(text),
411
- section: (text: string) => styleHelpers.text.bold(colors.primaryBright(text)),
412
-
413
- // Status styles
414
- success: (text: string) => colors.success(`${icons.success} ${text}`),
415
- error: (text: string) => colors.error(`${icons.error} ${text}`),
416
- warning: (text: string) => colors.warning(`${icons.warning} ${text}`),
417
- info: (text: string) => colors.info(`${icons.info} ${text}`),
418
- debug: (text: string) => colors.debug(`${icons.debug} ${text}`),
419
-
420
- // Code styles
421
- code: (text: string) => colors.codeBackground(` ${text} `),
422
- inlineCode: (text: string) => colors.codeText(`\`${text}\``),
423
-
424
- // Link styles
425
- link: (text: string, url: string) => colors.primaryBright(`${text}: ${styleHelpers.text.underline(url)}`),
426
-
427
- // Emphasis styles
428
- highlight: (text: string) => colors.highlight(text),
429
- accent: (text: string) => colors.accent(text),
430
- muted: (text: string) => colors.textMuted(text),
431
- dim: (text: string) => colors.textDim(text),
432
-
433
- // Separators
434
- separator: (width: number) => colors.border(icons.separator.repeat(width)),
435
- separatorDouble: (width: number) => colors.border(icons.separatorDouble.repeat(width)),
436
- separatorDashed: (width: number) => colors.border(icons.separatorDashed.repeat(width)),
437
-
438
- // Progress bar
439
- progressBar: (current: number, total: number, width: number = 30) => {
440
- const percentage = Math.round((current / total) * 100);
441
- const filled = Math.round((current / total) * width);
442
- const empty = width - filled;
443
-
444
- const filledBar = colors.success(icons.square.repeat(filled));
445
- const emptyBar = colors.border(icons.square.repeat(empty));
446
-
447
- return `${filledBar}${emptyBar} ${percentage}%`;
448
- }
449
- }
450
- };
451
-
452
- /**
453
- * Simple markdown renderer for terminal output
454
- */
455
- export function renderMarkdown(text: string, maxWidth: number = 80): string {
456
- if (!text) return '';
457
-
458
- const lines = text.split('\n');
459
- const result: string[] = [];
460
-
461
- let inCodeBlock = false;
462
- let codeLanguage = '';
463
- let codeContent: string[] = [];
464
-
465
- for (let i = 0; i < lines.length; i++) {
466
- const line = lines[i];
467
-
468
- // Check for code block start/end
469
- if (line.startsWith('```')) {
470
- if (!inCodeBlock) {
471
- // Start of code block
472
- inCodeBlock = true;
473
- codeLanguage = line.slice(3).trim() || '';
474
- codeContent = [];
475
- } else {
476
- // End of code block
477
- inCodeBlock = false;
478
- if (codeContent.length > 0) {
479
- result.push('');
480
- result.push(colors.accent(`${icons.code} ${codeLanguage ? codeLanguage + ' Code' : 'Code'}:`));
481
- codeContent.forEach(line => {
482
- result.push(colors.codeText(line));
483
- });
484
- result.push(colors.border(icons.separator.repeat(Math.min(40, maxWidth))));
485
- result.push('');
486
- }
487
- }
488
- continue;
489
- }
490
-
491
- if (inCodeBlock) {
492
- codeContent.push(line);
493
- continue;
494
- }
495
-
496
- // Process inline markdown
497
- let processed = line;
498
-
499
- // Headers (H1, H2, H3, H4)
500
- if (line.startsWith('#### ')) {
501
- processed = colors.primaryBright(line.slice(5));
502
- } else if (line.startsWith('### ')) {
503
- processed = colors.primaryBright(styleHelpers.text.bold(line.slice(4)));
504
- } else if (line.startsWith('## ')) {
505
- processed = colors.primaryBright(styleHelpers.text.bold(line.slice(3)));
506
- } else if (line.startsWith('# ')) {
507
- processed = colors.primaryBright(styleHelpers.text.bold(line.slice(2)));
508
- } else {
509
- // Inline formatting
510
- processed = processed
511
- // Code inline
512
- .replace(/`([^`]+)`/g, (_, code) => colors.codeText(code))
513
- // Bold
514
- .replace(/\*\*([^*]+)\*\*/g, (_, text) => styleHelpers.text.bold(text))
515
- // Italic
516
- .replace(/\*([^*]+)\*/g, (_, text) => styleHelpers.text.italic(text))
517
- // Strikethrough
518
- .replace(/~~([^~]+)~~/g, (_, text) => colors.textDim(text))
519
- // Links
520
- .replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => colors.primaryBright(`${text}: ${styleHelpers.text.underline(url)}`));
521
- }
522
-
523
- result.push(processed);
524
- }
525
-
526
- return result.join('\n');
527
- }
528
-
529
- /**
530
- * Parse a single diff line.
531
- * Format: "+<num> content" or "-<num> content" or " <num> content"
532
- * Also handles: "+<num>..." for skipped lines
533
- */
534
- function parseDiffLine(line: string): { prefix: string; lineNum: string; content: string } | null {
535
- // Skip empty lines
536
- if (!line || line.trim() === '') return null;
537
-
538
- const firstChar = line[0];
539
- if (!['+', '-', ' '].includes(firstChar)) {
540
- // Try to detect if this is a diff-like line with different format
541
- // e.g., "+ 1 content" (with padding)
542
- const match = line.match(/^[+\-\s]\s*/);
543
- if (match) {
544
- // This looks like a diff line but with unexpected format
545
- // Extract the content after the prefix
546
- const afterPrefix = line.slice(match[0].length).trim();
547
- return { prefix: firstChar, lineNum: '', content: afterPrefix };
548
- }
549
- return null;
550
- }
551
-
552
- // Extract content after the prefix char
553
- const afterPrefix = line.slice(1).trim();
554
-
555
- // Check for skipped lines marker
556
- if (afterPrefix === '...') {
557
- return { prefix: firstChar, lineNum: '', content: '...' };
558
- }
559
-
560
- // Return the rest as content
561
- return { prefix: firstChar, lineNum: '', content: afterPrefix };
562
- }
563
-
564
- /**
565
- * Replace tabs with spaces for consistent rendering.
566
- */
567
- function replaceTabs(text: string): string {
568
- return text.replace(/\t/g, ' ');
569
- }
570
-
571
- /**
572
- * Compute word-level diff and render with inverse on changed parts.
573
- * Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.
574
- */
575
- function renderIntraLineDiff(oldContent: string, newContent: string): { removedLine: string; addedLine: string } {
576
- // Simple word diff without external dependency
577
- const oldWords = oldContent.split(/(\s+)/);
578
- const newWords = newContent.split(/(\s+)/);
579
-
580
- let removedLine = '';
581
- let addedLine = '';
582
- let i = 0, j = 0;
583
-
584
- while (i < oldWords.length || j < newWords.length) {
585
- const oldWord = oldWords[i] || '';
586
- const newWord = newWords[j] || '';
587
-
588
- if (oldWord === newWord) {
589
- removedLine += oldWord;
590
- addedLine += newWord;
591
- i++;
592
- j++;
593
- } else if (oldWord === '' || oldWord.match(/^\s+$/)) {
594
- addedLine += newWord;
595
- j++;
596
- } else if (newWord === '' || newWord.match(/^\s+$/)) {
597
- removedLine += oldWord;
598
- i++;
599
- } else {
600
- // Simple heuristic: show removed with inverse, added with inverse
601
- removedLine += colors.diffRemovedInverse(oldWord);
602
- addedLine += colors.diffAddedInverse(newWord);
603
- i++;
604
- j++;
605
- }
606
- }
607
-
608
- return { removedLine, addedLine };
609
- }
610
-
611
- /**
612
- * Render a diff string with colored lines and intra-line change highlighting.
613
- * - Context lines: gray
614
- * - Removed lines: red
615
- * - Added lines: green
616
- */
617
- export function renderDiff(diffText: string): string {
618
- if (!diffText) return '';
619
-
620
- const lines = diffText.split('\n');
621
- const result: string[] = [];
622
-
623
- let i = 0;
624
- while (i < lines.length) {
625
- const line = lines[i];
626
- const parsed = parseDiffLine(line);
627
-
628
- if (!parsed) {
629
- result.push(colors.diffContext(line));
630
- i++;
631
- continue;
632
- }
633
-
634
- if (parsed.prefix === '-') {
635
- // Collect consecutive removed lines
636
- const removedLines: { lineNum: string; content: string }[] = [];
637
- while (i < lines.length) {
638
- const p = parseDiffLine(lines[i]);
639
- if (!p || p.prefix !== '-') break;
640
- removedLines.push({ lineNum: p.lineNum, content: p.content });
641
- i++;
642
- }
643
-
644
- // Collect consecutive added lines
645
- const addedLines: { lineNum: string; content: string }[] = [];
646
- while (i < lines.length) {
647
- const p = parseDiffLine(lines[i]);
648
- if (!p || p.prefix !== '+') break;
649
- addedLines.push({ lineNum: p.lineNum, content: p.content });
650
- i++;
651
- }
652
-
653
- // Intra-line diff for single line modification
654
- if (removedLines.length === 1 && addedLines.length === 1) {
655
- const removed = removedLines[0];
656
- const added = addedLines[0];
657
- const { removedLine, addedLine } = renderIntraLineDiff(replaceTabs(removed.content), replaceTabs(added.content));
658
- const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
659
- result.push(chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(textColor)(`-${removedLine}`));
660
- result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${addedLine}`));
661
- } else {
662
- const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
663
- for (const removed of removedLines) {
664
- result.push(chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(textColor)(`-${replaceTabs(removed.content)}`));
665
- }
666
- for (const added of addedLines) {
667
- result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${replaceTabs(added.content)}`));
668
- }
669
- }
670
- } else if (parsed.prefix === '+') {
671
- const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
672
- result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${replaceTabs(parsed.content)}`));
673
- i++;
674
- } else {
675
- result.push(chalk.hex('#374151')(` ${replaceTabs(parsed.content)}`));
676
- i++;
677
- }
678
- }
679
-
680
- return result.join('\n');
681
- }
682
-
683
- /**
684
- * Render a code preview with line numbers and syntax highlighting.
685
- * Automatically adapts to dark/light terminal backgrounds.
686
- */
687
- export function renderCodePreview(content: string, options: { filePath?: string; maxLines?: number; indent?: string } = {}): string {
688
- const { filePath = '', maxLines = 10, indent = '' } = options;
689
- const lines = content.split('\n');
690
- const displayLines = lines.slice(0, maxLines);
691
- const hasMore = lines.length > maxLines;
692
-
693
- const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2931';
694
- const bgColor = TERMINAL_BG === 'dark' ? '#1f2937' : '#f3f4f6';
695
- const codeStyle = chalk.bgHex(bgColor).hex(textColor);
696
-
697
- const lineNumWidth = String(displayLines.length).length;
698
- const parts: string[] = [];
699
-
700
- if (filePath) {
701
- parts.push(`${indent}${chalk.hex(TERMINAL_BG === 'dark' ? '#22d3ee' : '#0891b2').bold(filePath)}`);
702
- }
703
-
704
- displayLines.forEach((line, idx) => {
705
- const lineNum = String(idx + 1).padStart(lineNumWidth, ' ');
706
- parts.push(`${indent} ${codeStyle(`${lineNum} │ ${line}`)}`);
707
- });
708
-
709
- if (hasMore) {
710
- const dotsLine = `${indent} ${chalk.hex(TERMINAL_BG === 'dark' ? '#6b7280' : '#9ca3af').dim('...')}`;
711
- parts.push(dotsLine);
712
- }
713
-
714
- return parts.join('\n');
715
- }
716
-
717
- /**
718
- * Render new file content in diff-like style (without line numbers).
719
- * Uses + prefix for added lines.
720
- */
721
- export function renderLines(content: string, options: { maxLines?: number; indent?: string } = {}): string {
722
- const { maxLines = 20, indent = '' } = options;
723
- const lines = content.split('\n').slice(0, maxLines);
724
- const hasMore = content.split('\n').length > maxLines;
725
-
726
- const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
727
- const bgColor = mixWithBackground('#10b981', 0.15, TERMINAL_BG);
728
- const lineStyle = chalk.bgHex(bgColor).hex(textColor);
729
-
730
- const parts: string[] = lines.map(line => `${indent}${lineStyle(`+ ${line}`)}`);
731
-
732
- if (hasMore) {
733
- parts.push(`${indent}${chalk.hex(TERMINAL_BG === 'dark' ? '#6b7280' : '#9ca3af').dim('...')}`);
734
- }
735
-
736
- return parts.join('\n');
737
- }
738
-
1
+ import chalk from 'chalk';
2
+
3
+ /**
4
+ * Detect if terminal has dark or light background
5
+ * Returns 'dark' for dark backgrounds (default), 'light' for light backgrounds
6
+ */
7
+ function getTerminalBackground(): 'dark' | 'light' {
8
+ // Check common environment variables
9
+ const colorfgbg = process.env.COLORFGBG; // e.g., "15;0" (light fg, dark bg)
10
+ const termProgram = process.env.TERM_PROGRAM;
11
+ const termProgramVersion = process.env.TERM_PROGRAM_VERSION;
12
+
13
+ // Try to parse COLORFGBG (format: "fg;bg" or "fg;color;bg")
14
+ if (colorfgbg) {
15
+ const parts = colorfgbg.split(';');
16
+ const bg = parts[parts.length - 1];
17
+ // 0-6 are typically dark colors, 7-15 are light
18
+ const bgNum = parseInt(bg, 10);
19
+ if (!isNaN(bgNum)) {
20
+ // Most terminal colors: 0=black, 1=red, 2=green, ... 7=white, 8-15=bright variants
21
+ // For background: 0-6 = dark, 7 = light
22
+ if (bgNum >= 0 && bgNum <= 6) return 'dark';
23
+ if (bgNum >= 7) return 'light';
24
+ }
25
+ }
26
+
27
+ // iTerm2 on macOS can indicate background brightness
28
+ if (termProgram === 'Apple_Terminal' || termProgram === 'iTerm.app') {
29
+ // Apple Terminal and iTerm2 default to dark
30
+ return 'dark';
31
+ }
32
+
33
+ // Windows Terminal and VS Code Terminal typically dark
34
+ if (termProgram?.includes('WindowsTerminal') || termProgram?.includes('Code')) {
35
+ return 'dark';
36
+ }
37
+
38
+ // Default to dark background (most common for developers)
39
+ return 'dark';
40
+ }
41
+
42
+ /**
43
+ * Mix a color with background to create a transparent effect
44
+ * @param hexColor - The base color in hex format
45
+ * @param opacity - Opacity from 0 (background) to 1 (full color)
46
+ * @param background - Terminal background color ('dark' or 'light')
47
+ */
48
+ function mixWithBackground(hexColor: string, opacity: number, background: 'dark' | 'light' = 'dark'): string {
49
+ const hex = hexColor.replace('#', '');
50
+ const r = parseInt(hex.substring(0, 2), 16);
51
+ const g = parseInt(hex.substring(2, 4), 16);
52
+ const b = parseInt(hex.substring(4, 6), 16);
53
+
54
+ // Background colors
55
+ const bg = background === 'dark'
56
+ ? { r: 0, g: 0, b: 0 } // Black for dark terminals
57
+ : { r: 255, g: 255, b: 255 }; // White for light terminals
58
+
59
+ const mr = Math.round(bg.r + (r - bg.r) * opacity);
60
+ const mg = Math.round(bg.g + (g - bg.g) * opacity);
61
+ const mb = Math.round(bg.b + (b - bg.b) * opacity);
62
+
63
+ return `#${mr.toString(16).padStart(2, '0')}${mg.toString(16).padStart(2, '0')}${mb.toString(16).padStart(2, '0')}`;
64
+ }
65
+
66
+ // Get terminal background once at module load
67
+ const TERMINAL_BG = getTerminalBackground();
68
+ export { TERMINAL_BG, getTerminalBackground, mixWithBackground };
69
+
70
+ type ColorFunction = (text: string) => string;
71
+
72
+ interface BoxOptions {
73
+ width?: number;
74
+ indent?: string;
75
+ title?: string;
76
+ titleAlign?: 'left' | 'center' | 'right';
77
+ borderColor?: ColorFunction;
78
+ }
79
+
80
+ interface SubAgentBoxOptions {
81
+ indentLevel?: number;
82
+ accentColor?: ColorFunction;
83
+ }
84
+
85
+ interface BoxFunctions {
86
+ single: (content: string, options?: BoxOptions) => string;
87
+ double: (content: string, options?: BoxOptions) => string;
88
+ minimal: (content: string, options?: Omit<BoxOptions, 'title' | 'titleAlign'>) => string;
89
+ subAgent: (agentName: string, description: string, content: string, options?: SubAgentBoxOptions) => string;
90
+ }
91
+
92
+ /**
93
+ * Modern color scheme - using coordinated HSL colors
94
+ */
95
+ export const colors = {
96
+ // Primary colors - modern cyan-blue series
97
+ primary: chalk.hex('#06b6d4'), // Cyan-500
98
+ primaryBright: chalk.hex('#22d3ee'), // Cyan-400
99
+ primaryDark: chalk.hex('#0891b2'), // Cyan-600
100
+
101
+ // Success colors - soft green
102
+ success: chalk.hex('#10b981'), // Emerald-500
103
+ successBright: chalk.hex('#34d399'), // Emerald-400
104
+
105
+ // Warning colors - warm amber
106
+ warning: chalk.hex('#f59e0b'), // Amber-500
107
+ warningBright: chalk.hex('#fbbf24'), // Amber-400
108
+
109
+ // Error colors - soft red
110
+ error: chalk.hex('#ef4444'), // Red-500
111
+ errorBright: chalk.hex('#f87171'), // Red-400
112
+
113
+ // Info colors - indigo blue
114
+ info: chalk.hex('#6366f1'), // Indigo-500
115
+ infoBright: chalk.hex('#818cf8'), // Indigo-400
116
+
117
+ // Debug colors - neutral gray
118
+ debug: chalk.hex('#6b7280'), // Gray-500
119
+ debugBright: chalk.hex('#9ca3af'), // Gray-400
120
+
121
+ // Accent colors
122
+ accent: chalk.hex('#8b5cf6'), // Violet-500
123
+ highlight: chalk.hex('#ec4899'), // Pink-500
124
+
125
+ // Neutral colors
126
+ text: chalk.hex('#f3f4f6'), // Gray-100
127
+ textMuted: chalk.hex('#9ca3af'), // Gray-400
128
+ textDim: chalk.hex('#6b7280'), // Gray-500
129
+ border: chalk.hex('#374151'), // Gray-700
130
+ borderLight: chalk.hex('#4b5563'), // Gray-600
131
+
132
+ // Code block colors
133
+ codeBackground: chalk.hex('#1f2937'), // Gray-800
134
+ codeText: chalk.hex('#e5e7eb'), // Gray-200
135
+
136
+ // Diff colors - git-style diff highlighting with transparent backgrounds
137
+ diffAdded: chalk.hex('#10b981'), // Green - added lines
138
+ diffRemoved: chalk.hex('#ef4444'), // Red - removed lines
139
+ diffContext: chalk.hex('#6b7280'), // Gray - context lines
140
+ diffAddedInverse: (text: string) => chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937')(text), // Adaptive green bg
141
+ diffRemovedInverse: (text: string) => chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937')(text), // Adaptive red bg
142
+
143
+ // Gradient colors
144
+ gradient: (text: string) => {
145
+ const gradientColors = ['#06b6d4', '#8b5cf6', '#ec4899'];
146
+ let result = '';
147
+ for (let i = 0; i < text.length; i++) {
148
+ const colorIndex = Math.floor((i / text.length) * gradientColors.length);
149
+ const color = gradientColors[Math.min(colorIndex, gradientColors.length - 1)];
150
+ result += chalk.hex(color)(text[i]);
151
+ }
152
+ return result;
153
+ }
154
+ };
155
+
156
+ /**
157
+ * Icon system - using emoji and Unicode symbols
158
+ */
159
+ export const icons = {
160
+ // Status icons
161
+ success: '✓',
162
+ error: '✗',
163
+ warning: '⚠',
164
+ info: 'ℹ',
165
+ debug: '◦',
166
+ loading: '⟳',
167
+ processing: '⏳',
168
+
169
+ // Feature icons
170
+ robot: '🤖',
171
+ brain: '🧠',
172
+ tool: '🔧',
173
+ code: '💻',
174
+ file: '📄',
175
+ folder: '📁',
176
+ lock: '🔐',
177
+ unlock: '🔓',
178
+ star: '⭐',
179
+ sparkles: '✨',
180
+ fire: '🔥',
181
+ bolt: '⚡',
182
+ rocket: '🚀',
183
+ check: '✔',
184
+ cross: '✖',
185
+ arrow: '→',
186
+ arrowRight: '→',
187
+ arrowLeft: '←',
188
+ arrowUp: '↑',
189
+ arrowDown: '↓',
190
+ dots: '⋯',
191
+ plus: '+',
192
+ minus: '−',
193
+ bullet: '•',
194
+ diamond: '◆',
195
+ square: '■',
196
+ circle: '●',
197
+ triangle: '▲',
198
+
199
+ // Separators
200
+ separator: '─',
201
+ separatorDouble: '═',
202
+ separatorDashed: '┄',
203
+ separatorDotted: '┈',
204
+ cornerTopLeft: '┌',
205
+ cornerTopRight: '┐',
206
+ cornerBottomLeft: '└',
207
+ cornerBottomRight: '┘',
208
+ teeLeft: '├',
209
+ teeRight: '┤',
210
+ teeTop: '┬',
211
+ teeBottom: '┴',
212
+ crossChar: '┼'
213
+ };
214
+
215
+ /**
216
+ * Style configuration
217
+ */
218
+ export const styleHelpers = {
219
+ // Border styles
220
+ border: {
221
+ single: {
222
+ topLeft: '┌',
223
+ topRight: '┐',
224
+ bottomLeft: '└',
225
+ bottomRight: '┘',
226
+ horizontal: '─',
227
+ vertical: '│',
228
+ leftT: '├',
229
+ rightT: '┤',
230
+ topT: '┬',
231
+ bottomT: '┴',
232
+ cross: '┼'
233
+ },
234
+ double: {
235
+ topLeft: '╔',
236
+ topRight: '╗',
237
+ bottomLeft: '╚',
238
+ bottomRight: '╝',
239
+ horizontal: '═',
240
+ vertical: '║',
241
+ leftT: '╠',
242
+ rightT: '╣',
243
+ topT: '╦',
244
+ bottomT: '╩',
245
+ cross: '╬'
246
+ },
247
+ rounded: {
248
+ topLeft: '╭',
249
+ topRight: '╮',
250
+ bottomLeft: '╰',
251
+ bottomRight: '╯',
252
+ horizontal: '─',
253
+ vertical: '│',
254
+ leftT: '├',
255
+ rightT: '┤',
256
+ topT: '┬',
257
+ bottomT: '┴',
258
+ cross: '┼'
259
+ }
260
+ },
261
+
262
+ // Text styles
263
+ text: {
264
+ bold: chalk.bold,
265
+ dim: chalk.dim,
266
+ italic: chalk.italic,
267
+ underline: chalk.underline,
268
+ strikethrough: chalk.strikethrough,
269
+ inverse: chalk.inverse
270
+ },
271
+
272
+ // Animation effects
273
+ animation: {
274
+ spinner: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
275
+ dots: ['⠁', '⠂', '⠄', '⡀', '⡈', '⡐', '⡠', '⣀', '⣁', '⣂', '⣄', '⣌', '⣔', '⣤', '⣥', '�'],
276
+ bars: ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'],
277
+ arrows: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙']
278
+ },
279
+
280
+ // Box rendering for sub-agents
281
+ box: {
282
+ single: (content: string, options: { width?: number; indent?: string; title?: string; titleAlign?: 'left' | 'center' | 'right' } = {}) => {
283
+ const { width = 60, indent = '', title, titleAlign = 'left' } = options;
284
+ const chars = styleHelpers.border.single;
285
+ const availableWidth = width - 4;
286
+
287
+ let lines: string[] = [];
288
+
289
+ if (title) {
290
+ const titleContent = ` ${title} `;
291
+ const paddingNeeded = availableWidth - titleContent.length;
292
+ let leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
293
+ let rightPad = titleAlign === 'center' ? Math.ceil(paddingNeeded / 2) : (titleAlign === 'right' ? 0 : paddingNeeded);
294
+
295
+ lines.push(`${indent}${chars.topLeft}${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)}${chars.topRight}`);
296
+ } else {
297
+ lines.push(`${indent}${chars.topLeft}${chars.horizontal.repeat(availableWidth)}${chars.topRight}`);
298
+ }
299
+
300
+ const contentLines = content.split('\n');
301
+ for (const line of contentLines) {
302
+ const lineContent = line.length > availableWidth ? line.substring(0, availableWidth - 3) + '...' : line;
303
+ const padding = availableWidth - lineContent.length;
304
+ lines.push(`${indent}${chars.vertical} ${lineContent}${' '.repeat(padding - 1)} ${chars.vertical}`);
305
+ }
306
+
307
+ lines.push(`${indent}${chars.bottomLeft}${chars.horizontal.repeat(availableWidth)}${chars.bottomRight}`);
308
+
309
+ return lines.join('\n');
310
+ },
311
+
312
+ double: (content: string, options: { width?: number; indent?: string; title?: string; titleAlign?: 'left' | 'center' | 'right' } = {}) => {
313
+ const { width = 60, indent = '', title, titleAlign = 'left' } = options;
314
+ const chars = styleHelpers.border.double;
315
+ const availableWidth = width - 4;
316
+
317
+ let lines: string[] = [];
318
+
319
+ if (title) {
320
+ const titleContent = ` ${title} `;
321
+ const paddingNeeded = availableWidth - titleContent.length;
322
+ let leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
323
+ let rightPad = titleAlign === 'center' ? Math.ceil(paddingNeeded / 2) : (titleAlign === 'right' ? 0 : paddingNeeded);
324
+
325
+ lines.push(`${indent}${chars.topLeft}${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)}${chars.topRight}`);
326
+ } else {
327
+ lines.push(`${indent}${chars.topLeft}${chars.horizontal.repeat(availableWidth)}${chars.topRight}`);
328
+ }
329
+
330
+ const contentLines = content.split('\n');
331
+ for (const line of contentLines) {
332
+ const lineContent = line.length > availableWidth ? line.substring(0, availableWidth - 3) + '...' : line;
333
+ const padding = availableWidth - lineContent.length;
334
+ lines.push(`${indent}${chars.vertical} ${lineContent}${' '.repeat(padding - 1)} ${chars.vertical}`);
335
+ }
336
+
337
+ lines.push(`${indent}${chars.bottomLeft}${chars.horizontal.repeat(availableWidth)}${chars.bottomRight}`);
338
+
339
+ return lines.join('\n');
340
+ },
341
+
342
+ minimal: (content: string, options: { width?: number; indent?: string; borderColor?: (text: string) => string } = {}) => {
343
+ const { width = 60, indent = '', borderColor = colors.border } = options;
344
+ const chars = styleHelpers.border.single;
345
+ const availableWidth = width - 2;
346
+
347
+ const lines = [
348
+ borderColor(`${indent}${chars.topLeft}${chars.horizontal.repeat(availableWidth)}${chars.topRight}`),
349
+ ...content.split('\n').map(line => {
350
+ const lineContent = line.length > availableWidth ? line.substring(0, availableWidth - 3) + '...' : line;
351
+ return `${indent}${chars.vertical} ${lineContent}${' '.repeat(availableWidth - lineContent.length - 2)}${chars.vertical}`;
352
+ }),
353
+ borderColor(`${indent}${chars.bottomLeft}${chars.horizontal.repeat(availableWidth)}${chars.bottomRight}`)
354
+ ];
355
+
356
+ return lines.join('\n');
357
+ },
358
+
359
+ subAgent: (agentName: string, description: string, content: string, options: { indentLevel?: number; accentColor?: (text: string) => string; contentColor?: (text: string) => string } = {}) => {
360
+ const { indentLevel = 1, accentColor = colors.accent, contentColor = colors.text } = options;
361
+ const indent = ' '.repeat(indentLevel);
362
+ const chars = styleHelpers.border.single;
363
+ const width = Math.min(70, (process.stdout.columns || 80) - indentLevel * 2);
364
+ const availableWidth = width - 2;
365
+
366
+ const headerContent = `${colors.primaryBright(agentName)}: ${description}`;
367
+ const headerContentLength = headerContent.replace(/\x1b\[[0-9;]*m/g, '').length;
368
+ const headerFillLength = Math.max(0, availableWidth - 3 - headerContentLength);
369
+ const headerLine = `${indent}${accentColor(chars.topLeft)}${accentColor('─── ')}${headerContent} ${accentColor('─'.repeat(headerFillLength))}${accentColor(chars.topRight)}`;
370
+
371
+ const contentLines = content.split('\n');
372
+ const maxContentWidth = width - 4;
373
+ const middleLines = contentLines.map(line => {
374
+ const lineLength = line.length;
375
+ if (lineLength <= maxContentWidth) {
376
+ const paddingLength = Math.max(0, width - lineLength - 4);
377
+ return `${indent}${chars.vertical} ${contentColor(line)}${' '.repeat(paddingLength)}${chars.vertical}`;
378
+ }
379
+ const wrappedLines: string[] = [];
380
+ let remaining = line;
381
+ while (remaining.length > maxContentWidth) {
382
+ wrappedLines.push(`${indent}${chars.vertical} ${contentColor(remaining.substring(0, maxContentWidth - 3))}...${chars.vertical}`);
383
+ remaining = '... ' + remaining.substring(maxContentWidth - 3);
384
+ }
385
+ const remainingLength = remaining.length;
386
+ const remainingPadding = Math.max(0, width - remainingLength - 4);
387
+ wrappedLines.push(`${indent}${chars.vertical} ${contentColor(remaining)}${' '.repeat(remainingPadding)}${chars.vertical}`);
388
+ return wrappedLines.join('\n');
389
+ });
390
+
391
+ const bottomLine = `${indent}${accentColor(chars.bottomLeft)}${accentColor('─'.repeat(width - 2))}${accentColor(chars.bottomRight)}`;
392
+
393
+ return [headerLine, ...middleLines, bottomLine].join('\n');
394
+ }
395
+ }
396
+ };
397
+
398
+ /**
399
+ * Theme configuration
400
+ */
401
+ export const theme = {
402
+ colors,
403
+ icons,
404
+ styles: styleHelpers,
405
+
406
+ // Predefined style combinations
407
+ predefinedStyles: {
408
+ // Title styles
409
+ title: (text: string) => styleHelpers.text.bold(colors.primary(text)),
410
+ subtitle: (text: string) => colors.infoBright(text),
411
+ section: (text: string) => styleHelpers.text.bold(colors.primaryBright(text)),
412
+
413
+ // Status styles
414
+ success: (text: string) => colors.success(`${icons.success} ${text}`),
415
+ error: (text: string) => colors.error(`${icons.error} ${text}`),
416
+ warning: (text: string) => colors.warning(`${icons.warning} ${text}`),
417
+ info: (text: string) => colors.info(`${icons.info} ${text}`),
418
+ debug: (text: string) => colors.debug(`${icons.debug} ${text}`),
419
+
420
+ // Code styles
421
+ code: (text: string) => colors.codeBackground(` ${text} `),
422
+ inlineCode: (text: string) => colors.codeText(`\`${text}\``),
423
+
424
+ // Link styles
425
+ link: (text: string, url: string) => colors.primaryBright(`${text}: ${styleHelpers.text.underline(url)}`),
426
+
427
+ // Emphasis styles
428
+ highlight: (text: string) => colors.highlight(text),
429
+ accent: (text: string) => colors.accent(text),
430
+ muted: (text: string) => colors.textMuted(text),
431
+ dim: (text: string) => colors.textDim(text),
432
+
433
+ // Separators
434
+ separator: (width: number) => colors.border(icons.separator.repeat(width)),
435
+ separatorDouble: (width: number) => colors.border(icons.separatorDouble.repeat(width)),
436
+ separatorDashed: (width: number) => colors.border(icons.separatorDashed.repeat(width)),
437
+
438
+ // Progress bar
439
+ progressBar: (current: number, total: number, width: number = 30) => {
440
+ const percentage = Math.round((current / total) * 100);
441
+ const filled = Math.round((current / total) * width);
442
+ const empty = width - filled;
443
+
444
+ const filledBar = colors.success(icons.square.repeat(filled));
445
+ const emptyBar = colors.border(icons.square.repeat(empty));
446
+
447
+ return `${filledBar}${emptyBar} ${percentage}%`;
448
+ }
449
+ }
450
+ };
451
+
452
+ /**
453
+ * Simple markdown renderer for terminal output
454
+ */
455
+ export function renderMarkdown(text: string, maxWidth: number = 80): string {
456
+ if (!text) return '';
457
+
458
+ const lines = text.split('\n');
459
+ const result: string[] = [];
460
+
461
+ let inCodeBlock = false;
462
+ let codeLanguage = '';
463
+ let codeContent: string[] = [];
464
+
465
+ for (let i = 0; i < lines.length; i++) {
466
+ const line = lines[i];
467
+
468
+ // Check for code block start/end
469
+ if (line.startsWith('```')) {
470
+ if (!inCodeBlock) {
471
+ // Start of code block
472
+ inCodeBlock = true;
473
+ codeLanguage = line.slice(3).trim() || '';
474
+ codeContent = [];
475
+ } else {
476
+ // End of code block
477
+ inCodeBlock = false;
478
+ if (codeContent.length > 0) {
479
+ result.push('');
480
+ result.push(colors.accent(`${icons.code} ${codeLanguage ? codeLanguage + ' Code' : 'Code'}:`));
481
+ codeContent.forEach(line => {
482
+ result.push(colors.codeText(line));
483
+ });
484
+ result.push(colors.border(icons.separator.repeat(Math.min(40, maxWidth))));
485
+ result.push('');
486
+ }
487
+ }
488
+ continue;
489
+ }
490
+
491
+ if (inCodeBlock) {
492
+ codeContent.push(line);
493
+ continue;
494
+ }
495
+
496
+ // Process inline markdown
497
+ let processed = line;
498
+
499
+ // Headers (H1, H2, H3, H4)
500
+ if (line.startsWith('#### ')) {
501
+ processed = colors.primaryBright(line.slice(5));
502
+ } else if (line.startsWith('### ')) {
503
+ processed = colors.primaryBright(styleHelpers.text.bold(line.slice(4)));
504
+ } else if (line.startsWith('## ')) {
505
+ processed = colors.primaryBright(styleHelpers.text.bold(line.slice(3)));
506
+ } else if (line.startsWith('# ')) {
507
+ processed = colors.primaryBright(styleHelpers.text.bold(line.slice(2)));
508
+ } else {
509
+ // Inline formatting
510
+ processed = processed
511
+ // Code inline
512
+ .replace(/`([^`]+)`/g, (_, code) => colors.codeText(code))
513
+ // Bold
514
+ .replace(/\*\*([^*]+)\*\*/g, (_, text) => styleHelpers.text.bold(text))
515
+ // Italic
516
+ .replace(/\*([^*]+)\*/g, (_, text) => styleHelpers.text.italic(text))
517
+ // Strikethrough
518
+ .replace(/~~([^~]+)~~/g, (_, text) => colors.textDim(text))
519
+ // Links
520
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => colors.primaryBright(`${text}: ${styleHelpers.text.underline(url)}`));
521
+ }
522
+
523
+ result.push(processed);
524
+ }
525
+
526
+ return result.join('\n');
527
+ }
528
+
529
+ /**
530
+ * Parse a single diff line.
531
+ * Format: "+<num> content" or "-<num> content" or " <num> content"
532
+ * Also handles: "+<num>..." for skipped lines
533
+ */
534
+ function parseDiffLine(line: string): { prefix: string; lineNum: string; content: string } | null {
535
+ // Skip empty lines
536
+ if (!line || line.trim() === '') return null;
537
+
538
+ const firstChar = line[0];
539
+ if (!['+', '-', ' '].includes(firstChar)) {
540
+ // Try to detect if this is a diff-like line with different format
541
+ // e.g., "+ 1 content" (with padding)
542
+ const match = line.match(/^[+\-\s]\s*/);
543
+ if (match) {
544
+ // This looks like a diff line but with unexpected format
545
+ // Extract the content after the prefix
546
+ const afterPrefix = line.slice(match[0].length).trim();
547
+ return { prefix: firstChar, lineNum: '', content: afterPrefix };
548
+ }
549
+ return null;
550
+ }
551
+
552
+ // Extract content after the prefix char
553
+ const afterPrefix = line.slice(1).trim();
554
+
555
+ // Check for skipped lines marker
556
+ if (afterPrefix === '...') {
557
+ return { prefix: firstChar, lineNum: '', content: '...' };
558
+ }
559
+
560
+ // Return the rest as content
561
+ return { prefix: firstChar, lineNum: '', content: afterPrefix };
562
+ }
563
+
564
+ /**
565
+ * Replace tabs with spaces for consistent rendering.
566
+ */
567
+ function replaceTabs(text: string): string {
568
+ return text.replace(/\t/g, ' ');
569
+ }
570
+
571
+ /**
572
+ * Compute word-level diff and render with inverse on changed parts.
573
+ * Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.
574
+ */
575
+ function renderIntraLineDiff(oldContent: string, newContent: string): { removedLine: string; addedLine: string } {
576
+ // Simple word diff without external dependency
577
+ const oldWords = oldContent.split(/(\s+)/);
578
+ const newWords = newContent.split(/(\s+)/);
579
+
580
+ let removedLine = '';
581
+ let addedLine = '';
582
+ let i = 0, j = 0;
583
+
584
+ while (i < oldWords.length || j < newWords.length) {
585
+ const oldWord = oldWords[i] || '';
586
+ const newWord = newWords[j] || '';
587
+
588
+ if (oldWord === newWord) {
589
+ removedLine += oldWord;
590
+ addedLine += newWord;
591
+ i++;
592
+ j++;
593
+ } else if (oldWord === '' || oldWord.match(/^\s+$/)) {
594
+ addedLine += newWord;
595
+ j++;
596
+ } else if (newWord === '' || newWord.match(/^\s+$/)) {
597
+ removedLine += oldWord;
598
+ i++;
599
+ } else {
600
+ // Simple heuristic: show removed with inverse, added with inverse
601
+ removedLine += colors.diffRemovedInverse(oldWord);
602
+ addedLine += colors.diffAddedInverse(newWord);
603
+ i++;
604
+ j++;
605
+ }
606
+ }
607
+
608
+ return { removedLine, addedLine };
609
+ }
610
+
611
+ /**
612
+ * Render a diff string with colored lines and intra-line change highlighting.
613
+ * - Context lines: gray
614
+ * - Removed lines: red
615
+ * - Added lines: green
616
+ */
617
+ export function renderDiff(diffText: string): string {
618
+ if (!diffText) return '';
619
+
620
+ const lines = diffText.split('\n');
621
+ const result: string[] = [];
622
+
623
+ let i = 0;
624
+ while (i < lines.length) {
625
+ const line = lines[i];
626
+ const parsed = parseDiffLine(line);
627
+
628
+ if (!parsed) {
629
+ result.push(colors.diffContext(line));
630
+ i++;
631
+ continue;
632
+ }
633
+
634
+ if (parsed.prefix === '-') {
635
+ // Collect consecutive removed lines
636
+ const removedLines: { lineNum: string; content: string }[] = [];
637
+ while (i < lines.length) {
638
+ const p = parseDiffLine(lines[i]);
639
+ if (!p || p.prefix !== '-') break;
640
+ removedLines.push({ lineNum: p.lineNum, content: p.content });
641
+ i++;
642
+ }
643
+
644
+ // Collect consecutive added lines
645
+ const addedLines: { lineNum: string; content: string }[] = [];
646
+ while (i < lines.length) {
647
+ const p = parseDiffLine(lines[i]);
648
+ if (!p || p.prefix !== '+') break;
649
+ addedLines.push({ lineNum: p.lineNum, content: p.content });
650
+ i++;
651
+ }
652
+
653
+ // Intra-line diff for single line modification
654
+ if (removedLines.length === 1 && addedLines.length === 1) {
655
+ const removed = removedLines[0];
656
+ const added = addedLines[0];
657
+ const { removedLine, addedLine } = renderIntraLineDiff(replaceTabs(removed.content), replaceTabs(added.content));
658
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
659
+ result.push(chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(textColor)(`-${removedLine}`));
660
+ result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${addedLine}`));
661
+ } else {
662
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
663
+ for (const removed of removedLines) {
664
+ result.push(chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(textColor)(`-${replaceTabs(removed.content)}`));
665
+ }
666
+ for (const added of addedLines) {
667
+ result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${replaceTabs(added.content)}`));
668
+ }
669
+ }
670
+ } else if (parsed.prefix === '+') {
671
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
672
+ result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${replaceTabs(parsed.content)}`));
673
+ i++;
674
+ } else {
675
+ result.push(chalk.hex('#374151')(` ${replaceTabs(parsed.content)}`));
676
+ i++;
677
+ }
678
+ }
679
+
680
+ return result.join('\n');
681
+ }
682
+
683
+ /**
684
+ * Render a code preview with line numbers and syntax highlighting.
685
+ * Automatically adapts to dark/light terminal backgrounds.
686
+ */
687
+ export function renderCodePreview(content: string, options: { filePath?: string; maxLines?: number; indent?: string } = {}): string {
688
+ const { filePath = '', maxLines = 10, indent = '' } = options;
689
+ const lines = content.split('\n');
690
+ const displayLines = lines.slice(0, maxLines);
691
+ const hasMore = lines.length > maxLines;
692
+
693
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2931';
694
+ const bgColor = TERMINAL_BG === 'dark' ? '#1f2937' : '#f3f4f6';
695
+ const codeStyle = chalk.bgHex(bgColor).hex(textColor);
696
+
697
+ const lineNumWidth = String(displayLines.length).length;
698
+ const parts: string[] = [];
699
+
700
+ if (filePath) {
701
+ parts.push(`${indent}${chalk.hex(TERMINAL_BG === 'dark' ? '#22d3ee' : '#0891b2').bold(filePath)}`);
702
+ }
703
+
704
+ displayLines.forEach((line, idx) => {
705
+ const lineNum = String(idx + 1).padStart(lineNumWidth, ' ');
706
+ parts.push(`${indent} ${codeStyle(`${lineNum} │ ${line}`)}`);
707
+ });
708
+
709
+ if (hasMore) {
710
+ const dotsLine = `${indent} ${chalk.hex(TERMINAL_BG === 'dark' ? '#6b7280' : '#9ca3af').dim('...')}`;
711
+ parts.push(dotsLine);
712
+ }
713
+
714
+ return parts.join('\n');
715
+ }
716
+
717
+ /**
718
+ * Render new file content in diff-like style (without line numbers).
719
+ * Uses + prefix for added lines.
720
+ */
721
+ export function renderLines(content: string, options: { maxLines?: number; indent?: string } = {}): string {
722
+ const { maxLines = 20, indent = '' } = options;
723
+ const lines = content.split('\n').slice(0, maxLines);
724
+ const hasMore = content.split('\n').length > maxLines;
725
+
726
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
727
+ const bgColor = mixWithBackground('#10b981', 0.15, TERMINAL_BG);
728
+ const lineStyle = chalk.bgHex(bgColor).hex(textColor);
729
+
730
+ const parts: string[] = lines.map(line => `${indent}${lineStyle(`+ ${line}`)}`);
731
+
732
+ if (hasMore) {
733
+ parts.push(`${indent}${chalk.hex(TERMINAL_BG === 'dark' ? '#6b7280' : '#9ca3af').dim('...')}`);
734
+ }
735
+
736
+ return parts.join('\n');
737
+ }
738
+
739
739
  export default theme;