@travisennis/acai 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -760
- package/bin/acai +52 -0
- package/dist/agent/index.d.ts +12 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +380 -199
- package/dist/agent/sub-agent.d.ts +23 -0
- package/dist/agent/sub-agent.d.ts.map +1 -0
- package/dist/agent/sub-agent.js +109 -0
- package/dist/cli/index.d.ts +26 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{cli.js → cli/index.js} +84 -77
- package/dist/{stdin.d.ts → cli/stdin.d.ts} +2 -1
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/{stdin.js → cli/stdin.js} +11 -0
- package/dist/commands/copy/index.js +2 -2
- package/dist/commands/copy/utils.d.ts.map +1 -1
- package/dist/commands/copy/utils.js +15 -13
- package/dist/commands/generate-rules/index.d.ts +1 -1
- package/dist/commands/generate-rules/index.d.ts.map +1 -1
- package/dist/commands/generate-rules/index.js +16 -101
- package/dist/commands/generate-rules/service.d.ts +22 -0
- package/dist/commands/generate-rules/service.d.ts.map +1 -0
- package/dist/commands/generate-rules/service.js +103 -0
- package/dist/commands/handoff/index.js +2 -2
- package/dist/commands/health/index.js +1 -1
- package/dist/commands/health/utils.d.ts +3 -2
- package/dist/commands/health/utils.d.ts.map +1 -1
- package/dist/commands/health/utils.js +6 -0
- package/dist/commands/history/index.d.ts +1 -1
- package/dist/commands/history/index.d.ts.map +1 -1
- package/dist/commands/history/index.js +17 -18
- package/dist/commands/history/types.d.ts +38 -0
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/history/utils.d.ts.map +1 -1
- package/dist/commands/history/utils.js +63 -58
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +3 -8
- package/dist/commands/init-project/index.d.ts.map +1 -1
- package/dist/commands/init-project/index.js +3 -3
- package/dist/commands/init-project/utils.d.ts +2 -1
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +10 -2
- package/dist/commands/list-tools/index.d.ts.map +1 -1
- package/dist/commands/list-tools/index.js +7 -31
- package/dist/commands/manager.d.ts +2 -2
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +55 -33
- package/dist/commands/model/index.d.ts.map +1 -1
- package/dist/commands/model/index.js +20 -151
- package/dist/commands/model/model-panel.d.ts +4 -0
- package/dist/commands/model/model-panel.d.ts.map +1 -0
- package/dist/commands/model/model-panel.js +144 -0
- package/dist/commands/paste/index.d.ts.map +1 -1
- package/dist/commands/paste/index.js +59 -62
- package/dist/commands/paste/utils.d.ts.map +1 -1
- package/dist/commands/paste/utils.js +88 -58
- package/dist/commands/pickup/index.d.ts.map +1 -1
- package/dist/commands/pickup/index.js +6 -3
- package/dist/commands/pickup/utils.js +3 -3
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +33 -50
- package/dist/commands/review/index.d.ts.map +1 -1
- package/dist/commands/review/index.js +3 -117
- package/dist/commands/review/review-panel.d.ts +3 -0
- package/dist/commands/review/review-panel.d.ts.map +1 -0
- package/dist/commands/review/review-panel.js +186 -0
- package/dist/commands/review/utils.d.ts +15 -1
- package/dist/commands/review/utils.d.ts.map +1 -1
- package/dist/commands/review/utils.js +127 -68
- package/dist/commands/session/index.d.ts +1 -1
- package/dist/commands/session/index.d.ts.map +1 -1
- package/dist/commands/session/index.js +124 -135
- package/dist/commands/shell/index.d.ts.map +1 -1
- package/dist/commands/shell/index.js +16 -1
- package/dist/commands/types.d.ts +2 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/{config.d.ts → config/index.d.ts} +20 -9
- package/dist/config/index.d.ts.map +1 -0
- package/dist/{config.js → config/index.js} +43 -42
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +75 -55
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -141
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +18 -36
- package/dist/models/ai-config.d.ts +1 -0
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +4 -3
- package/dist/models/anthropic-provider.d.ts +2 -5
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -70
- package/dist/models/deepseek-provider.d.ts +1 -0
- package/dist/models/deepseek-provider.d.ts.map +1 -1
- package/dist/models/google-provider.d.ts +2 -3
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +0 -26
- package/dist/models/groq-provider.d.ts +1 -0
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/manager.d.ts +13 -2
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +20 -8
- package/dist/models/openai-provider.d.ts +2 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +0 -52
- package/dist/models/opencode-go-provider.d.ts +25 -0
- package/dist/models/opencode-go-provider.d.ts.map +1 -0
- package/dist/models/opencode-go-provider.js +78 -0
- package/dist/models/opencode-zen-provider.d.ts +7 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +49 -10
- package/dist/models/openrouter-provider.d.ts +27 -31
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +121 -180
- package/dist/models/providers.d.ts +3 -3
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +6 -0
- package/dist/models/xai-provider.d.ts +4 -3
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +18 -18
- package/dist/modes/manager.d.ts +24 -0
- package/dist/modes/manager.d.ts.map +1 -0
- package/dist/modes/manager.js +77 -0
- package/dist/modes/prompts.d.ts +2 -0
- package/dist/modes/prompts.d.ts.map +1 -0
- package/dist/modes/prompts.js +142 -0
- package/dist/prompts/mentions.d.ts +11 -0
- package/dist/prompts/mentions.d.ts.map +1 -0
- package/dist/{mentions.js → prompts/mentions.js} +55 -85
- package/dist/{prompts.d.ts → prompts/system-prompt.d.ts} +7 -2
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +31 -16
- package/dist/repl/index.d.ts +174 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/{repl-new.js → repl/index.js} +397 -76
- package/dist/repl/project-status.d.ts +1 -0
- package/dist/repl/project-status.d.ts.map +1 -1
- package/dist/repl/project-status.js +4 -1
- package/dist/sessions/manager.d.ts +92 -0
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +262 -9
- package/dist/sessions/summary.d.ts +4 -0
- package/dist/sessions/summary.d.ts.map +1 -0
- package/dist/sessions/summary.js +30 -0
- package/dist/skills/index.d.ts +29 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +16 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +231 -0
- package/dist/terminal/control.d.ts +1 -1
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +3 -3
- package/dist/terminal/east-asian-width.d.ts.map +1 -1
- package/dist/terminal/east-asian-width.js +404 -351
- package/dist/terminal/keys.d.ts +17 -0
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +37 -0
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +24 -12
- package/dist/terminal/string-width.d.ts.map +1 -1
- package/dist/terminal/string-width.js +25 -27
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/style.js +4 -7
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +41 -27
- package/dist/terminal/table/cell.d.ts +12 -0
- package/dist/terminal/table/cell.d.ts.map +1 -1
- package/dist/terminal/table/cell.js +40 -25
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +100 -68
- package/dist/terminal/table/utils.d.ts +1 -1
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +17 -10
- package/dist/terminal/wrap-ansi.d.ts.map +1 -1
- package/dist/terminal/wrap-ansi.js +174 -105
- package/dist/tokens/tracker.d.ts +1 -0
- package/dist/tokens/tracker.d.ts.map +1 -1
- package/dist/tokens/tracker.js +3 -0
- package/dist/tools/agent.d.ts +27 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/agent.js +81 -0
- package/dist/tools/apply-patch.d.ts +62 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +377 -0
- package/dist/tools/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +349 -141
- package/dist/tools/directory-tree.d.ts +3 -3
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +8 -5
- package/dist/tools/dynamic-tool-loader.d.ts +3 -6
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +20 -4
- package/dist/tools/edit-file.d.ts +7 -7
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +292 -85
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +110 -63
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +315 -193
- package/dist/tools/index.d.ts +114 -9
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +39 -24
- package/dist/tools/ls.d.ts +2 -2
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +7 -5
- package/dist/tools/read-file.d.ts +4 -6
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +84 -39
- package/dist/tools/save-file.d.ts +3 -3
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +36 -31
- package/dist/tools/skill.d.ts +23 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +65 -0
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +2 -9
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +12 -0
- package/dist/tools/web-fetch.d.ts +50 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +446 -0
- package/dist/tools/web-search.d.ts +44 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +226 -0
- package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
- package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/attachment-provider.js +25 -78
- package/dist/tui/autocomplete/base-provider.d.ts +1 -0
- package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
- package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.js +3 -17
- package/dist/tui/autocomplete/command-provider.d.ts +1 -0
- package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/command-provider.js +3 -0
- package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
- package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/file-search-provider.js +37 -17
- package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
- package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
- package/dist/tui/autocomplete/skill-provider.js +49 -0
- package/dist/tui/autocomplete/utils.d.ts +2 -1
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +25 -23
- package/dist/tui/autocomplete.d.ts +2 -2
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +3 -5
- package/dist/tui/components/assistant-message.d.ts.map +1 -1
- package/dist/tui/components/assistant-message.js +0 -4
- package/dist/tui/components/editor.d.ts +18 -3
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +211 -237
- package/dist/tui/components/footer.d.ts +6 -4
- package/dist/tui/components/footer.d.ts.map +1 -1
- package/dist/tui/components/footer.js +49 -25
- package/dist/tui/components/markdown.d.ts +10 -7
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +57 -39
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +35 -33
- package/dist/tui/components/notification.d.ts +13 -2
- package/dist/tui/components/notification.d.ts.map +1 -1
- package/dist/tui/components/notification.js +36 -2
- package/dist/tui/components/progress-bar.js +1 -1
- package/dist/tui/components/select-list.d.ts +1 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +14 -11
- package/dist/tui/components/text.d.ts +16 -0
- package/dist/tui/components/text.d.ts.map +1 -1
- package/dist/tui/components/text.js +72 -57
- package/dist/tui/components/thinking-block.d.ts +9 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -1
- package/dist/tui/components/thinking-block.js +43 -11
- package/dist/tui/components/tool-execution.d.ts +5 -1
- package/dist/tui/components/tool-execution.d.ts.map +1 -1
- package/dist/tui/components/tool-execution.js +19 -10
- package/dist/tui/components/user-message.d.ts.map +1 -1
- package/dist/tui/components/user-message.js +0 -3
- package/dist/tui/components/welcome.d.ts +2 -1
- package/dist/tui/components/welcome.d.ts.map +1 -1
- package/dist/tui/components/welcome.js +2 -2
- package/dist/tui/editor-launcher.d.ts +3 -2
- package/dist/tui/editor-launcher.d.ts.map +1 -1
- package/dist/tui/index.d.ts +0 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +10 -2
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +166 -41
- package/dist/tui/utils.d.ts +1 -5
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +271 -44
- package/dist/utils/bash/parse.d.ts +19 -0
- package/dist/utils/bash/parse.d.ts.map +1 -0
- package/dist/utils/bash/parse.js +223 -0
- package/dist/utils/bash/quote.d.ts +6 -0
- package/dist/utils/bash/quote.d.ts.map +1 -0
- package/dist/utils/bash/quote.js +23 -0
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +211 -126
- package/dist/utils/command-protection.d.ts +28 -0
- package/dist/utils/command-protection.d.ts.map +1 -0
- package/dist/utils/command-protection.js +324 -0
- package/dist/utils/dedent.d.ts.map +1 -0
- package/dist/utils/env-expand.d.ts +2 -0
- package/dist/utils/env-expand.d.ts.map +1 -0
- package/dist/utils/env-expand.js +8 -0
- package/dist/utils/filesystem/path-display.d.ts +11 -0
- package/dist/utils/filesystem/path-display.d.ts.map +1 -0
- package/dist/utils/filesystem/path-display.js +32 -0
- package/dist/utils/filesystem/security.d.ts +2 -2
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +28 -30
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/{formatting.js → utils/formatting.js} +1 -1
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +30 -0
- package/dist/utils/glob.d.ts +1 -1
- package/dist/utils/glob.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/{logger.js → utils/logger.js} +1 -1
- package/dist/utils/parsing.d.ts.map +1 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +90 -37
- package/dist/utils/templates.d.ts +2 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +24 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/{version.js → utils/version.js} +1 -1
- package/package.json +35 -26
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +0 -1
- package/dist/commands/add-directory/types.d.ts +0 -6
- package/dist/commands/add-directory/types.d.ts.map +0 -1
- package/dist/commands/add-directory/types.js +0 -1
- package/dist/commands/copy/types.d.ts +0 -3
- package/dist/commands/copy/types.d.ts.map +0 -1
- package/dist/commands/copy/types.js +0 -1
- package/dist/commands/exit/index.d.ts +0 -10
- package/dist/commands/exit/index.d.ts.map +0 -1
- package/dist/commands/exit/index.js +0 -21
- package/dist/commands/exit/types.d.ts +0 -8
- package/dist/commands/exit/types.d.ts.map +0 -1
- package/dist/commands/exit/types.js +0 -1
- package/dist/commands/exit/utils.d.ts +0 -2
- package/dist/commands/exit/utils.d.ts.map +0 -1
- package/dist/commands/exit/utils.js +0 -13
- package/dist/commands/prompt/index.d.ts +0 -5
- package/dist/commands/prompt/index.d.ts.map +0 -1
- package/dist/commands/prompt/index.js +0 -122
- package/dist/commands/prompt/types.d.ts +0 -15
- package/dist/commands/prompt/types.d.ts.map +0 -1
- package/dist/commands/prompt/types.js +0 -1
- package/dist/commands/prompt/utils.d.ts +0 -12
- package/dist/commands/prompt/utils.d.ts.map +0 -1
- package/dist/commands/prompt/utils.js +0 -107
- package/dist/commands/reset/index.d.ts +0 -3
- package/dist/commands/reset/index.d.ts.map +0 -1
- package/dist/commands/reset/index.js +0 -25
- package/dist/commands/reset/types.d.ts +0 -1
- package/dist/commands/reset/types.d.ts.map +0 -1
- package/dist/commands/reset/types.js +0 -3
- package/dist/commands/review/types.d.ts +0 -12
- package/dist/commands/review/types.d.ts.map +0 -1
- package/dist/commands/review/types.js +0 -1
- package/dist/commands/save/index.d.ts +0 -3
- package/dist/commands/save/index.d.ts.map +0 -1
- package/dist/commands/save/index.js +0 -19
- package/dist/config.d.ts.map +0 -1
- package/dist/dedent.d.ts.map +0 -1
- package/dist/formatting.d.ts.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/mentions.d.ts +0 -14
- package/dist/mentions.d.ts.map +0 -1
- package/dist/parsing.d.ts.map +0 -1
- package/dist/prompts.d.ts.map +0 -1
- package/dist/repl-new.d.ts +0 -65
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts +0 -16
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- package/dist/stdin.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.d.ts +0 -21
- package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.js +0 -164
- package/dist/utils/iterables.d.ts +0 -2
- package/dist/utils/iterables.d.ts.map +0 -1
- package/dist/utils/iterables.js +0 -6
- package/dist/version.d.ts.map +0 -1
- /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
- /package/dist/{dedent.js → utils/dedent.js} +0 -0
- /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
- /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
- /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
- /package/dist/{parsing.js → utils/parsing.js} +0 -0
- /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
import { logger } from "../utils/logger.js";
|
|
5
|
+
import { parseFrontMatter } from "../utils/yaml.js";
|
|
6
|
+
const CONFIG_DIR_NAME = ".acai";
|
|
7
|
+
// Validation functions
|
|
8
|
+
function validateSkillName(name, directoryName) {
|
|
9
|
+
// Check required field
|
|
10
|
+
if (!name) {
|
|
11
|
+
return { valid: false, error: "Name field is required" };
|
|
12
|
+
}
|
|
13
|
+
// Check length (1-64 characters)
|
|
14
|
+
if (name.length < 1 || name.length > 64) {
|
|
15
|
+
return { valid: false, error: "Name must be 1-64 characters long" };
|
|
16
|
+
}
|
|
17
|
+
// Check allowed characters (lowercase letters, numbers, hyphens)
|
|
18
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
19
|
+
return {
|
|
20
|
+
valid: false,
|
|
21
|
+
error: "Name can only contain lowercase letters, numbers, and hyphens",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Check no leading or trailing hyphens
|
|
25
|
+
if (name.startsWith("-") || name.endsWith("-")) {
|
|
26
|
+
return { valid: false, error: "Name cannot start or end with a hyphen" };
|
|
27
|
+
}
|
|
28
|
+
// Check no consecutive hyphens
|
|
29
|
+
if (name.includes("--")) {
|
|
30
|
+
return { valid: false, error: "Name cannot contain consecutive hyphens" };
|
|
31
|
+
}
|
|
32
|
+
// Check matches directory name
|
|
33
|
+
if (name !== directoryName) {
|
|
34
|
+
return {
|
|
35
|
+
valid: false,
|
|
36
|
+
error: `Name "${name}" must match directory name "${directoryName}"`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return { valid: true };
|
|
40
|
+
}
|
|
41
|
+
function validateSkillDescription(description) {
|
|
42
|
+
// Check required field
|
|
43
|
+
if (!description) {
|
|
44
|
+
return { valid: false, error: "Description field is required" };
|
|
45
|
+
}
|
|
46
|
+
// Check length (1-1024 characters)
|
|
47
|
+
if (description.length < 1 || description.length > 1024) {
|
|
48
|
+
return {
|
|
49
|
+
valid: false,
|
|
50
|
+
error: "Description must be 1-1024 characters long",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { valid: true };
|
|
54
|
+
}
|
|
55
|
+
function parseFrontmatter(content) {
|
|
56
|
+
const { data, content: body } = parseFrontMatter(content);
|
|
57
|
+
// Type cast and validate required fields
|
|
58
|
+
const name = data["name"];
|
|
59
|
+
const description = data["description"];
|
|
60
|
+
// Set default empty values for optional fields
|
|
61
|
+
const userInvocable = data["user-invocable"];
|
|
62
|
+
const disableModelInvocation = data["disable-model-invocation"];
|
|
63
|
+
const frontmatter = {
|
|
64
|
+
name: name || "",
|
|
65
|
+
description: description || "",
|
|
66
|
+
license: data["license"] || undefined,
|
|
67
|
+
compatibility: data["compatibility"] || undefined,
|
|
68
|
+
metadata: data["metadata"] || undefined,
|
|
69
|
+
"allowed-tools": data["allowed-tools"] || undefined,
|
|
70
|
+
"user-invocable": typeof userInvocable === "boolean" ? userInvocable : undefined,
|
|
71
|
+
"disable-model-invocation": typeof disableModelInvocation === "boolean"
|
|
72
|
+
? disableModelInvocation
|
|
73
|
+
: undefined,
|
|
74
|
+
arguments: data["arguments"] || undefined,
|
|
75
|
+
examples: data["examples"] || undefined,
|
|
76
|
+
};
|
|
77
|
+
return { frontmatter, body };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates a Skill object from frontmatter and path info
|
|
81
|
+
*/
|
|
82
|
+
function createSkill(frontmatter, filePath, baseDir, source) {
|
|
83
|
+
return {
|
|
84
|
+
name: frontmatter.name,
|
|
85
|
+
description: frontmatter.description,
|
|
86
|
+
filePath,
|
|
87
|
+
baseDir,
|
|
88
|
+
source,
|
|
89
|
+
userInvocable: frontmatter["user-invocable"] ?? false,
|
|
90
|
+
disableModelInvocation: frontmatter["disable-model-invocation"] ?? false,
|
|
91
|
+
allowedTools: frontmatter["allowed-tools"],
|
|
92
|
+
arguments: frontmatter.arguments,
|
|
93
|
+
examples: frontmatter.examples,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validates and creates a skill from a SKILL.md file
|
|
98
|
+
* Returns null if validation fails
|
|
99
|
+
*/
|
|
100
|
+
async function tryLoadSkillFromFile(skillPath, directoryName, baseDir, source) {
|
|
101
|
+
try {
|
|
102
|
+
const content = await readFile(skillPath, "utf8");
|
|
103
|
+
const { frontmatter } = parseFrontmatter(content);
|
|
104
|
+
const nameValidation = validateSkillName(frontmatter.name, directoryName);
|
|
105
|
+
if (!nameValidation.valid) {
|
|
106
|
+
logger.warn(`Invalid skill name in ${skillPath}: ${nameValidation.error}`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const descriptionValidation = validateSkillDescription(frontmatter.description);
|
|
110
|
+
if (!descriptionValidation.valid) {
|
|
111
|
+
logger.warn(`Invalid skill description in ${skillPath}: ${descriptionValidation.error}`);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return createSkill(frontmatter, skillPath, baseDir, source);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
logger.warn(error, `Failed to load skill from ${skillPath}:`);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Checks if an entry should be skipped (hidden files, inaccessible paths)
|
|
123
|
+
*/
|
|
124
|
+
async function shouldSkipEntry(entryPath, entryName) {
|
|
125
|
+
if (entryName.startsWith(".")) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
await stat(entryPath);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
async function loadSkillsFromDirInternal(dir, source, mode, _useColonPath, subdir = "", visited = new Set()) {
|
|
137
|
+
const skills = [];
|
|
138
|
+
const fullDir = join(dir, subdir);
|
|
139
|
+
// Resolve the real path to detect symlink cycles
|
|
140
|
+
try {
|
|
141
|
+
const real = await realpath(fullDir);
|
|
142
|
+
if (visited.has(real)) {
|
|
143
|
+
logger.warn(`Skipping ${fullDir}: symlink cycle detected`);
|
|
144
|
+
return skills;
|
|
145
|
+
}
|
|
146
|
+
visited.add(real);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return skills;
|
|
150
|
+
}
|
|
151
|
+
let entries;
|
|
152
|
+
try {
|
|
153
|
+
// @ts-expect-error - Node.js types have a quirk with withFileTypes
|
|
154
|
+
entries = await readdir(fullDir, { withFileTypes: true });
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
// Directory doesn't exist or can't be read
|
|
158
|
+
if (error.code !== "ENOENT") {
|
|
159
|
+
logger.error(error, `Error reading skills directory ${fullDir}:`);
|
|
160
|
+
}
|
|
161
|
+
return skills;
|
|
162
|
+
}
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
const entryName = entry.name.toString();
|
|
165
|
+
const entryPath = join(fullDir, entryName);
|
|
166
|
+
// Skip hidden files, symlinks, etc.
|
|
167
|
+
if (await shouldSkipEntry(entryPath, entryName)) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
// Handle directories
|
|
171
|
+
if (entry.isDirectory()) {
|
|
172
|
+
if (mode === "recursive") {
|
|
173
|
+
// Recursively scan subdirectories
|
|
174
|
+
const newSubdir = subdir ? join(subdir, entryName) : entryName;
|
|
175
|
+
const subSkills = await loadSkillsFromDirInternal(dir, source, mode, false, newSubdir, visited);
|
|
176
|
+
skills.push(...subSkills);
|
|
177
|
+
}
|
|
178
|
+
else if (mode === "claude") {
|
|
179
|
+
// Claude mode: only check immediate subdirectories for SKILL.md
|
|
180
|
+
const skillPath = join(entryPath, "SKILL.md");
|
|
181
|
+
const skill = await tryLoadSkillFromFile(skillPath, entryName, entryPath, source);
|
|
182
|
+
if (skill) {
|
|
183
|
+
skills.push(skill);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Handle files
|
|
189
|
+
if (entry.isFile() && entryName === "SKILL.md" && mode === "recursive") {
|
|
190
|
+
// Base directory is the directory containing the SKILL.md file
|
|
191
|
+
const baseDir = subdir ? join(dir, subdir) : dir;
|
|
192
|
+
const skill = await tryLoadSkillFromFile(entryPath, basename(dirname(entryPath)), baseDir, source);
|
|
193
|
+
if (skill) {
|
|
194
|
+
skills.push(skill);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return skills;
|
|
199
|
+
}
|
|
200
|
+
export async function loadSkillsFromDir(options, subdir = "") {
|
|
201
|
+
const { dir, source, useColonPath = false } = options;
|
|
202
|
+
return await loadSkillsFromDirInternal(dir, source, "recursive", useColonPath, subdir);
|
|
203
|
+
}
|
|
204
|
+
export class Skills {
|
|
205
|
+
skills;
|
|
206
|
+
constructor(skills) {
|
|
207
|
+
this.skills = skills;
|
|
208
|
+
}
|
|
209
|
+
getAll() {
|
|
210
|
+
return this.skills;
|
|
211
|
+
}
|
|
212
|
+
getUserInvocable() {
|
|
213
|
+
return this.skills.filter((s) => s.userInvocable);
|
|
214
|
+
}
|
|
215
|
+
getModelInvocable() {
|
|
216
|
+
return this.skills.filter((s) => !s.disableModelInvocation);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export async function loadSkills() {
|
|
220
|
+
const skillMap = new Map();
|
|
221
|
+
// Codex: recursive, simple directory name
|
|
222
|
+
const codexUserDir = join(homedir(), ".codex", "skills");
|
|
223
|
+
for (const skill of await loadSkillsFromDirInternal(codexUserDir, "codex-user", "recursive", false)) {
|
|
224
|
+
skillMap.set(skill.name, skill);
|
|
225
|
+
}
|
|
226
|
+
// Claude: single level only
|
|
227
|
+
const claudeUserDir = join(homedir(), ".claude", "skills");
|
|
228
|
+
for (const skill of await loadSkillsFromDirInternal(claudeUserDir, "claude-user", "claude", false)) {
|
|
229
|
+
skillMap.set(skill.name, skill);
|
|
230
|
+
}
|
|
231
|
+
const claudeProjectDir = resolve(process.cwd(), ".claude", "skills");
|
|
232
|
+
for (const skill of await loadSkillsFromDirInternal(claudeProjectDir, "claude-project", "claude", false)) {
|
|
233
|
+
skillMap.set(skill.name, skill);
|
|
234
|
+
}
|
|
235
|
+
// Deprecated: warn if skills exist in old .acai directories
|
|
236
|
+
const deprecatedGlobalDir = join(homedir(), CONFIG_DIR_NAME, "skills");
|
|
237
|
+
try {
|
|
238
|
+
const entries = await readdir(deprecatedGlobalDir);
|
|
239
|
+
if (entries.length > 0) {
|
|
240
|
+
logger.warn("Skills found in ~/.acai/skills/ are deprecated and will not be loaded. Move them to ~/.agents/skills/ to continue using them.");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Directory doesn't exist, no warning needed
|
|
245
|
+
}
|
|
246
|
+
const deprecatedProjectDir = resolve(process.cwd(), CONFIG_DIR_NAME, "skills");
|
|
247
|
+
try {
|
|
248
|
+
const entries = await readdir(deprecatedProjectDir);
|
|
249
|
+
if (entries.length > 0) {
|
|
250
|
+
logger.warn("Skills found in .acai/skills/ are deprecated and will not be loaded. Move them to .agents/skills/ to continue using them.");
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
// Directory doesn't exist, no warning needed
|
|
255
|
+
}
|
|
256
|
+
// .agents: recursive, colon-separated path names (primary)
|
|
257
|
+
const agentsGlobalSkillsDir = join(homedir(), ".agents", "skills");
|
|
258
|
+
for (const skill of await loadSkillsFromDirInternal(agentsGlobalSkillsDir, "user", "recursive", true)) {
|
|
259
|
+
skillMap.set(skill.name, skill);
|
|
260
|
+
}
|
|
261
|
+
const agentsProjectSkillsDir = resolve(process.cwd(), ".agents", "skills");
|
|
262
|
+
for (const skill of await loadSkillsFromDirInternal(agentsProjectSkillsDir, "project", "recursive", true)) {
|
|
263
|
+
skillMap.set(skill.name, skill);
|
|
264
|
+
}
|
|
265
|
+
return new Skills(Array.from(skillMap.values()));
|
|
266
|
+
}
|
|
267
|
+
export function formatSkillsForPrompt(skills) {
|
|
268
|
+
const modelInvocableSkills = skills.filter((s) => !s.disableModelInvocation);
|
|
269
|
+
if (modelInvocableSkills.length === 0) {
|
|
270
|
+
return "";
|
|
271
|
+
}
|
|
272
|
+
const lines = [
|
|
273
|
+
"\n\n## Skills",
|
|
274
|
+
"",
|
|
275
|
+
"<skills_instructions>",
|
|
276
|
+
"When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.",
|
|
277
|
+
"Use the Skill tool to load a skill's instructions when the task matches its description.",
|
|
278
|
+
"</skills_instructions>",
|
|
279
|
+
"",
|
|
280
|
+
"<available_skills>",
|
|
281
|
+
];
|
|
282
|
+
for (const skill of modelInvocableSkills) {
|
|
283
|
+
lines.push("<skill>");
|
|
284
|
+
lines.push("<name>");
|
|
285
|
+
lines.push(skill.name);
|
|
286
|
+
lines.push("</name>");
|
|
287
|
+
lines.push("<description>");
|
|
288
|
+
lines.push(skill.description);
|
|
289
|
+
lines.push("</description>");
|
|
290
|
+
lines.push("</skill>");
|
|
291
|
+
}
|
|
292
|
+
lines.push("</available_skills>");
|
|
293
|
+
return lines.join("\n");
|
|
294
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface Subagent {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
model?: string;
|
|
5
|
+
tools?: string[];
|
|
6
|
+
timeout: number;
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
filePath: string;
|
|
9
|
+
source: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadSubagents(): Promise<Subagent[]>;
|
|
12
|
+
export declare function getSubagent(name: string): Promise<Subagent | undefined>;
|
|
13
|
+
export declare function formatSubagentsForDescription(subagents: Subagent[]): string;
|
|
14
|
+
export declare function formatSubagentsForPrompt(subagents: Subagent[]): string;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/subagents/index.ts"],"names":[],"mappings":"AAeA,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAkND,wBAAsB,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAgBzD;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAG7E;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAa3E;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CA6CtE"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { logger } from "../utils/logger.js";
|
|
5
|
+
import { parseFrontMatter } from "../utils/yaml.js";
|
|
6
|
+
const CONFIG_DIR_NAME = ".acai";
|
|
7
|
+
const DEFAULT_TIMEOUT = 900;
|
|
8
|
+
// Validation functions
|
|
9
|
+
function validateSubagentName(name, fileName) {
|
|
10
|
+
// Check required field
|
|
11
|
+
if (!name) {
|
|
12
|
+
return { valid: false, error: "Name field is required" };
|
|
13
|
+
}
|
|
14
|
+
// Check length (1-64 characters)
|
|
15
|
+
if (name.length < 1 || name.length > 64) {
|
|
16
|
+
return { valid: false, error: "Name must be 1-64 characters long" };
|
|
17
|
+
}
|
|
18
|
+
// Check allowed characters (lowercase letters, numbers, hyphens)
|
|
19
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
20
|
+
return {
|
|
21
|
+
valid: false,
|
|
22
|
+
error: "Name can only contain lowercase letters, numbers, and hyphens",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// Check no leading or trailing hyphens
|
|
26
|
+
if (name.startsWith("-") || name.endsWith("-")) {
|
|
27
|
+
return { valid: false, error: "Name cannot start or end with a hyphen" };
|
|
28
|
+
}
|
|
29
|
+
// Check no consecutive hyphens
|
|
30
|
+
if (name.includes("--")) {
|
|
31
|
+
return { valid: false, error: "Name cannot contain consecutive hyphens" };
|
|
32
|
+
}
|
|
33
|
+
// Check matches filename (without .md)
|
|
34
|
+
const expectedName = fileName.replace(/\.md$/, "");
|
|
35
|
+
if (name !== expectedName) {
|
|
36
|
+
return {
|
|
37
|
+
valid: false,
|
|
38
|
+
error: `Name "${name}" must match filename "${fileName}" (without .md)`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { valid: true };
|
|
42
|
+
}
|
|
43
|
+
function validateSubagentDescription(description) {
|
|
44
|
+
// Check required field
|
|
45
|
+
if (!description) {
|
|
46
|
+
return { valid: false, error: "Description field is required" };
|
|
47
|
+
}
|
|
48
|
+
// Check length (1-1024 characters)
|
|
49
|
+
if (description.length < 1 || description.length > 1024) {
|
|
50
|
+
return {
|
|
51
|
+
valid: false,
|
|
52
|
+
error: "Description must be 1-1024 characters long",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return { valid: true };
|
|
56
|
+
}
|
|
57
|
+
function validateSubagentTimeout(timeout) {
|
|
58
|
+
if (timeout === undefined) {
|
|
59
|
+
return { valid: true };
|
|
60
|
+
}
|
|
61
|
+
if (typeof timeout !== "number" || timeout < 1 || timeout > 3600) {
|
|
62
|
+
return {
|
|
63
|
+
valid: false,
|
|
64
|
+
error: "Timeout must be a number between 1 and 3600 seconds",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return { valid: true };
|
|
68
|
+
}
|
|
69
|
+
function parseFrontmatter(content) {
|
|
70
|
+
const { data, content: body } = parseFrontMatter(content);
|
|
71
|
+
// Type cast and validate required fields
|
|
72
|
+
const name = data["name"];
|
|
73
|
+
const description = data["description"];
|
|
74
|
+
// Set default empty values for optional fields
|
|
75
|
+
const frontmatter = {
|
|
76
|
+
name: name || "",
|
|
77
|
+
description: description || "",
|
|
78
|
+
model: data["model"] || undefined,
|
|
79
|
+
tools: data["tools"] || undefined,
|
|
80
|
+
timeout: data["timeout"] || undefined,
|
|
81
|
+
};
|
|
82
|
+
return { frontmatter, body };
|
|
83
|
+
}
|
|
84
|
+
async function loadSubagentsFromDir(dir, source) {
|
|
85
|
+
const subagents = [];
|
|
86
|
+
try {
|
|
87
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
// Skip hidden files and directories
|
|
90
|
+
if (entry.name.startsWith(".")) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// Only process .md files
|
|
94
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const entryPath = join(dir, entry.name);
|
|
98
|
+
// Skip symbolic links to avoid infinite recursion
|
|
99
|
+
try {
|
|
100
|
+
const stats = await stat(entryPath);
|
|
101
|
+
if (stats.isSymbolicLink()) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// If we can't stat, skip it
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const content = await readFile(entryPath, "utf8");
|
|
111
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
112
|
+
// Validate required fields
|
|
113
|
+
const nameValidation = validateSubagentName(frontmatter.name, entry.name);
|
|
114
|
+
if (!nameValidation.valid) {
|
|
115
|
+
logger.warn(`Invalid subagent name in ${entryPath}: ${nameValidation.error}`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const descriptionValidation = validateSubagentDescription(frontmatter.description);
|
|
119
|
+
if (!descriptionValidation.valid) {
|
|
120
|
+
logger.warn(`Invalid subagent description in ${entryPath}: ${descriptionValidation.error}`);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const timeoutValidation = validateSubagentTimeout(frontmatter.timeout);
|
|
124
|
+
if (!timeoutValidation.valid) {
|
|
125
|
+
logger.warn(`Invalid subagent timeout in ${entryPath}: ${timeoutValidation.error}`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
// Parse tools if provided
|
|
129
|
+
let tools;
|
|
130
|
+
if (frontmatter.tools) {
|
|
131
|
+
tools = frontmatter.tools
|
|
132
|
+
.split(",")
|
|
133
|
+
.map((t) => t.trim())
|
|
134
|
+
.filter((t) => t.length > 0);
|
|
135
|
+
}
|
|
136
|
+
subagents.push({
|
|
137
|
+
name: frontmatter.name,
|
|
138
|
+
description: frontmatter.description,
|
|
139
|
+
model: frontmatter.model,
|
|
140
|
+
tools,
|
|
141
|
+
timeout: frontmatter.timeout ?? DEFAULT_TIMEOUT,
|
|
142
|
+
systemPrompt: body,
|
|
143
|
+
filePath: entryPath,
|
|
144
|
+
source,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
logger.warn(error, `Failed to load subagent from ${entryPath}:`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// Directory doesn't exist or can't be read
|
|
154
|
+
if (error.code !== "ENOENT") {
|
|
155
|
+
logger.error(error, `Error reading subagents directory ${dir}:`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return subagents;
|
|
159
|
+
}
|
|
160
|
+
export async function loadSubagents() {
|
|
161
|
+
const subagentMap = new Map();
|
|
162
|
+
// Load from user directory (~/.acai/subagents)
|
|
163
|
+
const userDir = join(homedir(), CONFIG_DIR_NAME, "subagents");
|
|
164
|
+
for (const subagent of await loadSubagentsFromDir(userDir, "user")) {
|
|
165
|
+
subagentMap.set(subagent.name, subagent);
|
|
166
|
+
}
|
|
167
|
+
// Load from project directory (.acai/subagents) - overrides user
|
|
168
|
+
const projectDir = resolve(process.cwd(), CONFIG_DIR_NAME, "subagents");
|
|
169
|
+
for (const subagent of await loadSubagentsFromDir(projectDir, "project")) {
|
|
170
|
+
subagentMap.set(subagent.name, subagent);
|
|
171
|
+
}
|
|
172
|
+
return Array.from(subagentMap.values());
|
|
173
|
+
}
|
|
174
|
+
export async function getSubagent(name) {
|
|
175
|
+
const subagents = await loadSubagents();
|
|
176
|
+
return subagents.find((s) => s.name === name);
|
|
177
|
+
}
|
|
178
|
+
export function formatSubagentsForDescription(subagents) {
|
|
179
|
+
if (subagents.length === 0) {
|
|
180
|
+
return " No subagents available";
|
|
181
|
+
}
|
|
182
|
+
const lines = subagents.map((subagent) => {
|
|
183
|
+
const toolsStr = subagent.tools
|
|
184
|
+
? ` (tools: ${subagent.tools.join(", ")})`
|
|
185
|
+
: "";
|
|
186
|
+
return ` - ${subagent.name}: ${subagent.description}${toolsStr}`;
|
|
187
|
+
});
|
|
188
|
+
return lines.join("\n");
|
|
189
|
+
}
|
|
190
|
+
export function formatSubagentsForPrompt(subagents) {
|
|
191
|
+
if (subagents.length === 0) {
|
|
192
|
+
return "";
|
|
193
|
+
}
|
|
194
|
+
const lines = [
|
|
195
|
+
"## Subagents (Agent Tool)",
|
|
196
|
+
"",
|
|
197
|
+
"Use the Agent tool to delegate complex, multi-step tasks to specialized subagents. Subagents operate autonomously and return a single result.",
|
|
198
|
+
"",
|
|
199
|
+
"**When to use subagents:**",
|
|
200
|
+
"- Deep codebase research or architecture exploration",
|
|
201
|
+
"- Complex multi-file refactoring or implementation tasks",
|
|
202
|
+
"- Writing comprehensive tests across multiple files",
|
|
203
|
+
"- Creating detailed implementation plans",
|
|
204
|
+
"- Tasks requiring investigation across many files",
|
|
205
|
+
"",
|
|
206
|
+
"<available_subagents>",
|
|
207
|
+
];
|
|
208
|
+
for (const subagent of subagents) {
|
|
209
|
+
lines.push("<subagent>");
|
|
210
|
+
lines.push("<name>");
|
|
211
|
+
lines.push(subagent.name);
|
|
212
|
+
lines.push("</name>");
|
|
213
|
+
lines.push("<description>");
|
|
214
|
+
lines.push(subagent.description);
|
|
215
|
+
lines.push("</description>");
|
|
216
|
+
if (subagent.tools && subagent.tools.length > 0) {
|
|
217
|
+
lines.push("<tools>");
|
|
218
|
+
lines.push(subagent.tools.join(", "));
|
|
219
|
+
lines.push("</tools>");
|
|
220
|
+
}
|
|
221
|
+
lines.push("</subagent>");
|
|
222
|
+
}
|
|
223
|
+
lines.push("</available_subagents>");
|
|
224
|
+
lines.push("");
|
|
225
|
+
lines.push("**Usage notes:**");
|
|
226
|
+
lines.push("- Subagents are stateless - provide all context in your prompt");
|
|
227
|
+
lines.push("- Be specific about what information you need returned");
|
|
228
|
+
lines.push("- Use longer timeouts for complex tasks (1800-3600 seconds)");
|
|
229
|
+
lines.push("- Launch multiple subagents concurrently for independent tasks");
|
|
230
|
+
return lines.join("\n");
|
|
231
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides functions for controlling terminal behavior and state.
|
|
5
5
|
*/
|
|
6
|
-
export { isAltBackspace, isAltEnter, isAltLeft, isAltRight, isArrowDown, isArrowLeft, isArrowRight, isArrowUp, isBackspace, isCtrlA, isCtrlC, isCtrlD, isCtrlE, isCtrlG, isCtrlK, isCtrlL, isCtrlP, isCtrlT, isCtrlU, isCtrlW, isCtrlZ, isDelete, isEnd, isEnter, isEscape, isHome, isKittyCtrl, isKittyKey, isNavigationKey, isPageDown, isPageUp, isShiftCtrlD, isShiftCtrlO, isShiftCtrlP, isShiftEnter, isShiftTab, isTab, } from "./keys.ts";
|
|
6
|
+
export { isAltBackspace, isAltEnter, isAltLeft, isAltRight, isArrowDown, isArrowLeft, isArrowRight, isArrowUp, isBackspace, isCtrlA, isCtrlC, isCtrlD, isCtrlE, isCtrlG, isCtrlK, isCtrlL, isCtrlM, isCtrlN, isCtrlO, isCtrlP, isCtrlR, isCtrlT, isCtrlU, isCtrlW, isCtrlZ, isDelete, isEnd, isEnter, isEscape, isHome, isKittyCtrl, isKittyKey, isNavigationKey, isPageDown, isPageUp, isShiftCtrlD, isShiftCtrlO, isShiftCtrlP, isShiftEnter, isShiftTab, isTab, } from "./keys.ts";
|
|
7
7
|
/**
|
|
8
8
|
* Get the current shell
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../../source/terminal/control.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,WAAW,EACX,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,QAAQ,EACR,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,WAAW,EACX,UAAU,EACV,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,KAAK,GACN,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,wBAAgB,QAAQ,WAEvB;AAED;;GAEG;AACH,wBAAgB,aAAa,YAE5B;AAED;;GAEG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB3C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAYpD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgBnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAQnC"}
|
|
1
|
+
{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../../source/terminal/control.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,SAAS,EACT,WAAW,EACX,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,OAAO,EACP,QAAQ,EACR,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,WAAW,EACX,UAAU,EACV,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,KAAK,GACN,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,wBAAgB,QAAQ,WAEvB;AAED;;GAEG;AACH,wBAAgB,aAAa,YAE5B;AAED;;GAEG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB3C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAM7C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAYpD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgBnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,IAAI,CAQnC"}
|
package/dist/terminal/control.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides functions for controlling terminal behavior and state.
|
|
5
5
|
*/
|
|
6
|
-
import { config } from "../config.js";
|
|
7
|
-
import { logger } from "../logger.js";
|
|
6
|
+
import { config } from "../config/index.js";
|
|
7
|
+
import { logger } from "../utils/logger.js";
|
|
8
8
|
// Re-export key functions from keys.ts for convenient imports
|
|
9
|
-
export { isAltBackspace, isAltEnter, isAltLeft, isAltRight, isArrowDown, isArrowLeft, isArrowRight, isArrowUp, isBackspace, isCtrlA, isCtrlC, isCtrlD, isCtrlE, isCtrlG, isCtrlK, isCtrlL, isCtrlP, isCtrlT, isCtrlU, isCtrlW, isCtrlZ, isDelete, isEnd, isEnter, isEscape, isHome, isKittyCtrl, isKittyKey, isNavigationKey, isPageDown, isPageUp, isShiftCtrlD, isShiftCtrlO, isShiftCtrlP, isShiftEnter, isShiftTab, isTab, } from "./keys.js";
|
|
9
|
+
export { isAltBackspace, isAltEnter, isAltLeft, isAltRight, isArrowDown, isArrowLeft, isArrowRight, isArrowUp, isBackspace, isCtrlA, isCtrlC, isCtrlD, isCtrlE, isCtrlG, isCtrlK, isCtrlL, isCtrlM, isCtrlN, isCtrlO, isCtrlP, isCtrlR, isCtrlT, isCtrlU, isCtrlW, isCtrlZ, isDelete, isEnd, isEnter, isEscape, isHome, isKittyCtrl, isKittyKey, isNavigationKey, isPageDown, isPageUp, isShiftCtrlD, isShiftCtrlO, isShiftCtrlP, isShiftEnter, isShiftTab, isTab, } from "./keys.js";
|
|
10
10
|
/**
|
|
11
11
|
* Get the current shell
|
|
12
12
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"east-asian-width.d.ts","sourceRoot":"","sources":["../../source/terminal/east-asian-width.ts"],"names":[],"mappings":"AAAA,KAAK,kBAAkB,GACnB,WAAW,GACX,WAAW,GACX,MAAM,GACN,QAAQ,GACR,SAAS,GACT,WAAW,CAAC;AAEhB,UAAU,qBAAqB;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"east-asian-width.d.ts","sourceRoot":"","sources":["../../source/terminal/east-asian-width.ts"],"names":[],"mappings":"AAAA,KAAK,kBAAkB,GACnB,WAAW,GACX,WAAW,GACX,MAAM,GACN,QAAQ,GACR,SAAS,GACT,WAAW,CAAC;AAEhB,UAAU,qBAAqB;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAsdD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAGxE;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,qBAA0B,GAClC,CAAC,GAAG,CAAC,CAWP"}
|