shortcutxl 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. package/README.md +59 -0
  2. package/agent-docs/README.md +397 -0
  3. package/agent-docs/docs/compaction.md +390 -0
  4. package/agent-docs/docs/custom-provider.md +580 -0
  5. package/agent-docs/docs/development.md +69 -0
  6. package/agent-docs/docs/extensions.md +1971 -0
  7. package/agent-docs/docs/json.md +79 -0
  8. package/agent-docs/docs/keybindings.md +174 -0
  9. package/agent-docs/docs/models.md +293 -0
  10. package/agent-docs/docs/packages.md +209 -0
  11. package/agent-docs/docs/prompt-templates.md +67 -0
  12. package/agent-docs/docs/providers.md +186 -0
  13. package/agent-docs/docs/rpc.md +1317 -0
  14. package/agent-docs/docs/sdk.md +962 -0
  15. package/agent-docs/docs/session.md +412 -0
  16. package/agent-docs/docs/settings.md +223 -0
  17. package/agent-docs/docs/shell-aliases.md +13 -0
  18. package/agent-docs/docs/skills.md +231 -0
  19. package/agent-docs/docs/terminal-setup.md +70 -0
  20. package/agent-docs/docs/termux.md +127 -0
  21. package/agent-docs/docs/themes.md +295 -0
  22. package/agent-docs/docs/tree.md +219 -0
  23. package/agent-docs/docs/tui.md +887 -0
  24. package/agent-docs/docs/windows.md +17 -0
  25. package/agent-docs/examples/README.md +25 -0
  26. package/agent-docs/examples/extensions/README.md +205 -0
  27. package/agent-docs/examples/extensions/antigravity-image-gen.ts +447 -0
  28. package/agent-docs/examples/extensions/auto-commit-on-exit.ts +49 -0
  29. package/agent-docs/examples/extensions/bash-spawn-hook.ts +30 -0
  30. package/agent-docs/examples/extensions/bookmark.ts +50 -0
  31. package/agent-docs/examples/extensions/built-in-tool-renderer.ts +256 -0
  32. package/agent-docs/examples/extensions/claude-rules.ts +86 -0
  33. package/agent-docs/examples/extensions/commands.ts +75 -0
  34. package/agent-docs/examples/extensions/confirm-destructive.ts +59 -0
  35. package/agent-docs/examples/extensions/custom-compaction.ts +126 -0
  36. package/agent-docs/examples/extensions/custom-footer.ts +63 -0
  37. package/agent-docs/examples/extensions/custom-header.ts +73 -0
  38. package/agent-docs/examples/extensions/custom-provider-anthropic/index.ts +660 -0
  39. package/agent-docs/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  40. package/agent-docs/examples/extensions/custom-provider-anthropic/package.json +19 -0
  41. package/agent-docs/examples/extensions/custom-provider-gitlab-duo/index.ts +362 -0
  42. package/agent-docs/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  43. package/agent-docs/examples/extensions/custom-provider-gitlab-duo/test.ts +88 -0
  44. package/agent-docs/examples/extensions/custom-provider-qwen-cli/index.ts +349 -0
  45. package/agent-docs/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
  46. package/agent-docs/examples/extensions/dirty-repo-guard.ts +56 -0
  47. package/agent-docs/examples/extensions/doom-overlay/README.md +46 -0
  48. package/agent-docs/examples/extensions/doom-overlay/doom/build.sh +152 -0
  49. package/agent-docs/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  50. package/agent-docs/examples/extensions/doom-overlay/doom-component.ts +133 -0
  51. package/agent-docs/examples/extensions/doom-overlay/doom-engine.ts +186 -0
  52. package/agent-docs/examples/extensions/doom-overlay/doom-keys.ts +108 -0
  53. package/agent-docs/examples/extensions/doom-overlay/index.ts +74 -0
  54. package/agent-docs/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  55. package/agent-docs/examples/extensions/dynamic-resources/SKILL.md +8 -0
  56. package/agent-docs/examples/extensions/dynamic-resources/dynamic.json +79 -0
  57. package/agent-docs/examples/extensions/dynamic-resources/dynamic.md +5 -0
  58. package/agent-docs/examples/extensions/dynamic-resources/index.ts +15 -0
  59. package/agent-docs/examples/extensions/dynamic-tools.ts +77 -0
  60. package/agent-docs/examples/extensions/event-bus.ts +43 -0
  61. package/agent-docs/examples/extensions/file-trigger.ts +41 -0
  62. package/agent-docs/examples/extensions/git-checkpoint.ts +53 -0
  63. package/agent-docs/examples/extensions/handoff.ts +155 -0
  64. package/agent-docs/examples/extensions/hello.ts +25 -0
  65. package/agent-docs/examples/extensions/inline-bash.ts +94 -0
  66. package/agent-docs/examples/extensions/input-transform.ts +43 -0
  67. package/agent-docs/examples/extensions/interactive-shell.ts +209 -0
  68. package/agent-docs/examples/extensions/mac-system-theme.ts +47 -0
  69. package/agent-docs/examples/extensions/message-renderer.ts +59 -0
  70. package/agent-docs/examples/extensions/minimal-mode.ts +430 -0
  71. package/agent-docs/examples/extensions/modal-editor.ts +90 -0
  72. package/agent-docs/examples/extensions/model-status.ts +31 -0
  73. package/agent-docs/examples/extensions/notify.ts +55 -0
  74. package/agent-docs/examples/extensions/overlay-qa-tests.ts +936 -0
  75. package/agent-docs/examples/extensions/overlay-test.ts +159 -0
  76. package/agent-docs/examples/extensions/permission-gate.ts +37 -0
  77. package/agent-docs/examples/extensions/pirate.ts +47 -0
  78. package/agent-docs/examples/extensions/plan-mode/README.md +65 -0
  79. package/agent-docs/examples/extensions/plan-mode/index.ts +363 -0
  80. package/agent-docs/examples/extensions/plan-mode/utils.ts +173 -0
  81. package/agent-docs/examples/extensions/preset.ts +418 -0
  82. package/agent-docs/examples/extensions/protected-paths.ts +30 -0
  83. package/agent-docs/examples/extensions/qna.ts +122 -0
  84. package/agent-docs/examples/extensions/question.ts +278 -0
  85. package/agent-docs/examples/extensions/questionnaire.ts +440 -0
  86. package/agent-docs/examples/extensions/rainbow-editor.ts +90 -0
  87. package/agent-docs/examples/extensions/reload-runtime.ts +37 -0
  88. package/agent-docs/examples/extensions/rpc-demo.ts +124 -0
  89. package/agent-docs/examples/extensions/sandbox/index.ts +324 -0
  90. package/agent-docs/examples/extensions/sandbox/package-lock.json +92 -0
  91. package/agent-docs/examples/extensions/sandbox/package.json +19 -0
  92. package/agent-docs/examples/extensions/send-user-message.ts +97 -0
  93. package/agent-docs/examples/extensions/session-name.ts +27 -0
  94. package/agent-docs/examples/extensions/shutdown-command.ts +69 -0
  95. package/agent-docs/examples/extensions/snake.ts +343 -0
  96. package/agent-docs/examples/extensions/space-invaders.ts +566 -0
  97. package/agent-docs/examples/extensions/ssh.ts +233 -0
  98. package/agent-docs/examples/extensions/status-line.ts +40 -0
  99. package/agent-docs/examples/extensions/subagent/README.md +172 -0
  100. package/agent-docs/examples/extensions/subagent/agents/planner.md +37 -0
  101. package/agent-docs/examples/extensions/subagent/agents/reviewer.md +35 -0
  102. package/agent-docs/examples/extensions/subagent/agents/scout.md +50 -0
  103. package/agent-docs/examples/extensions/subagent/agents/worker.md +24 -0
  104. package/agent-docs/examples/extensions/subagent/agents.ts +130 -0
  105. package/agent-docs/examples/extensions/subagent/index.ts +1068 -0
  106. package/agent-docs/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  107. package/agent-docs/examples/extensions/subagent/prompts/implement.md +10 -0
  108. package/agent-docs/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  109. package/agent-docs/examples/extensions/summarize.ts +206 -0
  110. package/agent-docs/examples/extensions/system-prompt-header.ts +17 -0
  111. package/agent-docs/examples/extensions/timed-confirm.ts +72 -0
  112. package/agent-docs/examples/extensions/titlebar-spinner.ts +58 -0
  113. package/agent-docs/examples/extensions/todo.ts +314 -0
  114. package/agent-docs/examples/extensions/tool-override.ts +146 -0
  115. package/agent-docs/examples/extensions/tools.ts +145 -0
  116. package/agent-docs/examples/extensions/trigger-compact.ts +40 -0
  117. package/agent-docs/examples/extensions/truncated-tool.ts +194 -0
  118. package/agent-docs/examples/extensions/widget-placement.ts +17 -0
  119. package/agent-docs/examples/extensions/with-deps/index.ts +37 -0
  120. package/agent-docs/examples/extensions/with-deps/package-lock.json +31 -0
  121. package/agent-docs/examples/extensions/with-deps/package.json +22 -0
  122. package/agent-docs/examples/rpc-extension-ui.ts +654 -0
  123. package/agent-docs/examples/sdk/01-minimal.ts +22 -0
  124. package/agent-docs/examples/sdk/02-custom-model.ts +48 -0
  125. package/agent-docs/examples/sdk/03-custom-prompt.ts +55 -0
  126. package/agent-docs/examples/sdk/04-skills.ts +53 -0
  127. package/agent-docs/examples/sdk/05-tools.ts +56 -0
  128. package/agent-docs/examples/sdk/06-extensions.ts +88 -0
  129. package/agent-docs/examples/sdk/07-context-files.ts +40 -0
  130. package/agent-docs/examples/sdk/08-prompt-templates.ts +47 -0
  131. package/agent-docs/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  132. package/agent-docs/examples/sdk/10-settings.ts +54 -0
  133. package/agent-docs/examples/sdk/11-sessions.ts +48 -0
  134. package/agent-docs/examples/sdk/12-full-control.ts +82 -0
  135. package/agent-docs/examples/sdk/README.md +144 -0
  136. package/agent-docs/xll-skill.md +61 -0
  137. package/agent-docs/xll-spec.md +110 -0
  138. package/dist/cli/args.js +290 -0
  139. package/dist/cli/config-selector.js +31 -0
  140. package/dist/cli/file-processor.js +79 -0
  141. package/dist/cli/list-models.js +92 -0
  142. package/dist/cli/package-commands.js +210 -0
  143. package/dist/cli/report-settings-errors.js +11 -0
  144. package/dist/cli/session-picker.js +34 -0
  145. package/dist/cli.js +19 -0
  146. package/dist/config.js +288 -0
  147. package/dist/core/abort.js +15 -0
  148. package/dist/core/agent-loop.js +352 -0
  149. package/dist/core/agent-session.js +2019 -0
  150. package/dist/core/agent.js +410 -0
  151. package/dist/core/auth-storage.js +456 -0
  152. package/dist/core/bash-executor.js +222 -0
  153. package/dist/core/compaction/branch-summarization.js +242 -0
  154. package/dist/core/compaction/compaction.js +610 -0
  155. package/dist/core/compaction/index.js +7 -0
  156. package/dist/core/compaction/utils.js +139 -0
  157. package/dist/core/defaults.js +6 -0
  158. package/dist/core/diagnostics.js +2 -0
  159. package/dist/core/event-bus.js +25 -0
  160. package/dist/core/exec.js +71 -0
  161. package/dist/core/export-html/ansi-to-html.js +256 -0
  162. package/dist/core/export-html/index.js +238 -0
  163. package/dist/core/export-html/session-view-model.js +342 -0
  164. package/dist/core/export-html/template.css +1110 -0
  165. package/dist/core/export-html/template.html +76 -0
  166. package/dist/core/export-html/template.js +1990 -0
  167. package/dist/core/export-html/tool-renderer.js +63 -0
  168. package/dist/core/export-html/vendor/highlight.min.js +7725 -0
  169. package/dist/core/export-html/vendor/marked.min.js +1803 -0
  170. package/dist/core/extensions/index.js +9 -0
  171. package/dist/core/extensions/loader.js +422 -0
  172. package/dist/core/extensions/runner.js +651 -0
  173. package/dist/core/extensions/types.js +35 -0
  174. package/dist/core/extensions/wrapper.js +102 -0
  175. package/dist/core/footer-data-provider.js +162 -0
  176. package/dist/core/index.js +9 -0
  177. package/dist/core/keybindings.js +153 -0
  178. package/dist/core/messages.js +133 -0
  179. package/dist/core/model-registry.js +539 -0
  180. package/dist/core/model-resolver.js +370 -0
  181. package/dist/core/package-manager.js +1485 -0
  182. package/dist/core/prompt-templates.js +253 -0
  183. package/dist/core/resolve-config-value.js +59 -0
  184. package/dist/core/resource-loader.js +700 -0
  185. package/dist/core/sdk.js +197 -0
  186. package/dist/core/session-bash.js +99 -0
  187. package/dist/core/session-compaction.js +165 -0
  188. package/dist/core/session-manager.js +1153 -0
  189. package/dist/core/session-models.js +99 -0
  190. package/dist/core/session-retry.js +155 -0
  191. package/dist/core/settings-manager.js +572 -0
  192. package/dist/core/skills.js +382 -0
  193. package/dist/core/slash-commands.js +31 -0
  194. package/dist/core/system-prompt.js +161 -0
  195. package/dist/core/theme.js +770 -0
  196. package/dist/core/timings.js +26 -0
  197. package/dist/core/tools/bash.js +258 -0
  198. package/dist/core/tools/edit-diff.js +245 -0
  199. package/dist/core/tools/edit.js +148 -0
  200. package/dist/core/tools/find.js +208 -0
  201. package/dist/core/tools/grep.js +246 -0
  202. package/dist/core/tools/index.js +67 -0
  203. package/dist/core/tools/ls.js +123 -0
  204. package/dist/core/tools/path-utils.js +81 -0
  205. package/dist/core/tools/read.js +160 -0
  206. package/dist/core/tools/truncate.js +70 -0
  207. package/dist/core/tools/write.js +82 -0
  208. package/dist/custom/agents/action.js +13 -0
  209. package/dist/custom/agents/document-reader.js +70 -0
  210. package/dist/custom/agents/general.js +26 -0
  211. package/dist/custom/agents/index.js +49 -0
  212. package/dist/custom/agents/installation.js +13 -0
  213. package/dist/custom/agents/types.js +7 -0
  214. package/dist/custom/auth/refresh-timer.js +33 -0
  215. package/dist/custom/auth/shortcut-oauth.js +145 -0
  216. package/dist/custom/constants.js +21 -0
  217. package/dist/custom/context/workbook-summary.js +73 -0
  218. package/dist/custom/credits/shortcut-credits.js +29 -0
  219. package/dist/custom/cron/cron-daemon-entry.js +18 -0
  220. package/dist/custom/cron/daemon-ipc.js +131 -0
  221. package/dist/custom/cron/daemon.js +224 -0
  222. package/dist/custom/cron/jobs.js +226 -0
  223. package/dist/custom/cron/run-log.js +51 -0
  224. package/dist/custom/cron/schedule.js +72 -0
  225. package/dist/custom/cron/status-line.js +98 -0
  226. package/dist/custom/cron/store.js +87 -0
  227. package/dist/custom/cron/types.js +8 -0
  228. package/dist/custom/dev/index.js +59 -0
  229. package/dist/custom/dev/trace-export.js +58 -0
  230. package/dist/custom/ensure-excel.js +63 -0
  231. package/dist/custom/excel-config.js +36 -0
  232. package/dist/custom/preflight.js +422 -0
  233. package/dist/custom/prompts/action.js +100 -0
  234. package/dist/custom/prompts/api.js +66 -0
  235. package/dist/custom/prompts/installation.js +124 -0
  236. package/dist/custom/prompts/shared.js +138 -0
  237. package/dist/custom/providers/llm-usage.js +42 -0
  238. package/dist/custom/providers/message-converter.js +74 -0
  239. package/dist/custom/providers/provider-ids.js +9 -0
  240. package/dist/custom/providers/register-openai-codex-provider.js +27 -0
  241. package/dist/custom/providers/register-shortcut-provider.js +52 -0
  242. package/dist/custom/providers/shortcut-invoke.js +117 -0
  243. package/dist/custom/providers/shortcut-stream.js +252 -0
  244. package/dist/custom/providers/sse-protocol.js +38 -0
  245. package/dist/custom/sync-xll.js +130 -0
  246. package/dist/custom/tools/cron.js +413 -0
  247. package/dist/custom/tools/excel-exec.js +167 -0
  248. package/dist/custom/tools/excel-range.js +50 -0
  249. package/dist/custom/tools/llm-analysis.js +265 -0
  250. package/dist/custom/tools/render-helpers.js +38 -0
  251. package/dist/custom/tools/switch-mode.js +94 -0
  252. package/dist/custom/tools/task/agents.js +6 -0
  253. package/dist/custom/tools/task/index.js +8 -0
  254. package/dist/custom/tools/task/render.js +348 -0
  255. package/dist/custom/tools/task/subprocess.js +320 -0
  256. package/dist/custom/tools/task/task.js +205 -0
  257. package/dist/custom/tools/todo-list.js +195 -0
  258. package/dist/custom/tracing/session-upload.js +93 -0
  259. package/dist/index.js +45 -0
  260. package/dist/main.js +613 -0
  261. package/dist/migrations.js +265 -0
  262. package/dist/modes/index.js +8 -0
  263. package/dist/modes/interactive/components/armin.js +337 -0
  264. package/dist/modes/interactive/components/assistant-message.js +94 -0
  265. package/dist/modes/interactive/components/bash-execution.js +171 -0
  266. package/dist/modes/interactive/components/bordered-loader.js +51 -0
  267. package/dist/modes/interactive/components/branch-summary-message.js +45 -0
  268. package/dist/modes/interactive/components/compaction-summary-message.js +46 -0
  269. package/dist/modes/interactive/components/config-selector.js +488 -0
  270. package/dist/modes/interactive/components/countdown-timer.js +33 -0
  271. package/dist/modes/interactive/components/custom-editor.js +93 -0
  272. package/dist/modes/interactive/components/custom-message.js +81 -0
  273. package/dist/modes/interactive/components/daxnuts.js +140 -0
  274. package/dist/modes/interactive/components/diff.js +133 -0
  275. package/dist/modes/interactive/components/dynamic-border.js +21 -0
  276. package/dist/modes/interactive/components/extension-editor.js +105 -0
  277. package/dist/modes/interactive/components/extension-input.js +61 -0
  278. package/dist/modes/interactive/components/extension-selector.js +78 -0
  279. package/dist/modes/interactive/components/footer.js +309 -0
  280. package/dist/modes/interactive/components/index.js +33 -0
  281. package/dist/modes/interactive/components/keybinding-hints.js +61 -0
  282. package/dist/modes/interactive/components/layout.js +64 -0
  283. package/dist/modes/interactive/components/login-dialog.js +148 -0
  284. package/dist/modes/interactive/components/model-selector.js +237 -0
  285. package/dist/modes/interactive/components/oauth-selector.js +111 -0
  286. package/dist/modes/interactive/components/session-selector-search.js +157 -0
  287. package/dist/modes/interactive/components/session-selector.js +860 -0
  288. package/dist/modes/interactive/components/settings-selector.js +123 -0
  289. package/dist/modes/interactive/components/show-images-selector.js +35 -0
  290. package/dist/modes/interactive/components/skill-invocation-message.js +48 -0
  291. package/dist/modes/interactive/components/theme-selector.js +47 -0
  292. package/dist/modes/interactive/components/thinking-selector.js +47 -0
  293. package/dist/modes/interactive/components/tool-execution.js +789 -0
  294. package/dist/modes/interactive/components/tool-group.js +106 -0
  295. package/dist/modes/interactive/components/tree-selector.js +962 -0
  296. package/dist/modes/interactive/components/user-message-selector.js +115 -0
  297. package/dist/modes/interactive/components/user-message.js +48 -0
  298. package/dist/modes/interactive/components/visual-truncate.js +33 -0
  299. package/dist/modes/interactive/file-attachments.js +135 -0
  300. package/dist/modes/interactive/interactive-mode.js +3775 -0
  301. package/dist/modes/interactive/theme/dark.json +85 -0
  302. package/dist/modes/interactive/theme/light.json +85 -0
  303. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  304. package/dist/modes/interactive/theme/theme.js +177 -0
  305. package/dist/modes/print-mode.js +101 -0
  306. package/dist/modes/rpc/rpc-client.js +387 -0
  307. package/dist/modes/rpc/rpc-mode.js +509 -0
  308. package/dist/modes/rpc/rpc-types.js +8 -0
  309. package/dist/subagent-entry.js +145 -0
  310. package/dist/tool-names.js +34 -0
  311. package/dist/tui/autocomplete.js +596 -0
  312. package/dist/tui/components/box.js +104 -0
  313. package/dist/tui/components/cancellable-loader.js +35 -0
  314. package/dist/tui/components/editor.js +1679 -0
  315. package/dist/tui/components/image.js +69 -0
  316. package/dist/tui/components/input.js +433 -0
  317. package/dist/tui/components/loader.js +49 -0
  318. package/dist/tui/components/markdown.js +629 -0
  319. package/dist/tui/components/select-list.js +152 -0
  320. package/dist/tui/components/settings-list.js +185 -0
  321. package/dist/tui/components/spacer.js +23 -0
  322. package/dist/tui/components/text.js +89 -0
  323. package/dist/tui/components/truncated-text.js +51 -0
  324. package/dist/tui/editor-component.js +2 -0
  325. package/dist/tui/fuzzy.js +107 -0
  326. package/dist/tui/get-east-asian-width/index.js +32 -0
  327. package/dist/tui/get-east-asian-width/lookup.js +404 -0
  328. package/dist/tui/index.js +32 -0
  329. package/dist/tui/keybindings.js +114 -0
  330. package/dist/tui/keys.js +959 -0
  331. package/dist/tui/kill-ring.js +44 -0
  332. package/dist/tui/stdin-buffer.js +317 -0
  333. package/dist/tui/terminal-image.js +288 -0
  334. package/dist/tui/terminal.js +249 -0
  335. package/dist/tui/tui/autocomplete.js +596 -0
  336. package/dist/tui/tui/components/box.js +106 -0
  337. package/dist/tui/tui/components/cancellable-loader.js +35 -0
  338. package/dist/tui/tui/components/editor.js +1679 -0
  339. package/dist/tui/tui/components/image.js +69 -0
  340. package/dist/tui/tui/components/input.js +433 -0
  341. package/dist/tui/tui/components/loader.js +49 -0
  342. package/dist/tui/tui/components/markdown.js +629 -0
  343. package/dist/tui/tui/components/select-list.js +152 -0
  344. package/dist/tui/tui/components/settings-list.js +185 -0
  345. package/dist/tui/tui/components/spacer.js +23 -0
  346. package/dist/tui/tui/components/text.js +91 -0
  347. package/dist/tui/tui/components/truncated-text.js +51 -0
  348. package/dist/tui/tui/editor-component.js +2 -0
  349. package/dist/tui/tui/fuzzy.js +107 -0
  350. package/dist/tui/tui/get-east-asian-width/index.js +32 -0
  351. package/dist/tui/tui/get-east-asian-width/lookup.js +404 -0
  352. package/dist/tui/tui/index.js +32 -0
  353. package/dist/tui/tui/keybindings.js +114 -0
  354. package/dist/tui/tui/keys.js +959 -0
  355. package/dist/tui/tui/kill-ring.js +44 -0
  356. package/dist/tui/tui/stdin-buffer.js +317 -0
  357. package/dist/tui/tui/terminal-image.js +288 -0
  358. package/dist/tui/tui/terminal.js +249 -0
  359. package/dist/tui/tui/tui.js +955 -0
  360. package/dist/tui/tui/undo-stack.js +25 -0
  361. package/dist/tui/tui/utils.js +800 -0
  362. package/dist/tui/tui.js +955 -0
  363. package/dist/tui/undo-stack.js +25 -0
  364. package/dist/tui/utils.js +800 -0
  365. package/dist/utils/changelog.js +87 -0
  366. package/dist/utils/clipboard-image.js +164 -0
  367. package/dist/utils/clipboard-native.js +14 -0
  368. package/dist/utils/clipboard.js +67 -0
  369. package/dist/utils/frontmatter.js +26 -0
  370. package/dist/utils/git.js +166 -0
  371. package/dist/utils/image-convert.js +35 -0
  372. package/dist/utils/image-resize.js +183 -0
  373. package/dist/utils/mime.js +26 -0
  374. package/dist/utils/photon.js +121 -0
  375. package/dist/utils/shell.js +217 -0
  376. package/dist/utils/sleep.js +17 -0
  377. package/dist/utils/tools-manager.js +259 -0
  378. package/package.json +78 -0
  379. package/skills/excel-com-api/SKILL.md +74 -0
  380. package/skills/excel-com-api/excel-type-library.py +27767 -0
  381. package/skills/excel-com-api/office-type-library.py +10867 -0
  382. package/skills/integrations/SKILL.md +138 -0
  383. package/skills/integrations/alphasense.md +457 -0
  384. package/skills/integrations/bloomberg.md +803 -0
  385. package/skills/integrations/calcbench.md +315 -0
  386. package/skills/integrations/capiq.md +848 -0
  387. package/skills/integrations/dynamics-365-finance.md +354 -0
  388. package/skills/integrations/earnings_transcripts.md +387 -0
  389. package/skills/integrations/factset.md +758 -0
  390. package/skills/integrations/ice-fixed-income.md +344 -0
  391. package/skills/integrations/moodys-analytics.md +313 -0
  392. package/skills/integrations/morningstar.md +433 -0
  393. package/skills/integrations/nasdaq-data-link.md +249 -0
  394. package/skills/integrations/pitchbook.md +413 -0
  395. package/skills/integrations/preqin.md +422 -0
  396. package/skills/integrations/quickbooks.md +289 -0
  397. package/skills/integrations/quickfs.md +314 -0
  398. package/skills/integrations/refinitiv.md +473 -0
  399. package/skills/integrations/sage-intacct.md +401 -0
  400. package/skills/integrations/visible-alpha.md +320 -0
  401. package/skills/integrations/xero.md +393 -0
  402. package/skills/integrations/ycharts.md +306 -0
  403. package/skills/pdf-creation/SKILL.md +93 -0
  404. package/skills/pdf-extraction/SKILL.md +32 -0
  405. package/skills/powerpoint-creation/SKILL.md +110 -0
  406. package/skills/sec-edgar/SKILL.md +127 -0
  407. package/skills/sec-edgar/sec_to_pdf.py +109 -0
  408. package/xll/ShortcutXL.xll +0 -0
  409. package/xll/modules/debug_render.py +272 -0
  410. package/xll/modules/gameboy.py +241 -0
  411. package/xll/modules/pong.py +188 -0
  412. package/xll/modules/shortcut_xl/__init__.py +18 -0
  413. package/xll/modules/shortcut_xl/_categorize.py +200 -0
  414. package/xll/modules/shortcut_xl/_com.py +108 -0
  415. package/xll/modules/shortcut_xl/_format.py +252 -0
  416. package/xll/modules/shortcut_xl/_log.py +12 -0
  417. package/xll/modules/shortcut_xl/_managed.py +116 -0
  418. package/xll/modules/shortcut_xl/_registry.py +44 -0
  419. package/xll/modules/shortcut_xl/_threading.py +161 -0
  420. package/xll/modules/shortcut_xl/_tracking.py +283 -0
  421. package/xll/modules/stocks.py +100 -0
  422. package/xll/python3.dll +0 -0
  423. package/xll/python312.dll +0 -0
@@ -0,0 +1,770 @@
1
+ import { Type } from '@sinclair/typebox';
2
+ import { TypeCompiler } from '@sinclair/typebox/compiler';
3
+ import chalk from 'chalk';
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import { getCustomThemesDir, getThemesDir } from '../config.js';
7
+ // ============================================================================
8
+ // Types & Schema
9
+ // ============================================================================
10
+ const ColorValueSchema = Type.Union([
11
+ Type.String(), // hex "#ff0000", var ref "primary", or empty ""
12
+ Type.Integer({ minimum: 0, maximum: 255 }) // 256-color index
13
+ ]);
14
+ const ThemeJsonSchema = Type.Object({
15
+ $schema: Type.Optional(Type.String()),
16
+ name: Type.String(),
17
+ vars: Type.Optional(Type.Record(Type.String(), ColorValueSchema)),
18
+ colors: Type.Object({
19
+ // Core UI (10 colors)
20
+ accent: ColorValueSchema,
21
+ border: ColorValueSchema,
22
+ borderAccent: ColorValueSchema,
23
+ borderMuted: ColorValueSchema,
24
+ success: ColorValueSchema,
25
+ error: ColorValueSchema,
26
+ warning: ColorValueSchema,
27
+ muted: ColorValueSchema,
28
+ dim: ColorValueSchema,
29
+ text: ColorValueSchema,
30
+ thinkingText: ColorValueSchema,
31
+ // Backgrounds & Content Text (11 colors)
32
+ selectedBg: ColorValueSchema,
33
+ userMessageBg: ColorValueSchema,
34
+ userMessageText: ColorValueSchema,
35
+ customMessageBg: ColorValueSchema,
36
+ customMessageText: ColorValueSchema,
37
+ customMessageLabel: ColorValueSchema,
38
+ toolPendingBg: ColorValueSchema,
39
+ toolSuccessBg: ColorValueSchema,
40
+ toolErrorBg: ColorValueSchema,
41
+ toolTitle: ColorValueSchema,
42
+ toolOutput: ColorValueSchema,
43
+ // Markdown (10 colors)
44
+ mdHeading: ColorValueSchema,
45
+ mdLink: ColorValueSchema,
46
+ mdLinkUrl: ColorValueSchema,
47
+ mdCode: ColorValueSchema,
48
+ mdCodeBlock: ColorValueSchema,
49
+ mdCodeBlockBorder: ColorValueSchema,
50
+ mdQuote: ColorValueSchema,
51
+ mdQuoteBorder: ColorValueSchema,
52
+ mdHr: ColorValueSchema,
53
+ mdListBullet: ColorValueSchema,
54
+ // Tool Diffs (3 colors)
55
+ toolDiffAdded: ColorValueSchema,
56
+ toolDiffRemoved: ColorValueSchema,
57
+ toolDiffContext: ColorValueSchema,
58
+ // Syntax Highlighting (9 colors)
59
+ syntaxComment: ColorValueSchema,
60
+ syntaxKeyword: ColorValueSchema,
61
+ syntaxFunction: ColorValueSchema,
62
+ syntaxVariable: ColorValueSchema,
63
+ syntaxString: ColorValueSchema,
64
+ syntaxNumber: ColorValueSchema,
65
+ syntaxType: ColorValueSchema,
66
+ syntaxOperator: ColorValueSchema,
67
+ syntaxPunctuation: ColorValueSchema,
68
+ // Thinking Level Borders (6 colors)
69
+ thinkingOff: ColorValueSchema,
70
+ thinkingMinimal: ColorValueSchema,
71
+ thinkingLow: ColorValueSchema,
72
+ thinkingMedium: ColorValueSchema,
73
+ thinkingHigh: ColorValueSchema,
74
+ thinkingXhigh: ColorValueSchema,
75
+ // Bash Mode (1 color)
76
+ bashMode: ColorValueSchema
77
+ }),
78
+ export: Type.Optional(Type.Object({
79
+ pageBg: Type.Optional(ColorValueSchema),
80
+ cardBg: Type.Optional(ColorValueSchema),
81
+ infoBg: Type.Optional(ColorValueSchema)
82
+ }))
83
+ });
84
+ const validateThemeJson = TypeCompiler.Compile(ThemeJsonSchema);
85
+ // ============================================================================
86
+ // Color Utilities
87
+ // ============================================================================
88
+ function detectColorMode() {
89
+ const colorterm = process.env.COLORTERM;
90
+ if (colorterm === 'truecolor' || colorterm === '24bit') {
91
+ return 'truecolor';
92
+ }
93
+ // Windows Terminal supports truecolor
94
+ if (process.env.WT_SESSION) {
95
+ return 'truecolor';
96
+ }
97
+ const term = process.env.TERM || '';
98
+ // Fall back to 256color for truly limited terminals
99
+ if (term === 'dumb' || term === '' || term === 'linux') {
100
+ return '256color';
101
+ }
102
+ // Terminal.app also doesn't support truecolor
103
+ if (process.env.TERM_PROGRAM === 'Apple_Terminal') {
104
+ return '256color';
105
+ }
106
+ // Assume truecolor for everything else - virtually all modern terminals support it
107
+ return 'truecolor';
108
+ }
109
+ function hexToRgb(hex) {
110
+ const cleaned = hex.replace('#', '');
111
+ if (cleaned.length !== 6) {
112
+ throw new Error(`Invalid hex color: ${hex}`);
113
+ }
114
+ const r = parseInt(cleaned.substring(0, 2), 16);
115
+ const g = parseInt(cleaned.substring(2, 4), 16);
116
+ const b = parseInt(cleaned.substring(4, 6), 16);
117
+ if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
118
+ throw new Error(`Invalid hex color: ${hex}`);
119
+ }
120
+ return { r, g, b };
121
+ }
122
+ // The 6x6x6 color cube channel values (indices 0-5)
123
+ const CUBE_VALUES = [0, 95, 135, 175, 215, 255];
124
+ // Grayscale ramp values (indices 232-255, 24 grays from 8 to 238)
125
+ const GRAY_VALUES = Array.from({ length: 24 }, (_, i) => 8 + i * 10);
126
+ function findClosestCubeIndex(value) {
127
+ let minDist = Infinity;
128
+ let minIdx = 0;
129
+ for (let i = 0; i < CUBE_VALUES.length; i++) {
130
+ const dist = Math.abs(value - CUBE_VALUES[i]);
131
+ if (dist < minDist) {
132
+ minDist = dist;
133
+ minIdx = i;
134
+ }
135
+ }
136
+ return minIdx;
137
+ }
138
+ function findClosestGrayIndex(gray) {
139
+ let minDist = Infinity;
140
+ let minIdx = 0;
141
+ for (let i = 0; i < GRAY_VALUES.length; i++) {
142
+ const dist = Math.abs(gray - GRAY_VALUES[i]);
143
+ if (dist < minDist) {
144
+ minDist = dist;
145
+ minIdx = i;
146
+ }
147
+ }
148
+ return minIdx;
149
+ }
150
+ function colorDistance(r1, g1, b1, r2, g2, b2) {
151
+ // Weighted Euclidean distance (human eye is more sensitive to green)
152
+ const dr = r1 - r2;
153
+ const dg = g1 - g2;
154
+ const db = b1 - b2;
155
+ return dr * dr * 0.299 + dg * dg * 0.587 + db * db * 0.114;
156
+ }
157
+ function rgbTo256(r, g, b) {
158
+ // Find closest color in the 6x6x6 cube
159
+ const rIdx = findClosestCubeIndex(r);
160
+ const gIdx = findClosestCubeIndex(g);
161
+ const bIdx = findClosestCubeIndex(b);
162
+ const cubeR = CUBE_VALUES[rIdx];
163
+ const cubeG = CUBE_VALUES[gIdx];
164
+ const cubeB = CUBE_VALUES[bIdx];
165
+ const cubeIndex = 16 + 36 * rIdx + 6 * gIdx + bIdx;
166
+ const cubeDist = colorDistance(r, g, b, cubeR, cubeG, cubeB);
167
+ // Find closest grayscale
168
+ const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
169
+ const grayIdx = findClosestGrayIndex(gray);
170
+ const grayValue = GRAY_VALUES[grayIdx];
171
+ const grayIndex = 232 + grayIdx;
172
+ const grayDist = colorDistance(r, g, b, grayValue, grayValue, grayValue);
173
+ // Check if color has noticeable saturation (hue matters)
174
+ // If max-min spread is significant, prefer cube to preserve tint
175
+ const maxC = Math.max(r, g, b);
176
+ const minC = Math.min(r, g, b);
177
+ const spread = maxC - minC;
178
+ // Only consider grayscale if color is nearly neutral (spread < 10)
179
+ // AND grayscale is actually closer
180
+ if (spread < 10 && grayDist < cubeDist) {
181
+ return grayIndex;
182
+ }
183
+ return cubeIndex;
184
+ }
185
+ function hexTo256(hex) {
186
+ const { r, g, b } = hexToRgb(hex);
187
+ return rgbTo256(r, g, b);
188
+ }
189
+ function fgAnsi(color, mode) {
190
+ if (color === '')
191
+ return '\x1b[39m';
192
+ if (typeof color === 'number')
193
+ return `\x1b[38;5;${color}m`;
194
+ if (color.startsWith('#')) {
195
+ if (mode === 'truecolor') {
196
+ const { r, g, b } = hexToRgb(color);
197
+ return `\x1b[38;2;${r};${g};${b}m`;
198
+ }
199
+ else {
200
+ const index = hexTo256(color);
201
+ return `\x1b[38;5;${index}m`;
202
+ }
203
+ }
204
+ throw new Error(`Invalid color value: ${color}`);
205
+ }
206
+ function bgAnsi(color, mode) {
207
+ if (color === '')
208
+ return '\x1b[49m';
209
+ if (typeof color === 'number')
210
+ return `\x1b[48;5;${color}m`;
211
+ if (color.startsWith('#')) {
212
+ if (mode === 'truecolor') {
213
+ const { r, g, b } = hexToRgb(color);
214
+ return `\x1b[48;2;${r};${g};${b}m`;
215
+ }
216
+ else {
217
+ const index = hexTo256(color);
218
+ return `\x1b[48;5;${index}m`;
219
+ }
220
+ }
221
+ throw new Error(`Invalid color value: ${color}`);
222
+ }
223
+ function resolveVarRefs(value, vars, visited = new Set()) {
224
+ if (typeof value === 'number' || value === '' || value.startsWith('#')) {
225
+ return value;
226
+ }
227
+ if (visited.has(value)) {
228
+ throw new Error(`Circular variable reference detected: ${value}`);
229
+ }
230
+ if (!(value in vars)) {
231
+ throw new Error(`Variable reference not found: ${value}`);
232
+ }
233
+ visited.add(value);
234
+ return resolveVarRefs(vars[value], vars, visited);
235
+ }
236
+ function resolveThemeColors(colors, vars = {}) {
237
+ const resolved = {};
238
+ for (const [key, value] of Object.entries(colors)) {
239
+ resolved[key] = resolveVarRefs(value, vars);
240
+ }
241
+ return resolved;
242
+ }
243
+ // ============================================================================
244
+ // Theme Class
245
+ // ============================================================================
246
+ export class Theme {
247
+ name;
248
+ sourcePath;
249
+ fgColors;
250
+ bgColors;
251
+ mode;
252
+ constructor(fgColors, bgColors, mode, options = {}) {
253
+ this.name = options.name;
254
+ this.sourcePath = options.sourcePath;
255
+ this.mode = mode;
256
+ this.fgColors = new Map();
257
+ for (const [key, value] of Object.entries(fgColors)) {
258
+ this.fgColors.set(key, fgAnsi(value, mode));
259
+ }
260
+ this.bgColors = new Map();
261
+ for (const [key, value] of Object.entries(bgColors)) {
262
+ this.bgColors.set(key, bgAnsi(value, mode));
263
+ }
264
+ }
265
+ fg(color, text) {
266
+ const ansi = this.fgColors.get(color);
267
+ if (!ansi)
268
+ throw new Error(`Unknown theme color: ${color}`);
269
+ return `${ansi}${text}\x1b[39m`; // Reset only foreground color
270
+ }
271
+ bg(color, text) {
272
+ const ansi = this.bgColors.get(color);
273
+ if (!ansi)
274
+ throw new Error(`Unknown theme background color: ${color}`);
275
+ return `${ansi}${text}\x1b[49m`; // Reset only background color
276
+ }
277
+ bold(text) {
278
+ return chalk.bold(text);
279
+ }
280
+ italic(text) {
281
+ return chalk.italic(text);
282
+ }
283
+ underline(text) {
284
+ return chalk.underline(text);
285
+ }
286
+ inverse(text) {
287
+ return chalk.inverse(text);
288
+ }
289
+ strikethrough(text) {
290
+ return chalk.strikethrough(text);
291
+ }
292
+ getFgAnsi(color) {
293
+ const ansi = this.fgColors.get(color);
294
+ if (!ansi)
295
+ throw new Error(`Unknown theme color: ${color}`);
296
+ return ansi;
297
+ }
298
+ getBgAnsi(color) {
299
+ const ansi = this.bgColors.get(color);
300
+ if (!ansi)
301
+ throw new Error(`Unknown theme background color: ${color}`);
302
+ return ansi;
303
+ }
304
+ getColorMode() {
305
+ return this.mode;
306
+ }
307
+ getThinkingBorderColor(level) {
308
+ // Map thinking levels to dedicated theme colors
309
+ switch (level) {
310
+ case 'off':
311
+ return (str) => this.fg('thinkingOff', str);
312
+ case 'minimal':
313
+ return (str) => this.fg('thinkingMinimal', str);
314
+ case 'low':
315
+ return (str) => this.fg('thinkingLow', str);
316
+ case 'medium':
317
+ return (str) => this.fg('thinkingMedium', str);
318
+ case 'high':
319
+ return (str) => this.fg('thinkingHigh', str);
320
+ case 'xhigh':
321
+ return (str) => this.fg('thinkingXhigh', str);
322
+ default:
323
+ return (str) => this.fg('thinkingOff', str);
324
+ }
325
+ }
326
+ getBashModeBorderColor() {
327
+ return (str) => this.fg('bashMode', str);
328
+ }
329
+ }
330
+ // ============================================================================
331
+ // Theme Loading
332
+ // ============================================================================
333
+ let BUILTIN_THEMES;
334
+ function getBuiltinThemes() {
335
+ if (!BUILTIN_THEMES) {
336
+ const themesDir = getThemesDir();
337
+ const darkPath = path.join(themesDir, 'dark.json');
338
+ const lightPath = path.join(themesDir, 'light.json');
339
+ BUILTIN_THEMES = {
340
+ dark: JSON.parse(fs.readFileSync(darkPath, 'utf-8')),
341
+ light: JSON.parse(fs.readFileSync(lightPath, 'utf-8'))
342
+ };
343
+ }
344
+ return BUILTIN_THEMES;
345
+ }
346
+ export function getAvailableThemes() {
347
+ const themes = new Set(Object.keys(getBuiltinThemes()));
348
+ const customThemesDir = getCustomThemesDir();
349
+ if (fs.existsSync(customThemesDir)) {
350
+ const files = fs.readdirSync(customThemesDir);
351
+ for (const file of files) {
352
+ if (file.endsWith('.json')) {
353
+ themes.add(file.slice(0, -5));
354
+ }
355
+ }
356
+ }
357
+ for (const name of registeredThemes.keys()) {
358
+ themes.add(name);
359
+ }
360
+ return Array.from(themes).sort();
361
+ }
362
+ export function getAvailableThemesWithPaths() {
363
+ const themesDir = getThemesDir();
364
+ const customThemesDir = getCustomThemesDir();
365
+ const result = [];
366
+ // Built-in themes
367
+ for (const name of Object.keys(getBuiltinThemes())) {
368
+ result.push({ name, path: path.join(themesDir, `${name}.json`) });
369
+ }
370
+ // Custom themes
371
+ if (fs.existsSync(customThemesDir)) {
372
+ for (const file of fs.readdirSync(customThemesDir)) {
373
+ if (file.endsWith('.json')) {
374
+ const name = file.slice(0, -5);
375
+ if (!result.some((t) => t.name === name)) {
376
+ result.push({ name, path: path.join(customThemesDir, file) });
377
+ }
378
+ }
379
+ }
380
+ }
381
+ for (const [name, theme] of registeredThemes.entries()) {
382
+ if (!result.some((t) => t.name === name)) {
383
+ result.push({ name, path: theme.sourcePath });
384
+ }
385
+ }
386
+ return result.sort((a, b) => a.name.localeCompare(b.name));
387
+ }
388
+ function parseThemeJson(label, json) {
389
+ if (!validateThemeJson.Check(json)) {
390
+ const errors = Array.from(validateThemeJson.Errors(json));
391
+ const missingColors = [];
392
+ const otherErrors = [];
393
+ for (const e of errors) {
394
+ // Check for missing required color properties
395
+ const match = e.path.match(/^\/colors\/(\w+)$/);
396
+ if (match && e.message.includes('Required')) {
397
+ missingColors.push(match[1]);
398
+ }
399
+ else {
400
+ otherErrors.push(` - ${e.path}: ${e.message}`);
401
+ }
402
+ }
403
+ let errorMessage = `Invalid theme "${label}":\n`;
404
+ if (missingColors.length > 0) {
405
+ errorMessage += '\nMissing required color tokens:\n';
406
+ errorMessage += missingColors.map((c) => ` - ${c}`).join('\n');
407
+ errorMessage += '\n\nPlease add these colors to your theme\'s "colors" object.';
408
+ errorMessage += '\nSee the built-in themes (dark.json, light.json) for reference values.';
409
+ }
410
+ if (otherErrors.length > 0) {
411
+ errorMessage += `\n\nOther errors:\n${otherErrors.join('\n')}`;
412
+ }
413
+ throw new Error(errorMessage);
414
+ }
415
+ return json;
416
+ }
417
+ function parseThemeJsonContent(label, content) {
418
+ let json;
419
+ try {
420
+ json = JSON.parse(content);
421
+ }
422
+ catch (error) {
423
+ throw new Error(`Failed to parse theme ${label}: ${error}`);
424
+ }
425
+ return parseThemeJson(label, json);
426
+ }
427
+ function loadThemeJson(name) {
428
+ const builtinThemes = getBuiltinThemes();
429
+ if (name in builtinThemes) {
430
+ return builtinThemes[name];
431
+ }
432
+ const registeredTheme = registeredThemes.get(name);
433
+ if (registeredTheme?.sourcePath) {
434
+ const content = fs.readFileSync(registeredTheme.sourcePath, 'utf-8');
435
+ return parseThemeJsonContent(registeredTheme.sourcePath, content);
436
+ }
437
+ if (registeredTheme) {
438
+ throw new Error(`Theme "${name}" does not have a source path for export`);
439
+ }
440
+ const customThemesDir = getCustomThemesDir();
441
+ const themePath = path.join(customThemesDir, `${name}.json`);
442
+ if (!fs.existsSync(themePath)) {
443
+ throw new Error(`Theme not found: ${name}`);
444
+ }
445
+ const content = fs.readFileSync(themePath, 'utf-8');
446
+ return parseThemeJsonContent(name, content);
447
+ }
448
+ function createTheme(themeJson, mode, sourcePath) {
449
+ const colorMode = mode ?? detectColorMode();
450
+ const resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars);
451
+ const fgColors = {};
452
+ const bgColors = {};
453
+ const bgColorKeys = new Set([
454
+ 'selectedBg',
455
+ 'userMessageBg',
456
+ 'customMessageBg',
457
+ 'toolPendingBg',
458
+ 'toolSuccessBg',
459
+ 'toolErrorBg'
460
+ ]);
461
+ for (const [key, value] of Object.entries(resolvedColors)) {
462
+ if (bgColorKeys.has(key)) {
463
+ bgColors[key] = value;
464
+ }
465
+ else {
466
+ fgColors[key] = value;
467
+ }
468
+ }
469
+ return new Theme(fgColors, bgColors, colorMode, {
470
+ name: themeJson.name,
471
+ sourcePath
472
+ });
473
+ }
474
+ export function loadThemeFromPath(themePath, mode) {
475
+ const content = fs.readFileSync(themePath, 'utf-8');
476
+ const themeJson = parseThemeJsonContent(themePath, content);
477
+ return createTheme(themeJson, mode, themePath);
478
+ }
479
+ function loadTheme(name, mode) {
480
+ const registeredTheme = registeredThemes.get(name);
481
+ if (registeredTheme) {
482
+ return registeredTheme;
483
+ }
484
+ const themeJson = loadThemeJson(name);
485
+ return createTheme(themeJson, mode);
486
+ }
487
+ export function getThemeByName(name) {
488
+ try {
489
+ return loadTheme(name);
490
+ }
491
+ catch {
492
+ return undefined;
493
+ }
494
+ }
495
+ function detectTerminalBackground() {
496
+ const colorfgbg = process.env.COLORFGBG || '';
497
+ if (colorfgbg) {
498
+ const parts = colorfgbg.split(';');
499
+ if (parts.length >= 2) {
500
+ const bg = parseInt(parts[1], 10);
501
+ if (!Number.isNaN(bg)) {
502
+ const result = bg < 8 ? 'dark' : 'light';
503
+ return result;
504
+ }
505
+ }
506
+ }
507
+ return 'dark';
508
+ }
509
+ function getDefaultTheme() {
510
+ return detectTerminalBackground();
511
+ }
512
+ // ============================================================================
513
+ // Global Theme Instance
514
+ // ============================================================================
515
+ // Use globalThis to share theme across module loaders (tsx + jiti in dev mode)
516
+ const THEME_KEY = Symbol.for('@mariozechner/pi-coding-agent:theme');
517
+ // Export theme as a getter that reads from globalThis
518
+ // This ensures all module instances (tsx, jiti) see the same theme
519
+ export const theme = new Proxy({}, {
520
+ get(_target, prop) {
521
+ const t = globalThis[THEME_KEY];
522
+ if (!t)
523
+ throw new Error('Theme not initialized. Call initTheme() first.');
524
+ return t[prop];
525
+ }
526
+ });
527
+ function setGlobalTheme(t) {
528
+ globalThis[THEME_KEY] = t;
529
+ }
530
+ let currentThemeName;
531
+ let themeWatcher;
532
+ let onThemeChangeCallback;
533
+ const registeredThemes = new Map();
534
+ export function setRegisteredThemes(themes) {
535
+ registeredThemes.clear();
536
+ for (const theme of themes) {
537
+ if (theme.name) {
538
+ registeredThemes.set(theme.name, theme);
539
+ }
540
+ }
541
+ }
542
+ export function initTheme(themeName, enableWatcher = false) {
543
+ const name = themeName ?? getDefaultTheme();
544
+ currentThemeName = name;
545
+ try {
546
+ setGlobalTheme(loadTheme(name));
547
+ if (enableWatcher) {
548
+ startThemeWatcher();
549
+ }
550
+ }
551
+ catch (_error) {
552
+ // Theme is invalid - fall back to dark theme silently
553
+ currentThemeName = 'dark';
554
+ setGlobalTheme(loadTheme('dark'));
555
+ // Don't start watcher for fallback theme
556
+ }
557
+ }
558
+ export function setTheme(name, enableWatcher = false) {
559
+ currentThemeName = name;
560
+ try {
561
+ setGlobalTheme(loadTheme(name));
562
+ if (enableWatcher) {
563
+ startThemeWatcher();
564
+ }
565
+ if (onThemeChangeCallback) {
566
+ onThemeChangeCallback();
567
+ }
568
+ return { success: true };
569
+ }
570
+ catch (error) {
571
+ // Theme is invalid - fall back to dark theme
572
+ currentThemeName = 'dark';
573
+ setGlobalTheme(loadTheme('dark'));
574
+ // Don't start watcher for fallback theme
575
+ return {
576
+ success: false,
577
+ error: error instanceof Error ? error.message : String(error)
578
+ };
579
+ }
580
+ }
581
+ export function setThemeInstance(themeInstance) {
582
+ setGlobalTheme(themeInstance);
583
+ currentThemeName = '<in-memory>';
584
+ stopThemeWatcher(); // Can't watch a direct instance
585
+ if (onThemeChangeCallback) {
586
+ onThemeChangeCallback();
587
+ }
588
+ }
589
+ export function onThemeChange(callback) {
590
+ onThemeChangeCallback = callback;
591
+ }
592
+ function startThemeWatcher() {
593
+ // Stop existing watcher if any
594
+ if (themeWatcher) {
595
+ themeWatcher.close();
596
+ themeWatcher = undefined;
597
+ }
598
+ // Only watch if it's a custom theme (not built-in)
599
+ if (!currentThemeName || currentThemeName === 'dark' || currentThemeName === 'light') {
600
+ return;
601
+ }
602
+ const customThemesDir = getCustomThemesDir();
603
+ const themeFile = path.join(customThemesDir, `${currentThemeName}.json`);
604
+ // Only watch if the file exists
605
+ if (!fs.existsSync(themeFile)) {
606
+ return;
607
+ }
608
+ try {
609
+ themeWatcher = fs.watch(themeFile, (eventType) => {
610
+ if (eventType === 'change') {
611
+ // Debounce rapid changes
612
+ setTimeout(() => {
613
+ try {
614
+ // Reload the theme
615
+ setGlobalTheme(loadTheme(currentThemeName));
616
+ // Notify callback (to invalidate UI)
617
+ if (onThemeChangeCallback) {
618
+ onThemeChangeCallback();
619
+ }
620
+ }
621
+ catch (_error) {
622
+ // Ignore errors (file might be in invalid state while being edited)
623
+ }
624
+ }, 100);
625
+ }
626
+ else if (eventType === 'rename') {
627
+ // File was deleted or renamed - fall back to default theme
628
+ setTimeout(() => {
629
+ if (!fs.existsSync(themeFile)) {
630
+ currentThemeName = 'dark';
631
+ setGlobalTheme(loadTheme('dark'));
632
+ if (themeWatcher) {
633
+ themeWatcher.close();
634
+ themeWatcher = undefined;
635
+ }
636
+ if (onThemeChangeCallback) {
637
+ onThemeChangeCallback();
638
+ }
639
+ }
640
+ }, 100);
641
+ }
642
+ });
643
+ }
644
+ catch (_error) {
645
+ // Ignore errors starting watcher
646
+ }
647
+ }
648
+ export function stopThemeWatcher() {
649
+ if (themeWatcher) {
650
+ themeWatcher.close();
651
+ themeWatcher = undefined;
652
+ }
653
+ }
654
+ // ============================================================================
655
+ // HTML Export Helpers
656
+ // ============================================================================
657
+ /**
658
+ * Convert a 256-color index to hex string.
659
+ * Indices 0-15: basic colors (approximate)
660
+ * Indices 16-231: 6x6x6 color cube
661
+ * Indices 232-255: grayscale ramp
662
+ */
663
+ function ansi256ToHex(index) {
664
+ // Basic colors (0-15) - approximate common terminal values
665
+ const basicColors = [
666
+ '#000000',
667
+ '#800000',
668
+ '#008000',
669
+ '#808000',
670
+ '#000080',
671
+ '#800080',
672
+ '#008080',
673
+ '#c0c0c0',
674
+ '#808080',
675
+ '#ff0000',
676
+ '#00ff00',
677
+ '#ffff00',
678
+ '#0000ff',
679
+ '#ff00ff',
680
+ '#00ffff',
681
+ '#ffffff'
682
+ ];
683
+ if (index < 16) {
684
+ return basicColors[index];
685
+ }
686
+ // Color cube (16-231): 6x6x6 = 216 colors
687
+ if (index < 232) {
688
+ const cubeIndex = index - 16;
689
+ const r = Math.floor(cubeIndex / 36);
690
+ const g = Math.floor((cubeIndex % 36) / 6);
691
+ const b = cubeIndex % 6;
692
+ const toHex = (n) => (n === 0 ? 0 : 55 + n * 40).toString(16).padStart(2, '0');
693
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
694
+ }
695
+ // Grayscale (232-255): 24 shades
696
+ const gray = 8 + (index - 232) * 10;
697
+ const grayHex = gray.toString(16).padStart(2, '0');
698
+ return `#${grayHex}${grayHex}${grayHex}`;
699
+ }
700
+ /**
701
+ * Get resolved theme colors as CSS-compatible hex strings.
702
+ * Used by HTML export to generate CSS custom properties.
703
+ */
704
+ export function getResolvedThemeColors(themeName) {
705
+ const name = themeName ?? currentThemeName ?? getDefaultTheme();
706
+ const isLight = name === 'light';
707
+ const themeJson = loadThemeJson(name);
708
+ const resolved = resolveThemeColors(themeJson.colors, themeJson.vars);
709
+ // Default text color for empty values (terminal uses default fg color)
710
+ const defaultText = isLight ? '#000000' : '#e5e5e7';
711
+ const cssColors = {};
712
+ for (const [key, value] of Object.entries(resolved)) {
713
+ if (typeof value === 'number') {
714
+ cssColors[key] = ansi256ToHex(value);
715
+ }
716
+ else if (value === '') {
717
+ // Empty means default terminal color - use sensible fallback for HTML
718
+ cssColors[key] = defaultText;
719
+ }
720
+ else {
721
+ cssColors[key] = value;
722
+ }
723
+ }
724
+ return cssColors;
725
+ }
726
+ /**
727
+ * Check if a theme is a "light" theme (for CSS that needs light/dark variants).
728
+ */
729
+ export function isLightTheme(themeName) {
730
+ // Currently just check the name - could be extended to analyze colors
731
+ return themeName === 'light';
732
+ }
733
+ /**
734
+ * Get explicit export colors from theme JSON, if specified.
735
+ * Returns undefined for each color that isn't explicitly set.
736
+ */
737
+ export function getThemeExportColors(themeName) {
738
+ const name = themeName ?? currentThemeName ?? getDefaultTheme();
739
+ try {
740
+ const themeJson = loadThemeJson(name);
741
+ const exportSection = themeJson.export;
742
+ if (!exportSection)
743
+ return {};
744
+ const vars = themeJson.vars ?? {};
745
+ const resolve = (value) => {
746
+ if (value === undefined)
747
+ return undefined;
748
+ if (typeof value === 'number')
749
+ return ansi256ToHex(value);
750
+ if (value.startsWith('$')) {
751
+ const resolved = vars[value];
752
+ if (resolved === undefined)
753
+ return undefined;
754
+ if (typeof resolved === 'number')
755
+ return ansi256ToHex(resolved);
756
+ return resolved;
757
+ }
758
+ return value;
759
+ };
760
+ return {
761
+ pageBg: resolve(exportSection.pageBg),
762
+ cardBg: resolve(exportSection.cardBg),
763
+ infoBg: resolve(exportSection.infoBg)
764
+ };
765
+ }
766
+ catch {
767
+ return {};
768
+ }
769
+ }
770
+ //# sourceMappingURL=theme.js.map