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,226 @@
1
+ /**
2
+ * Job CRUD and execution-result logic.
3
+ *
4
+ * Pure functions that operate on CronJob objects — no I/O.
5
+ */
6
+ import crypto from 'node:crypto';
7
+ import { computeNextRunAtMs } from './schedule.js';
8
+ // -- Constants ---------------------------------------------------------------
9
+ /** Clear runningAtMs markers older than this (stuck run detection). */
10
+ export const STUCK_RUN_MS = 2 * 60 * 60 * 1000;
11
+ /** Exponential backoff delays indexed by consecutive error count. */
12
+ const BACKOFF_MS = [
13
+ 30_000, // 1st → 30s
14
+ 60_000, // 2nd → 1m
15
+ 5 * 60_000, // 3rd → 5m
16
+ 15 * 60_000, // 4th → 15m
17
+ 60 * 60_000 // 5th+ → 60m
18
+ ];
19
+ /** Minimum gap between consecutive fires to prevent spin-loops. */
20
+ const MIN_REFIRE_GAP_MS = 2_000;
21
+ /** Max consecutive schedule errors before auto-disabling. */
22
+ const MAX_SCHEDULE_ERRORS = 3;
23
+ /** Max transient retries for one-shot (at) jobs. */
24
+ const MAX_TRANSIENT_RETRIES = 3;
25
+ const TRANSIENT_PATTERNS = [
26
+ /rate[_ ]limit|too many requests|429/i,
27
+ /overloaded|529|high demand/i,
28
+ /network|econnreset|econnrefused|fetch failed|socket/i,
29
+ /timeout|etimedout/i,
30
+ /(?:status|http|code)[:\s]+5\d{2}\b/i
31
+ ];
32
+ // -- Helpers -----------------------------------------------------------------
33
+ function errorBackoffMs(consecutiveErrors) {
34
+ const idx = Math.min(consecutiveErrors - 1, BACKOFF_MS.length - 1);
35
+ return BACKOFF_MS[Math.max(0, idx)];
36
+ }
37
+ function isTransientError(error) {
38
+ if (!error)
39
+ return false;
40
+ return TRANSIENT_PATTERNS.some((re) => re.test(error));
41
+ }
42
+ // -- Create / Patch ----------------------------------------------------------
43
+ export function createJob(input, nowMs) {
44
+ const id = crypto.randomUUID();
45
+ const schedule = input.schedule.kind === 'every' && input.schedule.anchorMs == null
46
+ ? { ...input.schedule, anchorMs: nowMs }
47
+ : input.schedule;
48
+ const deleteAfterRun = typeof input.deleteAfterRun === 'boolean'
49
+ ? input.deleteAfterRun
50
+ : schedule.kind === 'at'
51
+ ? true
52
+ : undefined;
53
+ const job = {
54
+ id,
55
+ name: input.name,
56
+ description: input.description,
57
+ enabled: input.enabled ?? true,
58
+ deleteAfterRun,
59
+ createdAtMs: nowMs,
60
+ updatedAtMs: nowMs,
61
+ schedule,
62
+ payload: input.payload,
63
+ state: { ...input.state }
64
+ };
65
+ job.state.nextRunAtMs = computeJobNextRun(job, nowMs);
66
+ return job;
67
+ }
68
+ export function applyJobPatch(job, patch, nowMs) {
69
+ if ('name' in patch && patch.name != null)
70
+ job.name = patch.name;
71
+ if ('description' in patch)
72
+ job.description = patch.description;
73
+ if (typeof patch.enabled === 'boolean')
74
+ job.enabled = patch.enabled;
75
+ if (typeof patch.deleteAfterRun === 'boolean')
76
+ job.deleteAfterRun = patch.deleteAfterRun;
77
+ if (patch.schedule)
78
+ job.schedule = patch.schedule;
79
+ if (patch.payload)
80
+ job.payload = { ...job.payload, ...patch.payload };
81
+ if (patch.state)
82
+ job.state = { ...job.state, ...patch.state };
83
+ job.updatedAtMs = nowMs;
84
+ // Recompute nextRunAtMs if schedule or enabled changed
85
+ if (patch.schedule != null || patch.enabled != null) {
86
+ job.state.nextRunAtMs = job.enabled ? computeJobNextRun(job, nowMs) : undefined;
87
+ if (!job.enabled)
88
+ job.state.runningAtMs = undefined;
89
+ if (patch.schedule != null)
90
+ job.state.scheduleErrorCount = 0;
91
+ }
92
+ }
93
+ // -- Schedule computation ----------------------------------------------------
94
+ export function computeJobNextRun(job, nowMs) {
95
+ if (!job.enabled)
96
+ return undefined;
97
+ // For 'every' jobs, anchor to lastRunAtMs if available
98
+ if (job.schedule.kind === 'every') {
99
+ const lastRun = job.state.lastRunAtMs;
100
+ if (typeof lastRun === 'number' && Number.isFinite(lastRun)) {
101
+ const next = Math.floor(lastRun) + Math.max(1, Math.floor(job.schedule.everyMs));
102
+ if (next > nowMs)
103
+ return next;
104
+ }
105
+ }
106
+ // For 'at' jobs that already ran successfully, don't re-schedule
107
+ if (job.schedule.kind === 'at' && job.state.lastRunStatus === 'ok') {
108
+ return undefined;
109
+ }
110
+ return computeNextRunAtMs(job.schedule, nowMs);
111
+ }
112
+ // -- Job-due check -----------------------------------------------------------
113
+ export function isJobDue(job, nowMs, forced = false) {
114
+ if (!job.enabled)
115
+ return false;
116
+ if (typeof job.state.runningAtMs === 'number')
117
+ return false;
118
+ if (forced)
119
+ return true;
120
+ return typeof job.state.nextRunAtMs === 'number' && nowMs >= job.state.nextRunAtMs;
121
+ }
122
+ /**
123
+ * Apply an execution result to a job's state.
124
+ * Returns true if the job should be deleted (one-shot success with deleteAfterRun).
125
+ */
126
+ export function applyJobResult(job, result) {
127
+ job.state.runningAtMs = undefined;
128
+ job.state.lastRunAtMs = result.startedAt;
129
+ job.state.lastRunStatus = result.status;
130
+ job.state.lastDurationMs = Math.max(0, result.endedAt - result.startedAt);
131
+ job.state.lastError = result.error;
132
+ job.updatedAtMs = result.endedAt;
133
+ if (result.status === 'error') {
134
+ job.state.consecutiveErrors = (job.state.consecutiveErrors ?? 0) + 1;
135
+ }
136
+ else {
137
+ job.state.consecutiveErrors = 0;
138
+ }
139
+ const shouldDelete = job.schedule.kind === 'at' &&
140
+ job.deleteAfterRun === true &&
141
+ (result.status === 'ok' || result.status === 'skipped');
142
+ if (shouldDelete)
143
+ return true;
144
+ if (job.schedule.kind === 'at') {
145
+ if (result.status === 'ok' || result.status === 'skipped') {
146
+ job.enabled = false;
147
+ job.state.nextRunAtMs = undefined;
148
+ }
149
+ else {
150
+ // One-shot error: retry if transient
151
+ const consecutive = job.state.consecutiveErrors ?? 1;
152
+ if (isTransientError(result.error) && consecutive <= MAX_TRANSIENT_RETRIES) {
153
+ job.state.nextRunAtMs = result.endedAt + errorBackoffMs(consecutive);
154
+ }
155
+ else {
156
+ job.enabled = false;
157
+ job.state.nextRunAtMs = undefined;
158
+ }
159
+ }
160
+ }
161
+ else if (result.status === 'error' && job.enabled) {
162
+ // Recurring job error: apply backoff
163
+ const backoff = errorBackoffMs(job.state.consecutiveErrors ?? 1);
164
+ const normalNext = computeJobNextRun(job, result.endedAt);
165
+ const backoffNext = result.endedAt + backoff;
166
+ job.state.nextRunAtMs = normalNext != null ? Math.max(normalNext, backoffNext) : backoffNext;
167
+ }
168
+ else if (job.enabled) {
169
+ // Recurring job success — enforce minimum gap to prevent spin loops
170
+ const naturalNext = computeJobNextRun(job, result.endedAt);
171
+ const minNext = result.endedAt + MIN_REFIRE_GAP_MS;
172
+ job.state.nextRunAtMs = naturalNext != null ? Math.max(naturalNext, minNext) : minNext;
173
+ }
174
+ else {
175
+ job.state.nextRunAtMs = undefined;
176
+ }
177
+ return false;
178
+ }
179
+ // -- Maintenance -------------------------------------------------------------
180
+ /**
181
+ * Normalize tick state: clear stuck runningAtMs, repair missing nextRunAtMs.
182
+ * Returns true if any field was changed.
183
+ */
184
+ export function normalizeJobState(job, nowMs) {
185
+ let changed = false;
186
+ // Clear stuck runs
187
+ const runningAt = job.state.runningAtMs;
188
+ if (typeof runningAt === 'number' && nowMs - runningAt > STUCK_RUN_MS) {
189
+ job.state.runningAtMs = undefined;
190
+ changed = true;
191
+ }
192
+ // Disabled jobs should have no schedule
193
+ if (!job.enabled) {
194
+ if (job.state.nextRunAtMs != null) {
195
+ job.state.nextRunAtMs = undefined;
196
+ changed = true;
197
+ }
198
+ if (job.state.runningAtMs != null) {
199
+ job.state.runningAtMs = undefined;
200
+ changed = true;
201
+ }
202
+ return changed;
203
+ }
204
+ // Repair missing nextRunAtMs for enabled jobs
205
+ if (job.state.nextRunAtMs == null) {
206
+ const computed = computeJobNextRun(job, nowMs);
207
+ if (computed != null) {
208
+ job.state.nextRunAtMs = computed;
209
+ changed = true;
210
+ }
211
+ }
212
+ return changed;
213
+ }
214
+ /**
215
+ * Record a schedule computation error. Auto-disables after MAX_SCHEDULE_ERRORS.
216
+ */
217
+ export function recordScheduleError(job, err) {
218
+ const count = (job.state.scheduleErrorCount ?? 0) + 1;
219
+ job.state.scheduleErrorCount = count;
220
+ job.state.nextRunAtMs = undefined;
221
+ job.state.lastError = `schedule error: ${String(err)}`;
222
+ if (count >= MAX_SCHEDULE_ERRORS) {
223
+ job.enabled = false;
224
+ }
225
+ }
226
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Run log — append-only NDJSON log of cron job executions.
3
+ *
4
+ * Each job gets its own log file: cron/runs/<jobId>.ndjson
5
+ * One line per execution with timestamp, status, duration, and error.
6
+ */
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import { getCronDir } from './store.js';
10
+ function getRunsDir() {
11
+ return path.join(getCronDir(), 'runs');
12
+ }
13
+ /** Max output stored per run (truncated beyond this). */
14
+ const MAX_LOG_OUTPUT = 4096;
15
+ /** Truncate output for storage. */
16
+ export function truncateRunOutput(text) {
17
+ if (text.length <= MAX_LOG_OUTPUT)
18
+ return text;
19
+ return text.slice(0, MAX_LOG_OUTPUT) + '\n... (truncated)';
20
+ }
21
+ /** Append a run log entry for a completed job. */
22
+ export async function appendRunLog(entry, runsDir = getRunsDir()) {
23
+ await fs.promises.mkdir(runsDir, { recursive: true, mode: 0o700 });
24
+ const logPath = path.join(runsDir, `${entry.jobId}.ndjson`);
25
+ const line = JSON.stringify(entry) + '\n';
26
+ await fs.promises.appendFile(logPath, line, { encoding: 'utf-8', mode: 0o600 });
27
+ }
28
+ /** Read recent run log entries for a job (newest first, up to limit). */
29
+ export async function readRunLog(jobId, limit = 20, runsDir = getRunsDir()) {
30
+ const logPath = path.join(runsDir, `${jobId}.ndjson`);
31
+ let raw;
32
+ try {
33
+ raw = await fs.promises.readFile(logPath, 'utf-8');
34
+ }
35
+ catch {
36
+ return [];
37
+ }
38
+ const lines = raw.trim().split('\n').filter(Boolean);
39
+ const entries = [];
40
+ // Read from end for newest-first
41
+ for (let i = lines.length - 1; i >= 0 && entries.length < limit; i--) {
42
+ try {
43
+ entries.push(JSON.parse(lines[i]));
44
+ }
45
+ catch {
46
+ // Skip corrupt lines
47
+ }
48
+ }
49
+ return entries;
50
+ }
51
+ //# sourceMappingURL=run-log.js.map
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Schedule computation — next-run-at logic for all three schedule kinds.
3
+ *
4
+ * Pure functions. No I/O. Caches parsed Cron instances for performance.
5
+ */
6
+ import { Cron } from 'croner';
7
+ // ---------------------------------------------------------------------------
8
+ // Cron expression cache
9
+ // ---------------------------------------------------------------------------
10
+ const CACHE_MAX = 512;
11
+ const cronCache = new Map();
12
+ function getCron(expr, tz) {
13
+ const key = tz ? `${expr}|${tz}` : expr;
14
+ let cron = cronCache.get(key);
15
+ if (cron)
16
+ return cron;
17
+ // Evict oldest entry if cache is full (FIFO)
18
+ if (cronCache.size >= CACHE_MAX) {
19
+ const oldest = cronCache.keys().next().value;
20
+ if (oldest)
21
+ cronCache.delete(oldest);
22
+ }
23
+ cron = new Cron(expr, { timezone: tz });
24
+ cronCache.set(key, cron);
25
+ return cron;
26
+ }
27
+ // ---------------------------------------------------------------------------
28
+ // Next-run computation
29
+ // ---------------------------------------------------------------------------
30
+ /**
31
+ * Compute the next run timestamp (epoch ms) for a schedule.
32
+ * Returns undefined if the schedule has no future runs (e.g. past "at" time).
33
+ */
34
+ export function computeNextRunAtMs(schedule, nowMs) {
35
+ switch (schedule.kind) {
36
+ case 'at': {
37
+ const target = new Date(schedule.at).getTime();
38
+ if (!Number.isFinite(target)) {
39
+ throw new Error(`Invalid "at" timestamp: ${schedule.at}`);
40
+ }
41
+ return target > nowMs ? target : undefined;
42
+ }
43
+ case 'every': {
44
+ const everyMs = Math.max(1, Math.floor(schedule.everyMs));
45
+ const anchor = typeof schedule.anchorMs === 'number' && Number.isFinite(schedule.anchorMs)
46
+ ? schedule.anchorMs
47
+ : nowMs;
48
+ if (anchor > nowMs)
49
+ return anchor;
50
+ const elapsed = nowMs - anchor;
51
+ const steps = Math.max(1, Math.ceil(elapsed / everyMs));
52
+ return anchor + steps * everyMs;
53
+ }
54
+ case 'cron': {
55
+ const cron = getCron(schedule.expr, schedule.tz);
56
+ const now = new Date(nowMs);
57
+ let next = cron.nextRun(now);
58
+ // Workaround: croner can return a past time if the reference date
59
+ // is very close to (but just after) a fire time, especially with
60
+ // timezone offsets. Retry with a +1s bump.
61
+ if (next && next.getTime() <= nowMs) {
62
+ const bumped = new Date(nowMs + 1000);
63
+ const retry = cron.nextRun(bumped);
64
+ if (retry && retry.getTime() > nowMs) {
65
+ next = retry;
66
+ }
67
+ }
68
+ return next ? next.getTime() : undefined;
69
+ }
70
+ }
71
+ }
72
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Cron status line — renders a one-line summary for the TUI footer.
3
+ *
4
+ * Reads jobs.json (cached) and PID file to build a status string like:
5
+ * ⏰ 3 jobs · next: "Morning Report" in 2m · scheduler: running
6
+ * ⏰ 0 jobs · scheduler: stopped
7
+ */
8
+ import { getDaemonStatus } from './daemon-ipc.js';
9
+ import { getCronStorePath, loadCronStore } from './store.js';
10
+ const STATUS_KEY = 'cron';
11
+ const POLL_INTERVAL_MS = 15_000;
12
+ let timer = null;
13
+ // ---------------------------------------------------------------------------
14
+ // Time formatting
15
+ // ---------------------------------------------------------------------------
16
+ function formatDelta(ms) {
17
+ if (ms < 0)
18
+ return 'now';
19
+ const secs = Math.round(ms / 1000);
20
+ if (secs < 60)
21
+ return `${secs}s`;
22
+ const mins = Math.round(secs / 60);
23
+ if (mins < 60)
24
+ return `${mins}m`;
25
+ const hours = Math.floor(mins / 60);
26
+ const remainMins = mins % 60;
27
+ return remainMins > 0 ? `${hours}h ${remainMins}m` : `${hours}h`;
28
+ }
29
+ export async function computeCronStatus(storePath = getCronStorePath()) {
30
+ const daemon = getDaemonStatus();
31
+ let jobCount = 0;
32
+ let nextJobName;
33
+ let nextRunMs;
34
+ try {
35
+ const store = await loadCronStore(storePath);
36
+ const enabled = store.jobs.filter((j) => j.enabled);
37
+ jobCount = enabled.length;
38
+ // Find the next job to fire
39
+ let nearestMs = Infinity;
40
+ for (const job of enabled) {
41
+ const next = job.state.nextRunAtMs;
42
+ if (typeof next === 'number' && next < nearestMs) {
43
+ nearestMs = next;
44
+ nextJobName = job.name;
45
+ nextRunMs = next;
46
+ }
47
+ }
48
+ }
49
+ catch {
50
+ // Store doesn't exist or is corrupt — show minimal status
51
+ }
52
+ const parts = [];
53
+ // Job count
54
+ const jobLabel = jobCount === 1 ? '1 job' : `${jobCount} jobs`;
55
+ parts.push(jobLabel);
56
+ // Next fire
57
+ if (nextRunMs != null && nextJobName) {
58
+ const delta = nextRunMs - Date.now();
59
+ parts.push(`next: "${nextJobName}" in ${formatDelta(delta)}`);
60
+ }
61
+ // Scheduler status
62
+ parts.push(`scheduler: ${daemon.running ? 'running' : 'stopped'}`);
63
+ const text = `⏰ ${parts.join(' · ')}`;
64
+ return { text, jobCount, schedulerRunning: daemon.running };
65
+ }
66
+ /**
67
+ * Start polling cron status and updating the TUI footer.
68
+ * Call once from main.ts after InteractiveMode is ready.
69
+ */
70
+ export function startCronStatusPolling(setStatus, storePath = getCronStorePath()) {
71
+ stopCronStatusPolling();
72
+ const update = async () => {
73
+ try {
74
+ const { text, jobCount, schedulerRunning } = await computeCronStatus(storePath);
75
+ // Only show status if there are jobs or the scheduler is running
76
+ if (jobCount > 0 || schedulerRunning) {
77
+ setStatus(STATUS_KEY, text);
78
+ }
79
+ else {
80
+ setStatus(STATUS_KEY, undefined);
81
+ }
82
+ }
83
+ catch {
84
+ // Silently ignore — don't crash the TUI
85
+ }
86
+ };
87
+ // Initial update
88
+ void update();
89
+ timer = setInterval(() => void update(), POLL_INTERVAL_MS);
90
+ timer.unref();
91
+ }
92
+ function stopCronStatusPolling() {
93
+ if (timer) {
94
+ clearInterval(timer);
95
+ timer = null;
96
+ }
97
+ }
98
+ //# sourceMappingURL=status-line.js.map
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Cron job store — persistent JSON file with atomic writes.
3
+ *
4
+ * Jobs live at ~/.shortcut/agent/cron/jobs.json.
5
+ * Writes use temp-file + rename for crash safety, with a .bak backup.
6
+ */
7
+ import { randomBytes } from 'node:crypto';
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { getAgentDir } from '../../config.js';
11
+ /** Lazy getter — avoids caching getAgentDir() at module load time. */
12
+ export function getCronDir() {
13
+ return path.join(getAgentDir(), 'cron');
14
+ }
15
+ /** Lazy getter — avoids caching getAgentDir() at module load time. */
16
+ export function getCronStorePath() {
17
+ return path.join(getCronDir(), 'jobs.json');
18
+ }
19
+ /** Cache to skip writes when content hasn't changed. */
20
+ const serializedCache = new Map();
21
+ export async function loadCronStore(storePath = getCronStorePath()) {
22
+ try {
23
+ const raw = await fs.promises.readFile(storePath, 'utf-8');
24
+ const parsed = JSON.parse(raw);
25
+ if (typeof parsed.version === 'number' && parsed.version !== 1) {
26
+ throw new Error(`Unsupported cron store version: ${parsed.version}`);
27
+ }
28
+ if ('jobs' in parsed && !Array.isArray(parsed.jobs)) {
29
+ throw new Error('Corrupt cron store: jobs is not an array');
30
+ }
31
+ const jobs = Array.isArray(parsed.jobs)
32
+ ? parsed.jobs.filter((j) => j != null &&
33
+ typeof j === 'object' &&
34
+ typeof j.id === 'string')
35
+ : [];
36
+ const store = { version: 1, jobs: jobs };
37
+ serializedCache.set(storePath, JSON.stringify(store, null, 2));
38
+ return store;
39
+ }
40
+ catch (err) {
41
+ if (err.code === 'ENOENT') {
42
+ serializedCache.delete(storePath);
43
+ return { version: 1, jobs: [] };
44
+ }
45
+ throw err;
46
+ }
47
+ }
48
+ export async function saveCronStore(storePath, store, opts) {
49
+ const json = JSON.stringify(store, null, 2);
50
+ if (serializedCache.get(storePath) === json)
51
+ return;
52
+ const dir = path.dirname(storePath);
53
+ await fs.promises.mkdir(dir, { recursive: true, mode: 0o700 });
54
+ // Backup existing file
55
+ if (!opts?.skipBackup) {
56
+ try {
57
+ await fs.promises.copyFile(storePath, `${storePath}.bak`);
58
+ }
59
+ catch {
60
+ // best-effort — file may not exist yet
61
+ }
62
+ }
63
+ // Atomic write: temp file → rename
64
+ const tmp = `${storePath}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
65
+ await fs.promises.writeFile(tmp, json, { encoding: 'utf-8', mode: 0o600 });
66
+ try {
67
+ await fs.promises.rename(tmp, storePath);
68
+ }
69
+ catch (err) {
70
+ // Windows fallback: rename can fail with EPERM/EEXIST when dest exists
71
+ const code = err.code;
72
+ if (code === 'EPERM' || code === 'EEXIST') {
73
+ await fs.promises.copyFile(tmp, storePath);
74
+ await fs.promises.unlink(tmp).catch(() => { });
75
+ }
76
+ else {
77
+ await fs.promises.unlink(tmp).catch(() => { });
78
+ throw err;
79
+ }
80
+ }
81
+ serializedCache.set(storePath, json);
82
+ }
83
+ /** Clear the serialization cache (for testing). */
84
+ export function clearStoreCache() {
85
+ serializedCache.clear();
86
+ }
87
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Cron job types.
3
+ *
4
+ * Simplified from OpenClaw — no delivery channels, no gateway, no failure alerts.
5
+ * Every cron job spawns an isolated agent run with a prompt.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Centralized dev-mode hooks for SHORTCUT_DEV_MODE=1.
3
+ *
4
+ * All dev-only behaviors are registered here so they're easy to discover,
5
+ * audit, and extend. The composition root (main.ts) calls getDevHooks()
6
+ * once and wires the returned hooks into the session/mode options.
7
+ *
8
+ * To add a new dev-mode feature:
9
+ * 1. Create a file in custom/dev/ with the implementation
10
+ * 2. Wire it into DevHooks and getDevHooks() below
11
+ * 3. Consume the hook in main.ts
12
+ */
13
+ import { exec } from 'child_process';
14
+ import { ALL_DEV_SLASH_COMMANDS } from '../../core/slash-commands.js';
15
+ import { exportDevTraces } from './trace-export.js';
16
+ function openInBrowser(filePath) {
17
+ const cmd = process.platform === 'win32'
18
+ ? `start "" "${filePath}"`
19
+ : process.platform === 'darwin'
20
+ ? `open "${filePath}"`
21
+ : `xdg-open "${filePath}"`;
22
+ exec(cmd, () => { });
23
+ }
24
+ /**
25
+ * Build all dev-mode hooks for the given session.
26
+ * Returns undefined when dev mode is off — callers can use optional chaining.
27
+ */
28
+ export function getDevHooks(session) {
29
+ // -- Trace export after each query --
30
+ let lastTracePaths = [];
31
+ const onAgentEnd = () => {
32
+ void exportDevTraces(session)
33
+ .then((paths) => {
34
+ lastTracePaths = paths;
35
+ })
36
+ .catch((err) => {
37
+ console.debug('[dev] trace export failed:', err);
38
+ });
39
+ };
40
+ // -- /trace command: open all traces in browser --
41
+ const onDevCommand = (command, showStatus) => {
42
+ if (command !== '/trace')
43
+ return false;
44
+ if (lastTracePaths.length === 0) {
45
+ showStatus('No traces exported yet');
46
+ return true;
47
+ }
48
+ for (const p of lastTracePaths)
49
+ openInBrowser(p);
50
+ showStatus(`Opened ${lastTracePaths.length} trace(s) in browser`);
51
+ return true;
52
+ };
53
+ return {
54
+ slashCommands: ALL_DEV_SLASH_COMMANDS,
55
+ onAgentEnd,
56
+ onDevCommand
57
+ };
58
+ }
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Dev-mode HTML export of session traces after each query.
3
+ *
4
+ * When SHORTCUT_DEV_MODE=1, exports the main session JSONL and any subagent
5
+ * JSONLs to HTML after each agent_end event. File paths are shown in the
6
+ * footer via extension statuses (one line per trace).
7
+ */
8
+ import { existsSync } from 'fs';
9
+ import { basename, dirname, join } from 'path';
10
+ import { exportFromFile } from '../../core/export-html/index.js';
11
+ /**
12
+ * Export main + subagent session JSONLs to HTML.
13
+ * Returns all exported HTML paths, or empty array if nothing was exported.
14
+ */
15
+ export async function exportDevTraces(session) {
16
+ const mainFile = session.sessionManager.getSessionFile();
17
+ if (!mainFile)
18
+ return [];
19
+ const outputDir = dirname(mainFile);
20
+ const paths = [];
21
+ // Export main session
22
+ try {
23
+ const mainBase = basename(mainFile, '.jsonl');
24
+ const mainHtml = join(outputDir, `${mainBase}.html`);
25
+ await exportFromFile(mainFile, { outputPath: mainHtml, title: 'Main Agent' });
26
+ paths.push(mainHtml);
27
+ }
28
+ catch {
29
+ // Silently skip — export may fail if session is empty
30
+ }
31
+ // Export subagent sessions from tool result details
32
+ const entries = session.sessionManager.getEntries();
33
+ let subIndex = 0;
34
+ for (const entry of entries) {
35
+ if (entry.type !== 'message')
36
+ continue;
37
+ const msg = entry.message;
38
+ if (msg?.role !== 'toolResult')
39
+ continue;
40
+ const subFile = msg?.details?.sessionFile;
41
+ if (typeof subFile === 'string' && existsSync(subFile)) {
42
+ try {
43
+ subIndex++;
44
+ const toolName = msg?.toolName;
45
+ const title = toolName ? `Subagent: ${toolName}` : `Subagent ${subIndex}`;
46
+ const subBase = basename(subFile, '.jsonl');
47
+ const subHtml = join(outputDir, `${subBase}.html`);
48
+ await exportFromFile(subFile, { outputPath: subHtml, title });
49
+ paths.push(subHtml);
50
+ }
51
+ catch {
52
+ // Skip failed subagent exports
53
+ }
54
+ }
55
+ }
56
+ return paths;
57
+ }
58
+ //# sourceMappingURL=trace-export.js.map