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
package/dist/config.js ADDED
@@ -0,0 +1,288 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { dirname, join, resolve } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ // =============================================================================
6
+ // Package Detection
7
+ // =============================================================================
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ /**
11
+ * Detect if we're running as a Bun compiled binary.
12
+ * Bun binaries have import.meta.url containing "$bunfs", "~BUN", or "%7EBUN" (Bun's virtual filesystem path)
13
+ */
14
+ export const isBunBinary = import.meta.url.includes('$bunfs') ||
15
+ import.meta.url.includes('~BUN') ||
16
+ import.meta.url.includes('%7EBUN');
17
+ /** Detect if Bun is the runtime (compiled binary or bun run) */
18
+ const isBunRuntime = !!process.versions.bun;
19
+ function detectInstallMethod() {
20
+ if (isBunBinary) {
21
+ return 'bun-binary';
22
+ }
23
+ const resolvedPath = `${__dirname}\0${process.execPath || ''}`.toLowerCase();
24
+ if (resolvedPath.includes('/pnpm/') ||
25
+ resolvedPath.includes('/.pnpm/') ||
26
+ resolvedPath.includes('\\pnpm\\')) {
27
+ return 'pnpm';
28
+ }
29
+ if (resolvedPath.includes('/yarn/') ||
30
+ resolvedPath.includes('/.yarn/') ||
31
+ resolvedPath.includes('\\yarn\\')) {
32
+ return 'yarn';
33
+ }
34
+ if (isBunRuntime) {
35
+ return 'bun';
36
+ }
37
+ if (resolvedPath.includes('/npm/') ||
38
+ resolvedPath.includes('/node_modules/') ||
39
+ resolvedPath.includes('\\npm\\')) {
40
+ return 'npm';
41
+ }
42
+ return 'unknown';
43
+ }
44
+ export function getUpdateInstruction(packageName) {
45
+ const method = detectInstallMethod();
46
+ switch (method) {
47
+ case 'bun-binary':
48
+ return `Download from: ${RELEASES_URL}`;
49
+ case 'pnpm':
50
+ return `Run: pnpm install -g ${packageName}`;
51
+ case 'yarn':
52
+ return `Run: yarn global add ${packageName}`;
53
+ case 'bun':
54
+ return `Run: bun install -g ${packageName}`;
55
+ case 'npm':
56
+ return `Run: npm install -g ${packageName}`;
57
+ default:
58
+ return `Run: npm install -g ${packageName}`;
59
+ }
60
+ }
61
+ /**
62
+ * Get the shell command to auto-update the agent package.
63
+ * Returns undefined for bun-binary (requires manual download).
64
+ */
65
+ export function getUpdateCommand(packageName) {
66
+ const method = detectInstallMethod();
67
+ switch (method) {
68
+ case 'bun-binary':
69
+ return undefined;
70
+ case 'pnpm':
71
+ return `pnpm install -g ${packageName}`;
72
+ case 'yarn':
73
+ return `yarn global add ${packageName}`;
74
+ case 'bun':
75
+ return `bun install -g ${packageName}`;
76
+ case 'npm':
77
+ default:
78
+ return `npm install -g ${packageName}`;
79
+ }
80
+ }
81
+ // =============================================================================
82
+ // Package Asset Paths (shipped with executable)
83
+ // =============================================================================
84
+ /**
85
+ * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md).
86
+ * - For Bun binary: returns the directory containing the executable
87
+ * - For Node.js (dist/): returns __dirname (the dist/ directory)
88
+ * - For tsx (src/): returns parent directory (the package root)
89
+ */
90
+ export function getPackageDir() {
91
+ // Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)
92
+ // SHORTCUT PATCH: renamed from PI_PACKAGE_DIR
93
+ const envDir = process.env.SHORTCUT_PACKAGE_DIR;
94
+ if (envDir) {
95
+ if (envDir === '~')
96
+ return homedir();
97
+ if (envDir.startsWith('~/'))
98
+ return homedir() + envDir.slice(1);
99
+ return envDir;
100
+ }
101
+ if (isBunBinary) {
102
+ // Bun binary: process.execPath points to the compiled executable
103
+ return dirname(process.execPath);
104
+ }
105
+ // Node.js: walk up from __dirname until we find package.json
106
+ let dir = __dirname;
107
+ while (dir !== dirname(dir)) {
108
+ if (existsSync(join(dir, 'package.json'))) {
109
+ return dir;
110
+ }
111
+ dir = dirname(dir);
112
+ }
113
+ // Fallback (shouldn't happen)
114
+ return __dirname;
115
+ }
116
+ /**
117
+ * Get path to built-in default skills directory (shipped with package).
118
+ * Located at skills/ in the package root.
119
+ */
120
+ export function getBundledSkillsDir() {
121
+ return join(getPackageDir(), 'skills');
122
+ }
123
+ /**
124
+ * Get path to built-in themes directory (shipped with package)
125
+ * - For Bun binary: theme/ next to executable
126
+ * - For Node.js (dist/): dist/modes/interactive/theme/
127
+ * - For tsx (src/): src/modes/interactive/theme/
128
+ */
129
+ export function getThemesDir() {
130
+ if (isBunBinary) {
131
+ return join(dirname(process.execPath), 'theme');
132
+ }
133
+ // Theme is in modes/interactive/theme/ relative to src/ or dist/
134
+ const packageDir = getPackageDir();
135
+ const srcOrDist = existsSync(join(packageDir, 'src')) ? 'src' : 'dist';
136
+ return join(packageDir, srcOrDist, 'modes', 'interactive', 'theme');
137
+ }
138
+ /**
139
+ * Get path to HTML export template directory (shipped with package)
140
+ * - For Bun binary: export-html/ next to executable
141
+ * - For Node.js (dist/): dist/core/export-html/
142
+ * - For tsx (src/): src/core/export-html/
143
+ */
144
+ export function getExportTemplateDir() {
145
+ if (isBunBinary) {
146
+ return join(dirname(process.execPath), 'export-html');
147
+ }
148
+ const packageDir = getPackageDir();
149
+ const srcOrDist = existsSync(join(packageDir, 'src')) ? 'src' : 'dist';
150
+ return join(packageDir, srcOrDist, 'core', 'export-html');
151
+ }
152
+ /** Get path to package.json */
153
+ function getPackageJsonPath() {
154
+ return join(getPackageDir(), 'package.json');
155
+ }
156
+ /** Get path to README.md */
157
+ export function getReadmePath() {
158
+ return resolve(join(getPackageDir(), 'README.md'));
159
+ }
160
+ /** Get path to docs directory */
161
+ export function getDocsPath() {
162
+ return resolve(join(getPackageDir(), 'docs'));
163
+ }
164
+ /** Get path to examples directory */
165
+ export function getExamplesPath() {
166
+ return resolve(join(getPackageDir(), 'examples'));
167
+ }
168
+ /** Get path to CHANGELOG.md */
169
+ export function getChangelogPath() {
170
+ return resolve(join(getPackageDir(), 'CHANGELOG.md'));
171
+ }
172
+ // =============================================================================
173
+ // App Config (from package.json shortcutConfig)
174
+ // =============================================================================
175
+ const pkg = JSON.parse(readFileSync(getPackageJsonPath(), 'utf-8'));
176
+ export const APP_NAME = pkg.shortcutConfig?.name || 'shortcut';
177
+ export const CONFIG_DIR_NAME = pkg.shortcutConfig?.configDir || '.shortcut';
178
+ export const VERSION = pkg.version;
179
+ export const NPM_PACKAGE_NAME = pkg.name || 'shortcutxl';
180
+ // e.g., SHORTCUT_CODING_AGENT_DIR
181
+ export const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`;
182
+ // -- Package & update URLs -------------------------------------------------
183
+ /** npm registry URL for version checks. */
184
+ export const NPM_REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
185
+ /** GitHub repo base URL (for changelog, releases). */
186
+ const GITHUB_REPO_URL = 'https://github.com/lyfegame/shortcut';
187
+ /** Releases URL shown for bun-binary update instructions. */
188
+ const RELEASES_URL = `${GITHUB_REPO_URL}/releases/latest`;
189
+ // =============================================================================
190
+ // Own Binary Resolution (for spawning subagent child processes)
191
+ // =============================================================================
192
+ /**
193
+ * Resolve how to spawn another instance of this agent as a child process.
194
+ *
195
+ * Returns [command, ...prefixArgs] such that:
196
+ * spawn(command, [...prefixArgs, '--mode', 'json', ...])
197
+ * produces a child running the same agent binary with all custom tools.
198
+ *
199
+ * Resolution order:
200
+ * 1. Bun binary → [process.execPath]
201
+ * 2. Global install (bin in PATH) → ['shortcut']
202
+ * 3. Dev mode (tsx) → ['tsx', '/abs/path/to/src/cli.ts']
203
+ * 4. Built (node) → ['node', '/abs/path/to/dist/cli.js']
204
+ */
205
+ export function resolveOwnBinary() {
206
+ if (isBunBinary) {
207
+ return [process.execPath];
208
+ }
209
+ // process.argv[1] is the script being executed (cli.ts or cli.js)
210
+ const script = process.argv[1];
211
+ if (script) {
212
+ const resolvedScript = resolve(script);
213
+ // Dev mode: running via tsx (e.g. `tsx src/cli.ts`)
214
+ if (resolvedScript.endsWith('.ts')) {
215
+ return ['tsx', resolvedScript];
216
+ }
217
+ // Built mode: running via node (e.g. `node dist/cli.js`)
218
+ // Also covers global install where the bin shim runs `node dist/cli.js`
219
+ if (resolvedScript.endsWith('.js')) {
220
+ return ['node', resolvedScript];
221
+ }
222
+ }
223
+ // Fallback: assume the bin name is in PATH (global npm/pnpm install)
224
+ return [APP_NAME];
225
+ }
226
+ // =============================================================================
227
+ // User Config Paths (~/.shortcut/agent/*)
228
+ // =============================================================================
229
+ /** Get the agent config directory (e.g., ~/.shortcut/agent/) */
230
+ export function getAgentDir() {
231
+ const envDir = process.env[ENV_AGENT_DIR];
232
+ if (envDir) {
233
+ // Expand tilde to home directory
234
+ if (envDir === '~')
235
+ return homedir();
236
+ if (envDir.startsWith('~/'))
237
+ return homedir() + envDir.slice(1);
238
+ return envDir;
239
+ }
240
+ return join(homedir(), CONFIG_DIR_NAME, 'agent');
241
+ }
242
+ /** Get path to user's custom themes directory */
243
+ export function getCustomThemesDir() {
244
+ return join(getAgentDir(), 'themes');
245
+ }
246
+ /** Get path to models.json */
247
+ export function getModelsPath() {
248
+ return join(getAgentDir(), 'models.json');
249
+ }
250
+ /** Get path to auth.json */
251
+ export function getAuthPath() {
252
+ return join(getAgentDir(), 'auth.json');
253
+ }
254
+ /** Get path to settings.json */
255
+ export function getSettingsPath() {
256
+ return join(getAgentDir(), 'settings.json');
257
+ }
258
+ /** Get path to managed binaries directory (fd, rg) */
259
+ export function getBinDir() {
260
+ return join(getAgentDir(), 'bin');
261
+ }
262
+ /** Get path to prompt templates directory */
263
+ export function getPromptsDir() {
264
+ return join(getAgentDir(), 'prompts');
265
+ }
266
+ /** Get path to sessions directory */
267
+ export function getSessionsDir() {
268
+ return join(getAgentDir(), 'sessions');
269
+ }
270
+ /** Get path to debug log file */
271
+ export function getDebugLogPath() {
272
+ return join(getAgentDir(), `${APP_NAME}-debug.log`);
273
+ }
274
+ /** Get path to installed marker file */
275
+ export function getInstalledMarkerPath() {
276
+ return join(getAgentDir(), '.installed');
277
+ }
278
+ /** Check if ShortcutXL installation has been completed (marker file exists). */
279
+ export function isInstalled() {
280
+ return existsSync(getInstalledMarkerPath());
281
+ }
282
+ /** Enable dev-only features (e.g. /export, verbose tool-download messages). */
283
+ export const DEV_MODE = process.env.SHORTCUT_DEV_MODE === '1';
284
+ /** Get path to ShortcutXL.xll (stable user-local copy at ~/.shortcut/agent/xll/). */
285
+ export function getXllPath() {
286
+ return join(getAgentDir(), "xll", "ShortcutXL.xll");
287
+ }
288
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Standardized abort/cancellation messages.
3
+ *
4
+ * Two audiences:
5
+ * - The **agent** (LLM) sees ABORT_AGENT_MESSAGE in tool results so it
6
+ * understands the user interrupted and can adjust.
7
+ * - The **user** sees ABORT_UI_MESSAGE rendered in the TUI.
8
+ */
9
+ /** Sent back to the LLM as the tool result text when a tool is interrupted. */
10
+ export const ABORT_AGENT_MESSAGE = 'User interrupted the operation.';
11
+ /** Shown to the user in the interactive UI when an operation is cancelled. */
12
+ export const ABORT_UI_LABEL = 'Interrupted \u00b7 What should Shortcut do instead?';
13
+ /** Short form for inline status indicators, e.g. "(interrupted)". */
14
+ export const ABORT_UI_LABEL_INLINE = '(interrupted)';
15
+ //# sourceMappingURL=abort.js.map
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Vendored agent loop from @mariozechner/pi-agent-core.
3
+ *
4
+ * SHORTCUT PATCH: executeToolCalls uses Promise.all for parallel execution
5
+ * instead of upstream's sequential for-loop. Steering is checked once after
6
+ * all tools complete, not between each tool.
7
+ */
8
+ import { EventStream, streamSimple, validateToolArguments } from '@mariozechner/pi-ai';
9
+ import { ABORT_AGENT_MESSAGE } from './abort.js';
10
+ import { DEFAULT_MAX_CHARS, ERROR_MAX_CHARS_LLM, truncateOutput } from './tools/truncate.js';
11
+ /** Yield to the event loop every N stream events to prevent microtask starvation. */
12
+ const STREAM_YIELD_INTERVAL = 5;
13
+ /**
14
+ * Start an agent loop with a new prompt message.
15
+ * The prompt is added to the context and events are emitted for it.
16
+ */
17
+ export function agentLoop(prompts, context, config, signal, streamFn) {
18
+ const stream = createAgentStream();
19
+ (async () => {
20
+ const newMessages = [...prompts];
21
+ const currentContext = {
22
+ ...context,
23
+ messages: [...context.messages, ...prompts]
24
+ };
25
+ stream.push({ type: 'agent_start' });
26
+ stream.push({ type: 'turn_start' });
27
+ for (const prompt of prompts) {
28
+ stream.push({ type: 'message_start', message: prompt });
29
+ stream.push({ type: 'message_end', message: prompt });
30
+ }
31
+ await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
32
+ })();
33
+ return stream;
34
+ }
35
+ /**
36
+ * Continue an agent loop from the current context without adding a new message.
37
+ * Used for retries - context already has user message or tool results.
38
+ *
39
+ * **Important:** The last message in context must convert to a `user` or `toolResult` message
40
+ * via `convertToLlm`. If it doesn't, the LLM provider will reject the request.
41
+ * This cannot be validated here since `convertToLlm` is only called once per turn.
42
+ */
43
+ export function agentLoopContinue(context, config, signal, streamFn) {
44
+ if (context.messages.length === 0) {
45
+ throw new Error('Cannot continue: no messages in context');
46
+ }
47
+ if (context.messages[context.messages.length - 1].role === 'assistant') {
48
+ throw new Error('Cannot continue from message role: assistant');
49
+ }
50
+ const stream = createAgentStream();
51
+ (async () => {
52
+ const newMessages = [];
53
+ const currentContext = { ...context };
54
+ stream.push({ type: 'agent_start' });
55
+ stream.push({ type: 'turn_start' });
56
+ await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
57
+ })();
58
+ return stream;
59
+ }
60
+ function createAgentStream() {
61
+ return new EventStream((event) => event.type === 'agent_end', (event) => (event.type === 'agent_end' ? event.messages : []));
62
+ }
63
+ /**
64
+ * Main loop logic shared by agentLoop and agentLoopContinue.
65
+ */
66
+ async function runLoop(currentContext, newMessages, config, signal, stream, streamFn) {
67
+ let firstTurn = true;
68
+ // Check for steering messages at start (user may have typed while waiting)
69
+ let pendingMessages = (await config.getSteeringMessages?.()) || [];
70
+ // Outer loop: continues when queued follow-up messages arrive after agent would stop
71
+ while (true) {
72
+ let hasMoreToolCalls = true;
73
+ let steeringAfterTools = null;
74
+ // Inner loop: process tool calls and steering messages
75
+ while (hasMoreToolCalls || pendingMessages.length > 0) {
76
+ if (!firstTurn) {
77
+ stream.push({ type: 'turn_start' });
78
+ }
79
+ else {
80
+ firstTurn = false;
81
+ }
82
+ // Process pending messages (inject before next assistant response)
83
+ if (pendingMessages.length > 0) {
84
+ for (const message of pendingMessages) {
85
+ stream.push({ type: 'message_start', message });
86
+ stream.push({ type: 'message_end', message });
87
+ currentContext.messages.push(message);
88
+ newMessages.push(message);
89
+ }
90
+ pendingMessages = [];
91
+ }
92
+ // SHORTCUT PATCH: switch to invokeAssistantResponse for non-streaming.
93
+ const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
94
+ newMessages.push(message);
95
+ if (message.stopReason === 'error' || message.stopReason === 'aborted') {
96
+ // Ensure the assistant message is never blank — inject error text so
97
+ // retries give the LLM useful context instead of an empty message.
98
+ // Skip for aborts: user-initiated cancellations are handled by the UI
99
+ // abort label and don't need "[Request failed: ...]" injected.
100
+ if (message.stopReason !== 'aborted' && message.content.length === 0 && message.errorMessage) {
101
+ message.content.push({
102
+ type: 'text',
103
+ text: `[Request failed: ${message.errorMessage.slice(0, ERROR_MAX_CHARS_LLM)}]`
104
+ });
105
+ }
106
+ // If the errored/aborted response contains tool calls, synthesize
107
+ // error tool_results so the tool_use→tool_result contract is never
108
+ // violated. Without this, the orphaned tool_use blocks make every
109
+ // subsequent API call fail with a 400.
110
+ const orphanedToolCalls = message.content.filter((c) => c.type === 'toolCall');
111
+ const errorToolResults = orphanedToolCalls.map((tc) => ({
112
+ role: 'toolResult',
113
+ toolCallId: tc.id,
114
+ toolName: tc.name,
115
+ content: [
116
+ {
117
+ type: 'text',
118
+ text: message.stopReason === 'aborted'
119
+ ? ABORT_AGENT_MESSAGE
120
+ : `Tool call failed: ${message.errorMessage || 'unknown error'}`
121
+ }
122
+ ],
123
+ isError: true,
124
+ timestamp: Date.now()
125
+ }));
126
+ for (const result of errorToolResults) {
127
+ stream.push({ type: 'message_start', message: result });
128
+ stream.push({ type: 'message_end', message: result });
129
+ newMessages.push(result);
130
+ }
131
+ stream.push({ type: 'turn_end', message, toolResults: errorToolResults });
132
+ stream.push({ type: 'agent_end', messages: newMessages });
133
+ stream.end(newMessages);
134
+ return;
135
+ }
136
+ // Check for tool calls
137
+ const toolCalls = message.content.filter((c) => c.type === 'toolCall');
138
+ hasMoreToolCalls = toolCalls.length > 0;
139
+ const toolResults = [];
140
+ if (hasMoreToolCalls) {
141
+ const toolExecution = await executeToolCalls(currentContext.tools, message, signal, stream, config.getSteeringMessages);
142
+ toolResults.push(...toolExecution.toolResults);
143
+ steeringAfterTools = toolExecution.steeringMessages ?? null;
144
+ for (const result of toolResults) {
145
+ currentContext.messages.push(result);
146
+ newMessages.push(result);
147
+ }
148
+ }
149
+ stream.push({ type: 'turn_end', message, toolResults });
150
+ // Get steering messages after turn completes
151
+ if (steeringAfterTools && steeringAfterTools.length > 0) {
152
+ pendingMessages = steeringAfterTools;
153
+ steeringAfterTools = null;
154
+ }
155
+ else {
156
+ pendingMessages = (await config.getSteeringMessages?.()) || [];
157
+ }
158
+ }
159
+ // Agent would stop here. Check for follow-up messages.
160
+ const followUpMessages = (await config.getFollowUpMessages?.()) || [];
161
+ if (followUpMessages.length > 0) {
162
+ // Set as pending so inner loop processes them
163
+ pendingMessages = followUpMessages;
164
+ continue;
165
+ }
166
+ // No more messages, exit
167
+ break;
168
+ }
169
+ stream.push({ type: 'agent_end', messages: newMessages });
170
+ stream.end(newMessages);
171
+ }
172
+ /**
173
+ * Build the LLM context and resolve the API key.
174
+ * Shared setup for both streaming and invoke paths.
175
+ */
176
+ async function prepareLlmCall(context, config, signal, streamFn) {
177
+ // Apply context transform if configured (AgentMessage[] → AgentMessage[])
178
+ let messages = context.messages;
179
+ if (config.transformContext) {
180
+ messages = await config.transformContext(messages, signal);
181
+ }
182
+ // Convert to LLM-compatible messages (AgentMessage[] → Message[])
183
+ const llmMessages = await config.convertToLlm(messages);
184
+ const llmContext = {
185
+ systemPrompt: context.systemPrompt,
186
+ messages: llmMessages,
187
+ tools: context.tools
188
+ };
189
+ const streamFunction = streamFn || streamSimple;
190
+ const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
191
+ return { llmContext, streamFunction, resolvedApiKey };
192
+ }
193
+ /**
194
+ * Get an assistant response via invoke (non-streaming).
195
+ * Waits for the complete response, then emits message_start/message_end.
196
+ * Currently unused — swap with streamAssistantResponse in runLoop to enable.
197
+ */
198
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
199
+ async function invokeAssistantResponse(context, config, signal, stream, streamFn) {
200
+ const { llmContext, streamFunction, resolvedApiKey } = await prepareLlmCall(context, config, signal, streamFn);
201
+ const response = await streamFunction(config.model, llmContext, {
202
+ ...config,
203
+ apiKey: resolvedApiKey,
204
+ signal
205
+ });
206
+ const finalMessage = await response.result();
207
+ context.messages.push(finalMessage);
208
+ stream.push({ type: 'message_start', message: { ...finalMessage } });
209
+ stream.push({ type: 'message_end', message: finalMessage });
210
+ return finalMessage;
211
+ }
212
+ /**
213
+ * Get an assistant response via streaming.
214
+ * Emits message_start, message_update deltas, then message_end.
215
+ */
216
+ async function streamAssistantResponse(context, config, signal, stream, streamFn) {
217
+ const { llmContext, streamFunction, resolvedApiKey } = await prepareLlmCall(context, config, signal, streamFn);
218
+ const response = await streamFunction(config.model, llmContext, {
219
+ ...config,
220
+ apiKey: resolvedApiKey,
221
+ signal
222
+ });
223
+ let partialMessage = null;
224
+ let addedPartial = false;
225
+ // SHORTCUT PATCH: yield to the event loop every N events to prevent
226
+ // microtask starvation that blocks TUI rendering on slower machines.
227
+ let eventCount = 0;
228
+ for await (const event of response) {
229
+ if (++eventCount % STREAM_YIELD_INTERVAL === 0) {
230
+ await new Promise((resolve) => setImmediate(resolve));
231
+ }
232
+ switch (event.type) {
233
+ case 'start':
234
+ partialMessage = event.partial;
235
+ context.messages.push(partialMessage);
236
+ addedPartial = true;
237
+ stream.push({ type: 'message_start', message: { ...partialMessage } });
238
+ break;
239
+ case 'text_start':
240
+ case 'text_delta':
241
+ case 'text_end':
242
+ case 'thinking_start':
243
+ case 'thinking_delta':
244
+ case 'thinking_end':
245
+ case 'toolcall_start':
246
+ case 'toolcall_delta':
247
+ case 'toolcall_end':
248
+ if (partialMessage) {
249
+ partialMessage = event.partial;
250
+ context.messages[context.messages.length - 1] = partialMessage;
251
+ stream.push({
252
+ type: 'message_update',
253
+ assistantMessageEvent: event,
254
+ message: { ...partialMessage }
255
+ });
256
+ }
257
+ break;
258
+ case 'done':
259
+ case 'error': {
260
+ const finalMessage = await response.result();
261
+ if (addedPartial) {
262
+ context.messages[context.messages.length - 1] = finalMessage;
263
+ }
264
+ else {
265
+ context.messages.push(finalMessage);
266
+ }
267
+ if (!addedPartial) {
268
+ stream.push({ type: 'message_start', message: { ...finalMessage } });
269
+ }
270
+ stream.push({ type: 'message_end', message: finalMessage });
271
+ return finalMessage;
272
+ }
273
+ }
274
+ }
275
+ return await response.result();
276
+ }
277
+ // SHORTCUT PATCH: parallel tool execution via Promise.all (upstream uses sequential for-loop).
278
+ // All tool calls run concurrently. Steering is checked once after all tools complete.
279
+ async function executeToolCalls(tools, assistantMessage, signal, stream, getSteeringMessages) {
280
+ const toolCalls = assistantMessage.content.filter((c) => c.type === 'toolCall');
281
+ const results = await Promise.all(toolCalls.map(async (toolCall) => {
282
+ const tool = tools?.find((t) => t.name === toolCall.name);
283
+ stream.push({
284
+ type: 'tool_execution_start',
285
+ toolCallId: toolCall.id,
286
+ toolName: toolCall.name,
287
+ args: toolCall.arguments
288
+ });
289
+ let result;
290
+ let isError = false;
291
+ try {
292
+ if (!tool)
293
+ throw new Error(`Tool ${toolCall.name} not found`);
294
+ const validatedArgs = validateToolArguments(tool, toolCall);
295
+ result = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {
296
+ stream.push({
297
+ type: 'tool_execution_update',
298
+ toolCallId: toolCall.id,
299
+ toolName: toolCall.name,
300
+ args: toolCall.arguments,
301
+ partialResult
302
+ });
303
+ });
304
+ }
305
+ catch (e) {
306
+ result = {
307
+ content: [{ type: 'text', text: e instanceof Error ? e.message : String(e) }],
308
+ details: {}
309
+ };
310
+ isError = true;
311
+ }
312
+ // SHORTCUT PATCH: central truncation safety net — ensures no oversized tool
313
+ // result reaches the LLM or trace logs, even if a tool forgets to truncate.
314
+ // Errors get a tighter limit (500 chars) since error bodies are rarely useful.
315
+ const maxChars = isError ? ERROR_MAX_CHARS_LLM : DEFAULT_MAX_CHARS;
316
+ result = {
317
+ ...result,
318
+ content: result.content.map((block) => {
319
+ if (block.type === 'text' && block.text.length > maxChars) {
320
+ return { ...block, text: truncateOutput(block.text, maxChars) };
321
+ }
322
+ return block;
323
+ })
324
+ };
325
+ stream.push({
326
+ type: 'tool_execution_end',
327
+ toolCallId: toolCall.id,
328
+ toolName: toolCall.name,
329
+ result,
330
+ isError
331
+ });
332
+ const toolResultMessage = {
333
+ role: 'toolResult',
334
+ toolCallId: toolCall.id,
335
+ toolName: toolCall.name,
336
+ content: result.content,
337
+ details: result.details,
338
+ isError,
339
+ timestamp: Date.now()
340
+ };
341
+ stream.push({ type: 'message_start', message: toolResultMessage });
342
+ stream.push({ type: 'message_end', message: toolResultMessage });
343
+ return toolResultMessage;
344
+ }));
345
+ // Check steering once after all tools complete
346
+ const steeringMessages = getSteeringMessages ? await getSteeringMessages() : undefined;
347
+ return {
348
+ toolResults: results,
349
+ steeringMessages: steeringMessages?.length ? steeringMessages : undefined
350
+ };
351
+ }
352
+ //# sourceMappingURL=agent-loop.js.map