@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,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Protection Module
|
|
3
|
+
* Detects and blocks destructive commands that could cause data loss
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Detects if a command is destructive and should be blocked
|
|
7
|
+
* @param command - The full command string to check
|
|
8
|
+
* @returns BlockedCommandResult if destructive, SafeCommandResult if safe
|
|
9
|
+
*/
|
|
10
|
+
export function detectDestructiveCommand(command) {
|
|
11
|
+
const trimmed = command.trim();
|
|
12
|
+
// Check for dangerous inline scripts first (bash -c, python -c, etc.)
|
|
13
|
+
const inlineScriptResult = detectDangerousInlineScripts(trimmed);
|
|
14
|
+
if (inlineScriptResult.blocked) {
|
|
15
|
+
return inlineScriptResult;
|
|
16
|
+
}
|
|
17
|
+
// Check for dangerous heredocs
|
|
18
|
+
const heredocResult = detectDangerousHeredocs(trimmed);
|
|
19
|
+
if (heredocResult.blocked) {
|
|
20
|
+
return heredocResult;
|
|
21
|
+
}
|
|
22
|
+
// Check for destructive git commands
|
|
23
|
+
const gitResult = detectDestructiveGitCommands(trimmed);
|
|
24
|
+
if (gitResult.blocked) {
|
|
25
|
+
return gitResult;
|
|
26
|
+
}
|
|
27
|
+
// Check for dangerous rm -rf commands
|
|
28
|
+
const rmResult = detectDangerousRmRf(trimmed);
|
|
29
|
+
if (rmResult.blocked) {
|
|
30
|
+
return rmResult;
|
|
31
|
+
}
|
|
32
|
+
return { blocked: false };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Detect destructive git commands
|
|
36
|
+
*/
|
|
37
|
+
function detectDestructiveGitCommands(command) {
|
|
38
|
+
const lowerCommand = command.toLowerCase();
|
|
39
|
+
// Block git reset --hard and --merge
|
|
40
|
+
if (lowerCommand.includes("git reset --hard") ||
|
|
41
|
+
lowerCommand.includes("git reset --merge")) {
|
|
42
|
+
return {
|
|
43
|
+
blocked: true,
|
|
44
|
+
reason: "git reset --hard or --merge destroys uncommitted changes",
|
|
45
|
+
command,
|
|
46
|
+
tip: "Consider using 'git stash' first to save your changes, or use 'git reset --soft' to preserve changes.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Block git checkout -- <file> (discarding local changes)
|
|
50
|
+
if (lowerCommand.match(/git\s+checkout\s+--\s+\S+/)) {
|
|
51
|
+
return {
|
|
52
|
+
blocked: true,
|
|
53
|
+
reason: "git checkout -- <file> discards uncommitted file changes",
|
|
54
|
+
command,
|
|
55
|
+
tip: "Use 'git restore --staged <file>' to unstage changes, or 'git stash' to save changes temporarily.",
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Block git restore without --staged (discards uncommitted changes)
|
|
59
|
+
if (lowerCommand.startsWith("git restore") &&
|
|
60
|
+
!lowerCommand.includes(" --staged")) {
|
|
61
|
+
// Check if it's restoring files (not branches)
|
|
62
|
+
const afterRestore = lowerCommand.substring("git restore".length).trim();
|
|
63
|
+
if (afterRestore && !afterRestore.startsWith("-b")) {
|
|
64
|
+
return {
|
|
65
|
+
blocked: true,
|
|
66
|
+
reason: "git restore <file> (without --staged) discards uncommitted changes",
|
|
67
|
+
command,
|
|
68
|
+
tip: "Use 'git restore --staged <file>' to only unstage, or 'git stash' to save changes.",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Block git clean -f (force deletes untracked files)
|
|
73
|
+
if (lowerCommand.includes("git clean -f") ||
|
|
74
|
+
lowerCommand.includes("git clean --force")) {
|
|
75
|
+
return {
|
|
76
|
+
blocked: true,
|
|
77
|
+
reason: "git clean -f permanently deletes untracked files",
|
|
78
|
+
command,
|
|
79
|
+
tip: "Use 'git clean -n' to preview what would be deleted, or 'git clean -f -d' to only delete untracked directories.",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// Block force push (but allow --force-with-lease which is safer)
|
|
83
|
+
if ((lowerCommand.includes("git push --force") &&
|
|
84
|
+
!lowerCommand.includes("--force-with-lease")) ||
|
|
85
|
+
lowerCommand.match(/git\s+push\s+-f\b/)) {
|
|
86
|
+
return {
|
|
87
|
+
blocked: true,
|
|
88
|
+
reason: "git push --force overwrites remote commit history",
|
|
89
|
+
command,
|
|
90
|
+
tip: "Use 'git push --force-with-lease' for safer force pushes, or prefer creating a new branch instead.",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Block git branch -D (force delete without merge check)
|
|
94
|
+
if (lowerCommand.match(/git\s+branch\s+-[a-z]/)) {
|
|
95
|
+
// Check if it's an uppercase letter (force delete)
|
|
96
|
+
const match = lowerCommand.match(/git\s+branch\s+-[a-z]/);
|
|
97
|
+
if (match && match[0].slice(-1) !== match[0].slice(-1).toLowerCase()) {
|
|
98
|
+
// It's uppercase, block it
|
|
99
|
+
}
|
|
100
|
+
else if (match) {
|
|
101
|
+
const upperMatch = command.match(/git\s+branch\s+-[A-Z]/);
|
|
102
|
+
if (upperMatch) {
|
|
103
|
+
return {
|
|
104
|
+
blocked: true,
|
|
105
|
+
reason: "git branch -D force-deletes branches without checking if they're merged",
|
|
106
|
+
command,
|
|
107
|
+
tip: "Use 'git branch -d' (lowercase) to safely delete branches that are merged.",
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Block git stash drop and git stash clear
|
|
113
|
+
if (lowerCommand.includes("git stash drop") ||
|
|
114
|
+
lowerCommand.includes("git stash clear")) {
|
|
115
|
+
return {
|
|
116
|
+
blocked: true,
|
|
117
|
+
reason: "git stash drop/clear permanently deletes stashed changes",
|
|
118
|
+
command,
|
|
119
|
+
tip: "Use 'git stash list' to see stashes, or 'git stash pop' to apply and remove a stash.",
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return { blocked: false };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Detect dangerous rm -rf commands outside of temporary directories
|
|
126
|
+
*/
|
|
127
|
+
function detectDangerousRmRf(command) {
|
|
128
|
+
// Check for rm -rf pattern (case insensitive)
|
|
129
|
+
const rmMatch = command.match(/rm\s+-rf\s+/i);
|
|
130
|
+
if (!rmMatch || rmMatch.index === undefined) {
|
|
131
|
+
return { blocked: false };
|
|
132
|
+
}
|
|
133
|
+
// Extract the path argument
|
|
134
|
+
const matchIndex = rmMatch.index + rmMatch[0].length;
|
|
135
|
+
const afterRmRf = command.substring(matchIndex).trim();
|
|
136
|
+
// If no path specified, don't block (will fail naturally)
|
|
137
|
+
if (!afterRmRf) {
|
|
138
|
+
return { blocked: false };
|
|
139
|
+
}
|
|
140
|
+
// Get temporary directory paths
|
|
141
|
+
const tempDirs = ["/tmp", "/var/tmp", process.env["TMPDIR"] || "/tmp"];
|
|
142
|
+
// Check if the path is explicitly targeting only temp directories
|
|
143
|
+
// This handles: rm -rf /tmp/*, rm -rf /var/tmp/*, rm -rf $TMPDIR/*, and any subpaths
|
|
144
|
+
const isTempDirectoryOnly = tempDirs.some((tempDir) => {
|
|
145
|
+
// Check if path starts with temp directory (e.g., /tmp/foo, /tmp/*)
|
|
146
|
+
if (afterRmRf === tempDir || afterRmRf.startsWith(`${tempDir}/`)) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
});
|
|
151
|
+
// Also check for $TMPDIR/* pattern (literal strings)
|
|
152
|
+
// Using string concatenation to avoid lint warnings about template-like strings
|
|
153
|
+
const tmpDirVar = "$" + "TMPDIR";
|
|
154
|
+
const tmpDirVarBraces = "$" + "{TMPDIR}";
|
|
155
|
+
if (afterRmRf === tmpDirVar ||
|
|
156
|
+
afterRmRf.startsWith(`${tmpDirVar}/`) ||
|
|
157
|
+
afterRmRf === tmpDirVarBraces ||
|
|
158
|
+
afterRmRf.startsWith(`${tmpDirVarBraces}/`)) {
|
|
159
|
+
return { blocked: false };
|
|
160
|
+
}
|
|
161
|
+
if (isTempDirectoryOnly) {
|
|
162
|
+
return { blocked: false };
|
|
163
|
+
}
|
|
164
|
+
// Block any other rm -rf
|
|
165
|
+
return {
|
|
166
|
+
blocked: true,
|
|
167
|
+
reason: "rm -rf outside of temporary directories can cause permanent data loss",
|
|
168
|
+
command,
|
|
169
|
+
tip: "Only rm -rf is allowed for /tmp/*, /var/tmp/*, or $TMPDIR/* to clean temporary files.",
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Detect dangerous patterns in inline scripts (-c flags)
|
|
174
|
+
*/
|
|
175
|
+
function detectDangerousInlineScripts(command) {
|
|
176
|
+
// Check for common inline script patterns and scan the content after -c for destructive commands
|
|
177
|
+
const languagePatterns = [
|
|
178
|
+
{ pattern: /\bbash\s+-c\s+\S+/i, language: "bash" },
|
|
179
|
+
{ pattern: /\bsh\s+-c\s+\S+/i, language: "sh" },
|
|
180
|
+
{ pattern: /\bpython\d?\s+-c\s+\S+/i, language: "Python" },
|
|
181
|
+
{ pattern: /\bnode\s+-e\s+\S+/i, language: "Node.js" },
|
|
182
|
+
{ pattern: /\bnpx\s+-c\s+\S+/i, language: "npx" },
|
|
183
|
+
{ pattern: /\bruby\s+-e\s+\S+/i, language: "Ruby" },
|
|
184
|
+
{ pattern: /\bperl\s+-e\s+\S+/i, language: "Perl" },
|
|
185
|
+
];
|
|
186
|
+
for (const { pattern, language } of languagePatterns) {
|
|
187
|
+
if (pattern.test(command)) {
|
|
188
|
+
// Found an inline script, scan the command for destructive patterns
|
|
189
|
+
// Look for patterns after -c flag, handling nested quotes
|
|
190
|
+
const destructivePatterns = [
|
|
191
|
+
/git\s+reset\s+--hard/i,
|
|
192
|
+
/git\s+reset\s+--merge/i,
|
|
193
|
+
/git\s+clean\s+-f/i,
|
|
194
|
+
/git\s+checkout\s+--\s+\S+/i,
|
|
195
|
+
/git\s+push\s+(-f|--force)/i,
|
|
196
|
+
/git\s+branch\s+-[A-Z]/i,
|
|
197
|
+
/git\s+stash\s+(drop|clear)/i,
|
|
198
|
+
/rm\s+-rf\s+\/home/i,
|
|
199
|
+
/rm\s+-rf\s+\/usr/i,
|
|
200
|
+
/rm\s+-rf\s+~/i,
|
|
201
|
+
];
|
|
202
|
+
// Check if any destructive pattern is present in the command
|
|
203
|
+
for (const destructivePattern of destructivePatterns) {
|
|
204
|
+
if (destructivePattern.test(command)) {
|
|
205
|
+
return {
|
|
206
|
+
blocked: true,
|
|
207
|
+
reason: `Inline ${language} script contains destructive operation`,
|
|
208
|
+
command,
|
|
209
|
+
tip: "Review the script content for destructive commands.",
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return { blocked: false };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Detect dangerous patterns in heredocs and here-strings
|
|
219
|
+
*/
|
|
220
|
+
function detectDangerousHeredocs(command) {
|
|
221
|
+
// Match heredoc patterns: <<EOF ... EOF
|
|
222
|
+
const heredocPattern = /<<-?\s*['"]?(\w+)['"]?\s*([\s\S]*?)\n\1\b/gi;
|
|
223
|
+
let match = null;
|
|
224
|
+
match = heredocPattern.exec(command);
|
|
225
|
+
while (match !== null) {
|
|
226
|
+
const heredocContent = match[2];
|
|
227
|
+
const heredocResult = detectDangerousScriptContent(heredocContent);
|
|
228
|
+
if (heredocResult.blocked) {
|
|
229
|
+
return {
|
|
230
|
+
blocked: true,
|
|
231
|
+
reason: "Heredoc contains destructive operation",
|
|
232
|
+
command,
|
|
233
|
+
tip: heredocResult.tip ||
|
|
234
|
+
"Review the heredoc content for destructive commands.",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
match = heredocPattern.exec(command);
|
|
238
|
+
}
|
|
239
|
+
// Match here-string patterns (<<<)
|
|
240
|
+
const hereStringPattern = /<<<\s*(['"])([^"']+)\1/gi;
|
|
241
|
+
match = null;
|
|
242
|
+
match = hereStringPattern.exec(command);
|
|
243
|
+
while (match !== null) {
|
|
244
|
+
const stringContent = match[2];
|
|
245
|
+
const stringResult = detectDangerousScriptContent(stringContent);
|
|
246
|
+
if (stringResult.blocked) {
|
|
247
|
+
return {
|
|
248
|
+
blocked: true,
|
|
249
|
+
reason: "Here-string contains destructive operation",
|
|
250
|
+
command,
|
|
251
|
+
tip: stringResult.tip ||
|
|
252
|
+
"Review the here-string content for destructive commands.",
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
match = hereStringPattern.exec(command);
|
|
256
|
+
}
|
|
257
|
+
return { blocked: false };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Check script content for dangerous patterns
|
|
261
|
+
*/
|
|
262
|
+
function detectDangerousScriptContent(content) {
|
|
263
|
+
const lowerContent = content.toLowerCase();
|
|
264
|
+
// Check for destructive git commands within scripts
|
|
265
|
+
const dangerousGitPatterns = [
|
|
266
|
+
/\bgit\s+reset\s+(--hard|--merge|--keep)\b/i,
|
|
267
|
+
/\bgit\s+clean\s+-f\b/i,
|
|
268
|
+
/\bgit\s+checkout\s+--\s+\S+/i,
|
|
269
|
+
/\bgit\s+restore\s+(?!--staged)\s+\S+/i,
|
|
270
|
+
/\bgit\s+push\s+(-f|--force)\b/i,
|
|
271
|
+
/\bgit\s+branch\s+-[D]\b/i,
|
|
272
|
+
/\bgit\s+stash\s+(drop|clear)\b/i,
|
|
273
|
+
];
|
|
274
|
+
for (const pattern of dangerousGitPatterns) {
|
|
275
|
+
if (pattern.test(lowerContent)) {
|
|
276
|
+
return {
|
|
277
|
+
blocked: true,
|
|
278
|
+
tip: "The script contains a destructive git command. Review the script content.",
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Check for dangerous rm -rf patterns (more permissive for scripts, block obvious dangers)
|
|
283
|
+
const dangerousRmPatterns = [
|
|
284
|
+
/\brm\s+-rf\s+\/[^\s*]*[a-z]/i, // rm -rf /something (but allow /tmp/* patterns)
|
|
285
|
+
/\brm\s+-rf\s+\/home/i,
|
|
286
|
+
/\brm\s+-rf\s+\/usr/i,
|
|
287
|
+
/\brm\s+-rf\s+\/etc/i,
|
|
288
|
+
/\brm\s+-rf\s+\/var\s*$/i, // Block /var alone but allow /var/tmp
|
|
289
|
+
/\brm\s+-rf\s+~(?!\/)/i, // rm -rf ~ but allow ~/tmp
|
|
290
|
+
];
|
|
291
|
+
for (const pattern of dangerousRmPatterns) {
|
|
292
|
+
if (pattern.test(content)) {
|
|
293
|
+
return {
|
|
294
|
+
blocked: true,
|
|
295
|
+
tip: "The script contains a dangerous rm -rf command.",
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Check for format string attacks and other dangerous patterns
|
|
300
|
+
const dangerousPatterns = [
|
|
301
|
+
/\brm\s+-rf\s+\$\w+/i, // rm -rf $VAR (variable expansion could be dangerous)
|
|
302
|
+
];
|
|
303
|
+
for (const pattern of dangerousPatterns) {
|
|
304
|
+
if (pattern.test(content)) {
|
|
305
|
+
return {
|
|
306
|
+
blocked: true,
|
|
307
|
+
tip: "The script contains a potentially dangerous rm command with variable expansion.",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return { blocked: false };
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Generate a user-friendly blocked command message
|
|
315
|
+
*/
|
|
316
|
+
export function formatBlockedCommandMessage(result) {
|
|
317
|
+
return `BLOCKED
|
|
318
|
+
|
|
319
|
+
Reason: ${result.reason}
|
|
320
|
+
|
|
321
|
+
Command: ${result.command}
|
|
322
|
+
|
|
323
|
+
Tip: ${result.tip}`;
|
|
324
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedent.d.ts","sourceRoot":"","sources":["../../source/utils/dedent.ts"],"names":[],"mappings":"AAAA,KAAK,MAAM,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC;AAI9E,eAAO,MAAM,MAAM,EAAE,MA+CpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-expand.d.ts","sourceRoot":"","sources":["../../source/utils/env-expand.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUxB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const ENV_VAR_PATTERN = /\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
2
|
+
export function expandEnvVars(vars) {
|
|
3
|
+
const result = {};
|
|
4
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
5
|
+
result[key] = value.replace(ENV_VAR_PATTERN, (_match, bracedName, plainName) => process.env[bracedName ?? plainName ?? ""] ?? "");
|
|
6
|
+
}
|
|
7
|
+
return result;
|
|
8
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an absolute path to a relative path for display purposes.
|
|
3
|
+
* If the path is within the current working directory, returns the relative path.
|
|
4
|
+
* Otherwise, returns the absolute path unchanged.
|
|
5
|
+
*
|
|
6
|
+
* @param absolutePath - The absolute path to convert
|
|
7
|
+
* @param cwd - The current working directory (defaults to process.cwd())
|
|
8
|
+
* @returns The display-ready path (relative if within cwd, absolute otherwise)
|
|
9
|
+
*/
|
|
10
|
+
export declare function toDisplayPath(absolutePath: string | undefined | null, cwd?: string): string;
|
|
11
|
+
//# sourceMappingURL=path-display.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-display.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/path-display.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EACvC,GAAG,GAAE,MAAsB,GAC1B,MAAM,CA0BR"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Converts an absolute path to a relative path for display purposes.
|
|
4
|
+
* If the path is within the current working directory, returns the relative path.
|
|
5
|
+
* Otherwise, returns the absolute path unchanged.
|
|
6
|
+
*
|
|
7
|
+
* @param absolutePath - The absolute path to convert
|
|
8
|
+
* @param cwd - The current working directory (defaults to process.cwd())
|
|
9
|
+
* @returns The display-ready path (relative if within cwd, absolute otherwise)
|
|
10
|
+
*/
|
|
11
|
+
export function toDisplayPath(absolutePath, cwd = process.cwd()) {
|
|
12
|
+
if (!absolutePath) {
|
|
13
|
+
return ".";
|
|
14
|
+
}
|
|
15
|
+
// If path is already relative, return as-is
|
|
16
|
+
if (!path.isAbsolute(absolutePath)) {
|
|
17
|
+
return absolutePath;
|
|
18
|
+
}
|
|
19
|
+
// Try to get relative path
|
|
20
|
+
const relativePath = path.relative(cwd, absolutePath);
|
|
21
|
+
// If relative path starts with '..', it means the path is outside cwd
|
|
22
|
+
// Return absolute path in that case
|
|
23
|
+
if (relativePath.startsWith("..")) {
|
|
24
|
+
return absolutePath;
|
|
25
|
+
}
|
|
26
|
+
// If relative path is empty (path equals cwd), return '.'
|
|
27
|
+
if (relativePath === "") {
|
|
28
|
+
return ".";
|
|
29
|
+
}
|
|
30
|
+
// Return relative path
|
|
31
|
+
return relativePath;
|
|
32
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Config } from "../../config/index.ts";
|
|
2
2
|
export declare function joinWorkingDir(userPath: string, workingDir: string): string;
|
|
3
3
|
export declare function isPathWithinAllowedDirs(requestedPath: string, allowedDirs: string[]): boolean;
|
|
4
4
|
export declare function validatePath(requestedPath: string, allowedDirectory: string | string[], options?: {
|
|
5
5
|
requireExistence?: boolean;
|
|
6
6
|
abortSignal?: AbortSignal;
|
|
7
7
|
}): Promise<string>;
|
|
8
|
-
export declare function validateFileNotReadOnly(filePath: string, config:
|
|
8
|
+
export declare function validateFileNotReadOnly(filePath: string, config: Config, workingDir: string): void;
|
|
9
9
|
//# sourceMappingURL=security.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/security.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../source/utils/filesystem/security.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAsCpD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK3E;AAoCD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAIT;AAsCD,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,GAAG,MAAM,EAAE,EACnC,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CAAO,GACtE,OAAO,CAAC,MAAM,CAAC,CAmGjB;AA8BD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,IAAI,CAIN"}
|
|
@@ -77,6 +77,33 @@ function isPathWithinBaseDir(requestedPath, baseDir) {
|
|
|
77
77
|
export function isPathWithinAllowedDirs(requestedPath, allowedDirs) {
|
|
78
78
|
return allowedDirs.some((allowedDir) => isPathWithinBaseDir(requestedPath, allowedDir));
|
|
79
79
|
}
|
|
80
|
+
async function resolveValidAncestor(startDir, isWithinAllowed) {
|
|
81
|
+
let current = startDir;
|
|
82
|
+
while (true) {
|
|
83
|
+
try {
|
|
84
|
+
const stat = await fs.stat(current);
|
|
85
|
+
if (!stat.isDirectory()) {
|
|
86
|
+
throw new Error(`Nearest existing ancestor is not a directory: ${current}`);
|
|
87
|
+
}
|
|
88
|
+
const realAncestor = await fs.realpath(current);
|
|
89
|
+
const normalizedAncestor = normalizePath(realAncestor);
|
|
90
|
+
if (!isWithinAllowed(normalizedAncestor)) {
|
|
91
|
+
throw new Error("Access denied - ancestor directory resolves outside allowed directories");
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err instanceof Error && err.message.startsWith("Access denied")) {
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
const parent = path.dirname(current);
|
|
100
|
+
if (parent === current) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
current = parent;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
80
107
|
// Security utilities
|
|
81
108
|
export async function validatePath(requestedPath, allowedDirectory, options = {}) {
|
|
82
109
|
const { requireExistence = true, abortSignal } = options;
|
|
@@ -136,36 +163,7 @@ export async function validatePath(requestedPath, allowedDirectory, options = {}
|
|
|
136
163
|
catch (_error) {
|
|
137
164
|
// For new files or paths where some directories don't exist yet:
|
|
138
165
|
// Walk up to the nearest existing ancestor directory and validate it.
|
|
139
|
-
|
|
140
|
-
let foundValidAncestor = false;
|
|
141
|
-
while (true) {
|
|
142
|
-
try {
|
|
143
|
-
const stat = await fs.stat(current);
|
|
144
|
-
if (!stat.isDirectory()) {
|
|
145
|
-
throw new Error(`Nearest existing ancestor is not a directory: ${current}`);
|
|
146
|
-
}
|
|
147
|
-
const realAncestor = await fs.realpath(current);
|
|
148
|
-
const normalizedAncestor = normalizePath(realAncestor);
|
|
149
|
-
if (!isWithinAllowed(normalizedAncestor)) {
|
|
150
|
-
throw new Error("Access denied - ancestor directory resolves outside allowed directories");
|
|
151
|
-
}
|
|
152
|
-
// Ancestor is within allowed; allow creation below it.
|
|
153
|
-
foundValidAncestor = true;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
// If it's a security denial, rethrow
|
|
158
|
-
if (err instanceof Error && err.message.startsWith("Access denied")) {
|
|
159
|
-
throw err;
|
|
160
|
-
}
|
|
161
|
-
// If we reached the filesystem root, break to fallback check
|
|
162
|
-
const parent = path.dirname(current);
|
|
163
|
-
if (parent === current) {
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
current = parent;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
166
|
+
const foundValidAncestor = await resolveValidAncestor(path.dirname(absolute), isWithinAllowed);
|
|
169
167
|
if (!foundValidAncestor) {
|
|
170
168
|
// Rely on intended path check
|
|
171
169
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../source/utils/formatting.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,GACjB,MAAM,CAaR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,GACjB,MAAM,CAWR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIrE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,GACjB,MAAM,CAWR;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MACG,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,MASjD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,GAAI,cAAc,MAAM,KAAG,MAuCrD,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MAwC1C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,IAAI,KAAG,MASvC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAGvD,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module formatting
|
|
6
6
|
*/
|
|
7
7
|
import path from "node:path";
|
|
8
|
-
import { getCodeblockFromFilePath } from "./
|
|
8
|
+
import { getCodeblockFromFilePath } from "./filetype-detection.js";
|
|
9
9
|
const MD_TRIPLE_QUOTE = "```";
|
|
10
10
|
/**
|
|
11
11
|
* Formats file content with metadata in the specified format.
|
package/dist/utils/git.d.ts
CHANGED
|
@@ -18,4 +18,8 @@ export declare function hasUncommittedChanges(): Promise<boolean>;
|
|
|
18
18
|
* Get the current git branch name
|
|
19
19
|
*/
|
|
20
20
|
export declare function getCurrentBranch(): Promise<string | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Count commits that exist locally but haven't been pushed to the remote branch
|
|
23
|
+
*/
|
|
24
|
+
export declare function getUnpushedCommitsCount(): Promise<number>;
|
|
21
25
|
//# sourceMappingURL=git.d.ts.map
|
package/dist/utils/git.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../source/utils/git.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW;;;;GAyDhC;AAED,wBAAsB,YAAY;;;;;GAmCjC;AAED,eAAO,MAAM,cAAc,QAAqB,OAAO,CAAC,OAAO,CAS7D,CAAC;AAEH;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAY9D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkB/D"}
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../source/utils/git.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW;;;;GAyDhC;AAED,wBAAsB,YAAY;;;;;GAmCjC;AAED,eAAO,MAAM,cAAc,QAAqB,OAAO,CAAC,OAAO,CAS7D,CAAC;AAEH;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAY9D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkB/D;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC,CAmC/D"}
|
package/dist/utils/git.js
CHANGED
|
@@ -133,3 +133,33 @@ export async function getCurrentBranch() {
|
|
|
133
133
|
return null;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Count commits that exist locally but haven't been pushed to the remote branch
|
|
138
|
+
*/
|
|
139
|
+
export async function getUnpushedCommitsCount() {
|
|
140
|
+
try {
|
|
141
|
+
// First, check if there's a remote configured
|
|
142
|
+
const remoteResult = await executeCommand(["git", "rev-parse", "--abbrev-ref", "@{u}"], {
|
|
143
|
+
cwd: process.cwd(),
|
|
144
|
+
throwOnError: false,
|
|
145
|
+
});
|
|
146
|
+
if (remoteResult.code !== 0) {
|
|
147
|
+
// No upstream configured or no remote
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
// Count unpushed commits using git rev-list
|
|
151
|
+
// @{u}..HEAD gives commits in HEAD but not in upstream (unpushed commits)
|
|
152
|
+
const result = await executeCommand(["git", "rev-list", "--count", "@{u}..HEAD"], {
|
|
153
|
+
cwd: process.cwd(),
|
|
154
|
+
throwOnError: false,
|
|
155
|
+
});
|
|
156
|
+
if (result.code !== 0 || !result.stdout.trim()) {
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
const count = Number.parseInt(result.stdout.trim(), 10);
|
|
160
|
+
return Number.isNaN(count) ? 0 : count;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
}
|
package/dist/utils/glob.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ type ExpandDirectoriesOption = boolean | readonly string[] | {
|
|
|
4
4
|
extensions?: readonly string[];
|
|
5
5
|
};
|
|
6
6
|
type FastGlobOptionsWithoutCwd = Omit<FastGlobOptions, "cwd">;
|
|
7
|
-
type Options = {
|
|
7
|
+
export type Options = {
|
|
8
8
|
/**
|
|
9
9
|
* If set to `true`, `glob` will automatically glob directories for you. If you define an `Array` it will only glob files that matches the patterns inside the `Array`. You can also define an `Object` with `files` and `extensions` like in the example below.
|
|
10
10
|
*
|
package/dist/utils/glob.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/utils/glob.ts"],"names":[],"mappings":"AAIA,OAAW,EAAc,KAAK,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAgB5E,KAAK,uBAAuB,GACxB,OAAO,GACP,SAAS,MAAM,EAAE,GACjB;IAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAElE,KAAK,yBAAyB,GAAG,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;AAE9D,
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/utils/glob.ts"],"names":[],"mappings":"AAIA,OAAW,EAAc,KAAK,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAgB5E,KAAK,uBAAuB,GACxB,OAAO,GACP,SAAS,MAAM,EAAE,GACjB;IAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAElE,KAAK,yBAAyB,GAAG,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;AAE9D,MAAM,MAAM,OAAO,GAAG;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,uBAAuB,CAAC;IAErD;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAElD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC;CAC7B,GAAG,yBAAyB,CAAC;AA6U9B;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,8DAtLa,OAAO,sBAoMpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../source/utils/logger.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AAgDxB,eAAO,MAAM,MAAM,6BAIjB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import pino from "pino";
|
|
3
|
-
import { config } from "
|
|
3
|
+
import { config } from "../config/index.js";
|
|
4
4
|
// Create a lazy logger factory that only initializes when first used
|
|
5
5
|
let loggerInstance = null;
|
|
6
6
|
function createLogger() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parsing.d.ts","sourceRoot":"","sources":["../../source/utils/parsing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBtC,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,8CAE1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../source/utils/process.ts"],"names":[],"mappings":"AAOA,UAAU,cAAc;IACtB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mGAAmG;IACnG,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;CACzB;AAED,KAAK,WAAW,GACZ;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;CAAE,GACzC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../source/utils/process.ts"],"names":[],"mappings":"AAOA,UAAU,cAAc;IACtB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,sDAAsD;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mGAAmG;IACnG,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;CACzB;AAED,KAAK,WAAW,GACZ;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;CAAE,GACzC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAwGjC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA8DpD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,EACvC,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,aAAa,CAAC,CAqGxB"}
|