@xagent-ai/cli 1.2.2 → 1.3.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/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/workflows/ci.yml +72 -0
- package/.github/workflows/release.yml +109 -0
- package/.gitmodules +3 -3
- package/README.md +326 -280
- package/README_CN.md +325 -279
- package/dist/ai-client/factory.d.ts +52 -0
- package/dist/ai-client/factory.d.ts.map +1 -0
- package/dist/ai-client/factory.js +132 -0
- package/dist/ai-client/factory.js.map +1 -0
- package/dist/ai-client/index.d.ts +20 -0
- package/dist/ai-client/index.d.ts.map +1 -0
- package/dist/ai-client/index.js +49 -0
- package/dist/ai-client/index.js.map +1 -0
- package/dist/ai-client/providers/anthropic.d.ts +57 -0
- package/dist/ai-client/providers/anthropic.d.ts.map +1 -0
- package/dist/ai-client/providers/anthropic.js +400 -0
- package/dist/ai-client/providers/anthropic.js.map +1 -0
- package/dist/ai-client/providers/openai.d.ts +57 -0
- package/dist/ai-client/providers/openai.d.ts.map +1 -0
- package/dist/ai-client/providers/openai.js +286 -0
- package/dist/ai-client/providers/openai.js.map +1 -0
- package/dist/ai-client/providers/remote.d.ts +111 -0
- package/dist/ai-client/providers/remote.d.ts.map +1 -0
- package/dist/ai-client/providers/remote.js +351 -0
- package/dist/ai-client/providers/remote.js.map +1 -0
- package/dist/ai-client/registry.d.ts +51 -0
- package/dist/ai-client/registry.d.ts.map +1 -0
- package/dist/ai-client/registry.js +81 -0
- package/dist/ai-client/registry.js.map +1 -0
- package/dist/ai-client/types.d.ts +260 -0
- package/dist/ai-client/types.d.ts.map +1 -0
- package/dist/ai-client/types.js +73 -0
- package/dist/ai-client/types.js.map +1 -0
- package/dist/ai-client-factory.d.ts +62 -0
- package/dist/ai-client-factory.d.ts.map +1 -0
- package/dist/ai-client-factory.js +157 -0
- package/dist/ai-client-factory.js.map +1 -0
- package/dist/auth.d.ts +23 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +160 -168
- package/dist/auth.js.map +1 -1
- package/dist/cancellation.d.ts +5 -4
- package/dist/cancellation.d.ts.map +1 -1
- package/dist/cancellation.js +55 -32
- package/dist/cancellation.js.map +1 -1
- package/dist/checkpoint.d.ts +1 -1
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +2 -2
- package/dist/checkpoint.js.map +1 -1
- package/dist/cli.js +626 -13
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +10 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +62 -25
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts +81 -16
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +712 -153
- package/dist/context-compressor.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +4 -2
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.d.ts +29 -2
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +87 -45
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +16 -1
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +4 -0
- package/dist/gui-subagent/index.js.map +1 -1
- package/dist/gui-subagent/operator/base-operator.d.ts.map +1 -1
- package/dist/gui-subagent/operator/base-operator.js +0 -1
- package/dist/gui-subagent/operator/base-operator.js.map +1 -1
- package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
- package/dist/gui-subagent/operator/computer-operator.js +29 -8
- package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
- package/dist/gui-subagent/types/actions.d.ts +1 -1
- package/dist/gui-subagent/types/actions.d.ts.map +1 -1
- package/dist/gui-subagent/types/actions.js +0 -1
- package/dist/gui-subagent/types/actions.js.map +1 -1
- package/dist/gui-subagent/types/operator.d.ts +1 -1
- package/dist/gui-subagent/types/operator.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/input-processor.d.ts.map +1 -1
- package/dist/input-processor.js +6 -3
- package/dist/input-processor.js.map +1 -1
- package/dist/mcp.d.ts +5 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +81 -35
- package/dist/mcp.js.map +1 -1
- package/dist/ripgrep.d.ts +29 -0
- package/dist/ripgrep.d.ts.map +1 -0
- package/dist/ripgrep.js +292 -0
- package/dist/ripgrep.js.map +1 -0
- package/dist/session.d.ts +23 -7
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +624 -243
- package/dist/session.js.map +1 -1
- package/dist/shell.d.ts +33 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +125 -0
- package/dist/shell.js.map +1 -0
- package/dist/skill-installer.d.ts +38 -0
- package/dist/skill-installer.d.ts.map +1 -0
- package/dist/skill-installer.js +447 -0
- package/dist/skill-installer.js.map +1 -0
- package/dist/skill-invoker.d.ts +7 -1
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +34 -13
- package/dist/skill-invoker.js.map +1 -1
- package/dist/skill-loader.d.ts +8 -3
- package/dist/skill-loader.d.ts.map +1 -1
- package/dist/skill-loader.js +46 -44
- package/dist/skill-loader.js.map +1 -1
- package/dist/skill-manager.d.ts +85 -0
- package/dist/skill-manager.d.ts.map +1 -0
- package/dist/skill-manager.js +340 -0
- package/dist/skill-manager.js.map +1 -0
- package/dist/slash-commands.d.ts +38 -1
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +912 -296
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +67 -55
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.d.ts +6 -0
- package/dist/system-prompt-generator.d.ts.map +1 -1
- package/dist/system-prompt-generator.js +84 -34
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/terminal.d.ts +28 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +82 -0
- package/dist/terminal.js.map +1 -0
- package/dist/tools.d.ts +23 -7
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +797 -437
- package/dist/tools.js.map +1 -1
- package/dist/truncate.d.ts +55 -0
- package/dist/truncate.d.ts.map +1 -0
- package/dist/truncate.js +130 -0
- package/dist/truncate.js.map +1 -0
- package/dist/types.d.ts +27 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +17 -28
- package/dist/update.js.map +1 -1
- package/dist/workflow.d.ts +5 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +60 -47
- package/dist/workflow.js.map +1 -1
- package/docs/architecture/mcp-integration-guide.md +304 -194
- package/docs/architecture/overview.md +169 -169
- package/docs/architecture/tool-system-design.md +134 -134
- package/docs/cli/commands.md +349 -238
- package/docs/smart-mode.md +281 -281
- package/docs/third-party-models.md +439 -439
- package/find-skills/SKILL.md +133 -0
- package/package.json +89 -90
- package/scripts/install-ripgrep.js +241 -0
- package/src/ai-client/factory.ts +151 -0
- package/src/ai-client/index.ts +61 -0
- package/src/ai-client/providers/anthropic.ts +466 -0
- package/src/ai-client/providers/openai.ts +342 -0
- package/src/ai-client/providers/remote.ts +436 -0
- package/src/ai-client/registry.ts +97 -0
- package/src/ai-client/types.ts +345 -0
- package/src/ai-client-factory.ts +204 -0
- package/src/auth.ts +663 -614
- package/src/cancellation.ts +205 -176
- package/src/checkpoint.ts +219 -219
- package/src/cli.ts +1406 -743
- package/src/config.ts +341 -297
- package/src/context-compressor.ts +982 -290
- package/src/conversation.ts +288 -288
- package/src/gui-subagent/action-parser/actionParser.ts +318 -315
- package/src/gui-subagent/action-parser/constants.ts +14 -14
- package/src/gui-subagent/action-parser/index.ts +8 -8
- package/src/gui-subagent/action-parser/types.ts +31 -31
- package/src/gui-subagent/agent/gui-agent.ts +1151 -1089
- package/src/gui-subagent/agent/index.ts +5 -5
- package/src/gui-subagent/index.ts +177 -163
- package/src/gui-subagent/operator/base-operator.ts +244 -245
- package/src/gui-subagent/operator/computer-operator.ts +540 -520
- package/src/gui-subagent/operator/index.ts +6 -6
- package/src/gui-subagent/types/actions.ts +260 -262
- package/src/gui-subagent/types/index.ts +6 -6
- package/src/gui-subagent/types/operator.ts +106 -106
- package/src/gui-subagent/utils.ts +51 -51
- package/src/index.ts +17 -18
- package/src/input-processor.ts +6 -3
- package/src/logger.ts +438 -438
- package/src/mcp.ts +730 -682
- package/src/memory.ts +344 -344
- package/src/ripgrep.ts +368 -0
- package/src/session-manager.ts +308 -308
- package/src/session.ts +948 -386
- package/src/shell.ts +133 -0
- package/src/skill-installer.ts +518 -0
- package/src/skill-invoker.ts +960 -935
- package/src/skill-loader.ts +501 -496
- package/src/skill-manager.ts +384 -0
- package/src/slash-commands.ts +2181 -1389
- package/src/smart-approval.ts +117 -73
- package/src/system-prompt-generator.ts +89 -34
- package/src/terminal.ts +96 -0
- package/src/theme.ts +738 -738
- package/src/tools.ts +1336 -773
- package/src/truncate.ts +173 -0
- package/src/types.ts +219 -198
- package/src/update.ts +22 -32
- package/src/workflow.ts +523 -508
- package/tsconfig.json +22 -22
- package/vitest.config.ts +19 -19
- package/dist/ai-client.d.ts +0 -86
- package/dist/ai-client.d.ts.map +0 -1
- package/dist/ai-client.js +0 -1372
- package/dist/ai-client.js.map +0 -1
- package/dist/gui-subagent/operator/browser-operator.d.ts +0 -36
- package/dist/gui-subagent/operator/browser-operator.d.ts.map +0 -1
- package/dist/gui-subagent/operator/browser-operator.js +0 -306
- package/dist/gui-subagent/operator/browser-operator.js.map +0 -1
- package/dist/gui-subagent/operator/desktop-operator.d.ts +0 -55
- package/dist/gui-subagent/operator/desktop-operator.d.ts.map +0 -1
- package/dist/gui-subagent/operator/desktop-operator.js +0 -527
- package/dist/gui-subagent/operator/desktop-operator.js.map +0 -1
- package/dist/hook.d.ts +0 -73
- package/dist/hook.d.ts.map +0 -1
- package/dist/hook.js +0 -156
- package/dist/hook.js.map +0 -1
- package/dist/input-history.d.ts +0 -24
- package/dist/input-history.d.ts.map +0 -1
- package/dist/input-history.js +0 -94
- package/dist/input-history.js.map +0 -1
- package/dist/keyboard-manager.d.ts +0 -151
- package/dist/keyboard-manager.d.ts.map +0 -1
- package/dist/keyboard-manager.js +0 -396
- package/dist/keyboard-manager.js.map +0 -1
- package/dist/print-system-prompt.d.ts +0 -2
- package/dist/print-system-prompt.d.ts.map +0 -1
- package/dist/print-system-prompt.js +0 -40
- package/dist/print-system-prompt.js.map +0 -1
- package/dist/remote-ai-client.d.ts +0 -104
- package/dist/remote-ai-client.d.ts.map +0 -1
- package/dist/remote-ai-client.js +0 -552
- package/dist/remote-ai-client.js.map +0 -1
- package/dist/sdk-output-adapter.d.ts +0 -232
- package/dist/sdk-output-adapter.d.ts.map +0 -1
- package/dist/sdk-output-adapter.js +0 -636
- package/dist/sdk-output-adapter.js.map +0 -1
- package/dist/sdk-session-v2.d.ts +0 -13
- package/dist/sdk-session-v2.d.ts.map +0 -1
- package/dist/sdk-session-v2.js +0 -46
- package/dist/sdk-session-v2.js.map +0 -1
- package/dist/sdk-session.d.ts +0 -13
- package/dist/sdk-session.d.ts.map +0 -1
- package/dist/sdk-session.js +0 -48
- package/dist/sdk-session.js.map +0 -1
- package/dist/test-boundary-conditions.d.ts.map +0 -1
- package/dist/test-boundary-conditions.js.map +0 -1
- package/dist/test-cancellation-fix.d.ts.map +0 -1
- package/dist/test-cancellation-fix.js.map +0 -1
- package/dist/test-input-history.d.ts.map +0 -1
- package/dist/test-input-history.js.map +0 -1
- package/dist/test-interaction-flow.d.ts.map +0 -1
- package/dist/test-interaction-flow.js.map +0 -1
- package/dist/test-quick.d.ts.map +0 -1
- package/dist/test-quick.js.map +0 -1
- package/dist/test-user-interaction.d.ts.map +0 -1
- package/dist/test-user-interaction.js.map +0 -1
- package/dist/tools/edit-diff.d.ts +0 -32
- package/dist/tools/edit-diff.d.ts.map +0 -1
- package/dist/tools/edit-diff.js +0 -185
- package/dist/tools/edit-diff.js.map +0 -1
- package/dist/tools/edit.d.ts +0 -11
- package/dist/tools/edit.d.ts.map +0 -1
- package/dist/tools/edit.js +0 -129
- package/dist/tools/edit.js.map +0 -1
- package/dist/unified-session.d.ts +0 -42
- package/dist/unified-session.d.ts.map +0 -1
- package/dist/unified-session.js +0 -271
- package/dist/unified-session.js.map +0 -1
- package/skills/.claude-plugin/marketplace.json +0 -45
- package/skills/README.md +0 -94
- package/skills/THIRD_PARTY_NOTICES.md +0 -405
- package/skills/skills/algorithmic-art/LICENSE.txt +0 -202
- package/skills/skills/algorithmic-art/SKILL.md +0 -405
- package/skills/skills/algorithmic-art/templates/generator_template.js +0 -223
- package/skills/skills/algorithmic-art/templates/viewer.html +0 -599
- package/skills/skills/brand-guidelines/LICENSE.txt +0 -202
- package/skills/skills/brand-guidelines/SKILL.md +0 -73
- package/skills/skills/canvas-design/LICENSE.txt +0 -202
- package/skills/skills/canvas-design/SKILL.md +0 -130
- package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
- package/skills/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
- package/skills/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/skills/skills/doc-coauthoring/SKILL.md +0 -375
- package/skills/skills/docx/LICENSE.txt +0 -30
- package/skills/skills/docx/SKILL.md +0 -197
- package/skills/skills/docx/docx-js.md +0 -350
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
- package/skills/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
- package/skills/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
- package/skills/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
- package/skills/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
- package/skills/skills/docx/ooxml/scripts/pack.py +0 -159
- package/skills/skills/docx/ooxml/scripts/unpack.py +0 -29
- package/skills/skills/docx/ooxml/scripts/validate.py +0 -69
- package/skills/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
- package/skills/skills/docx/ooxml/scripts/validation/base.py +0 -951
- package/skills/skills/docx/ooxml/scripts/validation/docx.py +0 -274
- package/skills/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
- package/skills/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
- package/skills/skills/docx/ooxml.md +0 -610
- package/skills/skills/docx/scripts/__init__.py +0 -1
- package/skills/skills/docx/scripts/document.py +0 -1276
- package/skills/skills/docx/scripts/templates/comments.xml +0 -3
- package/skills/skills/docx/scripts/templates/commentsExtended.xml +0 -3
- package/skills/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
- package/skills/skills/docx/scripts/templates/commentsIds.xml +0 -3
- package/skills/skills/docx/scripts/templates/people.xml +0 -3
- package/skills/skills/docx/scripts/utilities.py +0 -374
- package/skills/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/skills/frontend-design/SKILL.md +0 -42
- package/skills/skills/internal-comms/LICENSE.txt +0 -202
- package/skills/skills/internal-comms/SKILL.md +0 -32
- package/skills/skills/internal-comms/examples/3p-updates.md +0 -47
- package/skills/skills/internal-comms/examples/company-newsletter.md +0 -65
- package/skills/skills/internal-comms/examples/faq-answers.md +0 -30
- package/skills/skills/internal-comms/examples/general-comms.md +0 -16
- package/skills/skills/mcp-builder/LICENSE.txt +0 -202
- package/skills/skills/mcp-builder/SKILL.md +0 -236
- package/skills/skills/mcp-builder/reference/evaluation.md +0 -602
- package/skills/skills/mcp-builder/reference/mcp_best_practices.md +0 -249
- package/skills/skills/mcp-builder/reference/node_mcp_server.md +0 -970
- package/skills/skills/mcp-builder/reference/python_mcp_server.md +0 -719
- package/skills/skills/mcp-builder/scripts/connections.py +0 -151
- package/skills/skills/mcp-builder/scripts/evaluation.py +0 -373
- package/skills/skills/mcp-builder/scripts/example_evaluation.xml +0 -22
- package/skills/skills/mcp-builder/scripts/requirements.txt +0 -2
- package/skills/skills/pdf/LICENSE.txt +0 -30
- package/skills/skills/pdf/SKILL.md +0 -294
- package/skills/skills/pdf/forms.md +0 -205
- package/skills/skills/pdf/reference.md +0 -612
- package/skills/skills/pdf/scripts/check_bounding_boxes.py +0 -70
- package/skills/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
- package/skills/skills/pdf/scripts/check_fillable_fields.py +0 -12
- package/skills/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
- package/skills/skills/pdf/scripts/create_validation_image.py +0 -41
- package/skills/skills/pdf/scripts/extract_form_field_info.py +0 -152
- package/skills/skills/pdf/scripts/fill_fillable_fields.py +0 -114
- package/skills/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
- package/skills/skills/pptx/LICENSE.txt +0 -30
- package/skills/skills/pptx/SKILL.md +0 -484
- package/skills/skills/pptx/html2pptx.md +0 -625
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
- package/skills/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
- package/skills/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
- package/skills/skills/pptx/ooxml/schemas/mce/mc.xsd +0 -75
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
- package/skills/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
- package/skills/skills/pptx/ooxml/scripts/pack.py +0 -159
- package/skills/skills/pptx/ooxml/scripts/unpack.py +0 -29
- package/skills/skills/pptx/ooxml/scripts/validate.py +0 -69
- package/skills/skills/pptx/ooxml/scripts/validation/__init__.py +0 -15
- package/skills/skills/pptx/ooxml/scripts/validation/base.py +0 -951
- package/skills/skills/pptx/ooxml/scripts/validation/docx.py +0 -274
- package/skills/skills/pptx/ooxml/scripts/validation/pptx.py +0 -315
- package/skills/skills/pptx/ooxml/scripts/validation/redlining.py +0 -279
- package/skills/skills/pptx/ooxml.md +0 -427
- package/skills/skills/pptx/scripts/html2pptx.js +0 -979
- package/skills/skills/pptx/scripts/inventory.py +0 -1020
- package/skills/skills/pptx/scripts/rearrange.py +0 -231
- package/skills/skills/pptx/scripts/replace.py +0 -385
- package/skills/skills/pptx/scripts/thumbnail.py +0 -450
- package/skills/skills/skill-creator/LICENSE.txt +0 -202
- package/skills/skills/skill-creator/SKILL.md +0 -356
- package/skills/skills/skill-creator/references/output-patterns.md +0 -82
- package/skills/skills/skill-creator/references/workflows.md +0 -28
- package/skills/skills/skill-creator/scripts/init_skill.py +0 -303
- package/skills/skills/skill-creator/scripts/package_skill.py +0 -110
- package/skills/skills/skill-creator/scripts/quick_validate.py +0 -95
- package/skills/skills/slack-gif-creator/LICENSE.txt +0 -202
- package/skills/skills/slack-gif-creator/SKILL.md +0 -254
- package/skills/skills/slack-gif-creator/core/easing.py +0 -234
- package/skills/skills/slack-gif-creator/core/frame_composer.py +0 -176
- package/skills/skills/slack-gif-creator/core/gif_builder.py +0 -269
- package/skills/skills/slack-gif-creator/core/validators.py +0 -136
- package/skills/skills/slack-gif-creator/requirements.txt +0 -4
- package/skills/skills/theme-factory/LICENSE.txt +0 -202
- package/skills/skills/theme-factory/SKILL.md +0 -59
- package/skills/skills/theme-factory/theme-showcase.pdf +0 -0
- package/skills/skills/theme-factory/themes/arctic-frost.md +0 -19
- package/skills/skills/theme-factory/themes/botanical-garden.md +0 -19
- package/skills/skills/theme-factory/themes/desert-rose.md +0 -19
- package/skills/skills/theme-factory/themes/forest-canopy.md +0 -19
- package/skills/skills/theme-factory/themes/golden-hour.md +0 -19
- package/skills/skills/theme-factory/themes/midnight-galaxy.md +0 -19
- package/skills/skills/theme-factory/themes/modern-minimalist.md +0 -19
- package/skills/skills/theme-factory/themes/ocean-depths.md +0 -19
- package/skills/skills/theme-factory/themes/sunset-boulevard.md +0 -19
- package/skills/skills/theme-factory/themes/tech-innovation.md +0 -19
- package/skills/skills/web-artifacts-builder/LICENSE.txt +0 -202
- package/skills/skills/web-artifacts-builder/SKILL.md +0 -74
- package/skills/skills/web-artifacts-builder/scripts/bundle-artifact.sh +0 -54
- package/skills/skills/web-artifacts-builder/scripts/init-artifact.sh +0 -322
- package/skills/skills/webapp-testing/LICENSE.txt +0 -202
- package/skills/skills/webapp-testing/SKILL.md +0 -96
- package/skills/skills/webapp-testing/examples/console_logging.py +0 -35
- package/skills/skills/webapp-testing/examples/element_discovery.py +0 -40
- package/skills/skills/webapp-testing/examples/static_html_automation.py +0 -33
- package/skills/skills/webapp-testing/scripts/with_server.py +0 -106
- package/skills/skills/xlsx/LICENSE.txt +0 -30
- package/skills/skills/xlsx/SKILL.md +0 -289
- package/skills/skills/xlsx/recalc.py +0 -178
- package/skills/spec/agent-skills-spec.md +0 -3
- package/skills/template/SKILL.md +0 -6
- package/src/ai-client.ts +0 -1560
- package/src/remote-ai-client.ts +0 -664
package/dist/session.js
CHANGED
|
@@ -5,11 +5,18 @@ import axios from 'axios';
|
|
|
5
5
|
import crypto from 'crypto';
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import { createRequire } from 'module';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import fsPromises from 'fs/promises';
|
|
12
|
+
import os from 'os';
|
|
8
13
|
const require = createRequire(import.meta.url);
|
|
9
14
|
const packageJson = require('../package.json');
|
|
10
|
-
import { ExecutionMode, AuthType } from './types.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
15
|
+
import { ExecutionMode, AuthType, } from './types.js';
|
|
16
|
+
import { createAIClient } from './ai-client-factory.js';
|
|
17
|
+
import { detectThinkingKeywords, getThinkingTokens } from './ai-client/types.js';
|
|
18
|
+
import { TokenInvalidError } from './ai-client/types.js';
|
|
19
|
+
import { fetchDefaultModels } from './ai-client/providers/remote.js';
|
|
13
20
|
import { getConfigManager } from './config.js';
|
|
14
21
|
import { AuthService, selectAuthType } from './auth.js';
|
|
15
22
|
import { getToolRegistry } from './tools.js';
|
|
@@ -21,10 +28,11 @@ import { getConversationManager } from './conversation.js';
|
|
|
21
28
|
import { getSessionManager } from './session-manager.js';
|
|
22
29
|
import { SlashCommandHandler, parseInput } from './slash-commands.js';
|
|
23
30
|
import { SystemPromptGenerator } from './system-prompt-generator.js';
|
|
24
|
-
import { theme, icons, colors, styleHelpers, renderMarkdown, renderDiff, renderLines } from './theme.js';
|
|
31
|
+
import { theme, icons, colors, styleHelpers, renderMarkdown, renderDiff, renderLines, } from './theme.js';
|
|
25
32
|
import { getCancellationManager } from './cancellation.js';
|
|
26
|
-
import { getContextCompressor } from './context-compressor.js';
|
|
33
|
+
import { getContextCompressor, } from './context-compressor.js';
|
|
27
34
|
import { getLogger } from './logger.js';
|
|
35
|
+
import { ensureTtySane, setupEscKeyHandler } from './terminal.js';
|
|
28
36
|
const logger = getLogger();
|
|
29
37
|
export class InteractiveSession {
|
|
30
38
|
conversationManager;
|
|
@@ -33,7 +41,7 @@ export class InteractiveSession {
|
|
|
33
41
|
aiClient = null;
|
|
34
42
|
remoteAIClient = null;
|
|
35
43
|
conversation = [];
|
|
36
|
-
|
|
44
|
+
tool_calls = [];
|
|
37
45
|
executionMode;
|
|
38
46
|
slashCommandHandler;
|
|
39
47
|
configManager;
|
|
@@ -53,7 +61,7 @@ export class InteractiveSession {
|
|
|
53
61
|
constructor(indentLevel = 0) {
|
|
54
62
|
this.rl = readline.createInterface({
|
|
55
63
|
input: process.stdin,
|
|
56
|
-
output: process.stdout
|
|
64
|
+
output: process.stdout,
|
|
57
65
|
});
|
|
58
66
|
this.configManager = getConfigManager(process.cwd());
|
|
59
67
|
this.agentManager = getAgentManager(process.cwd());
|
|
@@ -66,7 +74,7 @@ export class InteractiveSession {
|
|
|
66
74
|
// Register /clear callback, clear local conversation when clearing dialogue
|
|
67
75
|
this.slashCommandHandler.setClearCallback(() => {
|
|
68
76
|
this.conversation = [];
|
|
69
|
-
this.
|
|
77
|
+
this.tool_calls = [];
|
|
70
78
|
this.currentTaskId = null;
|
|
71
79
|
this.taskCompleted = false;
|
|
72
80
|
this.isFirstApiCall = true;
|
|
@@ -76,6 +84,10 @@ export class InteractiveSession {
|
|
|
76
84
|
this.slashCommandHandler.setSystemPromptUpdateCallback(async () => {
|
|
77
85
|
await this.updateSystemPrompt();
|
|
78
86
|
});
|
|
87
|
+
// Register config update callback, update aiClient config when /auth changes config
|
|
88
|
+
this.slashCommandHandler.setConfigUpdateCallback(() => {
|
|
89
|
+
this.updateAiClientConfig();
|
|
90
|
+
});
|
|
79
91
|
this.executionMode = ExecutionMode.DEFAULT;
|
|
80
92
|
this.cancellationManager = getCancellationManager();
|
|
81
93
|
this.indentLevel = indentLevel;
|
|
@@ -88,6 +100,32 @@ export class InteractiveSession {
|
|
|
88
100
|
setAIClient(aiClient) {
|
|
89
101
|
this.aiClient = aiClient;
|
|
90
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Update aiClient config when /auth changes config (called from callback)
|
|
105
|
+
*/
|
|
106
|
+
updateAiClientConfig() {
|
|
107
|
+
const authConfig = this.configManager.getAuthConfig();
|
|
108
|
+
const isRemote = authConfig.type === AuthType.OAUTH_XAGENT;
|
|
109
|
+
if (isRemote) {
|
|
110
|
+
// Already in remote mode, no change needed
|
|
111
|
+
if (this.remoteAIClient !== null) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Switch to remote: clear local client, create remote client
|
|
115
|
+
this.aiClient = null;
|
|
116
|
+
this.remoteAIClient = createAIClient(authConfig);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// Already in local mode, no change needed
|
|
120
|
+
if (this.aiClient !== null) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Switch to local: clear remote client, create local client
|
|
124
|
+
this.remoteAIClient = null;
|
|
125
|
+
this.aiClient = createAIClient(authConfig);
|
|
126
|
+
}
|
|
127
|
+
this.slashCommandHandler.setRemoteAIClient(this.remoteAIClient);
|
|
128
|
+
}
|
|
91
129
|
setExecutionMode(mode) {
|
|
92
130
|
this.executionMode = mode;
|
|
93
131
|
}
|
|
@@ -95,25 +133,68 @@ export class InteractiveSession {
|
|
|
95
133
|
* Update system prompt to reflect MCP changes (called after add/remove MCP)
|
|
96
134
|
*/
|
|
97
135
|
async updateSystemPrompt() {
|
|
136
|
+
// Reload skills to pick up any newly added/removed skills
|
|
137
|
+
// First reset the SkillLoader to clear all cached skills
|
|
138
|
+
const { resetSkillLoader } = await import('./skill-loader.js');
|
|
139
|
+
resetSkillLoader();
|
|
140
|
+
// Then reload the skill invoker
|
|
141
|
+
const skillInvoker = (await import('./skill-invoker.js')).getSkillInvoker();
|
|
142
|
+
await skillInvoker.reload();
|
|
98
143
|
const toolRegistry = getToolRegistry();
|
|
99
144
|
const promptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode, undefined, this.mcpManager);
|
|
100
145
|
// Use the current agent's original system prompt as base
|
|
101
146
|
const baseSystemPrompt = this.currentAgent?.systemPrompt || 'You are xAgent, an AI-powered CLI tool.';
|
|
102
147
|
const newSystemPrompt = await promptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
|
|
103
148
|
// Replace old system prompt with new one
|
|
104
|
-
this.conversation = this.conversation.filter(msg => msg.role !== 'system');
|
|
149
|
+
this.conversation = this.conversation.filter((msg) => msg.role !== 'system');
|
|
105
150
|
this.conversation.unshift({
|
|
106
151
|
role: 'system',
|
|
107
152
|
content: newSystemPrompt,
|
|
108
|
-
timestamp: Date.now()
|
|
153
|
+
timestamp: Date.now(),
|
|
109
154
|
});
|
|
110
155
|
// Sync to slashCommandHandler
|
|
111
156
|
this.slashCommandHandler.setConversationHistory(this.conversation);
|
|
112
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Watch for skill updates from CLI and update system prompt accordingly
|
|
160
|
+
*/
|
|
161
|
+
startSkillUpdateWatcher() {
|
|
162
|
+
const SKILL_STATE_FILE = '.skill-state.json';
|
|
163
|
+
const configManager = getConfigManager();
|
|
164
|
+
const userSkillsPath = configManager.getUserSkillsPath();
|
|
165
|
+
const stateFilePath = userSkillsPath
|
|
166
|
+
? path.join(userSkillsPath, SKILL_STATE_FILE)
|
|
167
|
+
: null;
|
|
168
|
+
if (!stateFilePath) {
|
|
169
|
+
return; // No user skills path configured
|
|
170
|
+
}
|
|
171
|
+
let lastUpdateTime = 0;
|
|
172
|
+
// Check for updates every 2 seconds
|
|
173
|
+
const checkInterval = setInterval(async () => {
|
|
174
|
+
try {
|
|
175
|
+
const { existsSync, readFileSync } = await import('fs');
|
|
176
|
+
if (existsSync(stateFilePath)) {
|
|
177
|
+
const content = readFileSync(stateFilePath, 'utf-8');
|
|
178
|
+
const state = JSON.parse(content);
|
|
179
|
+
if (state.lastSkillUpdate && state.lastSkillUpdate > lastUpdateTime) {
|
|
180
|
+
lastUpdateTime = state.lastSkillUpdate;
|
|
181
|
+
// Update system prompt with new skills
|
|
182
|
+
await this.updateSystemPrompt();
|
|
183
|
+
console.log(colors.textMuted(' 🔄 Skills updated from CLI'));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
// Silent fail - watcher is optional
|
|
189
|
+
}
|
|
190
|
+
}, 2000);
|
|
191
|
+
// Clean up on session end
|
|
192
|
+
this._skillWatcherInterval = checkInterval;
|
|
193
|
+
}
|
|
113
194
|
setAgent(agent) {
|
|
114
195
|
this.currentAgent = agent;
|
|
115
196
|
}
|
|
116
|
-
async start() {
|
|
197
|
+
async start(initializedCount = 0) {
|
|
117
198
|
// Set this session as the singleton for access from other modules
|
|
118
199
|
setSingletonSession(this);
|
|
119
200
|
// Initialize taskId for GUI operations
|
|
@@ -122,25 +203,43 @@ export class InteractiveSession {
|
|
|
122
203
|
console.log('');
|
|
123
204
|
console.log(colors.gradient('╔════════════════════════════════════════════════════════════╗'));
|
|
124
205
|
console.log(colors.gradient('║') + ' '.repeat(58) + colors.gradient(' ║'));
|
|
125
|
-
console.log(colors.gradient('║') +
|
|
126
|
-
|
|
206
|
+
console.log(colors.gradient('║') +
|
|
207
|
+
' '.repeat(13) +
|
|
208
|
+
'🤖 ' +
|
|
209
|
+
colors.gradient('XAGENT CLI') +
|
|
210
|
+
' '.repeat(32) +
|
|
211
|
+
colors.gradient(' ║'));
|
|
212
|
+
console.log(colors.gradient('║') +
|
|
213
|
+
' '.repeat(16) +
|
|
214
|
+
colors.textMuted(`v${packageJson.version}`) +
|
|
215
|
+
' '.repeat(36) +
|
|
216
|
+
colors.gradient(' ║'));
|
|
127
217
|
console.log(colors.gradient('║') + ' '.repeat(58) + colors.gradient(' ║'));
|
|
128
218
|
console.log(colors.gradient('╚════════════════════════════════════════════════════════════╝'));
|
|
129
219
|
console.log(colors.textMuted(' AI-powered command-line assistant'));
|
|
220
|
+
// Show initialization message if skills were initialized
|
|
221
|
+
if (initializedCount > 0) {
|
|
222
|
+
console.log(colors.textMuted(` ✨ Initialized ${initializedCount} built-in skills`));
|
|
223
|
+
}
|
|
130
224
|
console.log('');
|
|
131
225
|
await this.initialize();
|
|
132
226
|
this.showWelcomeMessage();
|
|
227
|
+
// Start watching for skill updates from CLI
|
|
228
|
+
this.startSkillUpdateWatcher();
|
|
229
|
+
// Set up ESC key handler using the terminal module
|
|
230
|
+
// This avoids conflicts with readline and provides clean ESC detection
|
|
231
|
+
let escCleanup;
|
|
232
|
+
if (process.stdin.isTTY) {
|
|
233
|
+
escCleanup = setupEscKeyHandler(() => {
|
|
234
|
+
if (this._isOperationInProgress) {
|
|
235
|
+
// An operation is running, let it be cancelled
|
|
236
|
+
this.cancellationManager.cancel();
|
|
237
|
+
}
|
|
238
|
+
// No operation running, ignore ESC
|
|
239
|
+
});
|
|
240
|
+
}
|
|
133
241
|
// Track if an operation is in progress
|
|
134
242
|
this._isOperationInProgress = false;
|
|
135
|
-
// Listen for ESC cancellation - only cancel operations, don't exit the program
|
|
136
|
-
const cancelHandler = () => {
|
|
137
|
-
if (this._isOperationInProgress) {
|
|
138
|
-
// An operation is running, let it be cancelled
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
// No operation running, ignore ESC or show a message
|
|
142
|
-
};
|
|
143
|
-
this.cancellationManager.on('cancelled', cancelHandler);
|
|
144
243
|
this.promptLoop();
|
|
145
244
|
// Keep the promise pending until shutdown
|
|
146
245
|
return new Promise((resolve) => {
|
|
@@ -159,7 +258,7 @@ export class InteractiveSession {
|
|
|
159
258
|
frameIndex = (frameIndex + 1) % frames.length;
|
|
160
259
|
}, 120);
|
|
161
260
|
logger.debug('[SESSION] 调用 configManager.load()...');
|
|
162
|
-
|
|
261
|
+
this.configManager.load();
|
|
163
262
|
logger.debug('[SESSION] Config loaded');
|
|
164
263
|
let authConfig = this.configManager.getAuthConfig();
|
|
165
264
|
let selectedAuthType = this.configManager.get('selectedAuthType');
|
|
@@ -186,9 +285,8 @@ export class InteractiveSession {
|
|
|
186
285
|
clearInterval(refreshInterval);
|
|
187
286
|
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
188
287
|
if (newToken) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
await this.configManager.save('global');
|
|
288
|
+
this.configManager.set('apiKey', newToken);
|
|
289
|
+
this.configManager.save('global');
|
|
192
290
|
authConfig.apiKey = newToken;
|
|
193
291
|
isValid = true;
|
|
194
292
|
}
|
|
@@ -198,20 +296,18 @@ export class InteractiveSession {
|
|
|
198
296
|
console.log(colors.warning('Your xAgent session has expired or is not configured'));
|
|
199
297
|
console.log(colors.info('Please select an authentication method to continue.'));
|
|
200
298
|
console.log('');
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
await this.configManager.save('global');
|
|
206
|
-
await this.configManager.load();
|
|
299
|
+
this.configManager.set('apiKey', '');
|
|
300
|
+
this.configManager.set('refreshToken', '');
|
|
301
|
+
this.configManager.save('global');
|
|
302
|
+
this.configManager.load();
|
|
207
303
|
authConfig = this.configManager.getAuthConfig();
|
|
208
304
|
await this.setupAuthentication();
|
|
209
305
|
authConfig = this.configManager.getAuthConfig();
|
|
210
|
-
// Recreate readline interface after
|
|
306
|
+
// Recreate readline interface after interactive prompt
|
|
211
307
|
this.rl.close();
|
|
212
308
|
this.rl = readline.createInterface({
|
|
213
309
|
input: process.stdin,
|
|
214
|
-
output: process.stdout
|
|
310
|
+
output: process.stdout,
|
|
215
311
|
});
|
|
216
312
|
this.rl.on('close', () => {
|
|
217
313
|
// readline closed
|
|
@@ -226,11 +322,11 @@ export class InteractiveSession {
|
|
|
226
322
|
authConfig = this.configManager.getAuthConfig();
|
|
227
323
|
selectedAuthType = this.configManager.get('selectedAuthType');
|
|
228
324
|
logger.debug('[SESSION] selectedAuthType (after setup):', String(selectedAuthType));
|
|
229
|
-
// Recreate readline interface after
|
|
325
|
+
// Recreate readline interface after interactive prompt
|
|
230
326
|
this.rl.close();
|
|
231
327
|
this.rl = readline.createInterface({
|
|
232
328
|
input: process.stdin,
|
|
233
|
-
output: process.stdout
|
|
329
|
+
output: process.stdout,
|
|
234
330
|
});
|
|
235
331
|
this.rl.on('close', () => {
|
|
236
332
|
// readline closed
|
|
@@ -241,21 +337,42 @@ export class InteractiveSession {
|
|
|
241
337
|
process.stdout.write('\r' + ' '.repeat(50) + '\r');
|
|
242
338
|
}
|
|
243
339
|
// For OPENAI_COMPATIBLE with API key, skip validation and proceed directly
|
|
244
|
-
|
|
245
|
-
this.contextCompressor.setAIClient(this.aiClient);
|
|
246
|
-
// Initialize remote AI client for OAuth XAGENT mode
|
|
247
|
-
logger.debug('[SESSION] Final selectedAuthType:', String(selectedAuthType));
|
|
248
|
-
logger.debug('[SESSION] Creating RemoteAIClient?', String(selectedAuthType === AuthType.OAUTH_XAGENT));
|
|
340
|
+
// Initialize AI clients and set contextCompressor appropriately
|
|
249
341
|
if (selectedAuthType === AuthType.OAUTH_XAGENT) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
342
|
+
// Remote mode: fetch default models if not set
|
|
343
|
+
const currentLlm = this.configManager.get('remote_llmModelName');
|
|
344
|
+
const currentVlm = this.configManager.get('remote_vlmModelName');
|
|
345
|
+
if (!currentLlm || !currentVlm) {
|
|
346
|
+
const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
|
|
347
|
+
try {
|
|
348
|
+
const defaults = await fetchDefaultModels(authConfig.apiKey || '', webBaseUrl);
|
|
349
|
+
if (!currentLlm && defaults.llm?.name) {
|
|
350
|
+
this.configManager.set('remote_llmModelName', defaults.llm.name);
|
|
351
|
+
}
|
|
352
|
+
if (!currentVlm && defaults.vlm?.name) {
|
|
353
|
+
this.configManager.set('remote_vlmModelName', defaults.vlm.name);
|
|
354
|
+
}
|
|
355
|
+
this.configManager.save('global');
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
logger.debug('[SESSION] Failed to fetch default models:', error.message);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Remote mode: create RemoteAIClient and use it for context compression
|
|
362
|
+
this.remoteAIClient = createAIClient(authConfig);
|
|
363
|
+
this.contextCompressor.setAIClient(this.remoteAIClient);
|
|
253
364
|
logger.debug('[DEBUG Initialize] RemoteAIClient created successfully');
|
|
254
365
|
}
|
|
255
366
|
else {
|
|
367
|
+
// Local mode: create local AIClient
|
|
368
|
+
this.aiClient = createAIClient(authConfig);
|
|
369
|
+
this.contextCompressor.setAIClient(this.aiClient);
|
|
256
370
|
logger.debug('[DEBUG Initialize] RemoteAIClient NOT created (not OAuth XAGENT mode)');
|
|
257
371
|
}
|
|
258
|
-
|
|
372
|
+
// Sync remoteAIClient reference to slashCommandHandler for /provider command
|
|
373
|
+
this.slashCommandHandler.setRemoteAIClient(this.remoteAIClient);
|
|
374
|
+
this.executionMode =
|
|
375
|
+
this.configManager.getApprovalMode() || this.configManager.getExecutionMode();
|
|
259
376
|
await this.agentManager.loadAgents();
|
|
260
377
|
await this.memoryManager.loadMemory();
|
|
261
378
|
await this.conversationManager.initialize();
|
|
@@ -292,7 +409,7 @@ export class InteractiveSession {
|
|
|
292
409
|
this.checkpointManager = getCheckpointManager(process.cwd(), checkpointingConfig.enabled, checkpointingConfig.maxCheckpoints);
|
|
293
410
|
await this.checkpointManager.initialize();
|
|
294
411
|
}
|
|
295
|
-
this.currentAgent = this.agentManager.getAgent('general-purpose');
|
|
412
|
+
this.currentAgent = this.agentManager.getAgent('general-purpose') ?? null;
|
|
296
413
|
console.log(colors.success('✔ Initialization complete'));
|
|
297
414
|
}
|
|
298
415
|
catch (error) {
|
|
@@ -315,11 +432,11 @@ export class InteractiveSession {
|
|
|
315
432
|
logger.debug('[SESSION] Sending validation request to:', url);
|
|
316
433
|
const response = await axios.get(url, {
|
|
317
434
|
headers: {
|
|
318
|
-
|
|
319
|
-
'Content-Type': 'application/json'
|
|
435
|
+
Authorization: `Bearer ${apiKey}`,
|
|
436
|
+
'Content-Type': 'application/json',
|
|
320
437
|
},
|
|
321
438
|
httpsAgent,
|
|
322
|
-
timeout: 10000
|
|
439
|
+
timeout: 10000,
|
|
323
440
|
});
|
|
324
441
|
logger.debug('[SESSION] Validation response status:', String(response.status));
|
|
325
442
|
return response.status === 200;
|
|
@@ -341,7 +458,7 @@ export class InteractiveSession {
|
|
|
341
458
|
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
342
459
|
const response = await axios.post(url, { refreshToken }, {
|
|
343
460
|
httpsAgent,
|
|
344
|
-
timeout: 10000
|
|
461
|
+
timeout: 10000,
|
|
345
462
|
});
|
|
346
463
|
if (response.status === 200) {
|
|
347
464
|
const data = response.data;
|
|
@@ -363,11 +480,14 @@ export class InteractiveSession {
|
|
|
363
480
|
console.log('');
|
|
364
481
|
const authType = await selectAuthType();
|
|
365
482
|
this.configManager.set('selectedAuthType', authType);
|
|
483
|
+
// Get xagentApiBaseUrl from config (respects XAGENT_BASE_URL env var)
|
|
484
|
+
const config = this.configManager.getAuthConfig();
|
|
366
485
|
const authService = new AuthService({
|
|
367
486
|
type: authType,
|
|
368
487
|
apiKey: '',
|
|
369
488
|
baseUrl: '',
|
|
370
|
-
modelName: ''
|
|
489
|
+
modelName: '',
|
|
490
|
+
xagentApiBaseUrl: config.xagentApiBaseUrl,
|
|
371
491
|
});
|
|
372
492
|
const success = await authService.authenticate();
|
|
373
493
|
if (!success) {
|
|
@@ -377,16 +497,29 @@ export class InteractiveSession {
|
|
|
377
497
|
process.exit(1);
|
|
378
498
|
}
|
|
379
499
|
const authConfig = authService.getAuthConfig();
|
|
500
|
+
// Clear modelName for remote mode
|
|
501
|
+
if (authType === AuthType.OAUTH_XAGENT) {
|
|
502
|
+
authConfig.modelName = '';
|
|
503
|
+
}
|
|
380
504
|
// VLM configuration is optional - only show for non-OAuth (local) mode
|
|
381
505
|
// Remote mode uses backend VLM configuration
|
|
382
506
|
if (authType !== AuthType.OAUTH_XAGENT) {
|
|
383
507
|
console.log('');
|
|
384
508
|
console.log(colors.info(`${icons.info} VLM configuration is optional.`));
|
|
385
|
-
console.log(colors.info(`You can configure it later using the /
|
|
509
|
+
console.log(colors.info(`You can configure it later using the /model command if needed.`));
|
|
386
510
|
console.log('');
|
|
387
511
|
}
|
|
388
|
-
|
|
389
|
-
|
|
512
|
+
this.configManager.setAuthConfig(authConfig);
|
|
513
|
+
// Set default remote model settings if not already set
|
|
514
|
+
if (authType === AuthType.OAUTH_XAGENT) {
|
|
515
|
+
if (!this.configManager.get('remote_llmModelName')) {
|
|
516
|
+
this.configManager.set('remote_llmModelName', '');
|
|
517
|
+
}
|
|
518
|
+
if (!this.configManager.get('remote_vlmModelName')) {
|
|
519
|
+
this.configManager.set('remote_vlmModelName', '');
|
|
520
|
+
}
|
|
521
|
+
this.configManager.save('global');
|
|
522
|
+
}
|
|
390
523
|
}
|
|
391
524
|
showWelcomeMessage() {
|
|
392
525
|
const language = this.configManager.getLanguage();
|
|
@@ -410,28 +543,28 @@ export class InteractiveSession {
|
|
|
410
543
|
[ExecutionMode.YOLO]: {
|
|
411
544
|
color: colors.error,
|
|
412
545
|
icon: icons.fire,
|
|
413
|
-
description: 'Execute commands without confirmation'
|
|
546
|
+
description: 'Execute commands without confirmation',
|
|
414
547
|
},
|
|
415
548
|
[ExecutionMode.ACCEPT_EDITS]: {
|
|
416
549
|
color: colors.warning,
|
|
417
550
|
icon: icons.check,
|
|
418
|
-
description: 'Accept all edits automatically'
|
|
551
|
+
description: 'Accept all edits automatically',
|
|
419
552
|
},
|
|
420
553
|
[ExecutionMode.PLAN]: {
|
|
421
554
|
color: colors.info,
|
|
422
555
|
icon: icons.brain,
|
|
423
|
-
description: 'Plan before executing'
|
|
556
|
+
description: 'Plan before executing',
|
|
424
557
|
},
|
|
425
558
|
[ExecutionMode.DEFAULT]: {
|
|
426
559
|
color: colors.success,
|
|
427
560
|
icon: icons.bolt,
|
|
428
|
-
description: 'Safe execution with confirmations'
|
|
561
|
+
description: 'Safe execution with confirmations',
|
|
429
562
|
},
|
|
430
563
|
[ExecutionMode.SMART]: {
|
|
431
564
|
color: colors.primaryBright,
|
|
432
565
|
icon: icons.sparkles,
|
|
433
|
-
description: 'Smart approval with intelligent security checks'
|
|
434
|
-
}
|
|
566
|
+
description: 'Smart approval with intelligent security checks',
|
|
567
|
+
},
|
|
435
568
|
};
|
|
436
569
|
const config = modeConfig[this.executionMode];
|
|
437
570
|
const modeName = this.executionMode;
|
|
@@ -439,6 +572,26 @@ export class InteractiveSession {
|
|
|
439
572
|
console.log(` ${config.color(config.icon)} ${styleHelpers.text.bold(config.color(modeName))}`);
|
|
440
573
|
console.log(` ${colors.textDim(` ${config.description}`)}`);
|
|
441
574
|
console.log('');
|
|
575
|
+
this.showRemoteModelInfo();
|
|
576
|
+
}
|
|
577
|
+
showRemoteModelInfo() {
|
|
578
|
+
const authConfig = this.configManager.getAuthConfig();
|
|
579
|
+
const isRemote = authConfig.type === AuthType.OAUTH_XAGENT;
|
|
580
|
+
if (isRemote) {
|
|
581
|
+
const llmModel = authConfig.remote_llmModelName || colors.textMuted('Not set');
|
|
582
|
+
const vlmModel = authConfig.remote_vlmModelName || colors.textMuted('Not set');
|
|
583
|
+
console.log(colors.textMuted(`${icons.brain} Remote Models:`));
|
|
584
|
+
console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('LLM:')} ${llmModel}`);
|
|
585
|
+
console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('VLM:')} ${vlmModel}`);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
const modelName = authConfig.modelName || colors.textMuted('Not set');
|
|
589
|
+
const guiSubagentModel = this.configManager.get('guiSubagentModel') || colors.textMuted('Not set');
|
|
590
|
+
console.log(colors.textMuted(`${icons.brain} Local Models:`));
|
|
591
|
+
console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('LLM:')} ${modelName}`);
|
|
592
|
+
console.log(` ${colors.primaryBright(icons.arrowRight)} ${colors.info('VLM:')} ${guiSubagentModel}`);
|
|
593
|
+
}
|
|
594
|
+
console.log('');
|
|
442
595
|
}
|
|
443
596
|
async promptLoop() {
|
|
444
597
|
// Check if we're shutting down
|
|
@@ -449,15 +602,12 @@ export class InteractiveSession {
|
|
|
449
602
|
if (this.rl) {
|
|
450
603
|
this.rl.close();
|
|
451
604
|
}
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
process.stdin.resume();
|
|
457
|
-
readline.emitKeypressEvents(process.stdin);
|
|
605
|
+
// Ensure TTY is in proper state for input handling
|
|
606
|
+
// This handles any state left by @clack/prompts or other interactions
|
|
607
|
+
ensureTtySane();
|
|
458
608
|
this.rl = readline.createInterface({
|
|
459
609
|
input: process.stdin,
|
|
460
|
-
output: process.stdout
|
|
610
|
+
output: process.stdout,
|
|
461
611
|
});
|
|
462
612
|
const prompt = `${colors.primaryBright('❯')} `;
|
|
463
613
|
this.rl.question(prompt, async (input) => {
|
|
@@ -481,7 +631,8 @@ export class InteractiveSession {
|
|
|
481
631
|
if (trimmedInput.startsWith('/')) {
|
|
482
632
|
const handled = await this.slashCommandHandler.handleCommand(trimmedInput);
|
|
483
633
|
if (handled) {
|
|
484
|
-
this.executionMode =
|
|
634
|
+
this.executionMode =
|
|
635
|
+
this.configManager.getApprovalMode() || this.configManager.getExecutionMode();
|
|
485
636
|
// Sync conversation history to slashCommandHandler
|
|
486
637
|
this.slashCommandHandler.setConversationHistory(this.conversation);
|
|
487
638
|
}
|
|
@@ -513,9 +664,9 @@ export class InteractiveSession {
|
|
|
513
664
|
}
|
|
514
665
|
async processUserMessage(message, agent) {
|
|
515
666
|
const inputs = parseInput(message);
|
|
516
|
-
const textInput = inputs.find(i => i.type === 'text');
|
|
517
|
-
const fileInputs = inputs.filter(i => i.type === 'file');
|
|
518
|
-
const commandInput = inputs.find(i => i.type === 'command');
|
|
667
|
+
const textInput = inputs.find((i) => i.type === 'text');
|
|
668
|
+
const fileInputs = inputs.filter((i) => i.type === 'file');
|
|
669
|
+
const commandInput = inputs.find((i) => i.type === 'command');
|
|
519
670
|
if (commandInput) {
|
|
520
671
|
await this.executeShellCommand(commandInput.content);
|
|
521
672
|
return;
|
|
@@ -538,7 +689,7 @@ export class InteractiveSession {
|
|
|
538
689
|
type: 'text',
|
|
539
690
|
content: userContent,
|
|
540
691
|
rawInput: message,
|
|
541
|
-
timestamp: Date.now()
|
|
692
|
+
timestamp: Date.now(),
|
|
542
693
|
};
|
|
543
694
|
await this.sessionManager.addInput(sessionInput);
|
|
544
695
|
// Calculate thinking tokens based on config and user input
|
|
@@ -552,25 +703,19 @@ export class InteractiveSession {
|
|
|
552
703
|
const userMessage = {
|
|
553
704
|
role: 'user',
|
|
554
705
|
content: userContent,
|
|
555
|
-
timestamp: Date.now()
|
|
706
|
+
timestamp: Date.now(),
|
|
556
707
|
};
|
|
557
|
-
// Save last user message for recovery after compression
|
|
558
|
-
const lastUserMessage = userMessage;
|
|
559
708
|
this.conversation.push(userMessage);
|
|
560
709
|
await this.conversationManager.addMessage(userMessage);
|
|
561
|
-
// Check if context compression is needed
|
|
562
|
-
await this.checkAndCompressContext(lastUserMessage);
|
|
563
710
|
// Use remote AI client if available (OAuth XAGENT mode)
|
|
564
711
|
const currentSelectedAuthType = this.configManager.get('selectedAuthType');
|
|
565
|
-
logger.debug(
|
|
566
|
-
logger.debug('[DEBUG processUserMessage] selectedAuthType:', String(currentSelectedAuthType));
|
|
567
|
-
logger.debug('[DEBUG processUserMessage] AuthType.OAUTH_XAGENT:', String(AuthType.OAUTH_XAGENT));
|
|
712
|
+
logger.debug(`[DEBUG] processUserMessage: remoteAIClient exists=${!!this.remoteAIClient}, selectedAuthType=${currentSelectedAuthType}`);
|
|
568
713
|
if (this.remoteAIClient) {
|
|
569
|
-
logger.debug('[DEBUG
|
|
714
|
+
logger.debug('[DEBUG] Using generateRemoteResponse (remote mode)');
|
|
570
715
|
await this.generateRemoteResponse(thinkingTokens);
|
|
571
716
|
}
|
|
572
717
|
else {
|
|
573
|
-
logger.debug('[DEBUG
|
|
718
|
+
logger.debug('[DEBUG] Using generateResponse (local mode)');
|
|
574
719
|
await this.generateResponse(thinkingTokens);
|
|
575
720
|
}
|
|
576
721
|
}
|
|
@@ -615,52 +760,68 @@ export class InteractiveSession {
|
|
|
615
760
|
/**
|
|
616
761
|
* Check and compress conversation context
|
|
617
762
|
*/
|
|
618
|
-
async checkAndCompressContext(
|
|
763
|
+
async checkAndCompressContext() {
|
|
619
764
|
const compressionConfig = this.configManager.getContextCompressionConfig();
|
|
620
765
|
if (!compressionConfig.enabled) {
|
|
621
766
|
return;
|
|
622
767
|
}
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
768
|
+
const indent = this.getIndent();
|
|
769
|
+
const currentTokens = this.contextCompressor.estimateContextTokens(this.conversation);
|
|
770
|
+
const currentMessages = this.conversation.length;
|
|
771
|
+
const { needsCompression, reason, tokenCount } = this.contextCompressor.needsCompression(this.conversation, compressionConfig);
|
|
772
|
+
if (!needsCompression) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
// Extract threshold and contextWindow from reason
|
|
776
|
+
const thresholdMatch = reason.match(/budget\s*\((\d+)/);
|
|
777
|
+
const contextWindowMatch = reason.match(/contextWindow:\s*(\d+)/);
|
|
778
|
+
const threshold = thresholdMatch ? parseInt(thresholdMatch[1], 10) : 0;
|
|
779
|
+
const contextWindow = contextWindowMatch ? parseInt(contextWindowMatch[1], 10) : 0;
|
|
780
|
+
console.log('');
|
|
781
|
+
console.log(`${indent}${colors.success(`${icons.sparkles} Compressing context (${currentMessages} msgs, ${tokenCount.toLocaleString()} > ${threshold.toLocaleString()}/${contextWindow.toLocaleString()} tokens, ${Math.round((tokenCount / contextWindow) * 100)}% of context window)...`)}`);
|
|
782
|
+
const toolRegistry = getToolRegistry();
|
|
783
|
+
const baseSystemPrompt = this.currentAgent?.systemPrompt || 'You are a helpful AI assistant.';
|
|
784
|
+
const systemPromptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode);
|
|
785
|
+
const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
|
|
786
|
+
const result = await this.contextCompressor.compressContext(this.conversation, enhancedSystemPrompt, compressionConfig);
|
|
787
|
+
if (result.wasCompressed) {
|
|
788
|
+
this.conversation = result.compressedMessages;
|
|
789
|
+
const reductionPercent = Math.round((1 - result.compressedSize / result.originalSize) * 100);
|
|
790
|
+
console.log(`${indent}${colors.success(`${icons.success} Compressed ${result.originalMessageCount} → ${result.compressedMessageCount} messages (${reductionPercent}% smaller)`)}`);
|
|
791
|
+
// Summary is embedded in first user message, look for it
|
|
792
|
+
// The format is: "[Conversation Summary - X messages compressed]\n\n${summary}"
|
|
793
|
+
let summaryMessage = result.compressedMessages.find((m) => m.role === 'user' && m.content.includes('[Conversation Summary'));
|
|
794
|
+
if (summaryMessage) {
|
|
795
|
+
// Extract summary content after the header
|
|
796
|
+
const match = summaryMessage.content.match(/\[Conversation Summary.*?\]:\n\n(.+)/s);
|
|
797
|
+
if (match) {
|
|
798
|
+
summaryMessage = {
|
|
799
|
+
role: 'assistant',
|
|
800
|
+
content: match[1],
|
|
801
|
+
timestamp: summaryMessage.timestamp,
|
|
802
|
+
};
|
|
656
803
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
804
|
+
}
|
|
805
|
+
if (summaryMessage && summaryMessage.content) {
|
|
806
|
+
const maxPreviewLength = 800;
|
|
807
|
+
let summaryContent = summaryMessage.content;
|
|
808
|
+
const isTruncated = summaryContent.length > maxPreviewLength;
|
|
809
|
+
if (isTruncated) {
|
|
810
|
+
summaryContent = summaryContent.substring(0, maxPreviewLength) + '\n...';
|
|
660
811
|
}
|
|
661
|
-
|
|
662
|
-
|
|
812
|
+
console.log('');
|
|
813
|
+
console.log(`${indent}${theme.predefinedStyles.title(`${icons.sparkles} Conversation Summary`)}`);
|
|
814
|
+
const separator = icons.separator.repeat(Math.min(60, process.stdout.columns || 80) - indent.length * 2);
|
|
815
|
+
console.log(`${indent}${colors.border(separator)}`);
|
|
816
|
+
const renderedSummary = renderMarkdown(summaryContent, (process.stdout.columns || 80) - indent.length * 4);
|
|
817
|
+
console.log(`${indent}${theme.predefinedStyles.dim(renderedSummary).replace(/^/gm, indent)}`);
|
|
818
|
+
if (isTruncated) {
|
|
819
|
+
console.log(`${indent}${colors.textMuted(`(... ${summaryMessage.content.length - maxPreviewLength} more chars hidden)`)}`);
|
|
820
|
+
}
|
|
821
|
+
console.log(`${indent}${colors.border(separator)}`);
|
|
663
822
|
}
|
|
823
|
+
// Sync compressed conversation history to slashCommandHandler
|
|
824
|
+
this.slashCommandHandler.setConversationHistory(this.conversation);
|
|
664
825
|
}
|
|
665
826
|
}
|
|
666
827
|
async executeShellCommand(command) {
|
|
@@ -683,15 +844,15 @@ export class InteractiveSession {
|
|
|
683
844
|
tool: 'Bash',
|
|
684
845
|
params: { command },
|
|
685
846
|
result,
|
|
686
|
-
timestamp: Date.now()
|
|
847
|
+
timestamp: Date.now(),
|
|
687
848
|
};
|
|
688
|
-
this.
|
|
849
|
+
this.tool_calls.push(toolCall);
|
|
689
850
|
// Record command execution to session manager
|
|
690
851
|
await this.sessionManager.addInput({
|
|
691
852
|
type: 'command',
|
|
692
853
|
content: command,
|
|
693
854
|
rawInput: command,
|
|
694
|
-
timestamp: Date.now()
|
|
855
|
+
timestamp: Date.now(),
|
|
695
856
|
});
|
|
696
857
|
await this.sessionManager.addOutput({
|
|
697
858
|
role: 'tool',
|
|
@@ -699,7 +860,7 @@ export class InteractiveSession {
|
|
|
699
860
|
toolName: 'Bash',
|
|
700
861
|
toolParams: { command },
|
|
701
862
|
toolResult: result,
|
|
702
|
-
timestamp: Date.now()
|
|
863
|
+
timestamp: Date.now(),
|
|
703
864
|
});
|
|
704
865
|
}
|
|
705
866
|
catch (error) {
|
|
@@ -727,8 +888,19 @@ export class InteractiveSession {
|
|
|
727
888
|
createRemoteCaller(taskId, status) {
|
|
728
889
|
const client = this.remoteAIClient;
|
|
729
890
|
return {
|
|
730
|
-
chatCompletion: (messages, options) =>
|
|
731
|
-
|
|
891
|
+
chatCompletion: (messages, options) => {
|
|
892
|
+
// Must fetch authConfig inside the closure, otherwise it captures stale config
|
|
893
|
+
const authConfig = this.configManager.getAuthConfig();
|
|
894
|
+
logger.debug(`[DEBUG] createRemoteCaller: llmModelName=${authConfig.remote_llmModelName}, vlmModelName=${authConfig.remote_vlmModelName}`);
|
|
895
|
+
return client.chatCompletion(messages, {
|
|
896
|
+
...options,
|
|
897
|
+
taskId,
|
|
898
|
+
status: options.isFirstApiCall ? 'begin' : 'continue',
|
|
899
|
+
llmModelName: authConfig.remote_llmModelName,
|
|
900
|
+
vlmModelName: authConfig.remote_vlmModelName
|
|
901
|
+
});
|
|
902
|
+
},
|
|
903
|
+
isRemote: true,
|
|
732
904
|
};
|
|
733
905
|
}
|
|
734
906
|
/**
|
|
@@ -738,32 +910,22 @@ export class InteractiveSession {
|
|
|
738
910
|
const client = this.aiClient;
|
|
739
911
|
return {
|
|
740
912
|
chatCompletion: (messages, options) => client.chatCompletion(messages, options),
|
|
741
|
-
isRemote: false
|
|
913
|
+
isRemote: false,
|
|
742
914
|
};
|
|
743
915
|
}
|
|
744
|
-
async generateResponse(thinkingTokens = 0,
|
|
916
|
+
async generateResponse(thinkingTokens = 0, _customAIClient, existingTaskId) {
|
|
745
917
|
// Use existing taskId or create new one for this user interaction
|
|
746
918
|
// If taskId already exists (e.g., from tool calls), reuse it
|
|
747
919
|
const taskId = existingTaskId || this.currentTaskId || crypto.randomUUID();
|
|
748
920
|
this.currentTaskId = taskId;
|
|
749
|
-
|
|
750
|
-
//
|
|
921
|
+
// isFirstApiCall is reset in generateRemoteResponse for new tasks
|
|
922
|
+
// For continuation calls (existingTaskId provided), keep previous value
|
|
923
|
+
// Use unified LLM Caller with taskId (automatically selects local or remote mode)
|
|
751
924
|
const status = this.isFirstApiCall ? 'begin' : 'continue';
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
if (
|
|
756
|
-
// Custom client (used by remote mode) - pass taskId and status
|
|
757
|
-
chatCompletion = (messages, options) => customAIClient.chatCompletion(messages, { ...options, taskId, status });
|
|
758
|
-
isRemote = true;
|
|
759
|
-
}
|
|
760
|
-
else {
|
|
761
|
-
// Use unified LLM Caller with taskId (automatically selects local or remote mode)
|
|
762
|
-
const caller = this.createLLMCaller(taskId, status);
|
|
763
|
-
chatCompletion = caller.chatCompletion;
|
|
764
|
-
isRemote = caller.isRemote;
|
|
765
|
-
}
|
|
766
|
-
if (!isRemote && !this.aiClient && !customAIClient) {
|
|
925
|
+
const caller = this.createLLMCaller(taskId, status);
|
|
926
|
+
const chatCompletion = caller.chatCompletion;
|
|
927
|
+
const isRemote = caller.isRemote;
|
|
928
|
+
if (!isRemote && !this.aiClient) {
|
|
767
929
|
console.log(colors.error('AI client not initialized'));
|
|
768
930
|
return;
|
|
769
931
|
}
|
|
@@ -790,29 +952,29 @@ export class InteractiveSession {
|
|
|
790
952
|
const toolDefinitions = toolRegistry.getToolDefinitions();
|
|
791
953
|
// Available tools for this session
|
|
792
954
|
const availableTools = this.executionMode !== ExecutionMode.DEFAULT && allowedToolNames.length > 0
|
|
793
|
-
? toolDefinitions.filter((tool) =>
|
|
955
|
+
? toolDefinitions.filter((tool) => typeof tool.function?.name === 'string' &&
|
|
956
|
+
allowedToolNames.includes(tool.function.name))
|
|
794
957
|
: toolDefinitions;
|
|
795
|
-
const baseSystemPrompt = this.currentAgent?.systemPrompt;
|
|
958
|
+
const baseSystemPrompt = this.currentAgent?.systemPrompt ?? '';
|
|
796
959
|
const systemPromptGenerator = new SystemPromptGenerator(toolRegistry, this.executionMode, undefined, this.mcpManager);
|
|
797
960
|
const enhancedSystemPrompt = await systemPromptGenerator.generateEnhancedSystemPrompt(baseSystemPrompt);
|
|
798
961
|
const messages = [
|
|
799
962
|
{ role: 'system', content: `${enhancedSystemPrompt}\n\n${memory}`, timestamp: Date.now() },
|
|
800
|
-
...this.conversation
|
|
963
|
+
...this.conversation,
|
|
801
964
|
];
|
|
802
965
|
const operationId = `ai-response-${Date.now()}`;
|
|
803
966
|
const response = await this.cancellationManager.withCancellation(chatCompletion(messages, {
|
|
804
967
|
tools: availableTools,
|
|
805
968
|
toolChoice: availableTools.length > 0 ? 'auto' : 'none',
|
|
806
|
-
thinkingTokens
|
|
969
|
+
thinkingTokens,
|
|
970
|
+
isFirstApiCall: this.isFirstApiCall,
|
|
807
971
|
}), operationId);
|
|
808
972
|
// Mark that first API call is complete
|
|
809
973
|
this.isFirstApiCall = false;
|
|
810
974
|
clearInterval(spinnerInterval);
|
|
811
975
|
process.stdout.write('\r' + ' '.repeat(process.stdout.columns || 80) + '\r'); // Clear spinner line
|
|
812
976
|
const assistantMessage = response.choices[0].message;
|
|
813
|
-
const content = typeof assistantMessage.content === 'string'
|
|
814
|
-
? assistantMessage.content
|
|
815
|
-
: '';
|
|
977
|
+
const content = typeof assistantMessage.content === 'string' ? assistantMessage.content : '';
|
|
816
978
|
const reasoningContent = assistantMessage.reasoning_content || '';
|
|
817
979
|
// Display reasoning content if available and thinking mode is enabled
|
|
818
980
|
if (reasoningContent && this.configManager.getThinkingConfig().enabled) {
|
|
@@ -829,22 +991,25 @@ export class InteractiveSession {
|
|
|
829
991
|
role: 'assistant',
|
|
830
992
|
content,
|
|
831
993
|
timestamp: Date.now(),
|
|
832
|
-
reasoningContent,
|
|
833
|
-
|
|
994
|
+
reasoning_content: reasoningContent,
|
|
995
|
+
tool_calls: assistantMessage.tool_calls,
|
|
834
996
|
});
|
|
835
997
|
// Record output to session manager
|
|
836
998
|
await this.sessionManager.addOutput({
|
|
837
999
|
role: 'assistant',
|
|
838
1000
|
content,
|
|
839
1001
|
timestamp: Date.now(),
|
|
840
|
-
reasoningContent,
|
|
841
|
-
|
|
1002
|
+
reasoning_content: reasoningContent,
|
|
1003
|
+
tool_calls: assistantMessage.tool_calls,
|
|
842
1004
|
});
|
|
843
1005
|
if (assistantMessage.tool_calls) {
|
|
844
1006
|
await this.handleToolCalls(assistantMessage.tool_calls);
|
|
845
1007
|
}
|
|
1008
|
+
else {
|
|
1009
|
+
await this.checkAndCompressContext();
|
|
1010
|
+
}
|
|
846
1011
|
if (this.checkpointManager.isEnabled()) {
|
|
847
|
-
await this.checkpointManager.createCheckpoint(`Response generated at ${new Date().toLocaleString()}`, [...this.conversation], [...this.
|
|
1012
|
+
await this.checkpointManager.createCheckpoint(`Response generated at ${new Date().toLocaleString()}`, [...this.conversation], [...this.tool_calls]);
|
|
848
1013
|
}
|
|
849
1014
|
// Operation completed successfully, clear the flag
|
|
850
1015
|
this._isOperationInProgress = false;
|
|
@@ -855,16 +1020,18 @@ export class InteractiveSession {
|
|
|
855
1020
|
// Clear the operation flag
|
|
856
1021
|
this._isOperationInProgress = false;
|
|
857
1022
|
if (error.message === 'Operation cancelled by user') {
|
|
858
|
-
//
|
|
1023
|
+
// Notify backend to cancel the task
|
|
859
1024
|
if (this.remoteAIClient && this.currentTaskId) {
|
|
860
|
-
await this.remoteAIClient.cancelTask(this.currentTaskId).catch(() => { });
|
|
1025
|
+
await this.remoteAIClient.cancelTask?.(this.currentTaskId).catch(() => { });
|
|
861
1026
|
}
|
|
862
1027
|
return;
|
|
863
1028
|
}
|
|
864
|
-
//
|
|
865
|
-
|
|
1029
|
+
// Distinguish error types: timeout vs other failures
|
|
1030
|
+
const isTimeout = error.message.includes('timeout') || error.message.includes('Timeout');
|
|
1031
|
+
const failureReason = isTimeout ? 'timeout' : 'failure';
|
|
1032
|
+
logger.debug(`[Session] Task failed: taskId=${this.currentTaskId}, error: ${error.message}, reason: ${failureReason}`);
|
|
866
1033
|
if (this.remoteAIClient && this.currentTaskId) {
|
|
867
|
-
await this.remoteAIClient.
|
|
1034
|
+
await this.remoteAIClient.failTask?.(this.currentTaskId, failureReason).catch(() => { });
|
|
868
1035
|
}
|
|
869
1036
|
console.log(colors.error(`Error: ${error.message}`));
|
|
870
1037
|
}
|
|
@@ -881,12 +1048,10 @@ export class InteractiveSession {
|
|
|
881
1048
|
const taskId = existingTaskId || crypto.randomUUID();
|
|
882
1049
|
this.currentTaskId = taskId;
|
|
883
1050
|
logger.debug(`[Session] generateRemoteResponse: taskId=${taskId}, existingTaskId=${!!existingTaskId}`);
|
|
884
|
-
//
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
// Determine status based on whether this is the first API call
|
|
889
|
-
const status = this.isFirstApiCall ? 'begin' : 'continue';
|
|
1051
|
+
// Each new user message is a fresh task - always set isFirstApiCall = true
|
|
1052
|
+
// This ensures status is 'begin' for every user message
|
|
1053
|
+
this.isFirstApiCall = true;
|
|
1054
|
+
const status = 'begin';
|
|
890
1055
|
logger.debug(`[Session] Status for this call: ${status}, isFirstApiCall=${this.isFirstApiCall}`);
|
|
891
1056
|
// Check if remote client is available
|
|
892
1057
|
if (!this.remoteAIClient) {
|
|
@@ -894,18 +1059,23 @@ export class InteractiveSession {
|
|
|
894
1059
|
return;
|
|
895
1060
|
}
|
|
896
1061
|
try {
|
|
897
|
-
//
|
|
898
|
-
|
|
1062
|
+
// Use unified generateResponse without passing customAIClient,
|
|
1063
|
+
// let createLLMCaller handle remote/local selection
|
|
1064
|
+
await this.generateResponse(thinkingTokens, undefined, taskId);
|
|
899
1065
|
// Mark task as completed (发送 status: 'end')
|
|
900
1066
|
logger.debug(`[Session] Task completed: taskId=${this.currentTaskId}`);
|
|
901
|
-
if (this.currentTaskId) {
|
|
902
|
-
await this.remoteAIClient.completeTask(this.currentTaskId);
|
|
1067
|
+
if (this.remoteAIClient && this.currentTaskId) {
|
|
1068
|
+
await this.remoteAIClient.completeTask?.(this.currentTaskId);
|
|
903
1069
|
}
|
|
904
1070
|
}
|
|
905
1071
|
catch (error) {
|
|
906
1072
|
// Clear the operation flag
|
|
907
1073
|
this._isOperationInProgress = false;
|
|
908
1074
|
if (error.message === 'Operation cancelled by user') {
|
|
1075
|
+
// Notify backend to cancel the task
|
|
1076
|
+
if (this.remoteAIClient && this.currentTaskId) {
|
|
1077
|
+
await this.remoteAIClient.cancelTask?.(this.currentTaskId).catch(() => { });
|
|
1078
|
+
}
|
|
909
1079
|
return;
|
|
910
1080
|
}
|
|
911
1081
|
// Handle token invalid error - trigger re-authentication
|
|
@@ -915,46 +1085,48 @@ export class InteractiveSession {
|
|
|
915
1085
|
console.log(colors.info('Your browser session has been logged out. Please log in again.'));
|
|
916
1086
|
console.log('');
|
|
917
1087
|
// Clear invalid credentials and persist
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1088
|
+
this.configManager.set('apiKey', '');
|
|
1089
|
+
this.configManager.set('refreshToken', '');
|
|
1090
|
+
this.configManager.save('global');
|
|
921
1091
|
logger.debug('[DEBUG generateRemoteResponse] Cleared invalid credentials, starting re-authentication...');
|
|
922
1092
|
// Re-authenticate
|
|
923
1093
|
await this.setupAuthentication();
|
|
924
1094
|
// Reload config to ensure we have the latest authConfig
|
|
925
|
-
|
|
926
|
-
await this.configManager.load();
|
|
1095
|
+
this.configManager.load();
|
|
927
1096
|
const authConfig = this.configManager.getAuthConfig();
|
|
928
1097
|
logger.debug('[DEBUG generateRemoteResponse] After re-auth:');
|
|
929
1098
|
logger.debug(' - authConfig.apiKey exists:', !!authConfig.apiKey ? 'true' : 'false');
|
|
930
|
-
// Recreate readline interface after
|
|
1099
|
+
// Recreate readline interface after interactive prompt
|
|
931
1100
|
this.rl.close();
|
|
932
1101
|
this.rl = readline.createInterface({
|
|
933
1102
|
input: process.stdin,
|
|
934
|
-
output: process.stdout
|
|
1103
|
+
output: process.stdout,
|
|
935
1104
|
});
|
|
936
1105
|
this.rl.on('close', () => {
|
|
937
1106
|
logger.debug('DEBUG: readline interface closed');
|
|
938
1107
|
});
|
|
939
1108
|
// Reinitialize RemoteAIClient with new token
|
|
940
1109
|
if (authConfig.apiKey) {
|
|
941
|
-
const webBaseUrl = authConfig.xagentApiBaseUrl || 'https://www.xagent-colife.net';
|
|
942
1110
|
logger.debug('[DEBUG generateRemoteResponse] Reinitializing RemoteAIClient with new token');
|
|
943
|
-
this.remoteAIClient =
|
|
1111
|
+
this.remoteAIClient = createAIClient(authConfig);
|
|
944
1112
|
}
|
|
945
1113
|
else {
|
|
946
1114
|
logger.debug('[DEBUG generateRemoteResponse] WARNING: No apiKey after re-authentication!');
|
|
947
1115
|
}
|
|
1116
|
+
// Sync remoteAIClient reference to slashCommandHandler for /provider command
|
|
1117
|
+
this.slashCommandHandler.setRemoteAIClient(this.remoteAIClient);
|
|
948
1118
|
// Retry the current operation
|
|
949
1119
|
console.log('');
|
|
950
1120
|
console.log(colors.info('Retrying with new authentication...'));
|
|
951
1121
|
console.log('');
|
|
952
1122
|
return this.generateRemoteResponse(thinkingTokens);
|
|
953
1123
|
}
|
|
954
|
-
//
|
|
955
|
-
|
|
1124
|
+
// Distinguish error types: timeout vs other failures
|
|
1125
|
+
const isTimeout = error.message.includes('timeout') || error.message.includes('Timeout');
|
|
1126
|
+
const failureReason = isTimeout ? 'timeout' : 'failure';
|
|
1127
|
+
logger.debug(`[Session] Task failed: taskId=${this.currentTaskId}, error: ${error.message}, reason: ${failureReason}`);
|
|
956
1128
|
if (this.remoteAIClient && this.currentTaskId) {
|
|
957
|
-
await this.remoteAIClient.
|
|
1129
|
+
await this.remoteAIClient.failTask?.(this.currentTaskId, failureReason).catch(() => { });
|
|
958
1130
|
}
|
|
959
1131
|
console.log(colors.error(`Error: ${error.message}`));
|
|
960
1132
|
return;
|
|
@@ -991,32 +1163,50 @@ export class InteractiveSession {
|
|
|
991
1163
|
}
|
|
992
1164
|
}
|
|
993
1165
|
// Execute all tools in parallel
|
|
994
|
-
const results = await toolRegistry.executeAll(preparedToolCalls.map(tc => ({ name: tc.name, params: tc.params })), this.executionMode);
|
|
995
|
-
//
|
|
1166
|
+
const results = await toolRegistry.executeAll(preparedToolCalls.map((tc) => ({ name: tc.name, params: tc.params })), this.executionMode);
|
|
1167
|
+
// Create a map to store results by tool call index to maintain original order
|
|
1168
|
+
const resultsByIndex = new Map();
|
|
1169
|
+
const usedIndices = new Set();
|
|
1170
|
+
for (const result of results) {
|
|
1171
|
+
// Find the first unused original index in preparedToolCalls that matches the tool name
|
|
1172
|
+
const originalIndex = preparedToolCalls.findIndex((tc, idx) => tc.name === result.tool && !usedIndices.has(idx));
|
|
1173
|
+
if (originalIndex !== -1) {
|
|
1174
|
+
usedIndices.add(originalIndex);
|
|
1175
|
+
resultsByIndex.set(originalIndex, result);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
// Process results in the original tool_calls order (critical for Anthropic format APIs)
|
|
996
1179
|
let hasError = false;
|
|
997
|
-
for (
|
|
998
|
-
const toolCall = preparedToolCalls
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
const
|
|
1180
|
+
for (let i = 0; i < preparedToolCalls.length; i++) {
|
|
1181
|
+
const toolCall = preparedToolCalls[i];
|
|
1182
|
+
const { name: tool, params } = toolCall;
|
|
1183
|
+
const resultData = resultsByIndex.get(i);
|
|
1184
|
+
const result = resultData?.result;
|
|
1185
|
+
const error = resultData?.error;
|
|
1002
1186
|
if (error) {
|
|
1003
1187
|
if (error === 'Operation cancelled by user') {
|
|
1188
|
+
// Notify backend to cancel the task
|
|
1189
|
+
if (this.remoteAIClient && this.currentTaskId) {
|
|
1190
|
+
await this.remoteAIClient.cancelTask?.(this.currentTaskId).catch(() => { });
|
|
1191
|
+
}
|
|
1192
|
+
// 清理 conversation 中未完成的 tool_call
|
|
1193
|
+
this.cleanupIncompleteToolCalls();
|
|
1004
1194
|
this._isOperationInProgress = false;
|
|
1005
1195
|
return;
|
|
1006
1196
|
}
|
|
1007
1197
|
hasError = true;
|
|
1008
1198
|
console.log('');
|
|
1009
1199
|
console.log(`${indent}${colors.error(`${icons.cross} Tool Error: ${tool} - ${error}`)}`);
|
|
1010
|
-
//
|
|
1200
|
+
// Add detailed error info including tool name and params for AI understanding and correction
|
|
1011
1201
|
this.conversation.push({
|
|
1012
1202
|
role: 'tool',
|
|
1013
1203
|
content: JSON.stringify({
|
|
1014
1204
|
name: tool,
|
|
1015
1205
|
parameters: params,
|
|
1016
|
-
error: error
|
|
1206
|
+
error: error,
|
|
1017
1207
|
}),
|
|
1018
1208
|
tool_call_id: toolCall.id,
|
|
1019
|
-
timestamp: Date.now()
|
|
1209
|
+
timestamp: Date.now(),
|
|
1020
1210
|
});
|
|
1021
1211
|
}
|
|
1022
1212
|
else {
|
|
@@ -1054,7 +1244,10 @@ export class InteractiveSession {
|
|
|
1054
1244
|
// Show edit result with diff
|
|
1055
1245
|
console.log('');
|
|
1056
1246
|
const diffOutput = renderDiff(result.diff);
|
|
1057
|
-
const indentedDiff = diffOutput
|
|
1247
|
+
const indentedDiff = diffOutput
|
|
1248
|
+
.split('\n')
|
|
1249
|
+
.map((line) => `${displayIndent} ${line}`)
|
|
1250
|
+
.join('\n');
|
|
1058
1251
|
console.log(`${indentedDiff}`);
|
|
1059
1252
|
}
|
|
1060
1253
|
else if (hasFilePreview) {
|
|
@@ -1074,7 +1267,8 @@ export class InteractiveSession {
|
|
|
1074
1267
|
// Special handling for task tool (subagent) - show friendly summary
|
|
1075
1268
|
console.log('');
|
|
1076
1269
|
const subagentType = params.subagent_type;
|
|
1077
|
-
const subagentName = params.description ||
|
|
1270
|
+
const subagentName = params.description ||
|
|
1271
|
+
(params.prompt ? params.prompt.substring(0, 50).replace(/\n/g, ' ') : 'Unknown task');
|
|
1078
1272
|
if (result?.success) {
|
|
1079
1273
|
console.log(`${displayIndent}${colors.success(`${icons.check} ${subagentType}: Completed`)}`);
|
|
1080
1274
|
console.log(`${displayIndent}${colors.textDim(` Task: ${subagentName}`)}`);
|
|
@@ -1192,7 +1386,10 @@ export class InteractiveSession {
|
|
|
1192
1386
|
const resultPreview = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
1193
1387
|
const truncatedPreview = resultPreview.length > 200 ? resultPreview.substring(0, 200) + '...' : resultPreview;
|
|
1194
1388
|
// Indent the preview
|
|
1195
|
-
const indentedPreview = truncatedPreview
|
|
1389
|
+
const indentedPreview = truncatedPreview
|
|
1390
|
+
.split('\n')
|
|
1391
|
+
.map((line) => `${displayIndent} ${line}`)
|
|
1392
|
+
.join('\n');
|
|
1196
1393
|
console.log(`${indentedPreview}`);
|
|
1197
1394
|
}
|
|
1198
1395
|
else {
|
|
@@ -1202,9 +1399,9 @@ export class InteractiveSession {
|
|
|
1202
1399
|
tool,
|
|
1203
1400
|
params,
|
|
1204
1401
|
result,
|
|
1205
|
-
timestamp: Date.now()
|
|
1402
|
+
timestamp: Date.now(),
|
|
1206
1403
|
};
|
|
1207
|
-
this.
|
|
1404
|
+
this.tool_calls.push(toolCallRecord);
|
|
1208
1405
|
// Record tool output to session manager
|
|
1209
1406
|
await this.sessionManager.addOutput({
|
|
1210
1407
|
role: 'tool',
|
|
@@ -1212,77 +1409,104 @@ export class InteractiveSession {
|
|
|
1212
1409
|
toolName: tool,
|
|
1213
1410
|
toolParams: params,
|
|
1214
1411
|
toolResult: result,
|
|
1215
|
-
timestamp: Date.now()
|
|
1412
|
+
timestamp: Date.now(),
|
|
1216
1413
|
});
|
|
1217
|
-
//
|
|
1414
|
+
// Unified message format with tool name and params
|
|
1415
|
+
// Format: OpenAI-compatible tool result with plain text content
|
|
1218
1416
|
this.conversation.push({
|
|
1219
1417
|
role: 'tool',
|
|
1220
|
-
content: JSON.stringify(
|
|
1221
|
-
name: tool,
|
|
1222
|
-
parameters: params,
|
|
1223
|
-
result: result
|
|
1224
|
-
}),
|
|
1418
|
+
content: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
|
|
1225
1419
|
tool_call_id: toolCall.id,
|
|
1226
|
-
timestamp: Date.now()
|
|
1420
|
+
timestamp: Date.now(),
|
|
1227
1421
|
});
|
|
1228
1422
|
}
|
|
1229
1423
|
}
|
|
1230
1424
|
// Logic: Only skip returning results to main agent when user explicitly cancelled (ESC)
|
|
1231
1425
|
// For all other cases (success, failure, errors), always return results for further processing
|
|
1232
|
-
const guiSubagentCancelled = preparedToolCalls.some(tc => tc.name === 'task' &&
|
|
1426
|
+
const guiSubagentCancelled = preparedToolCalls.some((tc) => tc.name === 'task' &&
|
|
1427
|
+
tc.params?.subagent_type === 'gui-subagent' &&
|
|
1428
|
+
results.some((r) => r.tool === 'task' && r.result?.cancelled === true));
|
|
1233
1429
|
// If GUI agent was cancelled by user, don't continue generating response
|
|
1234
1430
|
// This avoids wasting API calls and tokens on cancelled tasks
|
|
1235
1431
|
if (guiSubagentCancelled) {
|
|
1236
|
-
console.log('');
|
|
1237
|
-
console.log(`${indent}${colors.textMuted('GUI task cancelled by user')}`);
|
|
1238
1432
|
this._isOperationInProgress = false;
|
|
1239
1433
|
return;
|
|
1240
1434
|
}
|
|
1241
|
-
//
|
|
1242
|
-
if (hasError) {
|
|
1243
|
-
this._isOperationInProgress = false;
|
|
1244
|
-
// 不再抛出异常,而是将错误结果返回给 AI,让 AI 决定如何处理
|
|
1245
|
-
// 这样可以避免工具错误导致程序退出
|
|
1246
|
-
}
|
|
1247
|
-
// Continue based on mode - 统一处理,无论是否有错误
|
|
1435
|
+
// Continue based on mode - unified handling for both success and error cases
|
|
1248
1436
|
if (onComplete) {
|
|
1437
|
+
await this.checkAndCompressContext();
|
|
1249
1438
|
// Remote mode: use provided callback
|
|
1250
1439
|
await onComplete();
|
|
1251
1440
|
}
|
|
1252
1441
|
else {
|
|
1442
|
+
await this.checkAndCompressContext();
|
|
1253
1443
|
// Local mode: default behavior - continue with generateResponse
|
|
1254
1444
|
await this.generateResponse();
|
|
1255
1445
|
}
|
|
1256
1446
|
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Clean up incomplete tool calls from conversation after cancellation
|
|
1449
|
+
* This removes assistant messages with tool_calls that don't have corresponding tool_results
|
|
1450
|
+
*/
|
|
1451
|
+
async cleanupIncompleteToolCalls() {
|
|
1452
|
+
// 从后往前找到包含 tool_calls 的 assistant 消息
|
|
1453
|
+
for (let i = this.conversation.length - 1; i >= 0; i--) {
|
|
1454
|
+
const msg = this.conversation[i];
|
|
1455
|
+
if (msg.role === 'assistant' && msg.tool_calls?.length) {
|
|
1456
|
+
// 收集所有 tool_call IDs
|
|
1457
|
+
const allToolCallIds = new Set(msg.tool_calls.map((tc) => tc.id));
|
|
1458
|
+
// 找出哪些 tool_call IDs 已经有对应的 tool_result
|
|
1459
|
+
const completedToolCallIds = new Set();
|
|
1460
|
+
for (let k = i + 1; k < this.conversation.length; k++) {
|
|
1461
|
+
const resultMsg = this.conversation[k];
|
|
1462
|
+
if (resultMsg.role === 'tool' && resultMsg.tool_call_id) {
|
|
1463
|
+
completedToolCallIds.add(resultMsg.tool_call_id);
|
|
1464
|
+
}
|
|
1465
|
+
else if (resultMsg.role === 'user' || resultMsg.role === 'assistant') {
|
|
1466
|
+
break; // 遇到下一个角色消息就停止
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
// 找出未完成的 tool_call IDs
|
|
1470
|
+
const incompleteToolCallIds = [...allToolCallIds].filter(id => !completedToolCallIds.has(id));
|
|
1471
|
+
// 如果所有 tool_call 都已完成,不需要清理
|
|
1472
|
+
if (incompleteToolCallIds.length === 0) {
|
|
1473
|
+
break;
|
|
1474
|
+
}
|
|
1475
|
+
// 只移除未完成的 tool_call,不移除已完成的 tool_result
|
|
1476
|
+
msg.tool_calls = msg.tool_calls.filter((tc) => !incompleteToolCallIds.includes(tc.id));
|
|
1477
|
+
break;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1257
1481
|
/**
|
|
1258
1482
|
* Get user-friendly description for tool
|
|
1259
1483
|
*/
|
|
1260
1484
|
getToolDescription(toolName, params) {
|
|
1261
1485
|
const descriptions = {
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1486
|
+
Read: (p) => `Read file: ${this.truncatePath(p.filePath)}`,
|
|
1487
|
+
Write: (p) => `Write file: ${this.truncatePath(p.filePath)}`,
|
|
1488
|
+
Grep: (p) => `Search text: "${p.pattern}"`,
|
|
1489
|
+
Bash: (p) => `Execute command: ${this.truncateCommand(p.command)}`,
|
|
1490
|
+
ListDirectory: (p) => `List directory: ${this.truncatePath(p.path || '.')}`,
|
|
1491
|
+
SearchFiles: (p) => `Search files: ${p.pattern}`,
|
|
1492
|
+
DeleteFile: (p) => `Delete file: ${this.truncatePath(p.filePath)}`,
|
|
1493
|
+
CreateDirectory: (p) => `Create directory: ${this.truncatePath(p.dirPath)}`,
|
|
1494
|
+
Edit: (p) => `Edit text: ${this.truncatePath(p.file_path)}`,
|
|
1495
|
+
web_search: (p) => `Web search: "${p.query}"`,
|
|
1496
|
+
todo_write: () => `Update todo list`,
|
|
1497
|
+
todo_read: () => `Read todo list`,
|
|
1498
|
+
task: (p) => `Launch subtask: ${p.description}`,
|
|
1499
|
+
ReadBashOutput: (p) => `Read task output: ${p.task_id}`,
|
|
1500
|
+
web_fetch: () => `Fetch web content`,
|
|
1501
|
+
ask_user_question: () => `Ask user`,
|
|
1502
|
+
save_memory: () => `Save memory`,
|
|
1503
|
+
exit_plan_mode: () => `Complete plan`,
|
|
1504
|
+
xml_escape: (p) => `XML escape: ${this.truncatePath(p.file_path)}`,
|
|
1505
|
+
image_read: (p) => `Read image: ${this.truncatePath(p.image_input)}`,
|
|
1282
1506
|
// 'Skill': (p) => `Execute skill: ${p.skill}`,
|
|
1283
1507
|
// 'ListSkills': () => `List available skills`,
|
|
1284
1508
|
// 'GetSkillDetails': (p) => `Get skill details: ${p.skill}`,
|
|
1285
|
-
|
|
1509
|
+
InvokeSkill: (p) => `Invoke skill: ${p.skillId} - ${this.truncatePath(p.taskDescription || '', 40)}`,
|
|
1286
1510
|
};
|
|
1287
1511
|
const getDescription = descriptions[toolName];
|
|
1288
1512
|
return getDescription ? getDescription(params) : `Execute tool: ${toolName}`;
|
|
@@ -1315,10 +1539,10 @@ export class InteractiveSession {
|
|
|
1315
1539
|
return `${indent}${colors.textMuted('No tasks')}`;
|
|
1316
1540
|
}
|
|
1317
1541
|
const statusConfig = {
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1542
|
+
pending: { icon: icons.circle, color: colors.textMuted, label: 'Pending' },
|
|
1543
|
+
in_progress: { icon: icons.loading, color: colors.warning, label: 'In Progress' },
|
|
1544
|
+
completed: { icon: icons.success, color: colors.success, label: 'Completed' },
|
|
1545
|
+
failed: { icon: icons.error, color: colors.error, label: 'Failed' },
|
|
1322
1546
|
};
|
|
1323
1547
|
const lines = [];
|
|
1324
1548
|
for (const todo of todos) {
|
|
@@ -1431,7 +1655,155 @@ export class InteractiveSession {
|
|
|
1431
1655
|
return this.currentTaskId;
|
|
1432
1656
|
}
|
|
1433
1657
|
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Clean up stale temporary workspaces from previous sessions.
|
|
1660
|
+
* Called at startup to ensure no leftover temp files accumulate.
|
|
1661
|
+
*/
|
|
1662
|
+
async function cleanupStaleWorkspaces() {
|
|
1663
|
+
try {
|
|
1664
|
+
const configManager = getConfigManager();
|
|
1665
|
+
const workspacePath = configManager.getWorkspacePath();
|
|
1666
|
+
// Use default workspace path if workspacePath is empty or undefined
|
|
1667
|
+
const effectiveWorkspacePath = (workspacePath && workspacePath.trim())
|
|
1668
|
+
? workspacePath
|
|
1669
|
+
: os.homedir();
|
|
1670
|
+
const baseWorkspaceDir = path.join(effectiveWorkspacePath, '.xagent', 'workspace');
|
|
1671
|
+
// First, verify the workspace directory exists before attempting cleanup
|
|
1672
|
+
try {
|
|
1673
|
+
const stats = await fsPromises.stat(baseWorkspaceDir);
|
|
1674
|
+
if (!stats.isDirectory()) {
|
|
1675
|
+
return; // Not a directory, skip cleanup
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
catch {
|
|
1679
|
+
// Directory doesn't exist - nothing to clean
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
try {
|
|
1683
|
+
const entries = await fsPromises.readdir(baseWorkspaceDir, { withFileTypes: true });
|
|
1684
|
+
let cleanedCount = 0;
|
|
1685
|
+
for (const entry of entries) {
|
|
1686
|
+
if (entry.isDirectory()) {
|
|
1687
|
+
const fullPath = path.join(baseWorkspaceDir, entry.name);
|
|
1688
|
+
try {
|
|
1689
|
+
await fsPromises.rm(fullPath, { recursive: true, force: true });
|
|
1690
|
+
cleanedCount++;
|
|
1691
|
+
}
|
|
1692
|
+
catch {
|
|
1693
|
+
// Skip directories that can't be removed (in use or permission issues)
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
if (cleanedCount > 0) {
|
|
1698
|
+
console.log(colors.textDim(`🧹 Cleaned up ${cleanedCount} stale workspace(s)`));
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
catch {
|
|
1702
|
+
// Can't read directory - skip cleanup
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
catch {
|
|
1706
|
+
// Config not available - skip cleanup
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Initialize built-in skills on first run.
|
|
1711
|
+
* Checks if user skills directory is empty or doesn't exist,
|
|
1712
|
+
* then copies all built-in skills including the protected find-skills.
|
|
1713
|
+
* @returns Number of skills initialized, or 0 if no initialization was needed.
|
|
1714
|
+
*/
|
|
1715
|
+
async function initializeSkillsOnDemand() {
|
|
1716
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
1717
|
+
const __dirname = path.dirname(__filename);
|
|
1718
|
+
// Get user skills directory (respects OS-specific paths)
|
|
1719
|
+
const configManager = getConfigManager();
|
|
1720
|
+
const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
|
|
1721
|
+
// Check if user skills directory exists and has skills
|
|
1722
|
+
let hasSkills = false;
|
|
1723
|
+
try {
|
|
1724
|
+
const entries = await fsPromises.readdir(userSkillsPath, { withFileTypes: true });
|
|
1725
|
+
hasSkills = entries.some(e => e.isDirectory());
|
|
1726
|
+
}
|
|
1727
|
+
catch {
|
|
1728
|
+
hasSkills = false;
|
|
1729
|
+
}
|
|
1730
|
+
// If skills already exist, skip initialization
|
|
1731
|
+
if (hasSkills) {
|
|
1732
|
+
return 0;
|
|
1733
|
+
}
|
|
1734
|
+
// Ensure user skills directory exists
|
|
1735
|
+
await fsPromises.mkdir(userSkillsPath, { recursive: true });
|
|
1736
|
+
// Define skill source directories
|
|
1737
|
+
const builtinSkillsDir = path.join(__dirname, '..', 'skills', 'skills');
|
|
1738
|
+
const findSkillsDir = path.join(__dirname, '..', 'find-skills');
|
|
1739
|
+
const skillsToInstall = [];
|
|
1740
|
+
// Add find-skills from root directory
|
|
1741
|
+
if (fs.existsSync(findSkillsDir) && fs.existsSync(path.join(findSkillsDir, 'SKILL.md'))) {
|
|
1742
|
+
skillsToInstall.push({ source: findSkillsDir, name: 'find-skills' });
|
|
1743
|
+
}
|
|
1744
|
+
// Add skills from skills/skills directory
|
|
1745
|
+
if (fs.existsSync(builtinSkillsDir)) {
|
|
1746
|
+
const entries = fs.readdirSync(builtinSkillsDir, { withFileTypes: true });
|
|
1747
|
+
for (const entry of entries) {
|
|
1748
|
+
if (entry.isDirectory()) {
|
|
1749
|
+
const skillPath = path.join(builtinSkillsDir, entry.name);
|
|
1750
|
+
if (fs.existsSync(path.join(skillPath, 'SKILL.md'))) {
|
|
1751
|
+
skillsToInstall.push({ source: skillPath, name: entry.name });
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
if (skillsToInstall.length === 0) {
|
|
1757
|
+
return 0;
|
|
1758
|
+
}
|
|
1759
|
+
// Create user skills directory (already done above, but ensure it exists)
|
|
1760
|
+
await fsPromises.mkdir(userSkillsPath, { recursive: true });
|
|
1761
|
+
// Copy all skills
|
|
1762
|
+
for (const { source, name } of skillsToInstall) {
|
|
1763
|
+
const destPath = path.join(userSkillsPath, name);
|
|
1764
|
+
if (!fs.existsSync(destPath)) {
|
|
1765
|
+
await copyDirectoryRecursiveAsync(source, destPath);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
return skillsToInstall.length;
|
|
1769
|
+
}
|
|
1770
|
+
// Synchronous version (kept for backwards compatibility)
|
|
1771
|
+
function copyDirectoryRecursive(src, dest) {
|
|
1772
|
+
if (!fs.existsSync(dest)) {
|
|
1773
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
1774
|
+
}
|
|
1775
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
1776
|
+
for (const entry of entries) {
|
|
1777
|
+
const srcPath = path.join(src, entry.name);
|
|
1778
|
+
const destPath = path.join(dest, entry.name);
|
|
1779
|
+
if (entry.isDirectory()) {
|
|
1780
|
+
copyDirectoryRecursive(srcPath, destPath);
|
|
1781
|
+
}
|
|
1782
|
+
else if (entry.isFile()) {
|
|
1783
|
+
fs.copyFileSync(srcPath, destPath);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
// Asynchronous version for concurrent-safe initialization
|
|
1788
|
+
async function copyDirectoryRecursiveAsync(src, dest) {
|
|
1789
|
+
await fsPromises.mkdir(dest, { recursive: true });
|
|
1790
|
+
const entries = await fsPromises.readdir(src, { withFileTypes: true });
|
|
1791
|
+
for (const entry of entries) {
|
|
1792
|
+
const srcPath = path.join(src, entry.name);
|
|
1793
|
+
const destPath = path.join(dest, entry.name);
|
|
1794
|
+
if (entry.isDirectory()) {
|
|
1795
|
+
await copyDirectoryRecursiveAsync(srcPath, destPath);
|
|
1796
|
+
}
|
|
1797
|
+
else if (entry.isFile()) {
|
|
1798
|
+
await fsPromises.copyFile(srcPath, destPath);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1434
1802
|
export async function startInteractiveSession() {
|
|
1803
|
+
// Clean up any leftover temp workspaces from previous sessions
|
|
1804
|
+
await cleanupStaleWorkspaces();
|
|
1805
|
+
// Initialize built-in skills on first run (silent, returns count)
|
|
1806
|
+
const initializedCount = await initializeSkillsOnDemand();
|
|
1435
1807
|
const session = new InteractiveSession();
|
|
1436
1808
|
// Flag to control shutdown
|
|
1437
1809
|
session._isShuttingDown = false;
|
|
@@ -1467,6 +1839,15 @@ export async function startInteractiveSession() {
|
|
|
1467
1839
|
// Force exit
|
|
1468
1840
|
process.exit(0);
|
|
1469
1841
|
});
|
|
1842
|
+
await session.start(initializedCount);
|
|
1843
|
+
// Check for updates on startup
|
|
1844
|
+
try {
|
|
1845
|
+
const { checkUpdatesOnStartup } = await import('./update.js');
|
|
1846
|
+
await checkUpdatesOnStartup();
|
|
1847
|
+
}
|
|
1848
|
+
catch (error) {
|
|
1849
|
+
// Silently ignore update check failures
|
|
1850
|
+
}
|
|
1470
1851
|
await session.start();
|
|
1471
1852
|
}
|
|
1472
1853
|
// Singleton session instance for access from other modules
|