@travisennis/acai 0.0.8 → 0.0.10
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 +48 -729
- 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 +378 -168
- 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 -76
- package/dist/cli/stdin.d.ts +9 -0
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/cli/stdin.js +37 -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 -100
- package/dist/commands/generate-rules/service.d.ts +21 -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.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.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 +57 -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 +9 -0
- 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 +134 -112
- package/dist/commands/session/types.d.ts +7 -0
- package/dist/commands/session/types.d.ts.map +1 -1
- package/dist/commands/share/html-renderer.d.ts +25 -0
- package/dist/commands/share/html-renderer.d.ts.map +1 -0
- package/dist/commands/share/html-renderer.js +384 -0
- package/dist/commands/share/index.d.ts +3 -0
- package/dist/commands/share/index.d.ts.map +1 -0
- package/dist/commands/share/index.js +122 -0
- 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 +170 -127
- 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 +5 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +27 -40
- package/dist/models/opencode-zen-provider.d.ts +8 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +68 -11
- package/dist/models/openrouter-provider.d.ts +24 -30
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +92 -177
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- 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 +23 -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 +143 -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} +21 -80
- package/dist/prompts/system-prompt.d.ts +26 -0
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +50 -22
- 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} +399 -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 +93 -1
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +264 -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.d.ts → skills/index.d.ts} +14 -2
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +15 -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 +30 -9
- 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.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 +172 -103
- 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/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +343 -121
- package/dist/tools/code-search.d.ts +41 -0
- package/dist/tools/code-search.d.ts.map +1 -0
- package/dist/tools/code-search.js +195 -0
- 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 +2 -5
- 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 +164 -66
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +95 -55
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +300 -192
- package/dist/tools/index.d.ts +143 -5
- 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 +3 -3
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +74 -34
- 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 +11 -11
- 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 +62 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +429 -0
- package/dist/tools/web-search.d.ts +62 -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 +36 -16
- 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.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 +21 -2
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +228 -236
- 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 +8 -5
- 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 +37 -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.js +2 -2
- package/dist/tui/editor-launcher.d.ts +13 -0
- package/dist/tui/editor-launcher.d.ts.map +1 -0
- package/dist/tui/editor-launcher.js +39 -0
- package/dist/tui/index.d.ts +3 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +1 -0
- package/dist/tui/terminal.d.ts +27 -0
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +144 -15
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +172 -41
- 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 +32 -31
- 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 +34 -25
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +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 -126
- 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/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 +0 -10
- package/dist/prompts.d.ts.map +0 -1
- package/dist/repl-new.d.ts +0 -62
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- 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/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,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SubAgent } from "../agent/sub-agent.js";
|
|
3
|
+
import { isSupportedModel } from "../models/providers.js";
|
|
4
|
+
import { environmentInfo } from "../prompts/system-prompt.js";
|
|
5
|
+
import { getSubagent, loadSubagents } from "../subagents/index.js";
|
|
6
|
+
import style from "../terminal/style.js";
|
|
7
|
+
export const AgentTool = {
|
|
8
|
+
name: "Agent",
|
|
9
|
+
};
|
|
10
|
+
async function getToolDescription() {
|
|
11
|
+
return "Delegate a task to a specialized subagent.";
|
|
12
|
+
}
|
|
13
|
+
const inputSchema = z.object({
|
|
14
|
+
prompt: z.string().describe("The task for the agent to perform"),
|
|
15
|
+
type: z.string().describe("The subagent type to use (matches subagent name)"),
|
|
16
|
+
timeout: z
|
|
17
|
+
.number()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Override default timeout in seconds"),
|
|
20
|
+
});
|
|
21
|
+
async function loadSubAgentDefinition(type) {
|
|
22
|
+
const subagent = await getSubagent(type);
|
|
23
|
+
if (!subagent) {
|
|
24
|
+
const available = await loadSubagents();
|
|
25
|
+
const names = available.map((s) => s.name).join(", ");
|
|
26
|
+
throw new Error(`Unknown subagent type: "${type}". Available: ${names}`);
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
model: subagent.model ?? "",
|
|
30
|
+
system: subagent.systemPrompt,
|
|
31
|
+
tools: subagent.tools,
|
|
32
|
+
timeout: subagent.timeout,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export const createAgentTools = async (options) => {
|
|
36
|
+
const description = await getToolDescription();
|
|
37
|
+
const toolDef = {
|
|
38
|
+
description,
|
|
39
|
+
inputSchema,
|
|
40
|
+
};
|
|
41
|
+
function display({ prompt, type }) {
|
|
42
|
+
return `${style.cyan(type)} - ${style.dim(prompt.substring(0, 25))}`;
|
|
43
|
+
}
|
|
44
|
+
async function execute({ prompt, type, timeout }, { abortSignal }) {
|
|
45
|
+
if (abortSignal?.aborted) {
|
|
46
|
+
throw new Error("Agent execution aborted");
|
|
47
|
+
}
|
|
48
|
+
const { model, system, tools, timeout: defaultTimeout, } = await loadSubAgentDefinition(type);
|
|
49
|
+
const systemPrompt = `${system}
|
|
50
|
+
|
|
51
|
+
${await environmentInfo(options.workspace.primaryDir, options.workspace.allowedDirs)}`;
|
|
52
|
+
const subagent = new SubAgent({ workspace: options.workspace });
|
|
53
|
+
const effectiveTimeout = timeout ?? defaultTimeout;
|
|
54
|
+
try {
|
|
55
|
+
const result = await subagent.execute({
|
|
56
|
+
model: isSupportedModel(model) ? model : "opencode:minimax-m2.5-free",
|
|
57
|
+
system: systemPrompt,
|
|
58
|
+
prompt,
|
|
59
|
+
abortSignal,
|
|
60
|
+
allowedTools: tools,
|
|
61
|
+
timeout: effectiveTimeout,
|
|
62
|
+
});
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const err = error;
|
|
67
|
+
const message = err.message || "Unknown error";
|
|
68
|
+
if (message.includes("timed out") ||
|
|
69
|
+
err.name === "AbortError" ||
|
|
70
|
+
err.name === "TimeoutError") {
|
|
71
|
+
return `Agent failed: ${message}. The timeout was ${effectiveTimeout} seconds. Consider increasing the timeout or breaking the task into smaller subtasks.`;
|
|
72
|
+
}
|
|
73
|
+
return `Agent failed: ${message}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
toolDef,
|
|
78
|
+
display,
|
|
79
|
+
execute,
|
|
80
|
+
};
|
|
81
|
+
};
|
package/dist/tools/bash.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { WorkspaceContext } from "../index.ts";
|
|
2
3
|
import type { ToolExecutionOptions } from "./types.ts";
|
|
3
4
|
export declare const BashTool: {
|
|
4
5
|
name: "Bash";
|
|
@@ -10,9 +11,9 @@ declare const inputSchema: z.ZodObject<{
|
|
|
10
11
|
background: z.ZodOptional<z.ZodBoolean>;
|
|
11
12
|
}, z.core.$strip>;
|
|
12
13
|
type BashInputSchema = z.infer<typeof inputSchema>;
|
|
13
|
-
export declare const createBashTool: (
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
export declare const createBashTool: (options: {
|
|
15
|
+
workspace: WorkspaceContext;
|
|
16
|
+
env?: Record<string, string>;
|
|
16
17
|
}) => Promise<{
|
|
17
18
|
toolDef: {
|
|
18
19
|
description: string;
|
package/dist/tools/bash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../source/tools/bash.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../source/tools/bash.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAUpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA0CvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAyLF,QAAA,MAAM,WAAW;;;;;iBAkBf,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc,GAAU,SAAS;IAC5C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;;;;;;;;;;yBAqFwB,eAAe;mDAIK,eAAe,mBACrC,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6BrB,CAAC"}
|
package/dist/tools/bash.js
CHANGED
|
@@ -1,25 +1,219 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
1
|
+
// import { execSync } from "node:child_process";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname } from "node:path";
|
|
2
5
|
import { z } from "zod";
|
|
3
6
|
import { initExecutionEnvironment } from "../execution/index.js";
|
|
4
|
-
import { logger } from "../logger.js";
|
|
5
7
|
import style from "../terminal/style.js";
|
|
6
8
|
import { resolveCwd, validatePaths } from "../utils/bash.js";
|
|
9
|
+
import { detectDestructiveCommand, formatBlockedCommandMessage, } from "../utils/command-protection.js";
|
|
10
|
+
import { expandEnvVars } from "../utils/env-expand.js";
|
|
11
|
+
import { logger } from "../utils/logger.js";
|
|
7
12
|
import { convertNullString } from "../utils/zod.js";
|
|
13
|
+
/**
|
|
14
|
+
* Detects git commit commands with multi-line -m messages that will fail in shell.
|
|
15
|
+
* Writes the message to a temp file and returns an error with the file path.
|
|
16
|
+
* Returns null if the command is safe.
|
|
17
|
+
*/
|
|
18
|
+
function detectMultilineGitCommit(command) {
|
|
19
|
+
const trimmed = command.trim();
|
|
20
|
+
// Check if it's a git commit command
|
|
21
|
+
if (!trimmed.startsWith("git commit") && !trimmed.startsWith("git ")) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// Look for -m or -am flags with a message containing newlines
|
|
25
|
+
// Match patterns like: git commit -m "message\nwith\nnewlines"
|
|
26
|
+
// or: git commit -am "message\nwith\nnewlines"
|
|
27
|
+
// Using [\s\S] instead of [^] to match any character including newlines
|
|
28
|
+
const messageMatch = trimmed.match(/-am?\s+["']([\s\S]*?)["']/);
|
|
29
|
+
if (!messageMatch) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const message = messageMatch[1];
|
|
33
|
+
if (message.includes("\n")) {
|
|
34
|
+
const randomId = randomBytes(4).toString("hex");
|
|
35
|
+
const commitMsgPath = `/tmp/acai/commit-msg-${randomId}.txt`;
|
|
36
|
+
try {
|
|
37
|
+
mkdirSync(dirname(commitMsgPath), { recursive: true });
|
|
38
|
+
writeFileSync(commitMsgPath, message, "utf-8");
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.error(error, "Failed to write commit message to temp file");
|
|
42
|
+
}
|
|
43
|
+
return `Multi-line commit messages with -m flag cause shell parsing errors. The commit message has been written to:
|
|
44
|
+
${commitMsgPath}
|
|
45
|
+
Use: git commit -F ${commitMsgPath}`;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
8
49
|
export const BashTool = {
|
|
9
50
|
name: "Bash",
|
|
10
51
|
};
|
|
11
|
-
const installedTools = getInstalledTools();
|
|
12
|
-
const toolDescription = `Execute commands in a shell. Commands can execute only within the allowed directories. Always use absolute paths.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
52
|
+
// const installedTools = getInstalledTools();
|
|
53
|
+
// const toolDescription = `Execute commands in a shell. Commands can execute only within the allowed directories. Always use absolute paths. Working directory persists between commands; shell state (everything else) does not. The shell environment is initialized from the user's profile (bash or zsh).
|
|
54
|
+
// IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead.
|
|
55
|
+
// Before executing the command, please follow these steps:
|
|
56
|
+
// 1. Directory Verification:
|
|
57
|
+
// - If the command will create new directories or files, first use \`ls\` to verify the parent directory exists and is the correct location
|
|
58
|
+
// - For example, before running "mkdir foo/bar", first use \`ls foo\` to check that "foo" exists and is the intended parent directory
|
|
59
|
+
// 2. Command Execution:
|
|
60
|
+
// - Always quote file paths that contain spaces with double quotes (e.g., cd "path with spaces/file.txt")
|
|
61
|
+
// - Examples of proper quoting:
|
|
62
|
+
// - cd "/Users/name/My Documents" (correct)
|
|
63
|
+
// - cd /Users/name/My Documents (incorrect - will fail)
|
|
64
|
+
// - python "/path/with spaces/script.py" (correct)
|
|
65
|
+
// - python /path/with spaces/script.py (incorrect - will fail)
|
|
66
|
+
// - After ensuring proper quoting, execute the command.
|
|
67
|
+
// - Capture the output of the command.
|
|
68
|
+
// Usage notes:
|
|
69
|
+
// - The command argument is required.
|
|
70
|
+
// - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 120000ms (2 minutes).
|
|
71
|
+
// - It is very helpful if you write a clear, concise description of what this command does. For simple commands, keep it brief (5-10 words). For complex commands (piped commands, obscure flags, or anything hard to understand at a glance), add enough context to clarify what it does.
|
|
72
|
+
// - If the output exceeds 30000 characters, output will be truncated before being returned to you.
|
|
73
|
+
// - You can use the \`background\` parameter to run the command in the background. Only use this if you don't need the result immediately and are OK being notified when the command completes later. You do not need to check the output right away - you'll be notified when it finishes. You do not need to use '&' at the end of the command when using this parameter.
|
|
74
|
+
// - Avoid using Bash with the \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or when these commands are truly necessary for the task. Instead, always prefer using the dedicated tools for these commands:
|
|
75
|
+
// - File listing: Use LS or DirectoryTree (not ls)
|
|
76
|
+
// - File search: Use Glob (NOT find or ls)
|
|
77
|
+
// - Content search: Use Grep (NOT grep or rg)
|
|
78
|
+
// - Read files: Use Read (NOT cat/head/tail)
|
|
79
|
+
// - Edit files: Use Edit (NOT sed/awk)
|
|
80
|
+
// - Write files: Use Write (NOT echo >/cat <<EOF)
|
|
81
|
+
// - Communication: Output text directly (NOT echo/printf)
|
|
82
|
+
// - When issuing multiple commands:
|
|
83
|
+
// - If the commands are independent and can run in parallel, make multiple Bash tool calls in a single message. For example, if you need to run "git status" and "git diff", send a single message with two Bash tool calls in parallel.
|
|
84
|
+
// - If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together (e.g., \`git add . && git commit -m "message" && git push\`). For instance, if one operation must complete before another starts (like mkdir before cp, Write before Bash for git operations, or git add before git commit), run these operations sequentially instead.
|
|
85
|
+
// - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
|
|
86
|
+
// - DO NOT use newlines to separate commands (newlines are ok in quoted strings)
|
|
87
|
+
// - Commands execute in the project root directory by default. Do NOT prepend \`cd <project-root> &&\` to commands—it's unnecessary.
|
|
88
|
+
// - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \`cd\`. You may use \`cd\` if the User explicitly requests it.
|
|
89
|
+
// <good-example>
|
|
90
|
+
// pytest /foo/bar/tests
|
|
91
|
+
// </good-example>
|
|
92
|
+
// <bad-example>
|
|
93
|
+
// cd /foo/bar && pytest tests
|
|
94
|
+
// </bad-example>
|
|
95
|
+
// ### Committing changes with git
|
|
96
|
+
// Only create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:
|
|
97
|
+
// Git Safety Protocol:
|
|
98
|
+
// - NEVER update the git config
|
|
99
|
+
// - NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) unless the user explicitly requests these actions. Taking unauthorized destructive actions is unhelpful and can result in lost work, so it's best to ONLY run these commands when given direct instructions
|
|
100
|
+
// - NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
|
|
101
|
+
// - NEVER run force push to main/master, warn the user if they request it
|
|
102
|
+
// - CRITICAL: Always create NEW commits rather than amending, unless the user explicitly requests a git amend. When a pre-commit hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit, which may result in destroying work or losing previous changes. Instead, after hook failure, fix the issue, re-stage, and create a NEW commit
|
|
103
|
+
// - When staging files, prefer adding specific files by name rather than using "git add -A" or "git add .", which can accidentally include sensitive files (.env, credentials) or large binaries
|
|
104
|
+
// - NEVER commit changes unless the user explicitly asks you to. It is VERY IMPORTANT to only commit when explicitly asked, otherwise the user will feel that you are being too proactive
|
|
105
|
+
// 1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following bash commands in parallel, each using the Bash tool:
|
|
106
|
+
// - Run a git status command to see all untracked files. IMPORTANT: Never use the -uall flag as it can cause memory issues on large repos.
|
|
107
|
+
// - Run a git diff command to see both staged and unstaged changes that will be committed.
|
|
108
|
+
// - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.
|
|
109
|
+
// 2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:
|
|
110
|
+
// - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. "add" means a wholly new feature, "update" means an enhancement to an existing feature, "fix" means a bug fix, etc.).
|
|
111
|
+
// - Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files
|
|
112
|
+
// - Draft a concise (1-2 sentences) commit message that focuses on the "why" rather than the "what"
|
|
113
|
+
// - Ensure it accurately reflects the changes and their purpose
|
|
114
|
+
// 3. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands:
|
|
115
|
+
// - Add relevant untracked files to the staging area.
|
|
116
|
+
// - Run git status after the commit completes to verify success.
|
|
117
|
+
// Note: git status depends on the commit completing, so run it sequentially after the commit.
|
|
118
|
+
// 4. If the commit fails due to pre-commit hook: fix the issue and create a NEW commit
|
|
119
|
+
// Important notes:
|
|
120
|
+
// - NEVER run additional commands to read or explore code, besides git bash commands
|
|
121
|
+
// - DO NOT push to the remote repository unless the user explicitly asks you to do so
|
|
122
|
+
// - IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.
|
|
123
|
+
// - IMPORTANT: Do not use --no-edit with git rebase commands, as the --no-edit flag is not a valid option for git rebase.
|
|
124
|
+
// - If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit
|
|
125
|
+
// - In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:
|
|
126
|
+
// <example>
|
|
127
|
+
// git commit -m "$(cat <<'EOF'
|
|
128
|
+
// Commit message here.
|
|
129
|
+
// EOF
|
|
130
|
+
// )"
|
|
131
|
+
// </example>
|
|
132
|
+
// ### Creating pull requests
|
|
133
|
+
// Use the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.
|
|
134
|
+
// IMPORTANT: When the user asks you to create a pull request, follow these steps carefully:
|
|
135
|
+
// 1. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following bash commands in parallel using the Bash tool, in order to understand the current state of the branch since it diverged from the main branch:
|
|
136
|
+
// - Run a git status command to see all untracked files (never use -uall flag)
|
|
137
|
+
// - Run a git diff command to see both staged and unstaged changes that will be committed
|
|
138
|
+
// - Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote
|
|
139
|
+
// - Run a git log command and \`git diff [base-branch]...HEAD\` to understand the full commit history for the current branch (from the time it diverged from the base branch)
|
|
140
|
+
// 2. Analyze all changes that will be included in the pull request, making sure to look at all relevant commits (NOT just the latest commit, but ALL commits that will be included in the pull request!!!), and draft a pull request title and summary:
|
|
141
|
+
// - Keep the PR title short (under 70 characters)
|
|
142
|
+
// - Use the description/body for details, not the title
|
|
143
|
+
// 3. You can call multiple tools in a single response. When multiple independent pieces of information are requested and all commands are likely to succeed, run multiple tool calls in parallel for optimal performance. run the following commands in parallel:
|
|
144
|
+
// - Create new branch if needed
|
|
145
|
+
// - Push to remote with -u flag if needed
|
|
146
|
+
// - Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.
|
|
147
|
+
// <example>
|
|
148
|
+
// gh pr create --title "the pr title" --body "$(cat <<'EOF'
|
|
149
|
+
// #### Summary
|
|
150
|
+
// <1-3 bullet points>
|
|
151
|
+
// #### Test plan
|
|
152
|
+
// [Bulleted markdown checklist of TODOs for testing the pull request...]
|
|
153
|
+
// EOF
|
|
154
|
+
// )"
|
|
155
|
+
// </example>
|
|
156
|
+
// Important:
|
|
157
|
+
// - Return the PR URL when you're done, so the user can see it
|
|
158
|
+
// ### Other common operations
|
|
159
|
+
// - View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments
|
|
160
|
+
// {
|
|
161
|
+
// "$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
162
|
+
// "type": "object",
|
|
163
|
+
// "properties": {
|
|
164
|
+
// "command": {
|
|
165
|
+
// "description": "The command to execute",
|
|
166
|
+
// "type": "string"
|
|
167
|
+
// },
|
|
168
|
+
// "timeout": {
|
|
169
|
+
// "description": "Optional timeout in milliseconds (max 600000)",
|
|
170
|
+
// "type": "number"
|
|
171
|
+
// },
|
|
172
|
+
// "description": {
|
|
173
|
+
// "description": "Clear, concise description of what this command does in active voice. Never use words like "complex" or "risk" in the description - just describe what it does.\n\nFor simple commands (git, npm, standard CLI tools), keep it brief (5-10 words):\n- ls → "List files in current directory"\n- git status → "Show working tree status"\n- npm install → "Install package dependencies"\n\nFor commands that are harder to parse at a glance (piped commands, obscure flags, etc.), add enough context to clarify what it does:\n- find . -name "*.tmp" -exec rm {} \\; → "Find and delete all .tmp files recursively"\n- git reset --hard origin/main → "Discard all local changes and match remote main"\n- curl -s url | jq '.data[]' → "Fetch JSON from URL and extract data array elements"",
|
|
174
|
+
// "type": "string"
|
|
175
|
+
// },
|
|
176
|
+
// "run_in_background": {
|
|
177
|
+
// "description": "Set to true to run this command in the background. Use TaskOutput to read the output later.",
|
|
178
|
+
// "type": "boolean"
|
|
179
|
+
// },
|
|
180
|
+
// "dangerouslyDisableSandbox": {
|
|
181
|
+
// "description": "Set this to true to dangerously override sandbox mode and run commands without sandboxing.",
|
|
182
|
+
// "type": "boolean"
|
|
183
|
+
// },
|
|
184
|
+
// "_simulatedSedEdit": {
|
|
185
|
+
// "description": "Internal: pre-computed sed edit result from preview",
|
|
186
|
+
// "type": "object",
|
|
187
|
+
// "properties": {
|
|
188
|
+
// "filePath": {
|
|
189
|
+
// "type": "string"
|
|
190
|
+
// },
|
|
191
|
+
// "newContent": {
|
|
192
|
+
// "type": "string"
|
|
193
|
+
// }
|
|
194
|
+
// },
|
|
195
|
+
// "required": [
|
|
196
|
+
// "filePath",
|
|
197
|
+
// "newContent"
|
|
198
|
+
// ],
|
|
199
|
+
// "additionalProperties": false
|
|
200
|
+
// }
|
|
201
|
+
// },
|
|
202
|
+
// "required": [
|
|
203
|
+
// "command"
|
|
204
|
+
// ],
|
|
205
|
+
// "additionalProperties": false
|
|
206
|
+
// }
|
|
207
|
+
// Tools available:
|
|
208
|
+
// ${installedTools}`;
|
|
209
|
+
const simpleDescription = "Run terminal commands.";
|
|
16
210
|
// Command execution timeout in milliseconds
|
|
17
211
|
const DEFAULT_TIMEOUT = 1.5 * 60 * 1000; // 1.5 minutes
|
|
18
212
|
const inputSchema = z.object({
|
|
19
213
|
command: z.string().describe("Full CLI command to execute."),
|
|
20
214
|
cwd: z
|
|
21
215
|
.preprocess((val) => convertNullString(val), z.string().nullable())
|
|
22
|
-
.describe("
|
|
216
|
+
.describe("Optional working directory. Commands execute in the project root by default. Only specify if you need a different directory. Must be within allowed directories."),
|
|
23
217
|
timeout: z
|
|
24
218
|
.preprocess((val) => convertNullString(val), z.coerce.number().nullable())
|
|
25
219
|
.describe(`Command execution timeout in milliseconds. Required but nullable. If null, the default value is ${DEFAULT_TIMEOUT}ms`),
|
|
@@ -28,138 +222,154 @@ const inputSchema = z.object({
|
|
|
28
222
|
.optional()
|
|
29
223
|
.describe("Run command in background. If true, command will run until program exit."),
|
|
30
224
|
});
|
|
31
|
-
export const createBashTool = async (
|
|
32
|
-
const
|
|
33
|
-
const
|
|
225
|
+
export const createBashTool = async (options) => {
|
|
226
|
+
const { primaryDir, allowedDirs } = options.workspace;
|
|
227
|
+
const configEnv = options.env ? expandEnvVars(options.env) : {};
|
|
228
|
+
const execEnv = await initExecutionEnvironment({
|
|
229
|
+
execution: {
|
|
230
|
+
env: {
|
|
231
|
+
...configEnv,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
const allowedDirectories = allowedDirs ?? [primaryDir];
|
|
236
|
+
function validateCommand(command, allowedDirs, cwd) {
|
|
237
|
+
const pathValidation = validatePaths(command, allowedDirs, cwd);
|
|
238
|
+
if (!pathValidation.isValid) {
|
|
239
|
+
throw new Error(pathValidation.error ?? "Unknown error.");
|
|
240
|
+
}
|
|
241
|
+
const multilineError = detectMultilineGitCommit(command);
|
|
242
|
+
if (multilineError) {
|
|
243
|
+
throw new Error(multilineError);
|
|
244
|
+
}
|
|
245
|
+
const destructiveCheck = detectDestructiveCommand(command);
|
|
246
|
+
if (destructiveCheck.blocked) {
|
|
247
|
+
throw new Error(formatBlockedCommandMessage(destructiveCheck));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function processCommand(cmd, isBackground) {
|
|
251
|
+
const stripped = stripTrailingAmpersand(cmd, isBackground);
|
|
252
|
+
return fixRgCommand(stripped);
|
|
253
|
+
}
|
|
254
|
+
function executeBackground(cmd, cwd, signal) {
|
|
255
|
+
const proc = execEnv.executeCommandInBackground(cmd, {
|
|
256
|
+
cwd,
|
|
257
|
+
abortSignal: signal,
|
|
258
|
+
onOutput: (output) => {
|
|
259
|
+
logger.debug({ output }, "Background command output:");
|
|
260
|
+
},
|
|
261
|
+
onError: (error) => {
|
|
262
|
+
logger.debug({ error }, "Background command error:");
|
|
263
|
+
},
|
|
264
|
+
onExit: (code) => {
|
|
265
|
+
logger.debug(`Background command exited with code ${code}`);
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
return `Background process started with PID: ${proc.pid}`;
|
|
269
|
+
}
|
|
270
|
+
async function executeSync(cmd, cwd, timeout, signal) {
|
|
271
|
+
const { output, exitCode } = await execEnv.executeCommand(cmd, {
|
|
272
|
+
cwd,
|
|
273
|
+
timeout,
|
|
274
|
+
abortSignal: signal,
|
|
275
|
+
preserveOutputOnError: true,
|
|
276
|
+
captureStderr: true,
|
|
277
|
+
throwOnError: false,
|
|
278
|
+
});
|
|
279
|
+
if (exitCode !== 0) {
|
|
280
|
+
throw new Error(output);
|
|
281
|
+
}
|
|
282
|
+
return output;
|
|
283
|
+
}
|
|
34
284
|
return {
|
|
35
285
|
toolDef: {
|
|
36
|
-
description:
|
|
286
|
+
description: simpleDescription,
|
|
37
287
|
inputSchema,
|
|
38
288
|
},
|
|
39
289
|
display({ command }) {
|
|
40
|
-
return
|
|
290
|
+
return `${style.cyan(command)}`;
|
|
41
291
|
},
|
|
42
292
|
async execute({ command, cwd, timeout, background }, { abortSignal }) {
|
|
43
293
|
if (abortSignal?.aborted) {
|
|
44
294
|
throw new Error("Command execution aborted");
|
|
45
295
|
}
|
|
46
|
-
// grok doesn't follow my instructions
|
|
47
296
|
const safeCwd = cwd === "null" ? null : cwd;
|
|
48
|
-
const resolvedCwd = resolveCwd(safeCwd,
|
|
297
|
+
const resolvedCwd = resolveCwd(safeCwd, primaryDir, allowedDirectories);
|
|
49
298
|
const safeTimeout = timeout ?? DEFAULT_TIMEOUT;
|
|
50
|
-
|
|
51
|
-
if (!pathValidation.isValid) {
|
|
52
|
-
throw new Error(pathValidation.error ?? "Unknown error.");
|
|
53
|
-
}
|
|
299
|
+
validateCommand(command, allowedDirectories, resolvedCwd);
|
|
54
300
|
if (abortSignal?.aborted) {
|
|
55
301
|
throw new Error("Command execution aborted before running the command");
|
|
56
302
|
}
|
|
57
|
-
|
|
303
|
+
const processedCommand = processCommand(command, background ?? false);
|
|
58
304
|
if (background) {
|
|
59
|
-
|
|
60
|
-
let processedCommand = command.trim();
|
|
61
|
-
if (processedCommand.endsWith("&")) {
|
|
62
|
-
logger.warn(`Stripping '&' from command since background=true: ${command}`);
|
|
63
|
-
processedCommand = processedCommand.slice(0, -1).trim();
|
|
64
|
-
}
|
|
65
|
-
// Fix rg commands that don't have an explicit path
|
|
66
|
-
processedCommand = fixRgCommand(processedCommand);
|
|
67
|
-
const backgroundProcess = execEnv.executeCommandInBackground(processedCommand, {
|
|
68
|
-
cwd: resolvedCwd,
|
|
69
|
-
abortSignal,
|
|
70
|
-
onOutput: (output) => {
|
|
71
|
-
logger.debug({ output }, "Background command output:");
|
|
72
|
-
},
|
|
73
|
-
onError: (error) => {
|
|
74
|
-
logger.debug({ error }, "Background command error:");
|
|
75
|
-
},
|
|
76
|
-
onExit: (code) => {
|
|
77
|
-
logger.debug(`Background command exited with code ${code}`);
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
return `Background process started with PID: ${backgroundProcess.pid}`;
|
|
81
|
-
}
|
|
82
|
-
// Handle regular synchronous execution
|
|
83
|
-
// Strip & if present to ensure synchronous behavior
|
|
84
|
-
let processedCommand = command.trim();
|
|
85
|
-
if (processedCommand.endsWith("&")) {
|
|
86
|
-
logger.warn(`Stripping '&' from command since background=false: ${command}`);
|
|
87
|
-
processedCommand = processedCommand.slice(0, -1).trim();
|
|
88
|
-
}
|
|
89
|
-
// Fix rg commands that don't have an explicit path
|
|
90
|
-
// rg hangs when stdin is a socket and no path is given
|
|
91
|
-
processedCommand = fixRgCommand(processedCommand);
|
|
92
|
-
const { output, exitCode } = await execEnv.executeCommand(processedCommand, {
|
|
93
|
-
cwd: resolvedCwd,
|
|
94
|
-
timeout: safeTimeout,
|
|
95
|
-
abortSignal,
|
|
96
|
-
preserveOutputOnError: true,
|
|
97
|
-
captureStderr: true,
|
|
98
|
-
throwOnError: false,
|
|
99
|
-
});
|
|
100
|
-
if (exitCode !== 0) {
|
|
101
|
-
throw new Error(output);
|
|
305
|
+
return executeBackground(processedCommand, resolvedCwd, abortSignal);
|
|
102
306
|
}
|
|
103
|
-
return
|
|
307
|
+
return executeSync(processedCommand, resolvedCwd, safeTimeout, abortSignal);
|
|
104
308
|
},
|
|
105
309
|
};
|
|
106
310
|
};
|
|
107
|
-
function getInstalledTools() {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
311
|
+
// function getInstalledTools() {
|
|
312
|
+
// // Check for required bash tools
|
|
313
|
+
// const tools = [
|
|
314
|
+
// {
|
|
315
|
+
// name: "git",
|
|
316
|
+
// command: "git --version",
|
|
317
|
+
// description:
|
|
318
|
+
// "Version control system - used for cloning repositories, checking out branches, committing changes, viewing history, and managing code versions",
|
|
319
|
+
// },
|
|
320
|
+
// {
|
|
321
|
+
// name: "gh",
|
|
322
|
+
// command: "gh --version",
|
|
323
|
+
// description:
|
|
324
|
+
// "GitHub CLI - used for creating pull requests, managing issues, interacting with GitHub API, and automating GitHub workflows",
|
|
325
|
+
// },
|
|
326
|
+
// {
|
|
327
|
+
// name: "rg",
|
|
328
|
+
// command: "rg --version",
|
|
329
|
+
// description:
|
|
330
|
+
// "ripgrep - fast text search tool for searching code patterns, file contents, and regular expressions across the codebase (use this instead of grep)",
|
|
331
|
+
// },
|
|
332
|
+
// {
|
|
333
|
+
// name: "fd",
|
|
334
|
+
// command: "fd --version",
|
|
335
|
+
// description:
|
|
336
|
+
// "Fast file finder - alternative to find command, used for finding files by name, pattern, or type with intuitive syntax (use this instead of find)",
|
|
337
|
+
// },
|
|
338
|
+
// {
|
|
339
|
+
// name: "ast-grep",
|
|
340
|
+
// command: "ast-grep --version",
|
|
341
|
+
// description:
|
|
342
|
+
// "AST-based code search - used for structural code search, refactoring, finding patterns in abstract syntax trees, and code transformations",
|
|
343
|
+
// },
|
|
344
|
+
// {
|
|
345
|
+
// name: "jq",
|
|
346
|
+
// command: "jq --version",
|
|
347
|
+
// description:
|
|
348
|
+
// "JSON processor - used for parsing, filtering, and manipulating JSON output from APIs, commands, and configuration files",
|
|
349
|
+
// },
|
|
350
|
+
// {
|
|
351
|
+
// name: "yq",
|
|
352
|
+
// command: "yq --version",
|
|
353
|
+
// description:
|
|
354
|
+
// "YAML processor - used for parsing and manipulating YAML files (configs, CI/CD pipelines, Kubernetes manifests) with jq-like syntax",
|
|
355
|
+
// },
|
|
356
|
+
// ];
|
|
357
|
+
// const toolStatus = tools
|
|
358
|
+
// .map((tool) => {
|
|
359
|
+
// let status = false;
|
|
360
|
+
// try {
|
|
361
|
+
// execSync(tool.command, { stdio: "ignore", timeout: 5000 });
|
|
362
|
+
// status = true;
|
|
363
|
+
// } catch (_error) {
|
|
364
|
+
// // Ignore error, tool is not installed
|
|
365
|
+
// }
|
|
366
|
+
// return { name: tool.name, description: tool.description, status };
|
|
367
|
+
// })
|
|
368
|
+
// .filter((tool) => tool.status)
|
|
369
|
+
// .map((tool) => `- **${tool.name}**: ${tool.description}`)
|
|
370
|
+
// .join("\n");
|
|
371
|
+
// return toolStatus;
|
|
372
|
+
// }
|
|
163
373
|
/**
|
|
164
374
|
* Fix rg commands that don't have an explicit path
|
|
165
375
|
* rg hangs when stdin is a socket and no path is given
|
|
@@ -179,7 +389,7 @@ function fixRgCommand(command) {
|
|
|
179
389
|
}
|
|
180
390
|
// Simple heuristic: if last token starts with -, add .
|
|
181
391
|
// This handles cases like: rg -l pattern --type ts --type js
|
|
182
|
-
const tokens = trimmed.split(
|
|
392
|
+
const tokens = trimmed.split(/\s+/);
|
|
183
393
|
const lastToken = tokens[tokens.length - 1];
|
|
184
394
|
if (lastToken?.startsWith("-")) {
|
|
185
395
|
// Command ends with an option, need to add path
|
|
@@ -214,3 +424,15 @@ function fixRgCommand(command) {
|
|
|
214
424
|
logger.debug(`Adding '.' to rg command: ${command}`);
|
|
215
425
|
return `${command} .`;
|
|
216
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Strips trailing '&' from command and logs a warning.
|
|
429
|
+
* Returns the processed command.
|
|
430
|
+
*/
|
|
431
|
+
function stripTrailingAmpersand(command, isBackground) {
|
|
432
|
+
let processedCommand = command.trim();
|
|
433
|
+
if (processedCommand.endsWith("&")) {
|
|
434
|
+
logger.warn(`Stripping '&' from command since background=${String(isBackground)}: ${command}`);
|
|
435
|
+
processedCommand = processedCommand.slice(0, -1).trim();
|
|
436
|
+
}
|
|
437
|
+
return processedCommand;
|
|
438
|
+
}
|