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.
- package/README.md +59 -0
- package/agent-docs/README.md +397 -0
- package/agent-docs/docs/compaction.md +390 -0
- package/agent-docs/docs/custom-provider.md +580 -0
- package/agent-docs/docs/development.md +69 -0
- package/agent-docs/docs/extensions.md +1971 -0
- package/agent-docs/docs/json.md +79 -0
- package/agent-docs/docs/keybindings.md +174 -0
- package/agent-docs/docs/models.md +293 -0
- package/agent-docs/docs/packages.md +209 -0
- package/agent-docs/docs/prompt-templates.md +67 -0
- package/agent-docs/docs/providers.md +186 -0
- package/agent-docs/docs/rpc.md +1317 -0
- package/agent-docs/docs/sdk.md +962 -0
- package/agent-docs/docs/session.md +412 -0
- package/agent-docs/docs/settings.md +223 -0
- package/agent-docs/docs/shell-aliases.md +13 -0
- package/agent-docs/docs/skills.md +231 -0
- package/agent-docs/docs/terminal-setup.md +70 -0
- package/agent-docs/docs/termux.md +127 -0
- package/agent-docs/docs/themes.md +295 -0
- package/agent-docs/docs/tree.md +219 -0
- package/agent-docs/docs/tui.md +887 -0
- package/agent-docs/docs/windows.md +17 -0
- package/agent-docs/examples/README.md +25 -0
- package/agent-docs/examples/extensions/README.md +205 -0
- package/agent-docs/examples/extensions/antigravity-image-gen.ts +447 -0
- package/agent-docs/examples/extensions/auto-commit-on-exit.ts +49 -0
- package/agent-docs/examples/extensions/bash-spawn-hook.ts +30 -0
- package/agent-docs/examples/extensions/bookmark.ts +50 -0
- package/agent-docs/examples/extensions/built-in-tool-renderer.ts +256 -0
- package/agent-docs/examples/extensions/claude-rules.ts +86 -0
- package/agent-docs/examples/extensions/commands.ts +75 -0
- package/agent-docs/examples/extensions/confirm-destructive.ts +59 -0
- package/agent-docs/examples/extensions/custom-compaction.ts +126 -0
- package/agent-docs/examples/extensions/custom-footer.ts +63 -0
- package/agent-docs/examples/extensions/custom-header.ts +73 -0
- package/agent-docs/examples/extensions/custom-provider-anthropic/index.ts +660 -0
- package/agent-docs/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
- package/agent-docs/examples/extensions/custom-provider-anthropic/package.json +19 -0
- package/agent-docs/examples/extensions/custom-provider-gitlab-duo/index.ts +362 -0
- package/agent-docs/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
- package/agent-docs/examples/extensions/custom-provider-gitlab-duo/test.ts +88 -0
- package/agent-docs/examples/extensions/custom-provider-qwen-cli/index.ts +349 -0
- package/agent-docs/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/agent-docs/examples/extensions/dirty-repo-guard.ts +56 -0
- package/agent-docs/examples/extensions/doom-overlay/README.md +46 -0
- package/agent-docs/examples/extensions/doom-overlay/doom/build.sh +152 -0
- package/agent-docs/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
- package/agent-docs/examples/extensions/doom-overlay/doom-component.ts +133 -0
- package/agent-docs/examples/extensions/doom-overlay/doom-engine.ts +186 -0
- package/agent-docs/examples/extensions/doom-overlay/doom-keys.ts +108 -0
- package/agent-docs/examples/extensions/doom-overlay/index.ts +74 -0
- package/agent-docs/examples/extensions/doom-overlay/wad-finder.ts +51 -0
- package/agent-docs/examples/extensions/dynamic-resources/SKILL.md +8 -0
- package/agent-docs/examples/extensions/dynamic-resources/dynamic.json +79 -0
- package/agent-docs/examples/extensions/dynamic-resources/dynamic.md +5 -0
- package/agent-docs/examples/extensions/dynamic-resources/index.ts +15 -0
- package/agent-docs/examples/extensions/dynamic-tools.ts +77 -0
- package/agent-docs/examples/extensions/event-bus.ts +43 -0
- package/agent-docs/examples/extensions/file-trigger.ts +41 -0
- package/agent-docs/examples/extensions/git-checkpoint.ts +53 -0
- package/agent-docs/examples/extensions/handoff.ts +155 -0
- package/agent-docs/examples/extensions/hello.ts +25 -0
- package/agent-docs/examples/extensions/inline-bash.ts +94 -0
- package/agent-docs/examples/extensions/input-transform.ts +43 -0
- package/agent-docs/examples/extensions/interactive-shell.ts +209 -0
- package/agent-docs/examples/extensions/mac-system-theme.ts +47 -0
- package/agent-docs/examples/extensions/message-renderer.ts +59 -0
- package/agent-docs/examples/extensions/minimal-mode.ts +430 -0
- package/agent-docs/examples/extensions/modal-editor.ts +90 -0
- package/agent-docs/examples/extensions/model-status.ts +31 -0
- package/agent-docs/examples/extensions/notify.ts +55 -0
- package/agent-docs/examples/extensions/overlay-qa-tests.ts +936 -0
- package/agent-docs/examples/extensions/overlay-test.ts +159 -0
- package/agent-docs/examples/extensions/permission-gate.ts +37 -0
- package/agent-docs/examples/extensions/pirate.ts +47 -0
- package/agent-docs/examples/extensions/plan-mode/README.md +65 -0
- package/agent-docs/examples/extensions/plan-mode/index.ts +363 -0
- package/agent-docs/examples/extensions/plan-mode/utils.ts +173 -0
- package/agent-docs/examples/extensions/preset.ts +418 -0
- package/agent-docs/examples/extensions/protected-paths.ts +30 -0
- package/agent-docs/examples/extensions/qna.ts +122 -0
- package/agent-docs/examples/extensions/question.ts +278 -0
- package/agent-docs/examples/extensions/questionnaire.ts +440 -0
- package/agent-docs/examples/extensions/rainbow-editor.ts +90 -0
- package/agent-docs/examples/extensions/reload-runtime.ts +37 -0
- package/agent-docs/examples/extensions/rpc-demo.ts +124 -0
- package/agent-docs/examples/extensions/sandbox/index.ts +324 -0
- package/agent-docs/examples/extensions/sandbox/package-lock.json +92 -0
- package/agent-docs/examples/extensions/sandbox/package.json +19 -0
- package/agent-docs/examples/extensions/send-user-message.ts +97 -0
- package/agent-docs/examples/extensions/session-name.ts +27 -0
- package/agent-docs/examples/extensions/shutdown-command.ts +69 -0
- package/agent-docs/examples/extensions/snake.ts +343 -0
- package/agent-docs/examples/extensions/space-invaders.ts +566 -0
- package/agent-docs/examples/extensions/ssh.ts +233 -0
- package/agent-docs/examples/extensions/status-line.ts +40 -0
- package/agent-docs/examples/extensions/subagent/README.md +172 -0
- package/agent-docs/examples/extensions/subagent/agents/planner.md +37 -0
- package/agent-docs/examples/extensions/subagent/agents/reviewer.md +35 -0
- package/agent-docs/examples/extensions/subagent/agents/scout.md +50 -0
- package/agent-docs/examples/extensions/subagent/agents/worker.md +24 -0
- package/agent-docs/examples/extensions/subagent/agents.ts +130 -0
- package/agent-docs/examples/extensions/subagent/index.ts +1068 -0
- package/agent-docs/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/agent-docs/examples/extensions/subagent/prompts/implement.md +10 -0
- package/agent-docs/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/agent-docs/examples/extensions/summarize.ts +206 -0
- package/agent-docs/examples/extensions/system-prompt-header.ts +17 -0
- package/agent-docs/examples/extensions/timed-confirm.ts +72 -0
- package/agent-docs/examples/extensions/titlebar-spinner.ts +58 -0
- package/agent-docs/examples/extensions/todo.ts +314 -0
- package/agent-docs/examples/extensions/tool-override.ts +146 -0
- package/agent-docs/examples/extensions/tools.ts +145 -0
- package/agent-docs/examples/extensions/trigger-compact.ts +40 -0
- package/agent-docs/examples/extensions/truncated-tool.ts +194 -0
- package/agent-docs/examples/extensions/widget-placement.ts +17 -0
- package/agent-docs/examples/extensions/with-deps/index.ts +37 -0
- package/agent-docs/examples/extensions/with-deps/package-lock.json +31 -0
- package/agent-docs/examples/extensions/with-deps/package.json +22 -0
- package/agent-docs/examples/rpc-extension-ui.ts +654 -0
- package/agent-docs/examples/sdk/01-minimal.ts +22 -0
- package/agent-docs/examples/sdk/02-custom-model.ts +48 -0
- package/agent-docs/examples/sdk/03-custom-prompt.ts +55 -0
- package/agent-docs/examples/sdk/04-skills.ts +53 -0
- package/agent-docs/examples/sdk/05-tools.ts +56 -0
- package/agent-docs/examples/sdk/06-extensions.ts +88 -0
- package/agent-docs/examples/sdk/07-context-files.ts +40 -0
- package/agent-docs/examples/sdk/08-prompt-templates.ts +47 -0
- package/agent-docs/examples/sdk/09-api-keys-and-oauth.ts +48 -0
- package/agent-docs/examples/sdk/10-settings.ts +54 -0
- package/agent-docs/examples/sdk/11-sessions.ts +48 -0
- package/agent-docs/examples/sdk/12-full-control.ts +82 -0
- package/agent-docs/examples/sdk/README.md +144 -0
- package/agent-docs/xll-skill.md +61 -0
- package/agent-docs/xll-spec.md +110 -0
- package/dist/cli/args.js +290 -0
- package/dist/cli/config-selector.js +31 -0
- package/dist/cli/file-processor.js +79 -0
- package/dist/cli/list-models.js +92 -0
- package/dist/cli/package-commands.js +210 -0
- package/dist/cli/report-settings-errors.js +11 -0
- package/dist/cli/session-picker.js +34 -0
- package/dist/cli.js +19 -0
- package/dist/config.js +288 -0
- package/dist/core/abort.js +15 -0
- package/dist/core/agent-loop.js +352 -0
- package/dist/core/agent-session.js +2019 -0
- package/dist/core/agent.js +410 -0
- package/dist/core/auth-storage.js +456 -0
- package/dist/core/bash-executor.js +222 -0
- package/dist/core/compaction/branch-summarization.js +242 -0
- package/dist/core/compaction/compaction.js +610 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/utils.js +139 -0
- package/dist/core/defaults.js +6 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/exec.js +71 -0
- package/dist/core/export-html/ansi-to-html.js +256 -0
- package/dist/core/export-html/index.js +238 -0
- package/dist/core/export-html/session-view-model.js +342 -0
- package/dist/core/export-html/template.css +1110 -0
- package/dist/core/export-html/template.html +76 -0
- package/dist/core/export-html/template.js +1990 -0
- package/dist/core/export-html/tool-renderer.js +63 -0
- package/dist/core/export-html/vendor/highlight.min.js +7725 -0
- package/dist/core/export-html/vendor/marked.min.js +1803 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/loader.js +422 -0
- package/dist/core/extensions/runner.js +651 -0
- package/dist/core/extensions/types.js +35 -0
- package/dist/core/extensions/wrapper.js +102 -0
- package/dist/core/footer-data-provider.js +162 -0
- package/dist/core/index.js +9 -0
- package/dist/core/keybindings.js +153 -0
- package/dist/core/messages.js +133 -0
- package/dist/core/model-registry.js +539 -0
- package/dist/core/model-resolver.js +370 -0
- package/dist/core/package-manager.js +1485 -0
- package/dist/core/prompt-templates.js +253 -0
- package/dist/core/resolve-config-value.js +59 -0
- package/dist/core/resource-loader.js +700 -0
- package/dist/core/sdk.js +197 -0
- package/dist/core/session-bash.js +99 -0
- package/dist/core/session-compaction.js +165 -0
- package/dist/core/session-manager.js +1153 -0
- package/dist/core/session-models.js +99 -0
- package/dist/core/session-retry.js +155 -0
- package/dist/core/settings-manager.js +572 -0
- package/dist/core/skills.js +382 -0
- package/dist/core/slash-commands.js +31 -0
- package/dist/core/system-prompt.js +161 -0
- package/dist/core/theme.js +770 -0
- package/dist/core/timings.js +26 -0
- package/dist/core/tools/bash.js +258 -0
- package/dist/core/tools/edit-diff.js +245 -0
- package/dist/core/tools/edit.js +148 -0
- package/dist/core/tools/find.js +208 -0
- package/dist/core/tools/grep.js +246 -0
- package/dist/core/tools/index.js +67 -0
- package/dist/core/tools/ls.js +123 -0
- package/dist/core/tools/path-utils.js +81 -0
- package/dist/core/tools/read.js +160 -0
- package/dist/core/tools/truncate.js +70 -0
- package/dist/core/tools/write.js +82 -0
- package/dist/custom/agents/action.js +13 -0
- package/dist/custom/agents/document-reader.js +70 -0
- package/dist/custom/agents/general.js +26 -0
- package/dist/custom/agents/index.js +49 -0
- package/dist/custom/agents/installation.js +13 -0
- package/dist/custom/agents/types.js +7 -0
- package/dist/custom/auth/refresh-timer.js +33 -0
- package/dist/custom/auth/shortcut-oauth.js +145 -0
- package/dist/custom/constants.js +21 -0
- package/dist/custom/context/workbook-summary.js +73 -0
- package/dist/custom/credits/shortcut-credits.js +29 -0
- package/dist/custom/cron/cron-daemon-entry.js +18 -0
- package/dist/custom/cron/daemon-ipc.js +131 -0
- package/dist/custom/cron/daemon.js +224 -0
- package/dist/custom/cron/jobs.js +226 -0
- package/dist/custom/cron/run-log.js +51 -0
- package/dist/custom/cron/schedule.js +72 -0
- package/dist/custom/cron/status-line.js +98 -0
- package/dist/custom/cron/store.js +87 -0
- package/dist/custom/cron/types.js +8 -0
- package/dist/custom/dev/index.js +59 -0
- package/dist/custom/dev/trace-export.js +58 -0
- package/dist/custom/ensure-excel.js +63 -0
- package/dist/custom/excel-config.js +36 -0
- package/dist/custom/preflight.js +422 -0
- package/dist/custom/prompts/action.js +100 -0
- package/dist/custom/prompts/api.js +66 -0
- package/dist/custom/prompts/installation.js +124 -0
- package/dist/custom/prompts/shared.js +138 -0
- package/dist/custom/providers/llm-usage.js +42 -0
- package/dist/custom/providers/message-converter.js +74 -0
- package/dist/custom/providers/provider-ids.js +9 -0
- package/dist/custom/providers/register-openai-codex-provider.js +27 -0
- package/dist/custom/providers/register-shortcut-provider.js +52 -0
- package/dist/custom/providers/shortcut-invoke.js +117 -0
- package/dist/custom/providers/shortcut-stream.js +252 -0
- package/dist/custom/providers/sse-protocol.js +38 -0
- package/dist/custom/sync-xll.js +130 -0
- package/dist/custom/tools/cron.js +413 -0
- package/dist/custom/tools/excel-exec.js +167 -0
- package/dist/custom/tools/excel-range.js +50 -0
- package/dist/custom/tools/llm-analysis.js +265 -0
- package/dist/custom/tools/render-helpers.js +38 -0
- package/dist/custom/tools/switch-mode.js +94 -0
- package/dist/custom/tools/task/agents.js +6 -0
- package/dist/custom/tools/task/index.js +8 -0
- package/dist/custom/tools/task/render.js +348 -0
- package/dist/custom/tools/task/subprocess.js +320 -0
- package/dist/custom/tools/task/task.js +205 -0
- package/dist/custom/tools/todo-list.js +195 -0
- package/dist/custom/tracing/session-upload.js +93 -0
- package/dist/index.js +45 -0
- package/dist/main.js +613 -0
- package/dist/migrations.js +265 -0
- package/dist/modes/index.js +8 -0
- package/dist/modes/interactive/components/armin.js +337 -0
- package/dist/modes/interactive/components/assistant-message.js +94 -0
- package/dist/modes/interactive/components/bash-execution.js +171 -0
- package/dist/modes/interactive/components/bordered-loader.js +51 -0
- package/dist/modes/interactive/components/branch-summary-message.js +45 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +46 -0
- package/dist/modes/interactive/components/config-selector.js +488 -0
- package/dist/modes/interactive/components/countdown-timer.js +33 -0
- package/dist/modes/interactive/components/custom-editor.js +93 -0
- package/dist/modes/interactive/components/custom-message.js +81 -0
- package/dist/modes/interactive/components/daxnuts.js +140 -0
- package/dist/modes/interactive/components/diff.js +133 -0
- package/dist/modes/interactive/components/dynamic-border.js +21 -0
- package/dist/modes/interactive/components/extension-editor.js +105 -0
- package/dist/modes/interactive/components/extension-input.js +61 -0
- package/dist/modes/interactive/components/extension-selector.js +78 -0
- package/dist/modes/interactive/components/footer.js +309 -0
- package/dist/modes/interactive/components/index.js +33 -0
- package/dist/modes/interactive/components/keybinding-hints.js +61 -0
- package/dist/modes/interactive/components/layout.js +64 -0
- package/dist/modes/interactive/components/login-dialog.js +148 -0
- package/dist/modes/interactive/components/model-selector.js +237 -0
- package/dist/modes/interactive/components/oauth-selector.js +111 -0
- package/dist/modes/interactive/components/session-selector-search.js +157 -0
- package/dist/modes/interactive/components/session-selector.js +860 -0
- package/dist/modes/interactive/components/settings-selector.js +123 -0
- package/dist/modes/interactive/components/show-images-selector.js +35 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +48 -0
- package/dist/modes/interactive/components/theme-selector.js +47 -0
- package/dist/modes/interactive/components/thinking-selector.js +47 -0
- package/dist/modes/interactive/components/tool-execution.js +789 -0
- package/dist/modes/interactive/components/tool-group.js +106 -0
- package/dist/modes/interactive/components/tree-selector.js +962 -0
- package/dist/modes/interactive/components/user-message-selector.js +115 -0
- package/dist/modes/interactive/components/user-message.js +48 -0
- package/dist/modes/interactive/components/visual-truncate.js +33 -0
- package/dist/modes/interactive/file-attachments.js +135 -0
- package/dist/modes/interactive/interactive-mode.js +3775 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +85 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.js +177 -0
- package/dist/modes/print-mode.js +101 -0
- package/dist/modes/rpc/rpc-client.js +387 -0
- package/dist/modes/rpc/rpc-mode.js +509 -0
- package/dist/modes/rpc/rpc-types.js +8 -0
- package/dist/subagent-entry.js +145 -0
- package/dist/tool-names.js +34 -0
- package/dist/tui/autocomplete.js +596 -0
- package/dist/tui/components/box.js +104 -0
- package/dist/tui/components/cancellable-loader.js +35 -0
- package/dist/tui/components/editor.js +1679 -0
- package/dist/tui/components/image.js +69 -0
- package/dist/tui/components/input.js +433 -0
- package/dist/tui/components/loader.js +49 -0
- package/dist/tui/components/markdown.js +629 -0
- package/dist/tui/components/select-list.js +152 -0
- package/dist/tui/components/settings-list.js +185 -0
- package/dist/tui/components/spacer.js +23 -0
- package/dist/tui/components/text.js +89 -0
- package/dist/tui/components/truncated-text.js +51 -0
- package/dist/tui/editor-component.js +2 -0
- package/dist/tui/fuzzy.js +107 -0
- package/dist/tui/get-east-asian-width/index.js +32 -0
- package/dist/tui/get-east-asian-width/lookup.js +404 -0
- package/dist/tui/index.js +32 -0
- package/dist/tui/keybindings.js +114 -0
- package/dist/tui/keys.js +959 -0
- package/dist/tui/kill-ring.js +44 -0
- package/dist/tui/stdin-buffer.js +317 -0
- package/dist/tui/terminal-image.js +288 -0
- package/dist/tui/terminal.js +249 -0
- package/dist/tui/tui/autocomplete.js +596 -0
- package/dist/tui/tui/components/box.js +106 -0
- package/dist/tui/tui/components/cancellable-loader.js +35 -0
- package/dist/tui/tui/components/editor.js +1679 -0
- package/dist/tui/tui/components/image.js +69 -0
- package/dist/tui/tui/components/input.js +433 -0
- package/dist/tui/tui/components/loader.js +49 -0
- package/dist/tui/tui/components/markdown.js +629 -0
- package/dist/tui/tui/components/select-list.js +152 -0
- package/dist/tui/tui/components/settings-list.js +185 -0
- package/dist/tui/tui/components/spacer.js +23 -0
- package/dist/tui/tui/components/text.js +91 -0
- package/dist/tui/tui/components/truncated-text.js +51 -0
- package/dist/tui/tui/editor-component.js +2 -0
- package/dist/tui/tui/fuzzy.js +107 -0
- package/dist/tui/tui/get-east-asian-width/index.js +32 -0
- package/dist/tui/tui/get-east-asian-width/lookup.js +404 -0
- package/dist/tui/tui/index.js +32 -0
- package/dist/tui/tui/keybindings.js +114 -0
- package/dist/tui/tui/keys.js +959 -0
- package/dist/tui/tui/kill-ring.js +44 -0
- package/dist/tui/tui/stdin-buffer.js +317 -0
- package/dist/tui/tui/terminal-image.js +288 -0
- package/dist/tui/tui/terminal.js +249 -0
- package/dist/tui/tui/tui.js +955 -0
- package/dist/tui/tui/undo-stack.js +25 -0
- package/dist/tui/tui/utils.js +800 -0
- package/dist/tui/tui.js +955 -0
- package/dist/tui/undo-stack.js +25 -0
- package/dist/tui/utils.js +800 -0
- package/dist/utils/changelog.js +87 -0
- package/dist/utils/clipboard-image.js +164 -0
- package/dist/utils/clipboard-native.js +14 -0
- package/dist/utils/clipboard.js +67 -0
- package/dist/utils/frontmatter.js +26 -0
- package/dist/utils/git.js +166 -0
- package/dist/utils/image-convert.js +35 -0
- package/dist/utils/image-resize.js +183 -0
- package/dist/utils/mime.js +26 -0
- package/dist/utils/photon.js +121 -0
- package/dist/utils/shell.js +217 -0
- package/dist/utils/sleep.js +17 -0
- package/dist/utils/tools-manager.js +259 -0
- package/package.json +78 -0
- package/skills/excel-com-api/SKILL.md +74 -0
- package/skills/excel-com-api/excel-type-library.py +27767 -0
- package/skills/excel-com-api/office-type-library.py +10867 -0
- package/skills/integrations/SKILL.md +138 -0
- package/skills/integrations/alphasense.md +457 -0
- package/skills/integrations/bloomberg.md +803 -0
- package/skills/integrations/calcbench.md +315 -0
- package/skills/integrations/capiq.md +848 -0
- package/skills/integrations/dynamics-365-finance.md +354 -0
- package/skills/integrations/earnings_transcripts.md +387 -0
- package/skills/integrations/factset.md +758 -0
- package/skills/integrations/ice-fixed-income.md +344 -0
- package/skills/integrations/moodys-analytics.md +313 -0
- package/skills/integrations/morningstar.md +433 -0
- package/skills/integrations/nasdaq-data-link.md +249 -0
- package/skills/integrations/pitchbook.md +413 -0
- package/skills/integrations/preqin.md +422 -0
- package/skills/integrations/quickbooks.md +289 -0
- package/skills/integrations/quickfs.md +314 -0
- package/skills/integrations/refinitiv.md +473 -0
- package/skills/integrations/sage-intacct.md +401 -0
- package/skills/integrations/visible-alpha.md +320 -0
- package/skills/integrations/xero.md +393 -0
- package/skills/integrations/ycharts.md +306 -0
- package/skills/pdf-creation/SKILL.md +93 -0
- package/skills/pdf-extraction/SKILL.md +32 -0
- package/skills/powerpoint-creation/SKILL.md +110 -0
- package/skills/sec-edgar/SKILL.md +127 -0
- package/skills/sec-edgar/sec_to_pdf.py +109 -0
- package/xll/ShortcutXL.xll +0 -0
- package/xll/modules/debug_render.py +272 -0
- package/xll/modules/gameboy.py +241 -0
- package/xll/modules/pong.py +188 -0
- package/xll/modules/shortcut_xl/__init__.py +18 -0
- package/xll/modules/shortcut_xl/_categorize.py +200 -0
- package/xll/modules/shortcut_xl/_com.py +108 -0
- package/xll/modules/shortcut_xl/_format.py +252 -0
- package/xll/modules/shortcut_xl/_log.py +12 -0
- package/xll/modules/shortcut_xl/_managed.py +116 -0
- package/xll/modules/shortcut_xl/_registry.py +44 -0
- package/xll/modules/shortcut_xl/_threading.py +161 -0
- package/xll/modules/shortcut_xl/_tracking.py +283 -0
- package/xll/modules/stocks.py +100 -0
- package/xll/python3.dll +0 -0
- package/xll/python312.dll +0 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI rendering for the task tool.
|
|
3
|
+
*
|
|
4
|
+
* Pure display functions — no I/O, no subprocess knowledge.
|
|
5
|
+
* Takes typed data, returns pi-tui Components.
|
|
6
|
+
*/
|
|
7
|
+
import { ABORT_UI_LABEL_INLINE } from '../../../core/abort.js';
|
|
8
|
+
import { Text } from '../../../tui/index.js';
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Formatting helpers (pure functions, exported for testing)
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
export function formatTokens(count) {
|
|
13
|
+
if (count < 1_000)
|
|
14
|
+
return count.toString();
|
|
15
|
+
// Upper bound is 9_950 so that toFixed(1) never rounds up to "10.0k"
|
|
16
|
+
// (9_949 → "9.9k", 9_950 would → "10.0k" which collides with the rounded tier).
|
|
17
|
+
if (count < 9_950)
|
|
18
|
+
return `${(count / 1_000).toFixed(1)}k`;
|
|
19
|
+
if (count < 1_000_000)
|
|
20
|
+
return `${Math.round(count / 1_000)}k`;
|
|
21
|
+
return `${(count / 1_000_000).toFixed(1)}M`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Format usage stats for display.
|
|
25
|
+
*
|
|
26
|
+
* When contextWindow is provided, shows "X% context used" instead of $cost
|
|
27
|
+
* (appropriate for credit-based models like shortcut-opus where cost is meaningless).
|
|
28
|
+
*/
|
|
29
|
+
export function formatUsage(usage, model, contextWindow, toolCallCount) {
|
|
30
|
+
const parts = [];
|
|
31
|
+
if (toolCallCount)
|
|
32
|
+
parts.push(`${toolCallCount} step${toolCallCount > 1 ? 's' : ''}`);
|
|
33
|
+
if (usage.input)
|
|
34
|
+
parts.push(`↑${formatTokens(usage.input)}`);
|
|
35
|
+
if (usage.output)
|
|
36
|
+
parts.push(`↓${formatTokens(usage.output)}`);
|
|
37
|
+
// Show context % instead of cost when we have a context window
|
|
38
|
+
if (contextWindow && contextWindow > 0 && usage.lastTurnInput > 0) {
|
|
39
|
+
const percent = (usage.lastTurnInput / contextWindow) * 100;
|
|
40
|
+
parts.push(`${percent.toFixed(1)}% context used`);
|
|
41
|
+
}
|
|
42
|
+
else if (!contextWindow && usage.cost) {
|
|
43
|
+
// Fallback: show cost only when no context window info
|
|
44
|
+
parts.push(`$${usage.cost.toFixed(4)}`);
|
|
45
|
+
}
|
|
46
|
+
if (model)
|
|
47
|
+
parts.push(model);
|
|
48
|
+
return parts.join(' ');
|
|
49
|
+
}
|
|
50
|
+
const MAX_TOOL_DESC = 50;
|
|
51
|
+
function truncate(s, max) {
|
|
52
|
+
return s.length > max ? s.slice(0, max) + '...' : s;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Format a tool call for display in the task result.
|
|
56
|
+
*
|
|
57
|
+
* bash and excel_exec show a short description (up to 50 chars).
|
|
58
|
+
* read/write/edit are omitted (returns null) — not useful in task context.
|
|
59
|
+
*/
|
|
60
|
+
export function formatToolCall(tc) {
|
|
61
|
+
switch (tc.name) {
|
|
62
|
+
case 'bash': {
|
|
63
|
+
const desc = tc.args.description;
|
|
64
|
+
if (desc)
|
|
65
|
+
return `$ ${truncate(desc, MAX_TOOL_DESC)}`;
|
|
66
|
+
const cmd = tc.args.command ?? '...';
|
|
67
|
+
return `$ ${truncate(cmd, MAX_TOOL_DESC)}`;
|
|
68
|
+
}
|
|
69
|
+
case 'excel_exec': {
|
|
70
|
+
const desc = tc.args.description ?? '';
|
|
71
|
+
return `𝕏 ${truncate(desc || '(code)', MAX_TOOL_DESC)}`;
|
|
72
|
+
}
|
|
73
|
+
case 'read':
|
|
74
|
+
case 'write':
|
|
75
|
+
case 'edit':
|
|
76
|
+
return null;
|
|
77
|
+
default: {
|
|
78
|
+
const argsStr = JSON.stringify(tc.args);
|
|
79
|
+
return `${tc.name} ${truncate(argsStr, MAX_TOOL_DESC)}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Resolve the icon, label, and color for a completed (non-running) task state. */
|
|
84
|
+
function taskStatus(isError, isAborted, theme) {
|
|
85
|
+
if (isError)
|
|
86
|
+
return { icon: theme.fg('error', '✗'), word: 'failed', color: 'error' };
|
|
87
|
+
if (isAborted)
|
|
88
|
+
return { icon: theme.fg('warning', '⊘'), word: ABORT_UI_LABEL_INLINE, color: 'warning' };
|
|
89
|
+
return { icon: theme.fg('success', '✓'), word: 'done', color: 'success' };
|
|
90
|
+
}
|
|
91
|
+
/** Max length for the query preview in the header */
|
|
92
|
+
const MAX_QUERY_PREVIEW = 120;
|
|
93
|
+
/**
|
|
94
|
+
* Render the task tool call header (shown while running / before result).
|
|
95
|
+
*
|
|
96
|
+
* Collapsed: name + truncated single-line query
|
|
97
|
+
* Expanded: name + full query
|
|
98
|
+
*/
|
|
99
|
+
export function renderTaskCall(data, expanded, theme) {
|
|
100
|
+
const title = theme.fg('toolTitle', theme.bold(data.name || 'task'));
|
|
101
|
+
if (data.query) {
|
|
102
|
+
if (expanded) {
|
|
103
|
+
return new Text(`${title}\n${theme.fg('text', data.query)}`, 0, 0);
|
|
104
|
+
}
|
|
105
|
+
// Collapsed: first line, truncated
|
|
106
|
+
const firstLine = data.query.split('\n')[0] ?? '';
|
|
107
|
+
const preview = firstLine.length > MAX_QUERY_PREVIEW
|
|
108
|
+
? firstLine.slice(0, MAX_QUERY_PREVIEW) + '...'
|
|
109
|
+
: firstLine;
|
|
110
|
+
return new Text(`${title}\n${theme.fg('text', preview)}`, 0, 0);
|
|
111
|
+
}
|
|
112
|
+
return new Text(title, 0, 0);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the "currently doing" description from the latest tool call.
|
|
116
|
+
* Walks backwards to find the last displayable tool call.
|
|
117
|
+
*/
|
|
118
|
+
export function getCurrentActivity(toolCalls) {
|
|
119
|
+
for (let i = toolCalls.length - 1; i >= 0; i--) {
|
|
120
|
+
const formatted = formatToolCall(toolCalls[i]);
|
|
121
|
+
if (formatted)
|
|
122
|
+
return formatted;
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Render the task tool result.
|
|
128
|
+
*
|
|
129
|
+
* Collapsed: compact 1-line status — "currently doing: X" or "✓ done"
|
|
130
|
+
* Expanded: full details — all tool calls, output text, usage stats
|
|
131
|
+
*/
|
|
132
|
+
export function renderTaskResult(data, expanded, theme) {
|
|
133
|
+
const icon = data.isRunning
|
|
134
|
+
? ' '
|
|
135
|
+
: data.isError
|
|
136
|
+
? theme.fg('error', '✗')
|
|
137
|
+
: theme.fg('success', '✓');
|
|
138
|
+
// ── Collapsed view: compact single-line status ──────────────────────
|
|
139
|
+
if (!expanded) {
|
|
140
|
+
if (data.isRunning) {
|
|
141
|
+
const activity = getCurrentActivity(data.toolCalls);
|
|
142
|
+
const activityStr = activity
|
|
143
|
+
? `${theme.fg('muted', 'currently doing:')} ${theme.fg('toolOutput', activity)}`
|
|
144
|
+
: theme.fg('muted', 'starting...');
|
|
145
|
+
const tcCount = data.toolCalls.length;
|
|
146
|
+
const usageStr = formatUsage(data.usage, undefined, data.contextWindow, tcCount);
|
|
147
|
+
const footer = usageStr ? `\n${theme.fg('dim', usageStr)}` : '';
|
|
148
|
+
return new Text(`${activityStr}${footer}`, 0, 0);
|
|
149
|
+
}
|
|
150
|
+
// Completed (error, aborted, or done)
|
|
151
|
+
const s = taskStatus(data.isError, data.isAborted, theme);
|
|
152
|
+
const errMsg = data.isError && data.errorMessage
|
|
153
|
+
? ` ${theme.fg('error', truncate(data.errorMessage, 80))}`
|
|
154
|
+
: '';
|
|
155
|
+
const tcCount = data.toolCalls.length;
|
|
156
|
+
const usageStr = formatUsage(data.usage, undefined, data.contextWindow, tcCount);
|
|
157
|
+
const usageSuffix = usageStr ? ` ${theme.fg('dim', usageStr)}` : '';
|
|
158
|
+
return new Text(`${icon} ${theme.fg(s.color, s.word)}${errMsg}${usageSuffix}`, 0, 0);
|
|
159
|
+
}
|
|
160
|
+
// ── Expanded view: full details ─────────────────────────────────────
|
|
161
|
+
const s = data.isRunning ? undefined : taskStatus(data.isError, data.isAborted, theme);
|
|
162
|
+
const statusWord = data.isRunning ? 'running...' : s.word;
|
|
163
|
+
let text = `${icon} ${theme.fg('accent', statusWord)}`;
|
|
164
|
+
// Error message
|
|
165
|
+
if (data.isError && data.errorMessage) {
|
|
166
|
+
text += `\n${theme.fg('error', data.errorMessage)}`;
|
|
167
|
+
}
|
|
168
|
+
// All tool calls
|
|
169
|
+
const calls = data.toolCalls;
|
|
170
|
+
if (calls.length > 0) {
|
|
171
|
+
for (const tc of calls) {
|
|
172
|
+
const formatted = formatToolCall(tc);
|
|
173
|
+
if (formatted) {
|
|
174
|
+
text += `\n${theme.fg('muted', '→ ')}${theme.fg('toolOutput', formatted)}`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Final output text
|
|
179
|
+
if (data.text) {
|
|
180
|
+
text += `\n\n${theme.fg('toolOutput', data.text)}`;
|
|
181
|
+
}
|
|
182
|
+
else if (!data.isRunning && !data.isError) {
|
|
183
|
+
text += `\n${theme.fg('muted', '(no output)')}`;
|
|
184
|
+
}
|
|
185
|
+
// Usage
|
|
186
|
+
const tcCount = data.toolCalls.length;
|
|
187
|
+
const usageStr = formatUsage(data.usage, data.model, data.contextWindow, tcCount);
|
|
188
|
+
if (usageStr) {
|
|
189
|
+
text += `\n${theme.fg('dim', usageStr)}`;
|
|
190
|
+
}
|
|
191
|
+
return new Text(text, 0, 0);
|
|
192
|
+
}
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Grouped rendering (for renderGroup — multiple concurrent tasks as one tree)
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Tree drawing characters — all prefixes are 3 chars wide for alignment
|
|
197
|
+
const BRANCH_MID = '├─ ';
|
|
198
|
+
const BRANCH_END = '└─ ';
|
|
199
|
+
const PIPE_MID = '│ ';
|
|
200
|
+
const PIPE_END = ' ';
|
|
201
|
+
const MAX_GROUP_QUERY_PREVIEW = 100;
|
|
202
|
+
const MAX_EXPANDED_TOOL_CALLS = 15;
|
|
203
|
+
/**
|
|
204
|
+
* Render a group of concurrent task calls as a single tree.
|
|
205
|
+
*
|
|
206
|
+
* Pure function — takes member snapshots from the framework, returns a Component.
|
|
207
|
+
*
|
|
208
|
+
* ✓ General Subagent
|
|
209
|
+
* ├─ Revenue Sheet: Analyze Q3 revenue data...
|
|
210
|
+
* │ ✓ done 18 steps claude-opus-4-6
|
|
211
|
+
* ├─ Income Statement: Build income statement...
|
|
212
|
+
* │ Step 3: >_ Running calculations claude-opus-4-6
|
|
213
|
+
* └─ Format Summary: Apply formatting...
|
|
214
|
+
* ⏳ starting...
|
|
215
|
+
*/
|
|
216
|
+
export function renderTaskGroup(members, options, theme) {
|
|
217
|
+
const { expanded } = options;
|
|
218
|
+
const lines = [];
|
|
219
|
+
// Determine agent type from first member's args
|
|
220
|
+
const firstArgs = members[0]?.args;
|
|
221
|
+
const agentType = firstArgs?.subagent_type ?? 'general';
|
|
222
|
+
const agentLabel = formatAgentGroupLabel(agentType, members.length);
|
|
223
|
+
// Header icon: all done or any error; no icon when still running
|
|
224
|
+
const allDone = members.every((m) => !m.isPartial);
|
|
225
|
+
const headerIcon = groupHeaderIcon(members, theme);
|
|
226
|
+
const header = allDone
|
|
227
|
+
? `${headerIcon} ${theme.fg('toolTitle', theme.bold(agentLabel))}`
|
|
228
|
+
: theme.fg('toolTitle', theme.bold(agentLabel));
|
|
229
|
+
lines.push(header);
|
|
230
|
+
// Tree entries
|
|
231
|
+
for (let i = 0; i < members.length; i++) {
|
|
232
|
+
const member = members[i];
|
|
233
|
+
const isLast = i === members.length - 1;
|
|
234
|
+
const branch = isLast ? BRANCH_END : BRANCH_MID;
|
|
235
|
+
const cont = isLast ? PIPE_END : PIPE_MID;
|
|
236
|
+
const name = member.args?.name || `Agent ${i + 1}`;
|
|
237
|
+
const query = member.args?.query;
|
|
238
|
+
const details = member.result?.details;
|
|
239
|
+
const isRunning = member.isPartial;
|
|
240
|
+
const isError = member.result?.isError ?? false;
|
|
241
|
+
if (expanded) {
|
|
242
|
+
lines.push(...renderGroupEntryExpanded(name, query, details, isRunning, isError, branch, cont, theme));
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
lines.push(...renderGroupEntryCollapsed(name, query, details, isRunning, isError, branch, cont, theme));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return new Text(lines.join('\n'), 0, 0);
|
|
249
|
+
}
|
|
250
|
+
function groupHeaderIcon(members, theme) {
|
|
251
|
+
const allDone = members.every((m) => !m.isPartial);
|
|
252
|
+
if (!allDone)
|
|
253
|
+
return ' ';
|
|
254
|
+
if (members.some((m) => m.result?.isError))
|
|
255
|
+
return theme.fg('error', '✗');
|
|
256
|
+
return theme.fg('success', '✓');
|
|
257
|
+
}
|
|
258
|
+
function renderGroupEntryCollapsed(name, query, details, isRunning, isError, branch, cont, theme) {
|
|
259
|
+
const line1 = `${theme.fg('dim', branch)}${theme.fg('accent', name)}`;
|
|
260
|
+
const prefix = theme.fg('dim', cont);
|
|
261
|
+
const queryLine = query ? `${prefix}${groupQueryPreview(query, theme)}` : undefined;
|
|
262
|
+
if (isRunning) {
|
|
263
|
+
const stepCount = details?.toolCalls.length ?? 0;
|
|
264
|
+
const activity = details ? getCurrentActivity(details.toolCalls) : null;
|
|
265
|
+
let status;
|
|
266
|
+
if (activity) {
|
|
267
|
+
status = `${theme.fg('muted', `Step ${stepCount}:`)} ${theme.fg('toolOutput', activity)}`;
|
|
268
|
+
}
|
|
269
|
+
else if (stepCount > 0) {
|
|
270
|
+
status = `${theme.fg('muted', `Step ${stepCount}: thinking...`)}`;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
status = theme.fg('muted', 'starting...');
|
|
274
|
+
}
|
|
275
|
+
const lines = [line1];
|
|
276
|
+
if (queryLine)
|
|
277
|
+
lines.push(queryLine);
|
|
278
|
+
lines.push(`${prefix} ${status}`);
|
|
279
|
+
return lines;
|
|
280
|
+
}
|
|
281
|
+
const s = taskStatus(isError, details?.isAborted, theme);
|
|
282
|
+
const steps = details?.toolCalls.length ?? 0;
|
|
283
|
+
const stepStr = steps > 0 ? ` ${theme.fg('dim', `${steps} step${steps > 1 ? 's' : ''}`)}` : '';
|
|
284
|
+
const lines = [line1];
|
|
285
|
+
if (queryLine)
|
|
286
|
+
lines.push(queryLine);
|
|
287
|
+
lines.push(`${prefix}${s.icon} ${theme.fg(s.color, s.word)}${stepStr}`);
|
|
288
|
+
return lines;
|
|
289
|
+
}
|
|
290
|
+
function renderGroupEntryExpanded(name, query, details, isRunning, isError, branch, cont, theme) {
|
|
291
|
+
const c = theme.fg('dim', cont);
|
|
292
|
+
const lines = [];
|
|
293
|
+
lines.push(`${theme.fg('dim', branch)}${theme.fg('accent', name)}`);
|
|
294
|
+
if (query)
|
|
295
|
+
lines.push(`${c}${groupQueryPreview(query, theme)}`);
|
|
296
|
+
const usageStr = details
|
|
297
|
+
? formatUsage(details.usage, details.model, details.contextWindow, details.toolCalls.length)
|
|
298
|
+
: '';
|
|
299
|
+
const usageSuffix = usageStr ? ` ${theme.fg('dim', usageStr)}` : '';
|
|
300
|
+
if (isRunning) {
|
|
301
|
+
lines.push(`${c}${theme.fg('accent', 'running...')}${usageSuffix}`);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
const s = taskStatus(isError, details?.isAborted, theme);
|
|
305
|
+
lines.push(`${c}${s.icon} ${theme.fg('accent', s.word)}${usageSuffix}`);
|
|
306
|
+
}
|
|
307
|
+
if (details) {
|
|
308
|
+
if (isError && details.errorMessage) {
|
|
309
|
+
lines.push(`${c}${theme.fg('error', details.errorMessage)}`);
|
|
310
|
+
}
|
|
311
|
+
const displayCalls = details.toolCalls.slice(-MAX_EXPANDED_TOOL_CALLS);
|
|
312
|
+
if (details.toolCalls.length > MAX_EXPANDED_TOOL_CALLS) {
|
|
313
|
+
lines.push(`${c}${theme.fg('muted', `... (${details.toolCalls.length - MAX_EXPANDED_TOOL_CALLS} earlier steps)`)}`);
|
|
314
|
+
}
|
|
315
|
+
for (const tc of displayCalls) {
|
|
316
|
+
const formatted = formatToolCall(tc);
|
|
317
|
+
if (formatted) {
|
|
318
|
+
lines.push(`${c}${theme.fg('muted', '→ ')}${theme.fg('toolOutput', formatted)}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (details.text && !isRunning) {
|
|
322
|
+
const outputLines = details.text.split('\n');
|
|
323
|
+
const maxLines = 5;
|
|
324
|
+
for (const line of outputLines.slice(0, maxLines)) {
|
|
325
|
+
lines.push(`${c}${theme.fg('toolOutput', line)}`);
|
|
326
|
+
}
|
|
327
|
+
if (outputLines.length > maxLines) {
|
|
328
|
+
lines.push(`${c}${theme.fg('muted', `... (${outputLines.length - maxLines} more lines)`)}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return lines;
|
|
333
|
+
}
|
|
334
|
+
function groupQueryPreview(query, theme) {
|
|
335
|
+
const firstLine = query.split('\n')[0] ?? '';
|
|
336
|
+
const preview = firstLine.length > MAX_GROUP_QUERY_PREVIEW
|
|
337
|
+
? firstLine.slice(0, MAX_GROUP_QUERY_PREVIEW) + '...'
|
|
338
|
+
: firstLine;
|
|
339
|
+
return theme.fg('text', preview);
|
|
340
|
+
}
|
|
341
|
+
export function formatAgentTypeLabel(agentType) {
|
|
342
|
+
return agentType.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()) + ' Subagent';
|
|
343
|
+
}
|
|
344
|
+
export function formatAgentGroupLabel(agentType, count) {
|
|
345
|
+
const name = agentType.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
346
|
+
return `${count} ${name} Agent${count > 1 ? 's' : ''}`;
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn a child agent process in JSON mode and collect structured results.
|
|
3
|
+
*
|
|
4
|
+
* This module is the only place that knows about child_process.
|
|
5
|
+
* It emits a stream of typed events and resolves to a SubagentResult.
|
|
6
|
+
*
|
|
7
|
+
* Zero UI knowledge — callers decide what to do with progress callbacks.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import { mkdtempSync, readdirSync, readFileSync, rmdirSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import { dirname, join } from 'node:path';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Implementation
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
function emptyUsage() {
|
|
17
|
+
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0, lastTurnInput: 0 };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse a single JSON event line from the agent's --mode json output.
|
|
21
|
+
* Returns extracted data or null if the line is not relevant.
|
|
22
|
+
*/
|
|
23
|
+
export function parseJsonEvent(line) {
|
|
24
|
+
if (!line.trim())
|
|
25
|
+
return null;
|
|
26
|
+
let event;
|
|
27
|
+
try {
|
|
28
|
+
event = JSON.parse(line);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
// Assistant message completed
|
|
34
|
+
if (event.type === 'message_end' && event.message?.role === 'assistant') {
|
|
35
|
+
const msg = event.message;
|
|
36
|
+
const textParts = [];
|
|
37
|
+
for (const part of msg.content ?? []) {
|
|
38
|
+
if (part.type === 'text')
|
|
39
|
+
textParts.push(part.text);
|
|
40
|
+
}
|
|
41
|
+
const u = msg.usage ?? {};
|
|
42
|
+
return {
|
|
43
|
+
type: 'assistant_message',
|
|
44
|
+
text: textParts.join(''),
|
|
45
|
+
usage: {
|
|
46
|
+
input: u.input ?? 0,
|
|
47
|
+
output: u.output ?? 0,
|
|
48
|
+
cacheRead: u.cacheRead ?? 0,
|
|
49
|
+
cacheWrite: u.cacheWrite ?? 0,
|
|
50
|
+
cost: u.cost?.total ?? 0
|
|
51
|
+
},
|
|
52
|
+
model: msg.model,
|
|
53
|
+
stopReason: msg.stopReason,
|
|
54
|
+
errorMessage: msg.errorMessage
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Tool call started (we grab the name + args for display)
|
|
58
|
+
if (event.type === 'tool_execution_start') {
|
|
59
|
+
return {
|
|
60
|
+
type: 'tool_call',
|
|
61
|
+
name: event.toolName ?? 'unknown',
|
|
62
|
+
args: event.args ?? {}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Write a system prompt to a temp file. Returns the file path.
|
|
69
|
+
* The caller is responsible for cleanup via cleanupTempFile().
|
|
70
|
+
*/
|
|
71
|
+
export function writeSystemPromptFile(prompt) {
|
|
72
|
+
const dir = mkdtempSync(join(tmpdir(), 'shortcut-subagent-'));
|
|
73
|
+
const filePath = join(dir, 'system-prompt.md');
|
|
74
|
+
writeFileSync(filePath, prompt, { encoding: 'utf-8', mode: 0o600 });
|
|
75
|
+
return filePath;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Clean up a temp file created by writeSystemPromptFile.
|
|
79
|
+
*/
|
|
80
|
+
export function cleanupTempFile(filePath) {
|
|
81
|
+
try {
|
|
82
|
+
unlinkSync(filePath);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
/* ignore */
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
rmdirSync(dirname(filePath));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
/* ignore */
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Spawn a child agent process in JSON mode and collect results.
|
|
96
|
+
*
|
|
97
|
+
* The child runs: <command> --mode json [agentArgs...] "Task: <task>"
|
|
98
|
+
*
|
|
99
|
+
* Each subagent persists its own session JSONL to a temp directory.
|
|
100
|
+
* The session ID is returned in SubagentResult.sessionId for trace linking.
|
|
101
|
+
*
|
|
102
|
+
* JSON events are parsed line-by-line. Progress callbacks fire on each
|
|
103
|
+
* assistant message and tool call.
|
|
104
|
+
*/
|
|
105
|
+
export function spawnSubagent(options) {
|
|
106
|
+
const { task, cwd, command, agentArgs = [], signal, onProgress } = options;
|
|
107
|
+
// Each subagent gets its own temp session dir to avoid file lock contention
|
|
108
|
+
const sessionDir = mkdtempSync(join(tmpdir(), 'shortcut-subtrace-'));
|
|
109
|
+
// Write the query to a file to avoid cmd.exe argument splitting on Windows.
|
|
110
|
+
// With shell: true, cmd.exe splits positional args on spaces and mangles
|
|
111
|
+
// special characters (&, |, ^, etc.). Passing a .txt file path (no spaces)
|
|
112
|
+
// as the positional arg sidesteps this entirely. The subagent entry resolves
|
|
113
|
+
// .txt paths to their contents (same pattern as the backend task tool).
|
|
114
|
+
// If the query is already a .txt file path, pass it through directly.
|
|
115
|
+
const trimmedTask = task.trim();
|
|
116
|
+
let taskArg;
|
|
117
|
+
if (trimmedTask.endsWith('.txt') && !trimmedTask.includes(' ')) {
|
|
118
|
+
taskArg = trimmedTask;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const taskFile = join(sessionDir, 'query.txt');
|
|
122
|
+
writeFileSync(taskFile, `Task: ${task}`, { encoding: 'utf-8', mode: 0o600 });
|
|
123
|
+
taskArg = taskFile;
|
|
124
|
+
}
|
|
125
|
+
const [bin, ...binPrefixArgs] = command;
|
|
126
|
+
const args = [
|
|
127
|
+
...binPrefixArgs,
|
|
128
|
+
'--subagent',
|
|
129
|
+
'--mode',
|
|
130
|
+
'json',
|
|
131
|
+
'--session-dir',
|
|
132
|
+
sessionDir,
|
|
133
|
+
...agentArgs,
|
|
134
|
+
taskArg
|
|
135
|
+
];
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
const proc = spawn(bin, args, {
|
|
138
|
+
cwd,
|
|
139
|
+
shell: process.platform === 'win32',
|
|
140
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
141
|
+
});
|
|
142
|
+
const usage = emptyUsage();
|
|
143
|
+
const toolCalls = [];
|
|
144
|
+
let lastText = '';
|
|
145
|
+
let model;
|
|
146
|
+
let stopReason;
|
|
147
|
+
let errorMessage;
|
|
148
|
+
let stderr = '';
|
|
149
|
+
let buffer = '';
|
|
150
|
+
let wasAborted = false;
|
|
151
|
+
const emitProgress = () => {
|
|
152
|
+
onProgress?.({
|
|
153
|
+
text: lastText,
|
|
154
|
+
toolCalls: [...toolCalls],
|
|
155
|
+
usage: { ...usage },
|
|
156
|
+
model
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
const processLine = (line) => {
|
|
160
|
+
const parsed = parseJsonEvent(line);
|
|
161
|
+
if (!parsed)
|
|
162
|
+
return;
|
|
163
|
+
if (parsed.type === 'assistant_message') {
|
|
164
|
+
lastText = parsed.text;
|
|
165
|
+
usage.turns++;
|
|
166
|
+
usage.input += parsed.usage.input ?? 0;
|
|
167
|
+
usage.output += parsed.usage.output ?? 0;
|
|
168
|
+
usage.cacheRead += parsed.usage.cacheRead ?? 0;
|
|
169
|
+
usage.cacheWrite += parsed.usage.cacheWrite ?? 0;
|
|
170
|
+
usage.cost += parsed.usage.cost ?? 0;
|
|
171
|
+
usage.lastTurnInput = parsed.usage.input ?? 0;
|
|
172
|
+
if (parsed.model)
|
|
173
|
+
model = parsed.model;
|
|
174
|
+
if (parsed.stopReason)
|
|
175
|
+
stopReason = parsed.stopReason;
|
|
176
|
+
if (parsed.errorMessage)
|
|
177
|
+
errorMessage = parsed.errorMessage;
|
|
178
|
+
emitProgress();
|
|
179
|
+
}
|
|
180
|
+
if (parsed.type === 'tool_call') {
|
|
181
|
+
toolCalls.push({ name: parsed.name, args: parsed.args });
|
|
182
|
+
emitProgress();
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
proc.stdout.on('data', (data) => {
|
|
186
|
+
buffer += data.toString();
|
|
187
|
+
const lines = buffer.split('\n');
|
|
188
|
+
buffer = lines.pop() || '';
|
|
189
|
+
for (const line of lines)
|
|
190
|
+
processLine(line);
|
|
191
|
+
});
|
|
192
|
+
proc.stderr.on('data', (data) => {
|
|
193
|
+
stderr += data.toString();
|
|
194
|
+
});
|
|
195
|
+
proc.on('close', (code) => {
|
|
196
|
+
if (buffer.trim())
|
|
197
|
+
processLine(buffer);
|
|
198
|
+
// Read subagent session ID and file path from the persisted JSONL
|
|
199
|
+
let sessionId;
|
|
200
|
+
let sessionFile;
|
|
201
|
+
try {
|
|
202
|
+
const files = readdirSync(sessionDir).filter((f) => f.endsWith('.jsonl'));
|
|
203
|
+
if (files.length > 0) {
|
|
204
|
+
sessionFile = join(sessionDir, files[0]);
|
|
205
|
+
const firstLine = readFileSync(sessionFile, 'utf-8').split('\n')[0];
|
|
206
|
+
const header = JSON.parse(firstLine);
|
|
207
|
+
if (header.type === 'session')
|
|
208
|
+
sessionId = header.id;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
/* ignore — session may not have been written */
|
|
213
|
+
}
|
|
214
|
+
resolve({
|
|
215
|
+
text: lastText,
|
|
216
|
+
toolCalls,
|
|
217
|
+
usage,
|
|
218
|
+
model,
|
|
219
|
+
exitCode: code ?? (wasAborted ? 130 : 1),
|
|
220
|
+
stderr,
|
|
221
|
+
stopReason,
|
|
222
|
+
errorMessage,
|
|
223
|
+
aborted: wasAborted,
|
|
224
|
+
sessionId,
|
|
225
|
+
sessionFile
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
proc.on('error', (err) => {
|
|
229
|
+
resolve({
|
|
230
|
+
text: lastText,
|
|
231
|
+
toolCalls,
|
|
232
|
+
usage,
|
|
233
|
+
model,
|
|
234
|
+
exitCode: 1,
|
|
235
|
+
stderr: stderr || `Failed to spawn process: ${err.message}`,
|
|
236
|
+
stopReason: 'error',
|
|
237
|
+
errorMessage: `Failed to spawn process: ${err.message}`
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
// Cancellation
|
|
241
|
+
if (signal) {
|
|
242
|
+
const killProc = () => {
|
|
243
|
+
wasAborted = true;
|
|
244
|
+
if (process.platform === 'win32' && proc.pid) {
|
|
245
|
+
// On Windows, shell: true means proc is cmd.exe — SIGTERM only kills
|
|
246
|
+
// the shell, not the child node process. Use taskkill /T to kill the
|
|
247
|
+
// entire process tree.
|
|
248
|
+
spawn('taskkill', ['/T', '/F', '/PID', String(proc.pid)], {
|
|
249
|
+
stdio: 'ignore'
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
proc.kill('SIGTERM');
|
|
254
|
+
setTimeout(() => {
|
|
255
|
+
if (!proc.killed)
|
|
256
|
+
proc.kill('SIGKILL');
|
|
257
|
+
}, 5000);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
if (signal.aborted)
|
|
261
|
+
killProc();
|
|
262
|
+
else
|
|
263
|
+
signal.addEventListener('abort', killProc, { once: true });
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
// CLI args builder — translates AgentDefinition into child process args
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
import { CORE_TOOL_NAMES } from '../../../tool-names.js';
|
|
271
|
+
/**
|
|
272
|
+
* Build CLI args for spawning a child process from an AgentDefinition.
|
|
273
|
+
*
|
|
274
|
+
* The agent's flat tools array is split into --tools (core) and
|
|
275
|
+
* --custom-tools (everything else) for the CLI flags.
|
|
276
|
+
*
|
|
277
|
+
* System prompt is written to a temp file to avoid shell escaping issues.
|
|
278
|
+
* The caller MUST clean up the temp file after the subprocess exits.
|
|
279
|
+
*/
|
|
280
|
+
export function buildAgentArgs(config) {
|
|
281
|
+
const args = [];
|
|
282
|
+
let promptFile;
|
|
283
|
+
// Model + thinking level
|
|
284
|
+
if (config.model) {
|
|
285
|
+
args.push('--model', config.model);
|
|
286
|
+
}
|
|
287
|
+
if (config.thinkingLevel) {
|
|
288
|
+
args.push('--thinking', config.thinkingLevel);
|
|
289
|
+
}
|
|
290
|
+
// Split flat tools list into core vs custom for CLI flags
|
|
291
|
+
const coreTools = [];
|
|
292
|
+
const customTools = [];
|
|
293
|
+
for (const t of config.tools) {
|
|
294
|
+
if (CORE_TOOL_NAMES.has(t)) {
|
|
295
|
+
coreTools.push(t);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
customTools.push(t);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (coreTools.length > 0) {
|
|
302
|
+
args.push('--tools', coreTools.join(','));
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
args.push('--no-tools');
|
|
306
|
+
}
|
|
307
|
+
if (customTools.length > 0) {
|
|
308
|
+
args.push('--custom-tools', customTools.join(','));
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
args.push('--no-custom-tools');
|
|
312
|
+
}
|
|
313
|
+
// System prompt — replace entirely via temp file
|
|
314
|
+
if (config.systemPrompt) {
|
|
315
|
+
promptFile = writeSystemPromptFile(config.systemPrompt);
|
|
316
|
+
args.push('--system-prompt', promptFile);
|
|
317
|
+
}
|
|
318
|
+
return { args, promptFile };
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=subprocess.js.map
|