@xagent-ai/cli 1.2.2 → 1.3.1

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 (602) 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/release.yml +76 -0
  4. package/.github/workflows/ci.yml +75 -0
  5. package/.github/workflows/release.yml +103 -0
  6. package/.gitmodules +3 -3
  7. package/README.md +326 -280
  8. package/README_CN.md +325 -279
  9. package/dist/agents.d.ts.map +1 -1
  10. package/dist/agents.js +7 -3
  11. package/dist/agents.js.map +1 -1
  12. package/dist/ai-client/factory.d.ts +40 -0
  13. package/dist/ai-client/factory.d.ts.map +1 -0
  14. package/dist/ai-client/factory.js +100 -0
  15. package/dist/ai-client/factory.js.map +1 -0
  16. package/dist/ai-client/index.d.ts +20 -0
  17. package/dist/ai-client/index.d.ts.map +1 -0
  18. package/dist/ai-client/index.js +49 -0
  19. package/dist/ai-client/index.js.map +1 -0
  20. package/dist/ai-client/providers/anthropic.d.ts +57 -0
  21. package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
  22. package/dist/ai-client/providers/anthropic.js +406 -0
  23. package/dist/ai-client/providers/anthropic.js.map +1 -0
  24. package/dist/ai-client/providers/openai.d.ts +57 -0
  25. package/dist/ai-client/providers/openai.d.ts.map +1 -0
  26. package/dist/ai-client/providers/openai.js +290 -0
  27. package/dist/ai-client/providers/openai.js.map +1 -0
  28. package/dist/ai-client/providers/remote.d.ts +110 -0
  29. package/dist/ai-client/providers/remote.d.ts.map +1 -0
  30. package/dist/ai-client/providers/remote.js +352 -0
  31. package/dist/ai-client/providers/remote.js.map +1 -0
  32. package/dist/ai-client/registry.d.ts +51 -0
  33. package/dist/ai-client/registry.d.ts.map +1 -0
  34. package/dist/ai-client/registry.js +81 -0
  35. package/dist/ai-client/registry.js.map +1 -0
  36. package/dist/ai-client/types.d.ts +274 -0
  37. package/dist/ai-client/types.d.ts.map +1 -0
  38. package/dist/ai-client/types.js +90 -0
  39. package/dist/ai-client/types.js.map +1 -0
  40. package/dist/ai-client-factory.d.ts +62 -0
  41. package/dist/ai-client-factory.d.ts.map +1 -0
  42. package/dist/ai-client-factory.js +157 -0
  43. package/dist/ai-client-factory.js.map +1 -0
  44. package/dist/auth.d.ts +23 -1
  45. package/dist/auth.d.ts.map +1 -1
  46. package/dist/auth.js +164 -174
  47. package/dist/auth.js.map +1 -1
  48. package/dist/cancellation.d.ts +5 -4
  49. package/dist/cancellation.d.ts.map +1 -1
  50. package/dist/cancellation.js +53 -32
  51. package/dist/cancellation.js.map +1 -1
  52. package/dist/checkpoint.d.ts +2 -1
  53. package/dist/checkpoint.d.ts.map +1 -1
  54. package/dist/checkpoint.js +39 -6
  55. package/dist/checkpoint.js.map +1 -1
  56. package/dist/cli.js +742 -29
  57. package/dist/cli.js.map +1 -1
  58. package/dist/config.d.ts +10 -4
  59. package/dist/config.d.ts.map +1 -1
  60. package/dist/config.js +62 -25
  61. package/dist/config.js.map +1 -1
  62. package/dist/context-compressor.d.ts +82 -18
  63. package/dist/context-compressor.d.ts.map +1 -1
  64. package/dist/context-compressor.js +718 -154
  65. package/dist/context-compressor.js.map +1 -1
  66. package/dist/conversation.d.ts +1 -1
  67. package/dist/conversation.d.ts.map +1 -1
  68. package/dist/conversation.js +8 -7
  69. package/dist/conversation.js.map +1 -1
  70. package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
  71. package/dist/gui-subagent/action-parser/actionParser.js +6 -4
  72. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  73. package/dist/gui-subagent/agent/gui-agent.d.ts +39 -2
  74. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  75. package/dist/gui-subagent/agent/gui-agent.js +189 -74
  76. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  77. package/dist/gui-subagent/index.d.ts +23 -1
  78. package/dist/gui-subagent/index.d.ts.map +1 -1
  79. package/dist/gui-subagent/index.js +6 -0
  80. package/dist/gui-subagent/index.js.map +1 -1
  81. package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
  82. package/dist/gui-subagent/operator/base-operator.js +0 -1
  83. package/dist/gui-subagent/operator/base-operator.js.map +1 -1
  84. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  85. package/dist/gui-subagent/operator/computer-operator.js +31 -8
  86. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  87. package/dist/gui-subagent/types/actions.d.ts +1 -1
  88. package/dist/gui-subagent/types/actions.d.ts.map +1 -1
  89. package/dist/gui-subagent/types/actions.js +0 -1
  90. package/dist/gui-subagent/types/actions.js.map +1 -1
  91. package/dist/gui-subagent/types/operator.d.ts +1 -1
  92. package/dist/gui-subagent/types/operator.d.ts.map +1 -1
  93. package/dist/index.d.ts +1 -2
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -2
  96. package/dist/index.js.map +1 -1
  97. package/dist/input-processor.d.ts.map +1 -1
  98. package/dist/input-processor.js +8 -5
  99. package/dist/input-processor.js.map +1 -1
  100. package/dist/logger.d.ts.map +1 -1
  101. package/dist/logger.js +1 -1
  102. package/dist/logger.js.map +1 -1
  103. package/dist/mcp.d.ts +7 -1
  104. package/dist/mcp.d.ts.map +1 -1
  105. package/dist/mcp.js +157 -49
  106. package/dist/mcp.js.map +1 -1
  107. package/dist/memory.d.ts.map +1 -1
  108. package/dist/memory.js +3 -3
  109. package/dist/memory.js.map +1 -1
  110. package/dist/output-util.d.ts +27 -0
  111. package/dist/output-util.d.ts.map +1 -0
  112. package/dist/output-util.js +74 -0
  113. package/dist/output-util.js.map +1 -0
  114. package/dist/retry.js +1 -1
  115. package/dist/retry.js.map +1 -1
  116. package/dist/ripgrep.d.ts +29 -0
  117. package/dist/ripgrep.d.ts.map +1 -0
  118. package/dist/ripgrep.js +294 -0
  119. package/dist/ripgrep.js.map +1 -0
  120. package/dist/sdk-output-adapter.d.ts +34 -1
  121. package/dist/sdk-output-adapter.d.ts.map +1 -1
  122. package/dist/sdk-output-adapter.js +67 -2
  123. package/dist/sdk-output-adapter.js.map +1 -1
  124. package/dist/sdk-session.d.ts.map +1 -1
  125. package/dist/sdk-session.js +2 -0
  126. package/dist/sdk-session.js.map +1 -1
  127. package/dist/session-manager.js +3 -3
  128. package/dist/session-manager.js.map +1 -1
  129. package/dist/session.d.ts +116 -6
  130. package/dist/session.d.ts.map +1 -1
  131. package/dist/session.js +1416 -448
  132. package/dist/session.js.map +1 -1
  133. package/dist/shell.d.ts +33 -0
  134. package/dist/shell.d.ts.map +1 -0
  135. package/dist/shell.js +126 -0
  136. package/dist/shell.js.map +1 -0
  137. package/dist/skill-installer.d.ts +38 -0
  138. package/dist/skill-installer.d.ts.map +1 -0
  139. package/dist/skill-installer.js +447 -0
  140. package/dist/skill-installer.js.map +1 -0
  141. package/dist/skill-invoker.d.ts +8 -2
  142. package/dist/skill-invoker.d.ts.map +1 -1
  143. package/dist/skill-invoker.js +36 -15
  144. package/dist/skill-invoker.js.map +1 -1
  145. package/dist/skill-loader.d.ts +8 -3
  146. package/dist/skill-loader.d.ts.map +1 -1
  147. package/dist/skill-loader.js +51 -48
  148. package/dist/skill-loader.js.map +1 -1
  149. package/dist/skill-manager.d.ts +85 -0
  150. package/dist/skill-manager.d.ts.map +1 -0
  151. package/dist/skill-manager.js +341 -0
  152. package/dist/skill-manager.js.map +1 -0
  153. package/dist/slash-commands.d.ts +39 -2
  154. package/dist/slash-commands.d.ts.map +1 -1
  155. package/dist/slash-commands.js +934 -305
  156. package/dist/slash-commands.js.map +1 -1
  157. package/dist/smart-approval.d.ts +20 -1
  158. package/dist/smart-approval.d.ts.map +1 -1
  159. package/dist/smart-approval.js +125 -56
  160. package/dist/smart-approval.js.map +1 -1
  161. package/dist/system-prompt-generator.d.ts +6 -0
  162. package/dist/system-prompt-generator.d.ts.map +1 -1
  163. package/dist/system-prompt-generator.js +86 -36
  164. package/dist/system-prompt-generator.js.map +1 -1
  165. package/dist/terminal.d.ts +28 -0
  166. package/dist/terminal.d.ts.map +1 -0
  167. package/dist/terminal.js +82 -0
  168. package/dist/terminal.js.map +1 -0
  169. package/dist/theme.d.ts.map +1 -1
  170. package/dist/theme.js +8 -7
  171. package/dist/theme.js.map +1 -1
  172. package/dist/tools.d.ts +38 -7
  173. package/dist/tools.d.ts.map +1 -1
  174. package/dist/tools.js +1249 -617
  175. package/dist/tools.js.map +1 -1
  176. package/dist/truncate.d.ts +55 -0
  177. package/dist/truncate.d.ts.map +1 -0
  178. package/dist/truncate.js +130 -0
  179. package/dist/truncate.js.map +1 -0
  180. package/dist/types.d.ts +84 -9
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/types.js +49 -0
  183. package/dist/types.js.map +1 -1
  184. package/dist/update.d.ts.map +1 -1
  185. package/dist/update.js +28 -36
  186. package/dist/update.js.map +1 -1
  187. package/dist/workflow.d.ts +5 -1
  188. package/dist/workflow.d.ts.map +1 -1
  189. package/dist/workflow.js +61 -49
  190. package/dist/workflow.js.map +1 -1
  191. package/docs/architecture/mcp-integration-guide.md +304 -194
  192. package/docs/architecture/overview.md +169 -169
  193. package/docs/architecture/tool-system-design.md +134 -134
  194. package/docs/cli/commands.md +349 -238
  195. package/docs/smart-mode.md +281 -281
  196. package/docs/third-party-models.md +440 -439
  197. package/find-skills/SKILL.md +133 -0
  198. package/package.json +91 -90
  199. package/scripts/install-ripgrep.js +241 -0
  200. package/src/agents.ts +7 -3
  201. package/src/ai-client/factory.ts +116 -0
  202. package/src/ai-client/index.ts +61 -0
  203. package/src/ai-client/providers/anthropic.ts +475 -0
  204. package/src/ai-client/providers/openai.ts +348 -0
  205. package/src/ai-client/providers/remote.ts +439 -0
  206. package/src/ai-client/registry.ts +97 -0
  207. package/src/ai-client/types.ts +364 -0
  208. package/src/ai-client-factory.ts +204 -0
  209. package/src/auth.ts +661 -614
  210. package/src/cancellation.ts +202 -176
  211. package/src/checkpoint.ts +255 -219
  212. package/src/cli.ts +1523 -743
  213. package/src/config.ts +341 -297
  214. package/src/context-compressor.ts +987 -290
  215. package/src/conversation.ts +290 -288
  216. package/src/gui-subagent/action-parser/actionParser.ts +318 -315
  217. package/src/gui-subagent/action-parser/constants.ts +14 -14
  218. package/src/gui-subagent/action-parser/index.ts +8 -8
  219. package/src/gui-subagent/action-parser/types.ts +31 -31
  220. package/src/gui-subagent/agent/gui-agent.ts +1234 -1089
  221. package/src/gui-subagent/agent/index.ts +5 -5
  222. package/src/gui-subagent/index.ts +185 -163
  223. package/src/gui-subagent/operator/base-operator.ts +244 -245
  224. package/src/gui-subagent/operator/computer-operator.ts +541 -520
  225. package/src/gui-subagent/operator/index.ts +6 -6
  226. package/src/gui-subagent/types/actions.ts +260 -262
  227. package/src/gui-subagent/types/index.ts +6 -6
  228. package/src/gui-subagent/types/operator.ts +106 -106
  229. package/src/gui-subagent/utils.ts +51 -51
  230. package/src/index.ts +17 -18
  231. package/src/input-processor.ts +8 -5
  232. package/src/logger.ts +436 -438
  233. package/src/mcp.ts +793 -682
  234. package/src/memory.ts +343 -344
  235. package/src/output-util.ts +80 -0
  236. package/src/retry.ts +1 -1
  237. package/src/ripgrep.ts +370 -0
  238. package/src/sdk-output-adapter.ts +842 -0
  239. package/src/sdk-session.ts +62 -0
  240. package/src/session-manager.ts +308 -308
  241. package/src/session.ts +1775 -573
  242. package/src/shell.ts +134 -0
  243. package/src/skill-installer.ts +518 -0
  244. package/src/skill-invoker.ts +959 -935
  245. package/src/skill-loader.ts +501 -496
  246. package/src/skill-manager.ts +385 -0
  247. package/src/slash-commands.ts +2189 -1389
  248. package/src/smart-approval.ts +193 -74
  249. package/src/system-prompt-generator.ts +91 -36
  250. package/src/terminal.ts +96 -0
  251. package/src/theme.ts +739 -738
  252. package/src/tools.ts +1790 -931
  253. package/src/truncate.ts +173 -0
  254. package/src/types.ts +337 -198
  255. package/src/update.ts +33 -40
  256. package/src/workflow.ts +521 -508
  257. package/test/cli-launch.test.ts +279 -0
  258. package/tsconfig.json +22 -22
  259. package/vitest.config.ts +21 -19
  260. package/dist/ai-client.d.ts +0 -86
  261. package/dist/ai-client.d.ts.map +0 -1
  262. package/dist/ai-client.js +0 -1372
  263. package/dist/ai-client.js.map +0 -1
  264. package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
  265. package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
  266. package/dist/gui-subagent/operator/browser-operator.js +0 -306
  267. package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
  268. package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
  269. package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
  270. package/dist/gui-subagent/operator/desktop-operator.js +0 -527
  271. package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
  272. package/dist/hook.d.ts +0 -73
  273. package/dist/hook.d.ts.map +0 -1
  274. package/dist/hook.js +0 -156
  275. package/dist/hook.js.map +0 -1
  276. package/dist/input-history.d.ts +0 -24
  277. package/dist/input-history.d.ts.map +0 -1
  278. package/dist/input-history.js +0 -94
  279. package/dist/input-history.js.map +0 -1
  280. package/dist/keyboard-manager.d.ts +0 -151
  281. package/dist/keyboard-manager.d.ts.map +0 -1
  282. package/dist/keyboard-manager.js +0 -396
  283. package/dist/keyboard-manager.js.map +0 -1
  284. package/dist/print-system-prompt.d.ts +0 -2
  285. package/dist/print-system-prompt.d.ts.map +0 -1
  286. package/dist/print-system-prompt.js +0 -40
  287. package/dist/print-system-prompt.js.map +0 -1
  288. package/dist/remote-ai-client.d.ts +0 -104
  289. package/dist/remote-ai-client.d.ts.map +0 -1
  290. package/dist/remote-ai-client.js +0 -552
  291. package/dist/remote-ai-client.js.map +0 -1
  292. package/dist/sdk-session-v2.d.ts +0 -13
  293. package/dist/sdk-session-v2.d.ts.map +0 -1
  294. package/dist/sdk-session-v2.js +0 -46
  295. package/dist/sdk-session-v2.js.map +0 -1
  296. package/dist/test-boundary-conditions.d.ts.map +0 -1
  297. package/dist/test-boundary-conditions.js.map +0 -1
  298. package/dist/test-cancellation-fix.d.ts.map +0 -1
  299. package/dist/test-cancellation-fix.js.map +0 -1
  300. package/dist/test-input-history.d.ts.map +0 -1
  301. package/dist/test-input-history.js.map +0 -1
  302. package/dist/test-interaction-flow.d.ts.map +0 -1
  303. package/dist/test-interaction-flow.js.map +0 -1
  304. package/dist/test-quick.d.ts.map +0 -1
  305. package/dist/test-quick.js.map +0 -1
  306. package/dist/test-user-interaction.d.ts.map +0 -1
  307. package/dist/test-user-interaction.js.map +0 -1
  308. package/dist/tools/edit-diff.d.ts +0 -32
  309. package/dist/tools/edit-diff.d.ts.map +0 -1
  310. package/dist/tools/edit-diff.js +0 -185
  311. package/dist/tools/edit-diff.js.map +0 -1
  312. package/dist/tools/edit.d.ts +0 -11
  313. package/dist/tools/edit.d.ts.map +0 -1
  314. package/dist/tools/edit.js +0 -129
  315. package/dist/tools/edit.js.map +0 -1
  316. package/dist/unified-session.d.ts +0 -42
  317. package/dist/unified-session.d.ts.map +0 -1
  318. package/dist/unified-session.js +0 -271
  319. package/dist/unified-session.js.map +0 -1
  320. package/skills/.claude-plugin/marketplace.json +0 -45
  321. package/skills/README.md +0 -94
  322. package/skills/THIRD_PARTY_NOTICES.md +0 -405
  323. package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
  324. package/skills/skills/algorithmic-art/SKILL.md +0 -405
  325. package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
  326. package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
  327. package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
  328. package/skills/skills/brand-guidelines/SKILL.md +0 -73
  329. package/skills/skills/canvas-design/LICENSE.txt +0 -202
  330. package/skills/skills/canvas-design/SKILL.md +0 -130
  331. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  332. package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  333. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  334. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  335. package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  336. package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  337. package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  338. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  339. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  340. package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  341. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  342. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  343. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  344. package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  345. package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  346. package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  347. package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  348. package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  349. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  350. package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  351. package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  352. package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  353. package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  354. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  355. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  356. package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  357. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  358. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  359. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  360. package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  361. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  362. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  363. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  364. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  365. package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  366. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  367. package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  368. package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  369. package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  370. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  371. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  372. package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  373. package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  374. package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  375. package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  376. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  377. package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  378. package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  379. package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  380. package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  381. package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  382. package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  383. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  384. package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  385. package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  386. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  387. package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  388. package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  389. package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  390. package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  391. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  392. package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  393. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  394. package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  395. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  396. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  397. package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  398. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  399. package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  400. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  401. package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  402. package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  403. package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  404. package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  405. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  406. package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  407. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  408. package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  409. package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  410. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  411. package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  412. package/skills/skills/doc-coauthoring/SKILL.md +0 -375
  413. package/skills/skills/docx/LICENSE.txt +0 -30
  414. package/skills/skills/docx/SKILL.md +0 -197
  415. package/skills/skills/docx/docx-js.md +0 -350
  416. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  417. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  418. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  419. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  420. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  421. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  422. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  423. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  424. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  425. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  426. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  427. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  428. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  429. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  430. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  431. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  432. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  433. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  434. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  435. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  436. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  437. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  438. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  439. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  440. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  441. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  442. package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  443. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  444. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  445. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  446. package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  447. package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  448. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  449. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  450. package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  451. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  452. package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  453. package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  454. package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  455. package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
  456. package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
  457. package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
  458. package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  459. package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
  460. package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  461. package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  462. package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  463. package/skills/skills/docx/ooxml.md +0 -610
  464. package/skills/skills/docx/scripts/__init__.py +0 -1
  465. package/skills/skills/docx/scripts/document.py +0 -1276
  466. package/skills/skills/docx/scripts/templates/comments.xml +0 -3
  467. package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  468. package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  469. package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
  470. package/skills/skills/docx/scripts/templates/people.xml +0 -3
  471. package/skills/skills/docx/scripts/utilities.py +0 -374
  472. package/skills/skills/frontend-design/LICENSE.txt +0 -177
  473. package/skills/skills/frontend-design/SKILL.md +0 -42
  474. package/skills/skills/internal-comms/LICENSE.txt +0 -202
  475. package/skills/skills/internal-comms/SKILL.md +0 -32
  476. package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
  477. package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
  478. package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
  479. package/skills/skills/internal-comms/examples/general-comms.md +0 -16
  480. package/skills/skills/mcp-builder/LICENSE.txt +0 -202
  481. package/skills/skills/mcp-builder/SKILL.md +0 -236
  482. package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
  483. package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
  484. package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
  485. package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
  486. package/skills/skills/mcp-builder/scripts/connections.py +0 -151
  487. package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
  488. package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
  489. package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
  490. package/skills/skills/pdf/LICENSE.txt +0 -30
  491. package/skills/skills/pdf/SKILL.md +0 -294
  492. package/skills/skills/pdf/forms.md +0 -205
  493. package/skills/skills/pdf/reference.md +0 -612
  494. package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  495. package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  496. package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
  497. package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  498. package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
  499. package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
  500. package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  501. package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  502. package/skills/skills/pptx/LICENSE.txt +0 -30
  503. package/skills/skills/pptx/SKILL.md +0 -484
  504. package/skills/skills/pptx/html2pptx.md +0 -625
  505. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  506. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  507. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  508. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  509. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  510. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  511. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  512. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  513. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  514. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  515. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  516. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  517. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  518. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  519. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  520. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  521. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  522. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  523. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  524. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  525. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  526. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  527. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  528. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  529. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  530. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  531. package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  532. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  533. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  534. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  535. package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  536. package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
  537. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  538. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  539. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  540. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  541. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  542. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  543. package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  544. package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
  545. package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
  546. package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
  547. package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
  548. package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
  549. package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
  550. package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
  551. package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
  552. package/skills/skills/pptx/ooxml.md +0 -427
  553. package/skills/skills/pptx/scripts/html2pptx.js +0 -979
  554. package/skills/skills/pptx/scripts/inventory.py +0 -1020
  555. package/skills/skills/pptx/scripts/rearrange.py +0 -231
  556. package/skills/skills/pptx/scripts/replace.py +0 -385
  557. package/skills/skills/pptx/scripts/thumbnail.py +0 -450
  558. package/skills/skills/skill-creator/LICENSE.txt +0 -202
  559. package/skills/skills/skill-creator/SKILL.md +0 -356
  560. package/skills/skills/skill-creator/references/output-patterns.md +0 -82
  561. package/skills/skills/skill-creator/references/workflows.md +0 -28
  562. package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
  563. package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
  564. package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
  565. package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
  566. package/skills/skills/slack-gif-creator/SKILL.md +0 -254
  567. package/skills/skills/slack-gif-creator/core/easing.py +0 -234
  568. package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
  569. package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
  570. package/skills/skills/slack-gif-creator/core/validators.py +0 -136
  571. package/skills/skills/slack-gif-creator/requirements.txt +0 -4
  572. package/skills/skills/theme-factory/LICENSE.txt +0 -202
  573. package/skills/skills/theme-factory/SKILL.md +0 -59
  574. package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
  575. package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
  576. package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
  577. package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
  578. package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
  579. package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
  580. package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
  581. package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
  582. package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
  583. package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
  584. package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
  585. package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
  586. package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
  587. package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
  588. package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
  589. package/skills/skills/webapp-testing/LICENSE.txt +0 -202
  590. package/skills/skills/webapp-testing/SKILL.md +0 -96
  591. package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
  592. package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
  593. package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
  594. package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
  595. package/skills/skills/xlsx/LICENSE.txt +0 -30
  596. package/skills/skills/xlsx/SKILL.md +0 -289
  597. package/skills/skills/xlsx/recalc.py +0 -178
  598. package/skills/spec/agent-skills-spec.md +0 -3
  599. package/skills/template/SKILL.md +0 -6
  600. package/src/ai-client.ts +0 -1560
  601. package/src/remote-ai-client.ts +0 -664
  602. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
package/src/theme.ts CHANGED
@@ -1,739 +1,740 @@
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
+ const lines: string[] = [];
288
+
289
+ if (title) {
290
+ const titleContent = ` ${title} `;
291
+ const paddingNeeded = availableWidth - titleContent.length;
292
+ const leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
293
+ const 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
+ const lines: string[] = [];
318
+
319
+ if (title) {
320
+ const titleContent = ` ${title} `;
321
+ const paddingNeeded = availableWidth - titleContent.length;
322
+ const leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
323
+ const 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
+ // eslint-disable-next-line no-control-regex
368
+ const headerContentLength = headerContent.replace(/\x1b\[[0-9;]*m/g, '').length;
369
+ const headerFillLength = Math.max(0, availableWidth - 3 - headerContentLength);
370
+ const headerLine = `${indent}${accentColor(chars.topLeft)}${accentColor('─── ')}${headerContent} ${accentColor('─'.repeat(headerFillLength))}${accentColor(chars.topRight)}`;
371
+
372
+ const contentLines = content.split('\n');
373
+ const maxContentWidth = width - 4;
374
+ const middleLines = contentLines.map(line => {
375
+ const lineLength = line.length;
376
+ if (lineLength <= maxContentWidth) {
377
+ const paddingLength = Math.max(0, width - lineLength - 4);
378
+ return `${indent}${chars.vertical} ${contentColor(line)}${' '.repeat(paddingLength)}${chars.vertical}`;
379
+ }
380
+ const wrappedLines: string[] = [];
381
+ let remaining = line;
382
+ while (remaining.length > maxContentWidth) {
383
+ wrappedLines.push(`${indent}${chars.vertical} ${contentColor(remaining.substring(0, maxContentWidth - 3))}...${chars.vertical}`);
384
+ remaining = '... ' + remaining.substring(maxContentWidth - 3);
385
+ }
386
+ const remainingLength = remaining.length;
387
+ const remainingPadding = Math.max(0, width - remainingLength - 4);
388
+ wrappedLines.push(`${indent}${chars.vertical} ${contentColor(remaining)}${' '.repeat(remainingPadding)}${chars.vertical}`);
389
+ return wrappedLines.join('\n');
390
+ });
391
+
392
+ const bottomLine = `${indent}${accentColor(chars.bottomLeft)}${accentColor('─'.repeat(width - 2))}${accentColor(chars.bottomRight)}`;
393
+
394
+ return [headerLine, ...middleLines, bottomLine].join('\n');
395
+ }
396
+ }
397
+ };
398
+
399
+ /**
400
+ * Theme configuration
401
+ */
402
+ export const theme = {
403
+ colors,
404
+ icons,
405
+ styles: styleHelpers,
406
+
407
+ // Predefined style combinations
408
+ predefinedStyles: {
409
+ // Title styles
410
+ title: (text: string) => styleHelpers.text.bold(colors.primary(text)),
411
+ subtitle: (text: string) => colors.infoBright(text),
412
+ section: (text: string) => styleHelpers.text.bold(colors.primaryBright(text)),
413
+
414
+ // Status styles
415
+ success: (text: string) => colors.success(`${icons.success} ${text}`),
416
+ error: (text: string) => colors.error(`${icons.error} ${text}`),
417
+ warning: (text: string) => colors.warning(`${icons.warning} ${text}`),
418
+ info: (text: string) => colors.info(`${icons.info} ${text}`),
419
+ debug: (text: string) => colors.debug(`${icons.debug} ${text}`),
420
+
421
+ // Code styles
422
+ code: (text: string) => colors.codeBackground(` ${text} `),
423
+ inlineCode: (text: string) => colors.codeText(`\`${text}\``),
424
+
425
+ // Link styles
426
+ link: (text: string, url: string) => colors.primaryBright(`${text}: ${styleHelpers.text.underline(url)}`),
427
+
428
+ // Emphasis styles
429
+ highlight: (text: string) => colors.highlight(text),
430
+ accent: (text: string) => colors.accent(text),
431
+ muted: (text: string) => colors.textMuted(text),
432
+ dim: (text: string) => colors.textDim(text),
433
+
434
+ // Separators
435
+ separator: (width: number) => colors.border(icons.separator.repeat(width)),
436
+ separatorDouble: (width: number) => colors.border(icons.separatorDouble.repeat(width)),
437
+ separatorDashed: (width: number) => colors.border(icons.separatorDashed.repeat(width)),
438
+
439
+ // Progress bar
440
+ progressBar: (current: number, total: number, width: number = 30) => {
441
+ const percentage = Math.round((current / total) * 100);
442
+ const filled = Math.round((current / total) * width);
443
+ const empty = width - filled;
444
+
445
+ const filledBar = colors.success(icons.square.repeat(filled));
446
+ const emptyBar = colors.border(icons.square.repeat(empty));
447
+
448
+ return `${filledBar}${emptyBar} ${percentage}%`;
449
+ }
450
+ }
451
+ };
452
+
453
+ /**
454
+ * Simple markdown renderer for terminal output
455
+ */
456
+ export function renderMarkdown(text: string, maxWidth: number = 80): string {
457
+ if (!text) return '';
458
+
459
+ const lines = text.split('\n');
460
+ const result: string[] = [];
461
+
462
+ let inCodeBlock = false;
463
+ let codeLanguage = '';
464
+ let codeContent: string[] = [];
465
+
466
+ for (let i = 0; i < lines.length; i++) {
467
+ const line = lines[i];
468
+
469
+ // Check for code block start/end
470
+ if (line.startsWith('```')) {
471
+ if (!inCodeBlock) {
472
+ // Start of code block
473
+ inCodeBlock = true;
474
+ codeLanguage = line.slice(3).trim() || '';
475
+ codeContent = [];
476
+ } else {
477
+ // End of code block
478
+ inCodeBlock = false;
479
+ if (codeContent.length > 0) {
480
+ result.push('');
481
+ result.push(colors.accent(`${icons.code} ${codeLanguage ? codeLanguage + ' Code' : 'Code'}:`));
482
+ codeContent.forEach(line => {
483
+ result.push(colors.codeText(line));
484
+ });
485
+ result.push(colors.border(icons.separator.repeat(Math.min(40, maxWidth))));
486
+ result.push('');
487
+ }
488
+ }
489
+ continue;
490
+ }
491
+
492
+ if (inCodeBlock) {
493
+ codeContent.push(line);
494
+ continue;
495
+ }
496
+
497
+ // Process inline markdown
498
+ let processed = line;
499
+
500
+ // Headers (H1, H2, H3, H4)
501
+ if (line.startsWith('#### ')) {
502
+ processed = colors.primaryBright(line.slice(5));
503
+ } else if (line.startsWith('### ')) {
504
+ processed = colors.primaryBright(styleHelpers.text.bold(line.slice(4)));
505
+ } else if (line.startsWith('## ')) {
506
+ processed = colors.primaryBright(styleHelpers.text.bold(line.slice(3)));
507
+ } else if (line.startsWith('# ')) {
508
+ processed = colors.primaryBright(styleHelpers.text.bold(line.slice(2)));
509
+ } else {
510
+ // Inline formatting
511
+ processed = processed
512
+ // Code inline
513
+ .replace(/`([^`]+)`/g, (_, code) => colors.codeText(code))
514
+ // Bold
515
+ .replace(/\*\*([^*]+)\*\*/g, (_, text) => styleHelpers.text.bold(text))
516
+ // Italic
517
+ .replace(/\*([^*]+)\*/g, (_, text) => styleHelpers.text.italic(text))
518
+ // Strikethrough
519
+ .replace(/~~([^~]+)~~/g, (_, text) => colors.textDim(text))
520
+ // Links
521
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, text, url) => colors.primaryBright(`${text}: ${styleHelpers.text.underline(url)}`));
522
+ }
523
+
524
+ result.push(processed);
525
+ }
526
+
527
+ return result.join('\n');
528
+ }
529
+
530
+ /**
531
+ * Parse a single diff line.
532
+ * Format: "+<num> content" or "-<num> content" or " <num> content"
533
+ * Also handles: "+<num>..." for skipped lines
534
+ */
535
+ function parseDiffLine(line: string): { prefix: string; lineNum: string; content: string } | null {
536
+ // Skip empty lines
537
+ if (!line || line.trim() === '') return null;
538
+
539
+ const firstChar = line[0];
540
+ if (!['+', '-', ' '].includes(firstChar)) {
541
+ // Try to detect if this is a diff-like line with different format
542
+ // e.g., "+ 1 content" (with padding)
543
+ const match = line.match(/^[+\-\s]\s*/);
544
+ if (match) {
545
+ // This looks like a diff line but with unexpected format
546
+ // Extract the content after the prefix
547
+ const afterPrefix = line.slice(match[0].length).trim();
548
+ return { prefix: firstChar, lineNum: '', content: afterPrefix };
549
+ }
550
+ return null;
551
+ }
552
+
553
+ // Extract content after the prefix char
554
+ const afterPrefix = line.slice(1).trim();
555
+
556
+ // Check for skipped lines marker
557
+ if (afterPrefix === '...') {
558
+ return { prefix: firstChar, lineNum: '', content: '...' };
559
+ }
560
+
561
+ // Return the rest as content
562
+ return { prefix: firstChar, lineNum: '', content: afterPrefix };
563
+ }
564
+
565
+ /**
566
+ * Replace tabs with spaces for consistent rendering.
567
+ */
568
+ function replaceTabs(text: string): string {
569
+ return text.replace(/\t/g, ' ');
570
+ }
571
+
572
+ /**
573
+ * Compute word-level diff and render with inverse on changed parts.
574
+ * Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.
575
+ */
576
+ function renderIntraLineDiff(oldContent: string, newContent: string): { removedLine: string; addedLine: string } {
577
+ // Simple word diff without external dependency
578
+ const oldWords = oldContent.split(/(\s+)/);
579
+ const newWords = newContent.split(/(\s+)/);
580
+
581
+ let removedLine = '';
582
+ let addedLine = '';
583
+ let i = 0, j = 0;
584
+
585
+ while (i < oldWords.length || j < newWords.length) {
586
+ const oldWord = oldWords[i] || '';
587
+ const newWord = newWords[j] || '';
588
+
589
+ if (oldWord === newWord) {
590
+ removedLine += oldWord;
591
+ addedLine += newWord;
592
+ i++;
593
+ j++;
594
+ } else if (oldWord === '' || oldWord.match(/^\s+$/)) {
595
+ addedLine += newWord;
596
+ j++;
597
+ } else if (newWord === '' || newWord.match(/^\s+$/)) {
598
+ removedLine += oldWord;
599
+ i++;
600
+ } else {
601
+ // Simple heuristic: show removed with inverse, added with inverse
602
+ removedLine += colors.diffRemovedInverse(oldWord);
603
+ addedLine += colors.diffAddedInverse(newWord);
604
+ i++;
605
+ j++;
606
+ }
607
+ }
608
+
609
+ return { removedLine, addedLine };
610
+ }
611
+
612
+ /**
613
+ * Render a diff string with colored lines and intra-line change highlighting.
614
+ * - Context lines: gray
615
+ * - Removed lines: red
616
+ * - Added lines: green
617
+ */
618
+ export function renderDiff(diffText: string): string {
619
+ if (!diffText) return '';
620
+
621
+ const lines = diffText.split('\n');
622
+ const result: string[] = [];
623
+
624
+ let i = 0;
625
+ while (i < lines.length) {
626
+ const line = lines[i];
627
+ const parsed = parseDiffLine(line);
628
+
629
+ if (!parsed) {
630
+ result.push(colors.diffContext(line));
631
+ i++;
632
+ continue;
633
+ }
634
+
635
+ if (parsed.prefix === '-') {
636
+ // Collect consecutive removed lines
637
+ const removedLines: { lineNum: string; content: string }[] = [];
638
+ while (i < lines.length) {
639
+ const p = parseDiffLine(lines[i]);
640
+ if (!p || p.prefix !== '-') break;
641
+ removedLines.push({ lineNum: p.lineNum, content: p.content });
642
+ i++;
643
+ }
644
+
645
+ // Collect consecutive added lines
646
+ const addedLines: { lineNum: string; content: string }[] = [];
647
+ while (i < lines.length) {
648
+ const p = parseDiffLine(lines[i]);
649
+ if (!p || p.prefix !== '+') break;
650
+ addedLines.push({ lineNum: p.lineNum, content: p.content });
651
+ i++;
652
+ }
653
+
654
+ // Intra-line diff for single line modification
655
+ if (removedLines.length === 1 && addedLines.length === 1) {
656
+ const removed = removedLines[0];
657
+ const added = addedLines[0];
658
+ const { removedLine, addedLine } = renderIntraLineDiff(replaceTabs(removed.content), replaceTabs(added.content));
659
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
660
+ result.push(chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(textColor)(`-${removedLine}`));
661
+ result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${addedLine}`));
662
+ } else {
663
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
664
+ for (const removed of removedLines) {
665
+ result.push(chalk.bgHex(mixWithBackground('#ef4444', 0.25, TERMINAL_BG)).hex(textColor)(`-${replaceTabs(removed.content)}`));
666
+ }
667
+ for (const added of addedLines) {
668
+ result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${replaceTabs(added.content)}`));
669
+ }
670
+ }
671
+ } else if (parsed.prefix === '+') {
672
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
673
+ result.push(chalk.bgHex(mixWithBackground('#10b981', 0.25, TERMINAL_BG)).hex(textColor)(`+${replaceTabs(parsed.content)}`));
674
+ i++;
675
+ } else {
676
+ result.push(chalk.hex('#374151')(` ${replaceTabs(parsed.content)}`));
677
+ i++;
678
+ }
679
+ }
680
+
681
+ return result.join('\n');
682
+ }
683
+
684
+ /**
685
+ * Render a code preview with line numbers and syntax highlighting.
686
+ * Automatically adapts to dark/light terminal backgrounds.
687
+ */
688
+ export function renderCodePreview(content: string, options: { filePath?: string; maxLines?: number; indent?: string } = {}): string {
689
+ const { filePath = '', maxLines = 10, indent = '' } = options;
690
+ const lines = content.split('\n');
691
+ const displayLines = lines.slice(0, maxLines);
692
+ const hasMore = lines.length > maxLines;
693
+
694
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2931';
695
+ const bgColor = TERMINAL_BG === 'dark' ? '#1f2937' : '#f3f4f6';
696
+ const codeStyle = chalk.bgHex(bgColor).hex(textColor);
697
+
698
+ const lineNumWidth = String(displayLines.length).length;
699
+ const parts: string[] = [];
700
+
701
+ if (filePath) {
702
+ parts.push(`${indent}${chalk.hex(TERMINAL_BG === 'dark' ? '#22d3ee' : '#0891b2').bold(filePath)}`);
703
+ }
704
+
705
+ displayLines.forEach((line, idx) => {
706
+ const lineNum = String(idx + 1).padStart(lineNumWidth, ' ');
707
+ parts.push(`${indent} ${codeStyle(`${lineNum} │ ${line}`)}`);
708
+ });
709
+
710
+ if (hasMore) {
711
+ const dotsLine = `${indent} ${chalk.hex(TERMINAL_BG === 'dark' ? '#6b7280' : '#9ca3af').dim('...')}`;
712
+ parts.push(dotsLine);
713
+ }
714
+
715
+ return parts.join('\n');
716
+ }
717
+
718
+ /**
719
+ * Render new file content in diff-like style (without line numbers).
720
+ * Uses + prefix for added lines.
721
+ */
722
+ export function renderLines(content: string, options: { maxLines?: number; indent?: string } = {}): string {
723
+ const { maxLines = 20, indent = '' } = options;
724
+ const lines = content.split('\n').slice(0, maxLines);
725
+ const hasMore = content.split('\n').length > maxLines;
726
+
727
+ const textColor = TERMINAL_BG === 'dark' ? '#e5e7eb' : '#1f2937';
728
+ const bgColor = mixWithBackground('#10b981', 0.15, TERMINAL_BG);
729
+ const lineStyle = chalk.bgHex(bgColor).hex(textColor);
730
+
731
+ const parts: string[] = lines.map(line => `${indent}${lineStyle(`+ ${line}`)}`);
732
+
733
+ if (hasMore) {
734
+ parts.push(`${indent}${chalk.hex(TERMINAL_BG === 'dark' ? '#6b7280' : '#9ca3af').dim('...')}`);
735
+ }
736
+
737
+ return parts.join('\n');
738
+ }
739
+
739
740
  export default theme;