@xagent-ai/cli 1.2.2 → 1.3.1
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/release.yml +76 -0
- package/.github/workflows/ci.yml +75 -0
- package/.github/workflows/release.yml +103 -0
- package/.gitmodules +3 -3
- package/README.md +326 -280
- package/README_CN.md +325 -279
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +7 -3
- package/dist/agents.js.map +1 -1
- package/dist/ai-client/factory.d.ts +40 -0
- package/dist/ai-client/factory.d.ts.map +1 -0
- package/dist/ai-client/factory.js +100 -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 +406 -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 +290 -0
- package/dist/ai-client/providers/openai.js.map +1 -0
- package/dist/ai-client/providers/remote.d.ts +110 -0
- package/dist/ai-client/providers/remote.d.ts.map +1 -0
- package/dist/ai-client/providers/remote.js +352 -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 +274 -0
- package/dist/ai-client/types.d.ts.map +1 -0
- package/dist/ai-client/types.js +90 -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 +164 -174
- 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 +53 -32
- package/dist/cancellation.js.map +1 -1
- package/dist/checkpoint.d.ts +2 -1
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +39 -6
- package/dist/checkpoint.js.map +1 -1
- package/dist/cli.js +742 -29
- 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 +82 -18
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +718 -154
- package/dist/context-compressor.js.map +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +8 -7
- package/dist/conversation.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.d.ts.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +6 -4
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.d.ts +39 -2
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +189 -74
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +23 -1
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +6 -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 +31 -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 +8 -5
- package/dist/input-processor.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mcp.d.ts +7 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +157 -49
- package/dist/mcp.js.map +1 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +3 -3
- package/dist/memory.js.map +1 -1
- package/dist/output-util.d.ts +27 -0
- package/dist/output-util.d.ts.map +1 -0
- package/dist/output-util.js +74 -0
- package/dist/output-util.js.map +1 -0
- package/dist/retry.js +1 -1
- package/dist/retry.js.map +1 -1
- package/dist/ripgrep.d.ts +29 -0
- package/dist/ripgrep.d.ts.map +1 -0
- package/dist/ripgrep.js +294 -0
- package/dist/ripgrep.js.map +1 -0
- package/dist/sdk-output-adapter.d.ts +34 -1
- package/dist/sdk-output-adapter.d.ts.map +1 -1
- package/dist/sdk-output-adapter.js +67 -2
- package/dist/sdk-output-adapter.js.map +1 -1
- package/dist/sdk-session.d.ts.map +1 -1
- package/dist/sdk-session.js +2 -0
- package/dist/sdk-session.js.map +1 -1
- package/dist/session-manager.js +3 -3
- package/dist/session-manager.js.map +1 -1
- package/dist/session.d.ts +116 -6
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +1416 -448
- 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 +126 -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 +8 -2
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +36 -15
- 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 +51 -48
- 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 +341 -0
- package/dist/skill-manager.js.map +1 -0
- package/dist/slash-commands.d.ts +39 -2
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +934 -305
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts +20 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +125 -56
- 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 +86 -36
- 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/theme.d.ts.map +1 -1
- package/dist/theme.js +8 -7
- package/dist/theme.js.map +1 -1
- package/dist/tools.d.ts +38 -7
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +1249 -617
- 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 +84 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +49 -0
- package/dist/types.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +28 -36
- 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 +61 -49
- 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 +440 -439
- package/find-skills/SKILL.md +133 -0
- package/package.json +91 -90
- package/scripts/install-ripgrep.js +241 -0
- package/src/agents.ts +7 -3
- package/src/ai-client/factory.ts +116 -0
- package/src/ai-client/index.ts +61 -0
- package/src/ai-client/providers/anthropic.ts +475 -0
- package/src/ai-client/providers/openai.ts +348 -0
- package/src/ai-client/providers/remote.ts +439 -0
- package/src/ai-client/registry.ts +97 -0
- package/src/ai-client/types.ts +364 -0
- package/src/ai-client-factory.ts +204 -0
- package/src/auth.ts +661 -614
- package/src/cancellation.ts +202 -176
- package/src/checkpoint.ts +255 -219
- package/src/cli.ts +1523 -743
- package/src/config.ts +341 -297
- package/src/context-compressor.ts +987 -290
- package/src/conversation.ts +290 -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 +1234 -1089
- package/src/gui-subagent/agent/index.ts +5 -5
- package/src/gui-subagent/index.ts +185 -163
- package/src/gui-subagent/operator/base-operator.ts +244 -245
- package/src/gui-subagent/operator/computer-operator.ts +541 -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 +8 -5
- package/src/logger.ts +436 -438
- package/src/mcp.ts +793 -682
- package/src/memory.ts +343 -344
- package/src/output-util.ts +80 -0
- package/src/retry.ts +1 -1
- package/src/ripgrep.ts +370 -0
- package/src/sdk-output-adapter.ts +842 -0
- package/src/sdk-session.ts +62 -0
- package/src/session-manager.ts +308 -308
- package/src/session.ts +1775 -573
- package/src/shell.ts +134 -0
- package/src/skill-installer.ts +518 -0
- package/src/skill-invoker.ts +959 -935
- package/src/skill-loader.ts +501 -496
- package/src/skill-manager.ts +385 -0
- package/src/slash-commands.ts +2189 -1389
- package/src/smart-approval.ts +193 -74
- package/src/system-prompt-generator.ts +91 -36
- package/src/terminal.ts +96 -0
- package/src/theme.ts +739 -738
- package/src/tools.ts +1790 -931
- package/src/truncate.ts +173 -0
- package/src/types.ts +337 -198
- package/src/update.ts +33 -40
- package/src/workflow.ts +521 -508
- package/test/cli-launch.test.ts +279 -0
- package/tsconfig.json +22 -22
- package/vitest.config.ts +21 -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-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/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/{.eslintrc.js → .eslintrc.cjs} +0 -0
package/src/shell.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { spawn, spawnSync } from 'child_process';
|
|
3
|
+
import { output as logOutput } from './output-util.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Find bash executable on PATH (Windows).
|
|
7
|
+
*/
|
|
8
|
+
function _findBashOnPath(): string | null {
|
|
9
|
+
try {
|
|
10
|
+
const result = spawnSync('where', ['bash.exe'], { encoding: 'utf-8', timeout: 5000 });
|
|
11
|
+
if (result.status === 0 && result.stdout) {
|
|
12
|
+
const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
|
|
13
|
+
if (firstMatch && existsSync(firstMatch)) {
|
|
14
|
+
return firstMatch;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
// Ignore errors
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get PowerShell version on Windows.
|
|
25
|
+
* @returns Version string (e.g., "5.1.22621") or "Unknown" if detection fails
|
|
26
|
+
*/
|
|
27
|
+
export function getPowerShellVersion(): string {
|
|
28
|
+
if (process.platform !== 'win32') {
|
|
29
|
+
return 'N/A';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const result = spawnSync('powershell', ['-NoProfile', '-Command', '($PSVersionTable.PSVersion | Select-Object -ExpandProperty Major), ($PSVersionTable.PSVersion | Select-Object -ExpandProperty Minor), ($PSVersionTable.PSVersion | Select-Object -ExpandProperty Build) -join "."'], {
|
|
34
|
+
encoding: 'utf-8',
|
|
35
|
+
timeout: 5000
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (result.status === 0 && result.stdout.trim()) {
|
|
39
|
+
return result.stdout.trim();
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// Ignore errors
|
|
43
|
+
}
|
|
44
|
+
return 'Unknown';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface ShellConfig {
|
|
48
|
+
/** Path to the shell executable */
|
|
49
|
+
shell: string;
|
|
50
|
+
/** Arguments to pass to the shell */
|
|
51
|
+
args: string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let cachedShellConfig: ShellConfig | null = null;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get shell configuration based on platform.
|
|
58
|
+
* Resolution order:
|
|
59
|
+
* 1. On Windows: PowerShell (preferred), then Git Bash as fallback
|
|
60
|
+
* 2. On Unix: /bin/bash
|
|
61
|
+
*
|
|
62
|
+
* @returns ShellConfig with shell path and args
|
|
63
|
+
*/
|
|
64
|
+
export function getShellConfig(): ShellConfig {
|
|
65
|
+
if (cachedShellConfig) {
|
|
66
|
+
return cachedShellConfig;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (process.platform === 'win32') {
|
|
70
|
+
// On Windows, prefer PowerShell for better compatibility and output handling
|
|
71
|
+
// Use -NoProfile to avoid profile script interference
|
|
72
|
+
// -Command executes the command string as PowerShell script
|
|
73
|
+
cachedShellConfig = {
|
|
74
|
+
shell: 'powershell',
|
|
75
|
+
args: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command']
|
|
76
|
+
};
|
|
77
|
+
return cachedShellConfig;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Unix: prefer bash over sh
|
|
81
|
+
if (existsSync('/bin/bash')) {
|
|
82
|
+
cachedShellConfig = { shell: '/bin/bash', args: ['-c'] };
|
|
83
|
+
} else {
|
|
84
|
+
cachedShellConfig = { shell: 'sh', args: ['-c'] };
|
|
85
|
+
}
|
|
86
|
+
return cachedShellConfig;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get a shell command string with proper quoting for the platform.
|
|
91
|
+
* @param command The command to execute
|
|
92
|
+
* @returns A properly quoted command string
|
|
93
|
+
*/
|
|
94
|
+
export function quoteShellCommand(command: string): string {
|
|
95
|
+
if (process.platform === 'win32') {
|
|
96
|
+
// For PowerShell -Command, the command string is passed directly
|
|
97
|
+
// PowerShell will parse and execute it as a script
|
|
98
|
+
// No additional quoting needed - just return the command as-is
|
|
99
|
+
return command;
|
|
100
|
+
} else {
|
|
101
|
+
// For bash/sh, use single quotes
|
|
102
|
+
return `'${command.replace(/'/g, "'\\''")}'`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Kill a process and all its children (cross-platform).
|
|
108
|
+
* @param pid Process ID to kill
|
|
109
|
+
*/
|
|
110
|
+
export function killProcessTree(pid: number): void {
|
|
111
|
+
if (process.platform === 'win32') {
|
|
112
|
+
// Use taskkill on Windows to kill process tree
|
|
113
|
+
try {
|
|
114
|
+
spawn('taskkill', ['/F', '/T', '/PID', String(pid)], {
|
|
115
|
+
stdio: 'ignore',
|
|
116
|
+
detached: true,
|
|
117
|
+
});
|
|
118
|
+
} catch (error) {
|
|
119
|
+
logOutput('warning', `[shell] Failed to kill process tree (PID ${pid})`, { error: error instanceof Error ? error.message : String(error) });
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// Use SIGKILL on Unix/Linux/Mac
|
|
123
|
+
try {
|
|
124
|
+
process.kill(-pid, 'SIGKILL');
|
|
125
|
+
} catch {
|
|
126
|
+
// Fallback to killing just the child if process group kill fails
|
|
127
|
+
try {
|
|
128
|
+
process.kill(pid, 'SIGKILL');
|
|
129
|
+
} catch (fallbackError) {
|
|
130
|
+
logOutput('warning', `[shell] Failed to kill process (PID ${pid})`, { error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError) });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Installer - Handles remote skill installation
|
|
3
|
+
* Supports: GitHub shorthand, GitHub URLs, direct SKILL.md URLs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs/promises';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import { mkdtemp, rm } from 'fs/promises';
|
|
10
|
+
import { tmpdir } from 'os';
|
|
11
|
+
import simpleGit from 'simple-git';
|
|
12
|
+
import { getConfigManager } from './config.js';
|
|
13
|
+
import { getLogger } from './logger.js';
|
|
14
|
+
|
|
15
|
+
const _logger = getLogger();
|
|
16
|
+
const CLONE_TIMEOUT_MS = 60000; // 60 seconds
|
|
17
|
+
|
|
18
|
+
export interface RemoteSource {
|
|
19
|
+
type: 'github' | 'direct-url' | 'local';
|
|
20
|
+
url: string;
|
|
21
|
+
ref?: string; // Branch/tag
|
|
22
|
+
subpath?: string; // Path to skill within repo
|
|
23
|
+
skillName?: string; // For @owner/repo@syntax
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface InstallResult {
|
|
27
|
+
success: boolean;
|
|
28
|
+
skillName?: string;
|
|
29
|
+
skillPath?: string;
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse a source string into structured format
|
|
35
|
+
*/
|
|
36
|
+
export function parseSource(input: string): RemoteSource {
|
|
37
|
+
const trimmed = input.trim();
|
|
38
|
+
|
|
39
|
+
// Check if local path
|
|
40
|
+
if (isLocalPath(trimmed)) {
|
|
41
|
+
return { type: 'local', url: trimmed };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Direct SKILL.md URL (non-GitHub)
|
|
45
|
+
if (isDirectSkillUrl(trimmed)) {
|
|
46
|
+
return { type: 'direct-url', url: trimmed };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// GitHub URL with path: https://github.com/owner/repo/tree/branch/path/to/skill
|
|
50
|
+
const githubTreeWithPathMatch = trimmed.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/);
|
|
51
|
+
if (githubTreeWithPathMatch) {
|
|
52
|
+
const [, owner, repo, ref, subpath] = githubTreeWithPathMatch;
|
|
53
|
+
return {
|
|
54
|
+
type: 'github',
|
|
55
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
56
|
+
ref,
|
|
57
|
+
subpath
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// GitHub URL with branch only: https://github.com/owner/repo/tree/branch
|
|
62
|
+
const githubTreeMatch = trimmed.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)$/);
|
|
63
|
+
if (githubTreeMatch) {
|
|
64
|
+
const [, owner, repo, ref] = githubTreeMatch;
|
|
65
|
+
return {
|
|
66
|
+
type: 'github',
|
|
67
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
68
|
+
ref
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// GitHub URL: https://github.com/owner/repo
|
|
73
|
+
const githubRepoMatch = trimmed.match(/github\.com\/([^/]+)\/([^/]+)/);
|
|
74
|
+
if (githubRepoMatch) {
|
|
75
|
+
const [, owner, repo] = githubRepoMatch;
|
|
76
|
+
const cleanRepo = repo.replace(/\.git$/, '');
|
|
77
|
+
return {
|
|
78
|
+
type: 'github',
|
|
79
|
+
url: `https://github.com/${owner}/${cleanRepo}.git`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// GitHub shorthand: owner/repo, owner/repo@skill-name
|
|
84
|
+
const atSkillMatch = trimmed.match(/^([^/]+)\/([^/@]+)@(.+)$/);
|
|
85
|
+
if (atSkillMatch && !trimmed.includes(':') && !trimmed.startsWith('.') && !trimmed.startsWith('/')) {
|
|
86
|
+
const [, owner, repo, skillName] = atSkillMatch;
|
|
87
|
+
return {
|
|
88
|
+
type: 'github',
|
|
89
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
90
|
+
skillName
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const shorthandMatch = trimmed.match(/^([^/]+)\/([^/]+)(?:\/(.+))?$/);
|
|
95
|
+
if (shorthandMatch && !trimmed.includes(':') && !trimmed.startsWith('.') && !trimmed.startsWith('/')) {
|
|
96
|
+
const [, owner, repo, subpath] = shorthandMatch;
|
|
97
|
+
return {
|
|
98
|
+
type: 'github',
|
|
99
|
+
url: `https://github.com/${owner}/${repo}.git`,
|
|
100
|
+
subpath
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Fallback: treat as direct URL
|
|
105
|
+
return { type: 'direct-url', url: trimmed };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if input is a local path
|
|
110
|
+
*/
|
|
111
|
+
function isLocalPath(input: string): boolean {
|
|
112
|
+
return (
|
|
113
|
+
path.isAbsolute(input) ||
|
|
114
|
+
input.startsWith('./') ||
|
|
115
|
+
input.startsWith('../') ||
|
|
116
|
+
input === '.' ||
|
|
117
|
+
input === '..' ||
|
|
118
|
+
/^[a-zA-Z]:[/\\]/.test(input)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Check if URL is a direct link to SKILL.md file
|
|
124
|
+
*/
|
|
125
|
+
function isDirectSkillUrl(input: string): boolean {
|
|
126
|
+
if (!input.startsWith('http://') && !input.startsWith('https://')) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!input.toLowerCase().endsWith('/skill.md') && !input.toLowerCase().endsWith('/skill')) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Exclude GitHub/GitLab URLs (they have their own handling)
|
|
135
|
+
if (input.includes('github.com/') && !input.includes('raw.githubusercontent.com')) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (input.includes('gitlab.com/') && !input.includes('/-/raw/')) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Extract skill name from SKILL.md content
|
|
147
|
+
*/
|
|
148
|
+
function extractSkillName(content: string): string | null {
|
|
149
|
+
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
150
|
+
return nameMatch ? nameMatch[1].trim() : null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Ensure directory exists
|
|
155
|
+
*/
|
|
156
|
+
async function ensureDir(dirPath: string): Promise<void> {
|
|
157
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Remove directory recursively
|
|
162
|
+
*/
|
|
163
|
+
async function removeDir(dirPath: string): Promise<void> {
|
|
164
|
+
try {
|
|
165
|
+
await fs.rm(dirPath, { recursive: true, force: true });
|
|
166
|
+
} catch {
|
|
167
|
+
// Ignore if doesn't exist
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Copy directory contents
|
|
173
|
+
*/
|
|
174
|
+
async function copyDir(src: string, dest: string): Promise<void> {
|
|
175
|
+
await ensureDir(dest);
|
|
176
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
177
|
+
|
|
178
|
+
for (const entry of entries) {
|
|
179
|
+
const srcPath = path.join(src, entry.name);
|
|
180
|
+
const destPath = path.join(dest, entry.name);
|
|
181
|
+
|
|
182
|
+
if (entry.isDirectory()) {
|
|
183
|
+
await copyDir(srcPath, destPath);
|
|
184
|
+
} else if (entry.isFile()) {
|
|
185
|
+
await fs.copyFile(srcPath, destPath);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Find SKILL.md in a directory
|
|
192
|
+
*/
|
|
193
|
+
async function findSkillMd(dirPath: string): Promise<string | null> {
|
|
194
|
+
try {
|
|
195
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
196
|
+
|
|
197
|
+
for (const entry of entries) {
|
|
198
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
199
|
+
|
|
200
|
+
if (entry.isDirectory()) {
|
|
201
|
+
// Skip hidden directories (except .)
|
|
202
|
+
if (entry.name.startsWith('.') && entry.name !== '.') continue;
|
|
203
|
+
|
|
204
|
+
// Check subdirectory for SKILL.md
|
|
205
|
+
const result = await findSkillMd(fullPath);
|
|
206
|
+
if (result) return result;
|
|
207
|
+
} else if (entry.isFile() && entry.name.toUpperCase() === 'SKILL.MD') {
|
|
208
|
+
return fullPath;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
// Ignore errors
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Fetch remote file content via HTTP with timeout
|
|
219
|
+
*/
|
|
220
|
+
async function fetchRemoteFile(url: string, timeoutMs: number = 30000): Promise<string> {
|
|
221
|
+
const controller = new AbortController();
|
|
222
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
226
|
+
clearTimeout(timeoutId);
|
|
227
|
+
|
|
228
|
+
if (!response.ok) {
|
|
229
|
+
throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
|
|
230
|
+
}
|
|
231
|
+
return response.text();
|
|
232
|
+
} catch (error) {
|
|
233
|
+
clearTimeout(timeoutId);
|
|
234
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
235
|
+
throw new Error(`Request timed out after ${timeoutMs}ms: ${url}`);
|
|
236
|
+
}
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Clone a GitHub repository to a temporary directory
|
|
243
|
+
*/
|
|
244
|
+
async function cloneRepo(url: string, ref?: string): Promise<string> {
|
|
245
|
+
const tempDir = await mkdtemp(path.join(tmpdir(), 'xagent-skills-'));
|
|
246
|
+
const git = simpleGit({ timeout: { block: CLONE_TIMEOUT_MS } });
|
|
247
|
+
const cloneOptions = ref ? ['--depth', '1', '--branch', ref] : ['--depth', '1'];
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
await git.clone(url, tempDir, cloneOptions);
|
|
251
|
+
return tempDir;
|
|
252
|
+
} catch (error) {
|
|
253
|
+
// Clean up temp dir on failure
|
|
254
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
255
|
+
|
|
256
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
257
|
+
const isTimeout = errorMessage.includes('block timeout') || errorMessage.includes('timed out');
|
|
258
|
+
|
|
259
|
+
if (isTimeout) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`Clone timed out after 60s. This often happens with private repos that require authentication.\n` +
|
|
262
|
+
` Ensure you have access and your SSH keys or credentials are configured.`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
throw new Error(`Failed to clone ${url}: ${errorMessage}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Install skill from direct URL (single SKILL.md file)
|
|
272
|
+
*/
|
|
273
|
+
async function installFromDirectUrl(source: RemoteSource): Promise<InstallResult> {
|
|
274
|
+
const configManager = getConfigManager();
|
|
275
|
+
const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
const content = await fetchRemoteFile(source.url);
|
|
279
|
+
const skillName = extractSkillName(content);
|
|
280
|
+
|
|
281
|
+
if (!skillName) {
|
|
282
|
+
return { success: false, error: 'Could not extract skill name from SKILL.md' };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const skillPath = path.join(userSkillsPath, skillName);
|
|
286
|
+
|
|
287
|
+
// Check if skill already exists
|
|
288
|
+
try {
|
|
289
|
+
await fs.access(skillPath);
|
|
290
|
+
return { success: false, error: `Skill "${skillName}" already installed` };
|
|
291
|
+
} catch {
|
|
292
|
+
// Doesn't exist, proceed
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Create skill directory
|
|
296
|
+
await ensureDir(skillPath);
|
|
297
|
+
|
|
298
|
+
// Write SKILL.md
|
|
299
|
+
await fs.writeFile(path.join(skillPath, 'SKILL.md'), content, 'utf-8');
|
|
300
|
+
|
|
301
|
+
return { success: true, skillName, skillPath };
|
|
302
|
+
} catch (error) {
|
|
303
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Install skill from GitHub repository using git clone
|
|
309
|
+
*/
|
|
310
|
+
async function installFromGitHub(source: RemoteSource): Promise<InstallResult> {
|
|
311
|
+
const configManager = getConfigManager();
|
|
312
|
+
const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
|
|
313
|
+
|
|
314
|
+
// Parse owner/repo from URL
|
|
315
|
+
const urlMatch = source.url.match(/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
316
|
+
if (!urlMatch) {
|
|
317
|
+
return { success: false, error: 'Invalid GitHub URL' };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const [, _owner, repo] = urlMatch;
|
|
321
|
+
const _cleanRepo = repo.replace(/\.git$/, '');
|
|
322
|
+
const ref = source.ref || 'main';
|
|
323
|
+
|
|
324
|
+
let tempDir: string | null = null;
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
// Clone the repository to a temporary directory
|
|
328
|
+
tempDir = await cloneRepo(source.url, ref);
|
|
329
|
+
|
|
330
|
+
// Find the skill directory in the cloned repo
|
|
331
|
+
let skillDir: string;
|
|
332
|
+
|
|
333
|
+
if (source.subpath) {
|
|
334
|
+
// Specific path to skill provided
|
|
335
|
+
skillDir = path.join(tempDir, source.subpath);
|
|
336
|
+
try {
|
|
337
|
+
await fs.access(skillDir);
|
|
338
|
+
} catch {
|
|
339
|
+
return { success: false, error: `Path "${source.subpath}" not found in repository` };
|
|
340
|
+
}
|
|
341
|
+
} else if (source.skillName) {
|
|
342
|
+
// @owner/repo@syntax - skill is in skills/<skill-name>/
|
|
343
|
+
skillDir = path.join(tempDir, 'skills', source.skillName);
|
|
344
|
+
try {
|
|
345
|
+
await fs.access(skillDir);
|
|
346
|
+
} catch {
|
|
347
|
+
return { success: false, error: `Skill "${source.skillName}" not found in skills/` };
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
// No specific path - find SKILL.md in the repo
|
|
351
|
+
const skillMdPath = await findSkillMd(tempDir);
|
|
352
|
+
if (!skillMdPath) {
|
|
353
|
+
return { success: false, error: 'No SKILL.md found in repository' };
|
|
354
|
+
}
|
|
355
|
+
skillDir = path.dirname(skillMdPath);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Read SKILL.md to get skill name
|
|
359
|
+
const skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
360
|
+
let skillContent: string;
|
|
361
|
+
try {
|
|
362
|
+
skillContent = await fs.readFile(skillMdPath, 'utf-8');
|
|
363
|
+
} catch {
|
|
364
|
+
return { success: false, error: 'SKILL.md not found in skill directory' };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const skillName = extractSkillName(skillContent);
|
|
368
|
+
if (!skillName) {
|
|
369
|
+
return { success: false, error: 'Could not extract skill name from SKILL.md' };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const skillPath = path.join(userSkillsPath, skillName);
|
|
373
|
+
|
|
374
|
+
// Check if skill already exists
|
|
375
|
+
try {
|
|
376
|
+
await fs.access(skillPath);
|
|
377
|
+
return { success: false, error: `Skill "${skillName}" already installed` };
|
|
378
|
+
} catch {
|
|
379
|
+
// Doesn't exist, proceed
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Copy skill files to user skills directory
|
|
383
|
+
await copyDir(skillDir, skillPath);
|
|
384
|
+
|
|
385
|
+
return { success: true, skillName, skillPath };
|
|
386
|
+
} catch (error) {
|
|
387
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
388
|
+
} finally {
|
|
389
|
+
// Clean up temporary directory
|
|
390
|
+
if (tempDir) {
|
|
391
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Install skill from local path
|
|
398
|
+
*/
|
|
399
|
+
async function installFromLocal(source: RemoteSource): Promise<InstallResult> {
|
|
400
|
+
const configManager = getConfigManager();
|
|
401
|
+
const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
const resolvedPath = path.resolve(source.url);
|
|
405
|
+
|
|
406
|
+
// Check if source exists
|
|
407
|
+
await fs.access(resolvedPath);
|
|
408
|
+
|
|
409
|
+
// Find SKILL.md
|
|
410
|
+
const skillMdPath = await findSkillMd(resolvedPath);
|
|
411
|
+
if (!skillMdPath) {
|
|
412
|
+
return { success: false, error: 'SKILL.md not found in source directory' };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const content = await fs.readFile(skillMdPath, 'utf-8');
|
|
416
|
+
const skillName = extractSkillName(content);
|
|
417
|
+
|
|
418
|
+
if (!skillName) {
|
|
419
|
+
return { success: false, error: 'Could not extract skill name from SKILL.md' };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const skillPath = path.join(userSkillsPath, skillName);
|
|
423
|
+
|
|
424
|
+
// Check if skill already exists
|
|
425
|
+
try {
|
|
426
|
+
await fs.access(skillPath);
|
|
427
|
+
return { success: false, error: `Skill "${skillName}" already installed` };
|
|
428
|
+
} catch {
|
|
429
|
+
// Doesn't exist, proceed
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Copy the skill directory
|
|
433
|
+
const sourceDir = path.dirname(skillMdPath);
|
|
434
|
+
await copyDir(sourceDir, skillPath);
|
|
435
|
+
|
|
436
|
+
return { success: true, skillName, skillPath };
|
|
437
|
+
} catch (error) {
|
|
438
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Main function to install a skill from source
|
|
444
|
+
*/
|
|
445
|
+
export async function installSkill(source: string): Promise<InstallResult> {
|
|
446
|
+
const parsed = parseSource(source);
|
|
447
|
+
|
|
448
|
+
switch (parsed.type) {
|
|
449
|
+
case 'direct-url':
|
|
450
|
+
return installFromDirectUrl(parsed);
|
|
451
|
+
case 'github':
|
|
452
|
+
return installFromGitHub(parsed);
|
|
453
|
+
case 'local':
|
|
454
|
+
return installFromLocal(parsed);
|
|
455
|
+
default:
|
|
456
|
+
return { success: false, error: 'Unknown source type' };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Remove an installed skill
|
|
462
|
+
*/
|
|
463
|
+
export async function removeSkill(skillName: string): Promise<InstallResult> {
|
|
464
|
+
const configManager = getConfigManager();
|
|
465
|
+
const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
|
|
466
|
+
const skillPath = path.join(userSkillsPath, skillName);
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
await fs.access(skillPath);
|
|
470
|
+
await removeDir(skillPath);
|
|
471
|
+
return { success: true, skillName, skillPath };
|
|
472
|
+
} catch {
|
|
473
|
+
return { success: false, error: `Skill "${skillName}" not found` };
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* List installed user skills
|
|
479
|
+
*/
|
|
480
|
+
export async function listUserSkills(): Promise<Array<{ name: string; description: string; path: string }>> {
|
|
481
|
+
const configManager = getConfigManager();
|
|
482
|
+
const userSkillsPath = configManager.getUserSkillsPath() || path.join(os.homedir(), '.xagent', 'skills');
|
|
483
|
+
|
|
484
|
+
const skills: Array<{ name: string; description: string; path: string }> = [];
|
|
485
|
+
|
|
486
|
+
try {
|
|
487
|
+
const entries = await fs.readdir(userSkillsPath, { withFileTypes: true });
|
|
488
|
+
|
|
489
|
+
for (const entry of entries) {
|
|
490
|
+
if (entry.isDirectory()) {
|
|
491
|
+
const skillPath = path.join(userSkillsPath, entry.name);
|
|
492
|
+
const skillMdPath = path.join(skillPath, 'SKILL.md');
|
|
493
|
+
|
|
494
|
+
try {
|
|
495
|
+
const content = await fs.readFile(skillMdPath, 'utf-8');
|
|
496
|
+
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
497
|
+
const descMatch = content.match(/^description:\s*(.+)$/m);
|
|
498
|
+
|
|
499
|
+
skills.push({
|
|
500
|
+
name: nameMatch ? nameMatch[1].trim() : entry.name,
|
|
501
|
+
description: descMatch ? descMatch[1].trim() : 'No description',
|
|
502
|
+
path: skillPath
|
|
503
|
+
});
|
|
504
|
+
} catch {
|
|
505
|
+
skills.push({
|
|
506
|
+
name: entry.name,
|
|
507
|
+
description: '(Missing SKILL.md)',
|
|
508
|
+
path: skillPath
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
} catch {
|
|
514
|
+
// Directory doesn't exist or is empty
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return skills;
|
|
518
|
+
}
|