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,456 @@
1
+ /**
2
+ * Credential storage for API keys and OAuth tokens.
3
+ * Handles loading, saving, and refreshing credentials from auth.json.
4
+ *
5
+ * Uses file locking to prevent race conditions when multiple pi instances
6
+ * try to refresh tokens simultaneously.
7
+ */
8
+ import { getEnvApiKey, getOAuthApiKey, getOAuthProvider, getOAuthProviders } from '@mariozechner/pi-ai';
9
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
10
+ import { dirname, join } from 'path';
11
+ import lockfile from 'proper-lockfile';
12
+ import { getAgentDir } from '../config.js';
13
+ import { resolveConfigValue } from './resolve-config-value.js';
14
+ export class FileAuthStorageBackend {
15
+ authPath;
16
+ constructor(authPath = join(getAgentDir(), 'auth.json')) {
17
+ this.authPath = authPath;
18
+ }
19
+ ensureParentDir() {
20
+ const dir = dirname(this.authPath);
21
+ if (!existsSync(dir)) {
22
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
23
+ }
24
+ }
25
+ ensureFileExists() {
26
+ if (!existsSync(this.authPath)) {
27
+ writeFileSync(this.authPath, '{}', 'utf-8');
28
+ chmodSync(this.authPath, 0o600);
29
+ }
30
+ }
31
+ withLock(fn) {
32
+ this.ensureParentDir();
33
+ this.ensureFileExists();
34
+ let release;
35
+ try {
36
+ release = lockfile.lockSync(this.authPath, { realpath: false });
37
+ const current = existsSync(this.authPath) ? readFileSync(this.authPath, 'utf-8') : undefined;
38
+ const { result, next } = fn(current);
39
+ if (next !== undefined) {
40
+ writeFileSync(this.authPath, next, 'utf-8');
41
+ chmodSync(this.authPath, 0o600);
42
+ }
43
+ return result;
44
+ }
45
+ finally {
46
+ if (release) {
47
+ release();
48
+ }
49
+ }
50
+ }
51
+ async withLockAsync(fn) {
52
+ this.ensureParentDir();
53
+ this.ensureFileExists();
54
+ let release;
55
+ let lockCompromised = false;
56
+ let lockCompromisedError;
57
+ const throwIfCompromised = () => {
58
+ if (lockCompromised) {
59
+ throw lockCompromisedError ?? new Error('Auth storage lock was compromised');
60
+ }
61
+ };
62
+ try {
63
+ release = await lockfile.lock(this.authPath, {
64
+ retries: {
65
+ retries: 10,
66
+ factor: 2,
67
+ minTimeout: 100,
68
+ maxTimeout: 10000,
69
+ randomize: true
70
+ },
71
+ stale: 30000,
72
+ onCompromised: (err) => {
73
+ lockCompromised = true;
74
+ lockCompromisedError = err;
75
+ }
76
+ });
77
+ throwIfCompromised();
78
+ const current = existsSync(this.authPath) ? readFileSync(this.authPath, 'utf-8') : undefined;
79
+ const { result, next } = await fn(current);
80
+ throwIfCompromised();
81
+ if (next !== undefined) {
82
+ writeFileSync(this.authPath, next, 'utf-8');
83
+ chmodSync(this.authPath, 0o600);
84
+ }
85
+ throwIfCompromised();
86
+ return result;
87
+ }
88
+ finally {
89
+ if (release) {
90
+ try {
91
+ await release();
92
+ }
93
+ catch {
94
+ // Ignore unlock errors when lock is compromised.
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ /**
101
+ * Read-only file backend for subagents.
102
+ * Reads auth.json without file locking to avoid contention when multiple
103
+ * subagents spawn concurrently. Never writes — the parent process owns
104
+ * token refresh and persists updated credentials.
105
+ */
106
+ export class ReadOnlyFileAuthStorageBackend {
107
+ authPath;
108
+ constructor(authPath = join(getAgentDir(), 'auth.json')) {
109
+ this.authPath = authPath;
110
+ }
111
+ withLock(fn) {
112
+ let content;
113
+ try {
114
+ if (existsSync(this.authPath)) {
115
+ content = readFileSync(this.authPath, 'utf-8');
116
+ }
117
+ }
118
+ catch {
119
+ // File may be mid-write by parent — return undefined, caller will retry later
120
+ }
121
+ const { result } = fn(content);
122
+ // Ignore `next` — read-only backend never writes
123
+ return result;
124
+ }
125
+ async withLockAsync(fn) {
126
+ let content;
127
+ try {
128
+ if (existsSync(this.authPath)) {
129
+ content = readFileSync(this.authPath, 'utf-8');
130
+ }
131
+ }
132
+ catch {
133
+ // File may be mid-write by parent — return undefined, caller will retry later
134
+ }
135
+ const { result } = await fn(content);
136
+ // Ignore `next` — read-only backend never writes
137
+ return result;
138
+ }
139
+ }
140
+ export class InMemoryAuthStorageBackend {
141
+ value;
142
+ withLock(fn) {
143
+ const { result, next } = fn(this.value);
144
+ if (next !== undefined) {
145
+ this.value = next;
146
+ }
147
+ return result;
148
+ }
149
+ async withLockAsync(fn) {
150
+ const { result, next } = await fn(this.value);
151
+ if (next !== undefined) {
152
+ this.value = next;
153
+ }
154
+ return result;
155
+ }
156
+ }
157
+ /**
158
+ * Credential storage backed by a JSON file.
159
+ */
160
+ export class AuthStorage {
161
+ storage;
162
+ data = {};
163
+ runtimeOverrides = new Map();
164
+ fallbackResolver;
165
+ loadError = null;
166
+ errors = [];
167
+ _readOnly = false;
168
+ constructor(storage) {
169
+ this.storage = storage;
170
+ this.reload();
171
+ }
172
+ static create(authPath) {
173
+ return new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), 'auth.json')));
174
+ }
175
+ static fromStorage(storage) {
176
+ return new AuthStorage(storage);
177
+ }
178
+ /**
179
+ * Create a read-only AuthStorage backed by auth.json.
180
+ * Reads without file locking — safe for concurrent subagents.
181
+ * Never writes or refreshes tokens; call reload() periodically
182
+ * to pick up tokens refreshed by the parent process.
183
+ */
184
+ static createReadOnly(authPath) {
185
+ const instance = new AuthStorage(new ReadOnlyFileAuthStorageBackend(authPath ?? join(getAgentDir(), 'auth.json')));
186
+ instance._readOnly = true;
187
+ return instance;
188
+ }
189
+ static inMemory(data = {}) {
190
+ const storage = new InMemoryAuthStorageBackend();
191
+ storage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));
192
+ return AuthStorage.fromStorage(storage);
193
+ }
194
+ /**
195
+ * Set a runtime API key override (not persisted to disk).
196
+ * Used for CLI --api-key flag.
197
+ */
198
+ setRuntimeApiKey(provider, apiKey) {
199
+ this.runtimeOverrides.set(provider, apiKey);
200
+ }
201
+ /**
202
+ * Remove a runtime API key override.
203
+ */
204
+ removeRuntimeApiKey(provider) {
205
+ this.runtimeOverrides.delete(provider);
206
+ }
207
+ /**
208
+ * Set a fallback resolver for API keys not found in auth.json or env vars.
209
+ * Used for custom provider keys from models.json.
210
+ */
211
+ setFallbackResolver(resolver) {
212
+ this.fallbackResolver = resolver;
213
+ }
214
+ recordError(error) {
215
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
216
+ this.errors.push(normalizedError);
217
+ }
218
+ parseStorageData(content) {
219
+ if (!content) {
220
+ return {};
221
+ }
222
+ return JSON.parse(content);
223
+ }
224
+ /**
225
+ * Reload credentials from storage.
226
+ */
227
+ reload() {
228
+ let content;
229
+ try {
230
+ this.storage.withLock((current) => {
231
+ content = current;
232
+ return { result: undefined };
233
+ });
234
+ this.data = this.parseStorageData(content);
235
+ this.loadError = null;
236
+ }
237
+ catch (error) {
238
+ this.loadError = error;
239
+ this.recordError(error);
240
+ }
241
+ }
242
+ persistProviderChange(provider, credential) {
243
+ if (this.loadError) {
244
+ return;
245
+ }
246
+ try {
247
+ this.storage.withLock((current) => {
248
+ const currentData = this.parseStorageData(current);
249
+ const merged = { ...currentData };
250
+ if (credential) {
251
+ merged[provider] = credential;
252
+ }
253
+ else {
254
+ delete merged[provider];
255
+ }
256
+ return { result: undefined, next: JSON.stringify(merged, null, 2) };
257
+ });
258
+ }
259
+ catch (error) {
260
+ this.recordError(error);
261
+ }
262
+ }
263
+ /**
264
+ * Get credential for a provider.
265
+ */
266
+ get(provider) {
267
+ return this.data[provider] ?? undefined;
268
+ }
269
+ /**
270
+ * Set credential for a provider.
271
+ */
272
+ set(provider, credential) {
273
+ this.data[provider] = credential;
274
+ this.persistProviderChange(provider, credential);
275
+ }
276
+ /**
277
+ * Remove credential for a provider.
278
+ */
279
+ remove(provider) {
280
+ delete this.data[provider];
281
+ this.persistProviderChange(provider, undefined);
282
+ }
283
+ /**
284
+ * List all providers with credentials.
285
+ */
286
+ list() {
287
+ return Object.keys(this.data);
288
+ }
289
+ /**
290
+ * Check if credentials exist for a provider in auth.json.
291
+ */
292
+ has(provider) {
293
+ return provider in this.data;
294
+ }
295
+ /**
296
+ * Check if any form of auth is configured for a provider.
297
+ * Only checks OAuth/stored credentials and runtime overrides — ignores
298
+ * environment variables so that e.g. ANTHROPIC_API_KEY doesn't cause
299
+ * Anthropic models to appear when the user hasn't logged in via OAuth.
300
+ */
301
+ hasAuth(provider) {
302
+ if (this.runtimeOverrides.has(provider))
303
+ return true;
304
+ if (this.data[provider])
305
+ return true;
306
+ if (this.fallbackResolver?.(provider))
307
+ return true;
308
+ return false;
309
+ }
310
+ /**
311
+ * Get all credentials (for passing to getOAuthApiKey).
312
+ */
313
+ getAll() {
314
+ return { ...this.data };
315
+ }
316
+ drainErrors() {
317
+ const drained = [...this.errors];
318
+ this.errors = [];
319
+ return drained;
320
+ }
321
+ /**
322
+ * Login to an OAuth provider.
323
+ */
324
+ async login(providerId, callbacks) {
325
+ const provider = getOAuthProvider(providerId);
326
+ if (!provider) {
327
+ throw new Error(`Unknown OAuth provider: ${providerId}`);
328
+ }
329
+ const credentials = await provider.login(callbacks);
330
+ this.set(providerId, { type: 'oauth', ...credentials });
331
+ }
332
+ /**
333
+ * Logout from a provider.
334
+ */
335
+ logout(provider) {
336
+ this.remove(provider);
337
+ }
338
+ /**
339
+ * Refresh OAuth token with backend locking to prevent race conditions.
340
+ * Multiple pi instances may try to refresh simultaneously when tokens expire.
341
+ */
342
+ async refreshOAuthTokenWithLock(providerId) {
343
+ const provider = getOAuthProvider(providerId);
344
+ if (!provider) {
345
+ return null;
346
+ }
347
+ const result = await this.storage.withLockAsync(async (current) => {
348
+ const currentData = this.parseStorageData(current);
349
+ this.data = currentData;
350
+ this.loadError = null;
351
+ const cred = currentData[providerId];
352
+ if (cred?.type !== 'oauth') {
353
+ return { result: null };
354
+ }
355
+ if (Date.now() < cred.expires) {
356
+ return { result: { apiKey: provider.getApiKey(cred), newCredentials: cred } };
357
+ }
358
+ const oauthCreds = {};
359
+ for (const [key, value] of Object.entries(currentData)) {
360
+ if (value.type === 'oauth') {
361
+ oauthCreds[key] = value;
362
+ }
363
+ }
364
+ const refreshed = await getOAuthApiKey(providerId, oauthCreds);
365
+ if (!refreshed) {
366
+ return { result: null };
367
+ }
368
+ const merged = {
369
+ ...currentData,
370
+ [providerId]: { type: 'oauth', ...refreshed.newCredentials }
371
+ };
372
+ this.data = merged;
373
+ this.loadError = null;
374
+ return { result: refreshed, next: JSON.stringify(merged, null, 2) };
375
+ });
376
+ return result;
377
+ }
378
+ /**
379
+ * Get API key for a provider.
380
+ * Priority:
381
+ * 1. Runtime override (CLI --api-key)
382
+ * 2. API key from auth.json
383
+ * 3. OAuth token from auth.json (auto-refreshed with locking)
384
+ * 4. Environment variable
385
+ * 5. Fallback resolver (models.json custom providers)
386
+ */
387
+ async getApiKey(providerId) {
388
+ // Runtime override takes highest priority
389
+ const runtimeKey = this.runtimeOverrides.get(providerId);
390
+ if (runtimeKey) {
391
+ return runtimeKey;
392
+ }
393
+ const cred = this.data[providerId];
394
+ if (cred?.type === 'api_key') {
395
+ return resolveConfigValue(cred.key);
396
+ }
397
+ if (cred?.type === 'oauth') {
398
+ const provider = getOAuthProvider(providerId);
399
+ if (!provider) {
400
+ // Unknown OAuth provider, can't get API key
401
+ return undefined;
402
+ }
403
+ // Check if token needs refresh
404
+ const needsRefresh = Date.now() >= cred.expires;
405
+ if (needsRefresh) {
406
+ if (this._readOnly) {
407
+ // Read-only mode (subagents): never refresh — re-read the file
408
+ // to pick up tokens the parent process may have refreshed.
409
+ this.reload();
410
+ const updatedCred = this.data[providerId];
411
+ if (updatedCred?.type === 'oauth') {
412
+ return provider.getApiKey(updatedCred);
413
+ }
414
+ return undefined;
415
+ }
416
+ // Use locked refresh to prevent race conditions
417
+ try {
418
+ const result = await this.refreshOAuthTokenWithLock(providerId);
419
+ if (result) {
420
+ return result.apiKey;
421
+ }
422
+ }
423
+ catch (error) {
424
+ this.recordError(error);
425
+ // Refresh failed - re-read file to check if another instance succeeded
426
+ this.reload();
427
+ const updatedCred = this.data[providerId];
428
+ if (updatedCred?.type === 'oauth' && Date.now() < updatedCred.expires) {
429
+ // Another instance refreshed successfully, use those credentials
430
+ return provider.getApiKey(updatedCred);
431
+ }
432
+ // Refresh truly failed - return undefined so model discovery skips this provider
433
+ // User can /login to re-authenticate (credentials preserved for retry)
434
+ return undefined;
435
+ }
436
+ }
437
+ else {
438
+ // Token not expired, use current access token
439
+ return provider.getApiKey(cred);
440
+ }
441
+ }
442
+ // Fall back to environment variable
443
+ const envKey = getEnvApiKey(providerId);
444
+ if (envKey)
445
+ return envKey;
446
+ // Fall back to custom resolver (e.g., models.json custom providers)
447
+ return this.fallbackResolver?.(providerId) ?? undefined;
448
+ }
449
+ /**
450
+ * Get all registered OAuth providers
451
+ */
452
+ getOAuthProviders() {
453
+ return getOAuthProviders();
454
+ }
455
+ }
456
+ //# sourceMappingURL=auth-storage.js.map
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Bash command execution with streaming support and cancellation.
3
+ *
4
+ * This module provides a unified bash execution implementation used by:
5
+ * - AgentSession.executeBash() for interactive and RPC modes
6
+ * - Direct calls from modes that need bash execution
7
+ */
8
+ import { spawn } from 'child_process';
9
+ import { randomBytes } from 'node:crypto';
10
+ import { createWriteStream } from 'node:fs';
11
+ import { tmpdir } from 'node:os';
12
+ import { join } from 'node:path';
13
+ import stripAnsi from 'strip-ansi';
14
+ import { getShellConfig, getShellEnv, killProcessTree, sanitizeBinaryOutput } from '../utils/shell.js';
15
+ import { SettingsManager } from './settings-manager.js';
16
+ import { DEFAULT_MAX_CHARS, truncateHead } from './tools/truncate.js';
17
+ // ============================================================================
18
+ // Implementation
19
+ // ============================================================================
20
+ /**
21
+ * Execute a bash command with optional streaming and cancellation support.
22
+ *
23
+ * Features:
24
+ * - Streams sanitized output via onChunk callback
25
+ * - Writes large output to temp file for later retrieval
26
+ * - Supports cancellation via AbortSignal
27
+ * - Sanitizes output (strips ANSI, removes binary garbage, normalizes newlines)
28
+ * - Truncates output to first 20k chars via head truncation
29
+ *
30
+ * @param command - The bash command to execute
31
+ * @param options - Optional streaming callback and abort signal
32
+ * @returns Promise resolving to execution result
33
+ */
34
+ export function executeBash(command, options) {
35
+ return new Promise((resolve, reject) => {
36
+ const { shell, args } = getShellConfig(SettingsManager.create().getShellPath());
37
+ const child = spawn(shell, [...args, command], {
38
+ detached: true,
39
+ env: getShellEnv(),
40
+ stdio: ['ignore', 'pipe', 'pipe']
41
+ });
42
+ const outputChunks = [];
43
+ let totalChars = 0;
44
+ // Temp file for large output
45
+ let tempFilePath;
46
+ let tempFileStream;
47
+ let settled = false;
48
+ // Handle abort signal — kill process tree and force-close pipes.
49
+ // On Windows, `start`-spawned processes can hold pipe handles open even
50
+ // after taskkill kills the shell, preventing the 'close' event from firing.
51
+ const abortHandler = () => {
52
+ if (child.pid) {
53
+ killProcessTree(child.pid);
54
+ }
55
+ child.stdout?.destroy();
56
+ child.stderr?.destroy();
57
+ // Safety net: if 'close' still doesn't fire (orphaned pipe handles),
58
+ // force-settle after 2 seconds so the command doesn't hang forever.
59
+ setTimeout(() => {
60
+ if (!settled) {
61
+ settled = true;
62
+ if (options?.signal) {
63
+ options.signal.removeEventListener('abort', abortHandler);
64
+ }
65
+ if (tempFileStream) {
66
+ tempFileStream.end();
67
+ }
68
+ const fullOutput = outputChunks.join('');
69
+ const truncationResult = truncateHead(fullOutput);
70
+ resolve({
71
+ output: truncationResult.truncated ? truncationResult.content : fullOutput,
72
+ exitCode: undefined,
73
+ cancelled: true,
74
+ truncated: truncationResult.truncated,
75
+ fullOutputPath: tempFilePath
76
+ });
77
+ }
78
+ }, 2000);
79
+ };
80
+ if (options?.signal) {
81
+ if (options.signal.aborted) {
82
+ child.kill();
83
+ resolve({
84
+ output: '',
85
+ exitCode: undefined,
86
+ cancelled: true,
87
+ truncated: false
88
+ });
89
+ return;
90
+ }
91
+ options.signal.addEventListener('abort', abortHandler, { once: true });
92
+ }
93
+ const decoder = new TextDecoder();
94
+ const handleData = (data) => {
95
+ // Sanitize once at the source: strip ANSI, replace binary garbage, normalize newlines
96
+ const text = sanitizeBinaryOutput(stripAnsi(decoder.decode(data, { stream: true }))).replace(/\r/g, '');
97
+ totalChars += text.length;
98
+ // Start writing to temp file if exceeds threshold
99
+ if (totalChars > DEFAULT_MAX_CHARS && !tempFilePath) {
100
+ const id = randomBytes(8).toString('hex');
101
+ tempFilePath = join(tmpdir(), `pi-bash-${id}.log`);
102
+ tempFileStream = createWriteStream(tempFilePath);
103
+ for (const chunk of outputChunks) {
104
+ tempFileStream.write(chunk);
105
+ }
106
+ }
107
+ if (tempFileStream) {
108
+ tempFileStream.write(text);
109
+ }
110
+ outputChunks.push(text);
111
+ // Stream to callback if provided
112
+ if (options?.onChunk) {
113
+ options.onChunk(text);
114
+ }
115
+ };
116
+ child.stdout?.on('data', handleData);
117
+ child.stderr?.on('data', handleData);
118
+ child.on('close', (code) => {
119
+ if (options?.signal) {
120
+ options.signal.removeEventListener('abort', abortHandler);
121
+ }
122
+ if (tempFileStream) {
123
+ tempFileStream.end();
124
+ }
125
+ if (settled)
126
+ return;
127
+ settled = true;
128
+ const fullOutput = outputChunks.join('');
129
+ const truncationResult = truncateHead(fullOutput);
130
+ const cancelled = code === null;
131
+ resolve({
132
+ output: truncationResult.truncated ? truncationResult.content : fullOutput,
133
+ exitCode: cancelled ? undefined : code,
134
+ cancelled,
135
+ truncated: truncationResult.truncated,
136
+ fullOutputPath: tempFilePath
137
+ });
138
+ });
139
+ child.on('error', (err) => {
140
+ if (options?.signal) {
141
+ options.signal.removeEventListener('abort', abortHandler);
142
+ }
143
+ if (tempFileStream) {
144
+ tempFileStream.end();
145
+ }
146
+ if (!settled) {
147
+ settled = true;
148
+ reject(err);
149
+ }
150
+ });
151
+ });
152
+ }
153
+ /**
154
+ * Execute a bash command using custom BashOperations.
155
+ * Used for remote execution (SSH, containers, etc.).
156
+ */
157
+ export async function executeBashWithOperations(command, cwd, operations, options) {
158
+ const outputChunks = [];
159
+ let totalChars = 0;
160
+ let tempFilePath;
161
+ let tempFileStream;
162
+ const decoder = new TextDecoder();
163
+ const onData = (data) => {
164
+ // Sanitize: strip ANSI, replace binary garbage, normalize newlines
165
+ const text = sanitizeBinaryOutput(stripAnsi(decoder.decode(data, { stream: true }))).replace(/\r/g, '');
166
+ totalChars += text.length;
167
+ // Start writing to temp file if exceeds threshold
168
+ if (totalChars > DEFAULT_MAX_CHARS && !tempFilePath) {
169
+ const id = randomBytes(8).toString('hex');
170
+ tempFilePath = join(tmpdir(), `pi-bash-${id}.log`);
171
+ tempFileStream = createWriteStream(tempFilePath);
172
+ for (const chunk of outputChunks) {
173
+ tempFileStream.write(chunk);
174
+ }
175
+ }
176
+ if (tempFileStream) {
177
+ tempFileStream.write(text);
178
+ }
179
+ outputChunks.push(text);
180
+ // Stream to callback
181
+ if (options?.onChunk) {
182
+ options.onChunk(text);
183
+ }
184
+ };
185
+ try {
186
+ const result = await operations.exec(command, cwd, {
187
+ onData,
188
+ signal: options?.signal
189
+ });
190
+ if (tempFileStream) {
191
+ tempFileStream.end();
192
+ }
193
+ const fullOutput = outputChunks.join('');
194
+ const truncationResult = truncateHead(fullOutput);
195
+ const cancelled = options?.signal?.aborted ?? false;
196
+ return {
197
+ output: truncationResult.truncated ? truncationResult.content : fullOutput,
198
+ exitCode: cancelled ? undefined : (result.exitCode ?? undefined),
199
+ cancelled,
200
+ truncated: truncationResult.truncated,
201
+ fullOutputPath: tempFilePath
202
+ };
203
+ }
204
+ catch (err) {
205
+ if (tempFileStream) {
206
+ tempFileStream.end();
207
+ }
208
+ if (options?.signal?.aborted) {
209
+ const fullOutput = outputChunks.join('');
210
+ const truncationResult = truncateHead(fullOutput);
211
+ return {
212
+ output: truncationResult.truncated ? truncationResult.content : fullOutput,
213
+ exitCode: undefined,
214
+ cancelled: true,
215
+ truncated: truncationResult.truncated,
216
+ fullOutputPath: tempFilePath
217
+ };
218
+ }
219
+ throw err;
220
+ }
221
+ }
222
+ //# sourceMappingURL=bash-executor.js.map