@qduc/term2 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/agent.d.ts +19 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +143 -0
- package/dist/agent.js.map +1 -0
- package/dist/app.d.ts +22 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +403 -0
- package/dist/app.js.map +1 -0
- package/dist/app.model-command-feedback.test.d.ts +2 -0
- package/dist/app.model-command-feedback.test.d.ts.map +1 -0
- package/dist/app.model-command-feedback.test.js +19 -0
- package/dist/app.model-command-feedback.test.js.map +1 -0
- package/dist/app.parseInput.test.d.ts +2 -0
- package/dist/app.parseInput.test.d.ts.map +1 -0
- package/dist/app.parseInput.test.js +97 -0
- package/dist/app.parseInput.test.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +241 -0
- package/dist/cli.js.map +1 -0
- package/dist/components/ApprovalPrompt.d.ts +10 -0
- package/dist/components/ApprovalPrompt.d.ts.map +1 -0
- package/dist/components/ApprovalPrompt.js +163 -0
- package/dist/components/ApprovalPrompt.js.map +1 -0
- package/dist/components/Banner.d.ts +9 -0
- package/dist/components/Banner.d.ts.map +1 -0
- package/dist/components/Banner.js +86 -0
- package/dist/components/Banner.js.map +1 -0
- package/dist/components/BottomArea.d.ts +33 -0
- package/dist/components/BottomArea.d.ts.map +1 -0
- package/dist/components/BottomArea.js +31 -0
- package/dist/components/BottomArea.js.map +1 -0
- package/dist/components/BottomArea.test.d.ts +2 -0
- package/dist/components/BottomArea.test.d.ts.map +1 -0
- package/dist/components/BottomArea.test.js +73 -0
- package/dist/components/BottomArea.test.js.map +1 -0
- package/dist/components/ChatMessage.d.ts +7 -0
- package/dist/components/ChatMessage.d.ts.map +1 -0
- package/dist/components/ChatMessage.js +10 -0
- package/dist/components/ChatMessage.js.map +1 -0
- package/dist/components/CommandMessage.d.ts +15 -0
- package/dist/components/CommandMessage.d.ts.map +1 -0
- package/dist/components/CommandMessage.js +188 -0
- package/dist/components/CommandMessage.js.map +1 -0
- package/dist/components/CommandMessage.test.d.ts +2 -0
- package/dist/components/CommandMessage.test.d.ts.map +1 -0
- package/dist/components/CommandMessage.test.js +35 -0
- package/dist/components/CommandMessage.test.js.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +27 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.js +77 -0
- package/dist/components/ErrorBoundary.js.map +1 -0
- package/dist/components/ErrorBoundary.test.d.ts +2 -0
- package/dist/components/ErrorBoundary.test.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.test.js +32 -0
- package/dist/components/ErrorBoundary.test.js.map +1 -0
- package/dist/components/Input/PopupManager.d.ts +42 -0
- package/dist/components/Input/PopupManager.d.ts.map +1 -0
- package/dist/components/Input/PopupManager.js +13 -0
- package/dist/components/Input/PopupManager.js.map +1 -0
- package/dist/components/InputBox.d.ts +18 -0
- package/dist/components/InputBox.d.ts.map +1 -0
- package/dist/components/InputBox.js +384 -0
- package/dist/components/InputBox.js.map +1 -0
- package/dist/components/InputBox.menu-logic.test.d.ts +2 -0
- package/dist/components/InputBox.menu-logic.test.d.ts.map +1 -0
- package/dist/components/InputBox.menu-logic.test.js +151 -0
- package/dist/components/InputBox.menu-logic.test.js.map +1 -0
- package/dist/components/InputBox.test.d.ts +2 -0
- package/dist/components/InputBox.test.d.ts.map +1 -0
- package/dist/components/InputBox.test.js +91 -0
- package/dist/components/InputBox.test.js.map +1 -0
- package/dist/components/LiveResponse.d.ts +13 -0
- package/dist/components/LiveResponse.d.ts.map +1 -0
- package/dist/components/LiveResponse.js +16 -0
- package/dist/components/LiveResponse.js.map +1 -0
- package/dist/components/MarkdownRenderer.d.ts +8 -0
- package/dist/components/MarkdownRenderer.d.ts.map +1 -0
- package/dist/components/MarkdownRenderer.js +225 -0
- package/dist/components/MarkdownRenderer.js.map +1 -0
- package/dist/components/MentorMode.test.d.ts +2 -0
- package/dist/components/MentorMode.test.d.ts.map +1 -0
- package/dist/components/MentorMode.test.js.map +1 -0
- package/dist/components/MessageList.d.ts +7 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.js +29 -0
- package/dist/components/MessageList.js.map +1 -0
- package/dist/components/MessageList.test.d.ts +2 -0
- package/dist/components/MessageList.test.d.ts.map +1 -0
- package/dist/components/MessageList.test.js +15 -0
- package/dist/components/MessageList.test.js.map +1 -0
- package/dist/components/ModelSelectionMenu.d.ts +18 -0
- package/dist/components/ModelSelectionMenu.d.ts.map +1 -0
- package/dist/components/ModelSelectionMenu.js +91 -0
- package/dist/components/ModelSelectionMenu.js.map +1 -0
- package/dist/components/ModelSelectionMenu.test.d.ts +2 -0
- package/dist/components/ModelSelectionMenu.test.d.ts.map +1 -0
- package/dist/components/ModelSelectionMenu.test.js +83 -0
- package/dist/components/ModelSelectionMenu.test.js.map +1 -0
- package/dist/components/PathSelectionMenu.d.ts +12 -0
- package/dist/components/PathSelectionMenu.d.ts.map +1 -0
- package/dist/components/PathSelectionMenu.js +42 -0
- package/dist/components/PathSelectionMenu.js.map +1 -0
- package/dist/components/SettingsSelectionMenu.d.ts +9 -0
- package/dist/components/SettingsSelectionMenu.d.ts.map +1 -0
- package/dist/components/SettingsSelectionMenu.js +21 -0
- package/dist/components/SettingsSelectionMenu.js.map +1 -0
- package/dist/components/SlashCommandMenu.d.ts +15 -0
- package/dist/components/SlashCommandMenu.d.ts.map +1 -0
- package/dist/components/SlashCommandMenu.js +20 -0
- package/dist/components/SlashCommandMenu.js.map +1 -0
- package/dist/components/StatusBar.d.ts +11 -0
- package/dist/components/StatusBar.d.ts.map +1 -0
- package/dist/components/StatusBar.js +59 -0
- package/dist/components/StatusBar.js.map +1 -0
- package/dist/components/TextInput.d.ts +42 -0
- package/dist/components/TextInput.d.ts.map +1 -0
- package/dist/components/TextInput.js +397 -0
- package/dist/components/TextInput.js.map +1 -0
- package/dist/components/TextInput.test.d.ts +2 -0
- package/dist/components/TextInput.test.d.ts.map +1 -0
- package/dist/components/TextInput.test.js +75 -0
- package/dist/components/TextInput.test.js.map +1 -0
- package/dist/context/InputContext.d.ts +31 -0
- package/dist/context/InputContext.d.ts.map +1 -0
- package/dist/context/InputContext.js +36 -0
- package/dist/context/InputContext.js.map +1 -0
- package/dist/context/InputContext.stability.test.d.ts +2 -0
- package/dist/context/InputContext.stability.test.d.ts.map +1 -0
- package/dist/context/InputContext.stability.test.js +28 -0
- package/dist/context/InputContext.stability.test.js.map +1 -0
- package/dist/context/InputContext.test.d.ts +2 -0
- package/dist/context/InputContext.test.d.ts.map +1 -0
- package/dist/context/InputContext.test.js +168 -0
- package/dist/context/InputContext.test.js.map +1 -0
- package/dist/debug-schema.d.ts +2 -0
- package/dist/debug-schema.d.ts.map +1 -0
- package/dist/debug-schema.js +22 -0
- package/dist/debug-schema.js.map +1 -0
- package/dist/hooks/use-conversation.d.ts +78 -0
- package/dist/hooks/use-conversation.d.ts.map +1 -0
- package/dist/hooks/use-conversation.js +1017 -0
- package/dist/hooks/use-conversation.js.map +1 -0
- package/dist/hooks/use-input-history.d.ts +16 -0
- package/dist/hooks/use-input-history.d.ts.map +1 -0
- package/dist/hooks/use-input-history.js +71 -0
- package/dist/hooks/use-input-history.js.map +1 -0
- package/dist/hooks/use-model-selection.d.ts +27 -0
- package/dist/hooks/use-model-selection.d.ts.map +1 -0
- package/dist/hooks/use-model-selection.js +187 -0
- package/dist/hooks/use-model-selection.js.map +1 -0
- package/dist/hooks/use-model-selection.test.d.ts +2 -0
- package/dist/hooks/use-model-selection.test.d.ts.map +1 -0
- package/dist/hooks/use-model-selection.test.js +28 -0
- package/dist/hooks/use-model-selection.test.js.map +1 -0
- package/dist/hooks/use-path-completion.d.ts +22 -0
- package/dist/hooks/use-path-completion.d.ts.map +1 -0
- package/dist/hooks/use-path-completion.js +153 -0
- package/dist/hooks/use-path-completion.js.map +1 -0
- package/dist/hooks/use-path-completion.test.d.ts +2 -0
- package/dist/hooks/use-path-completion.test.d.ts.map +1 -0
- package/dist/hooks/use-path-completion.test.js +29 -0
- package/dist/hooks/use-path-completion.test.js.map +1 -0
- package/dist/hooks/use-setting.d.ts +7 -0
- package/dist/hooks/use-setting.d.ts.map +1 -0
- package/dist/hooks/use-setting.js +35 -0
- package/dist/hooks/use-setting.js.map +1 -0
- package/dist/hooks/use-settings-completion.d.ts +23 -0
- package/dist/hooks/use-settings-completion.d.ts.map +1 -0
- package/dist/hooks/use-settings-completion.js +164 -0
- package/dist/hooks/use-settings-completion.js.map +1 -0
- package/dist/hooks/use-settings-completion.test.d.ts +2 -0
- package/dist/hooks/use-settings-completion.test.d.ts.map +1 -0
- package/dist/hooks/use-settings-completion.test.js +334 -0
- package/dist/hooks/use-settings-completion.test.js.map +1 -0
- package/dist/hooks/use-slash-commands.d.ts +21 -0
- package/dist/hooks/use-slash-commands.d.ts.map +1 -0
- package/dist/hooks/use-slash-commands.js +87 -0
- package/dist/hooks/use-slash-commands.js.map +1 -0
- package/dist/hooks/use-slash-commands.test.d.ts +2 -0
- package/dist/hooks/use-slash-commands.test.d.ts.map +1 -0
- package/dist/hooks/use-slash-commands.test.js +246 -0
- package/dist/hooks/use-slash-commands.test.js.map +1 -0
- package/dist/lib/editor-impl.d.ts +23 -0
- package/dist/lib/editor-impl.d.ts.map +1 -0
- package/dist/lib/editor-impl.js +235 -0
- package/dist/lib/editor-impl.js.map +1 -0
- package/dist/lib/openai-agent-client.chat.test.d.ts +2 -0
- package/dist/lib/openai-agent-client.chat.test.d.ts.map +1 -0
- package/dist/lib/openai-agent-client.chat.test.js +68 -0
- package/dist/lib/openai-agent-client.chat.test.js.map +1 -0
- package/dist/lib/openai-agent-client.d.ts +48 -0
- package/dist/lib/openai-agent-client.d.ts.map +1 -0
- package/dist/lib/openai-agent-client.js +653 -0
- package/dist/lib/openai-agent-client.js.map +1 -0
- package/dist/lib/openai-agent-client.test.d.ts +2 -0
- package/dist/lib/openai-agent-client.test.d.ts.map +1 -0
- package/dist/lib/openai-agent-client.test.js +181 -0
- package/dist/lib/openai-agent-client.test.js.map +1 -0
- package/dist/lib/shell.d.ts +7 -0
- package/dist/lib/shell.d.ts.map +1 -0
- package/dist/lib/shell.js +56 -0
- package/dist/lib/shell.js.map +1 -0
- package/dist/lib/tool-invoke.d.ts +4 -0
- package/dist/lib/tool-invoke.d.ts.map +1 -0
- package/dist/lib/tool-invoke.js +26 -0
- package/dist/lib/tool-invoke.js.map +1 -0
- package/dist/lib/tool-invoke.test.d.ts +2 -0
- package/dist/lib/tool-invoke.test.d.ts.map +1 -0
- package/dist/lib/tool-invoke.test.js +19 -0
- package/dist/lib/tool-invoke.test.js.map +1 -0
- package/dist/no-singleton-imports.test.d.ts +2 -0
- package/dist/no-singleton-imports.test.d.ts.map +1 -0
- package/dist/no-singleton-imports.test.js +30 -0
- package/dist/no-singleton-imports.test.js.map +1 -0
- package/dist/prompts/anthropic.md +79 -0
- package/dist/prompts/codex.md +97 -0
- package/dist/prompts/default.md +77 -0
- package/dist/prompts/default.md.bak +77 -0
- package/dist/prompts/gpt-5.md +318 -0
- package/dist/prompts/lite.md +29 -0
- package/dist/prompts/simple-mentor.md +207 -0
- package/dist/prompts/simple.md +189 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +8 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai-compatible/api.d.ts +17 -0
- package/dist/providers/openai-compatible/api.d.ts.map +1 -0
- package/dist/providers/openai-compatible/api.js +58 -0
- package/dist/providers/openai-compatible/api.js.map +1 -0
- package/dist/providers/openai-compatible/model.d.ts +17 -0
- package/dist/providers/openai-compatible/model.d.ts.map +1 -0
- package/dist/providers/openai-compatible/model.js +435 -0
- package/dist/providers/openai-compatible/model.js.map +1 -0
- package/dist/providers/openai-compatible/provider.d.ts +22 -0
- package/dist/providers/openai-compatible/provider.d.ts.map +1 -0
- package/dist/providers/openai-compatible/provider.js +43 -0
- package/dist/providers/openai-compatible/provider.js.map +1 -0
- package/dist/providers/openai-compatible/utils.d.ts +3 -0
- package/dist/providers/openai-compatible/utils.d.ts.map +1 -0
- package/dist/providers/openai-compatible/utils.js +11 -0
- package/dist/providers/openai-compatible/utils.js.map +1 -0
- package/dist/providers/openai-compatible.provider.d.ts +8 -0
- package/dist/providers/openai-compatible.provider.d.ts.map +1 -0
- package/dist/providers/openai-compatible.provider.js +71 -0
- package/dist/providers/openai-compatible.provider.js.map +1 -0
- package/dist/providers/openai.provider.d.ts +2 -0
- package/dist/providers/openai.provider.d.ts.map +1 -0
- package/dist/providers/openai.provider.js +36 -0
- package/dist/providers/openai.provider.js.map +1 -0
- package/dist/providers/openrouter/api.d.ts +39 -0
- package/dist/providers/openrouter/api.d.ts.map +1 -0
- package/dist/providers/openrouter/api.js +172 -0
- package/dist/providers/openrouter/api.js.map +1 -0
- package/dist/providers/openrouter/converters.d.ts +8 -0
- package/dist/providers/openrouter/converters.d.ts.map +1 -0
- package/dist/providers/openrouter/converters.js +382 -0
- package/dist/providers/openrouter/converters.js.map +1 -0
- package/dist/providers/openrouter/converters.test.d.ts +2 -0
- package/dist/providers/openrouter/converters.test.d.ts.map +1 -0
- package/dist/providers/openrouter/converters.test.js +158 -0
- package/dist/providers/openrouter/converters.test.js.map +1 -0
- package/dist/providers/openrouter/index.d.ts +4 -0
- package/dist/providers/openrouter/index.d.ts.map +1 -0
- package/dist/providers/openrouter/index.js +4 -0
- package/dist/providers/openrouter/index.js.map +1 -0
- package/dist/providers/openrouter/model.d.ts +14 -0
- package/dist/providers/openrouter/model.d.ts.map +1 -0
- package/dist/providers/openrouter/model.js +485 -0
- package/dist/providers/openrouter/model.js.map +1 -0
- package/dist/providers/openrouter/provider.d.ts +15 -0
- package/dist/providers/openrouter/provider.d.ts.map +1 -0
- package/dist/providers/openrouter/provider.js +21 -0
- package/dist/providers/openrouter/provider.js.map +1 -0
- package/dist/providers/openrouter/utils.d.ts +10 -0
- package/dist/providers/openrouter/utils.d.ts.map +1 -0
- package/dist/providers/openrouter/utils.js +27 -0
- package/dist/providers/openrouter/utils.js.map +1 -0
- package/dist/providers/openrouter.api.retry.test.d.ts +2 -0
- package/dist/providers/openrouter.api.retry.test.d.ts.map +1 -0
- package/dist/providers/openrouter.api.retry.test.js +148 -0
- package/dist/providers/openrouter.api.retry.test.js.map +1 -0
- package/dist/providers/openrouter.d.ts +2 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.history.test.d.ts +2 -0
- package/dist/providers/openrouter.history.test.d.ts.map +1 -0
- package/dist/providers/openrouter.history.test.js +533 -0
- package/dist/providers/openrouter.history.test.js.map +1 -0
- package/dist/providers/openrouter.js +4 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/openrouter.provider.createRunner.test.d.ts +2 -0
- package/dist/providers/openrouter.provider.createRunner.test.d.ts.map +1 -0
- package/dist/providers/openrouter.provider.createRunner.test.js +23 -0
- package/dist/providers/openrouter.provider.createRunner.test.js.map +1 -0
- package/dist/providers/openrouter.provider.d.ts +2 -0
- package/dist/providers/openrouter.provider.d.ts.map +1 -0
- package/dist/providers/openrouter.provider.js +56 -0
- package/dist/providers/openrouter.provider.js.map +1 -0
- package/dist/providers/openrouter.test.d.ts +2 -0
- package/dist/providers/openrouter.test.d.ts.map +1 -0
- package/dist/providers/openrouter.test.js +1382 -0
- package/dist/providers/openrouter.test.js.map +1 -0
- package/dist/providers/registry.d.ts +65 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +44 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/registry.test.d.ts +2 -0
- package/dist/providers/registry.test.d.ts.map +1 -0
- package/dist/providers/registry.test.js +76 -0
- package/dist/providers/registry.test.js.map +1 -0
- package/dist/providers/web-search/index.d.ts +8 -0
- package/dist/providers/web-search/index.d.ts.map +1 -0
- package/dist/providers/web-search/index.js +9 -0
- package/dist/providers/web-search/index.js.map +1 -0
- package/dist/providers/web-search/registry.d.ts +35 -0
- package/dist/providers/web-search/registry.d.ts.map +1 -0
- package/dist/providers/web-search/registry.js +56 -0
- package/dist/providers/web-search/registry.js.map +1 -0
- package/dist/providers/web-search/registry.test.d.ts +2 -0
- package/dist/providers/web-search/registry.test.d.ts.map +1 -0
- package/dist/providers/web-search/registry.test.js +105 -0
- package/dist/providers/web-search/registry.test.js.map +1 -0
- package/dist/providers/web-search/tavily.provider.d.ts +15 -0
- package/dist/providers/web-search/tavily.provider.d.ts.map +1 -0
- package/dist/providers/web-search/tavily.provider.js +69 -0
- package/dist/providers/web-search/tavily.provider.js.map +1 -0
- package/dist/providers/web-search/tavily.provider.test.d.ts +2 -0
- package/dist/providers/web-search/tavily.provider.test.d.ts.map +1 -0
- package/dist/providers/web-search/tavily.provider.test.js +67 -0
- package/dist/providers/web-search/tavily.provider.test.js.map +1 -0
- package/dist/providers/web-search/types.d.ts +55 -0
- package/dist/providers/web-search/types.d.ts.map +1 -0
- package/dist/providers/web-search/types.js +6 -0
- package/dist/providers/web-search/types.js.map +1 -0
- package/dist/safety-checker.js +57 -0
- package/dist/services/conversation-events.d.ts +76 -0
- package/dist/services/conversation-events.d.ts.map +1 -0
- package/dist/services/conversation-events.js +2 -0
- package/dist/services/conversation-events.js.map +1 -0
- package/dist/services/conversation-service.d.ts +31 -0
- package/dist/services/conversation-service.d.ts.map +1 -0
- package/dist/services/conversation-service.js +46 -0
- package/dist/services/conversation-service.js.map +1 -0
- package/dist/services/conversation-service.test.js +190 -0
- package/dist/services/conversation-session.d.ts +99 -0
- package/dist/services/conversation-session.d.ts.map +1 -0
- package/dist/services/conversation-session.js +978 -0
- package/dist/services/conversation-session.js.map +1 -0
- package/dist/services/conversation-store.d.ts +24 -0
- package/dist/services/conversation-store.d.ts.map +1 -0
- package/dist/services/conversation-store.js +216 -0
- package/dist/services/conversation-store.js.map +1 -0
- package/dist/services/conversation-store.test.d.ts +2 -0
- package/dist/services/conversation-store.test.d.ts.map +1 -0
- package/dist/services/conversation-store.test.js +167 -0
- package/dist/services/conversation-store.test.js.map +1 -0
- package/dist/services/execution-context.d.ts +10 -0
- package/dist/services/execution-context.d.ts.map +1 -0
- package/dist/services/execution-context.js +22 -0
- package/dist/services/execution-context.js.map +1 -0
- package/dist/services/execution-context.test.d.ts +2 -0
- package/dist/services/execution-context.test.d.ts.map +1 -0
- package/dist/services/execution-context.test.js +49 -0
- package/dist/services/execution-context.test.js.map +1 -0
- package/dist/services/file-service.d.ts +12 -0
- package/dist/services/file-service.d.ts.map +1 -0
- package/dist/services/file-service.js +90 -0
- package/dist/services/file-service.js.map +1 -0
- package/dist/services/history-service.d.ts +39 -0
- package/dist/services/history-service.d.ts.map +1 -0
- package/dist/services/history-service.js +152 -0
- package/dist/services/history-service.js.map +1 -0
- package/dist/services/logging-service.d.ts +75 -0
- package/dist/services/logging-service.d.ts.map +1 -0
- package/dist/services/logging-service.js +343 -0
- package/dist/services/logging-service.js.map +1 -0
- package/dist/services/model-service.d.ts +15 -0
- package/dist/services/model-service.d.ts.map +1 -0
- package/dist/services/model-service.js +46 -0
- package/dist/services/model-service.js.map +1 -0
- package/dist/services/model-service.test.d.ts +2 -0
- package/dist/services/model-service.test.d.ts.map +1 -0
- package/dist/services/model-service.test.js +128 -0
- package/dist/services/model-service.test.js.map +1 -0
- package/dist/services/service-interfaces.d.ts +33 -0
- package/dist/services/service-interfaces.d.ts.map +1 -0
- package/dist/services/service-interfaces.js +2 -0
- package/dist/services/service-interfaces.js.map +1 -0
- package/dist/services/settings-service.d.ts +316 -0
- package/dist/services/settings-service.d.ts.map +1 -0
- package/dist/services/settings-service.js +1128 -0
- package/dist/services/settings-service.js.map +1 -0
- package/dist/services/settings-service.mock.d.ts +20 -0
- package/dist/services/settings-service.mock.d.ts.map +1 -0
- package/dist/services/settings-service.mock.js +55 -0
- package/dist/services/settings-service.mock.js.map +1 -0
- package/dist/services/singleton-deprecation.test.d.ts +2 -0
- package/dist/services/singleton-deprecation.test.d.ts.map +1 -0
- package/dist/services/singleton-deprecation.test.js +59 -0
- package/dist/services/singleton-deprecation.test.js.map +1 -0
- package/dist/services/ssh-service.d.ts +32 -0
- package/dist/services/ssh-service.d.ts.map +1 -0
- package/dist/services/ssh-service.js +119 -0
- package/dist/services/ssh-service.js.map +1 -0
- package/dist/services/ssh-service.test.d.ts +2 -0
- package/dist/services/ssh-service.test.d.ts.map +1 -0
- package/dist/services/ssh-service.test.js +269 -0
- package/dist/services/ssh-service.test.js.map +1 -0
- package/dist/test-search-tool.d.ts +2 -0
- package/dist/test-search-tool.d.ts.map +1 -0
- package/dist/test-search-tool.js +36 -0
- package/dist/test-search-tool.js.map +1 -0
- package/dist/tools/apply-patch.d.ts +28 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +399 -0
- package/dist/tools/apply-patch.js.map +1 -0
- package/dist/tools/apply-patch.test.d.ts +2 -0
- package/dist/tools/apply-patch.test.d.ts.map +1 -0
- package/dist/tools/apply-patch.test.js +155 -0
- package/dist/tools/apply-patch.test.js.map +1 -0
- package/dist/tools/ask-mentor.d.ts +11 -0
- package/dist/tools/ask-mentor.d.ts.map +1 -0
- package/dist/tools/ask-mentor.js +52 -0
- package/dist/tools/ask-mentor.js.map +1 -0
- package/dist/tools/ask-mentor.test.d.ts +2 -0
- package/dist/tools/ask-mentor.test.d.ts.map +1 -0
- package/dist/tools/ask-mentor.test.js +47 -0
- package/dist/tools/ask-mentor.test.js.map +1 -0
- package/dist/tools/bash.d.ts +10 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +55 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/find-files.d.ts +15 -0
- package/dist/tools/find-files.d.ts.map +1 -0
- package/dist/tools/find-files.js +179 -0
- package/dist/tools/find-files.js.map +1 -0
- package/dist/tools/find-files.test.d.ts +2 -0
- package/dist/tools/find-files.test.d.ts.map +1 -0
- package/dist/tools/find-files.test.js +131 -0
- package/dist/tools/find-files.test.js.map +1 -0
- package/dist/tools/format-helpers.d.ts +34 -0
- package/dist/tools/format-helpers.d.ts.map +1 -0
- package/dist/tools/format-helpers.js +131 -0
- package/dist/tools/format-helpers.js.map +1 -0
- package/dist/tools/grep.d.ts +16 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +211 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/read-file.d.ts +15 -0
- package/dist/tools/read-file.d.ts.map +1 -0
- package/dist/tools/read-file.js +114 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/read-file.test.d.ts +2 -0
- package/dist/tools/read-file.test.d.ts.map +1 -0
- package/dist/tools/read-file.test.js +122 -0
- package/dist/tools/read-file.test.js.map +1 -0
- package/dist/tools/search-replace.d.ts +19 -0
- package/dist/tools/search-replace.d.ts.map +1 -0
- package/dist/tools/search-replace.js +411 -0
- package/dist/tools/search-replace.js.map +1 -0
- package/dist/tools/search-replace.test.d.ts +2 -0
- package/dist/tools/search-replace.test.d.ts.map +1 -0
- package/dist/tools/search-replace.test.js +302 -0
- package/dist/tools/search-replace.test.js.map +1 -0
- package/dist/tools/search.d.ts +15 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +143 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/shell.d.ts +19 -0
- package/dist/tools/shell.d.ts.map +1 -0
- package/dist/tools/shell.js +278 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/tool-execution-context.d.ts +7 -0
- package/dist/tools/tool-execution-context.d.ts.map +1 -0
- package/dist/tools/tool-execution-context.js +7 -0
- package/dist/tools/tool-execution-context.js.map +1 -0
- package/dist/tools/types.d.ts +30 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/utils.d.ts +12 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +19 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools/web-search.d.ts +29 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +106 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/tools/web-search.test.d.ts +2 -0
- package/dist/tools/web-search.test.d.ts.map +1 -0
- package/dist/tools/web-search.test.js +176 -0
- package/dist/tools/web-search.test.js.map +1 -0
- package/dist/utils/command-logger.d.ts +11 -0
- package/dist/utils/command-logger.d.ts.map +1 -0
- package/dist/utils/command-logger.js +34 -0
- package/dist/utils/command-logger.js.map +1 -0
- package/dist/utils/command-safety/constants.d.ts +21 -0
- package/dist/utils/command-safety/constants.d.ts.map +1 -0
- package/dist/utils/command-safety/constants.js +245 -0
- package/dist/utils/command-safety/constants.js.map +1 -0
- package/dist/utils/command-safety/find-helpers.d.ts +15 -0
- package/dist/utils/command-safety/find-helpers.d.ts.map +1 -0
- package/dist/utils/command-safety/find-helpers.js +218 -0
- package/dist/utils/command-safety/find-helpers.js.map +1 -0
- package/dist/utils/command-safety/handlers/find-handler.d.ts +6 -0
- package/dist/utils/command-safety/handlers/find-handler.d.ts.map +1 -0
- package/dist/utils/command-safety/handlers/find-handler.js +113 -0
- package/dist/utils/command-safety/handlers/find-handler.js.map +1 -0
- package/dist/utils/command-safety/handlers/git-handler.d.ts +6 -0
- package/dist/utils/command-safety/handlers/git-handler.d.ts.map +1 -0
- package/dist/utils/command-safety/handlers/git-handler.js +68 -0
- package/dist/utils/command-safety/handlers/git-handler.js.map +1 -0
- package/dist/utils/command-safety/handlers/index.d.ts +13 -0
- package/dist/utils/command-safety/handlers/index.d.ts.map +1 -0
- package/dist/utils/command-safety/handlers/index.js +20 -0
- package/dist/utils/command-safety/handlers/index.js.map +1 -0
- package/dist/utils/command-safety/handlers/sed-handler.d.ts +6 -0
- package/dist/utils/command-safety/handlers/sed-handler.d.ts.map +1 -0
- package/dist/utils/command-safety/handlers/sed-handler.js +94 -0
- package/dist/utils/command-safety/handlers/sed-handler.js.map +1 -0
- package/dist/utils/command-safety/handlers/types.d.ts +36 -0
- package/dist/utils/command-safety/handlers/types.d.ts.map +1 -0
- package/dist/utils/command-safety/handlers/types.js +2 -0
- package/dist/utils/command-safety/handlers/types.js.map +1 -0
- package/dist/utils/command-safety/index.d.ts +14 -0
- package/dist/utils/command-safety/index.d.ts.map +1 -0
- package/dist/utils/command-safety/index.js +183 -0
- package/dist/utils/command-safety/index.js.map +1 -0
- package/dist/utils/command-safety/path-analysis.d.ts +4 -0
- package/dist/utils/command-safety/path-analysis.d.ts.map +1 -0
- package/dist/utils/command-safety/path-analysis.js +153 -0
- package/dist/utils/command-safety/path-analysis.js.map +1 -0
- package/dist/utils/command-safety/utils.d.ts +2 -0
- package/dist/utils/command-safety/utils.d.ts.map +1 -0
- package/dist/utils/command-safety/utils.js +22 -0
- package/dist/utils/command-safety/utils.js.map +1 -0
- package/dist/utils/command-safety.d.ts +21 -0
- package/dist/utils/command-safety.d.ts.map +1 -0
- package/dist/utils/command-safety.find.test.d.ts +2 -0
- package/dist/utils/command-safety.find.test.d.ts.map +1 -0
- package/dist/utils/command-safety.find.test.js +342 -0
- package/dist/utils/command-safety.find.test.js.map +1 -0
- package/dist/utils/command-safety.js +702 -0
- package/dist/utils/command-safety.js.map +1 -0
- package/dist/utils/command-safety.path.test.d.ts +2 -0
- package/dist/utils/command-safety.path.test.d.ts.map +1 -0
- package/dist/utils/command-safety.path.test.js +360 -0
- package/dist/utils/command-safety.path.test.js.map +1 -0
- package/dist/utils/diff.d.ts +2 -0
- package/dist/utils/diff.d.ts.map +1 -0
- package/dist/utils/diff.js +44 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/diff.test.d.ts +2 -0
- package/dist/utils/diff.test.d.ts.map +1 -0
- package/dist/utils/diff.test.js +85 -0
- package/dist/utils/diff.test.js.map +1 -0
- package/dist/utils/error-helpers.d.ts +6 -0
- package/dist/utils/error-helpers.d.ts.map +1 -0
- package/dist/utils/error-helpers.js +46 -0
- package/dist/utils/error-helpers.js.map +1 -0
- package/dist/utils/error-helpers.test.d.ts +2 -0
- package/dist/utils/error-helpers.test.d.ts.map +1 -0
- package/dist/utils/error-helpers.test.js +152 -0
- package/dist/utils/error-helpers.test.js.map +1 -0
- package/dist/utils/execute-shell.d.ts +15 -0
- package/dist/utils/execute-shell.d.ts.map +1 -0
- package/dist/utils/execute-shell.js +34 -0
- package/dist/utils/execute-shell.js.map +1 -0
- package/dist/utils/execute-shell.test.d.ts +2 -0
- package/dist/utils/execute-shell.test.d.ts.map +1 -0
- package/dist/utils/execute-shell.test.js +20 -0
- package/dist/utils/execute-shell.test.js.map +1 -0
- package/dist/utils/extract-command-messages.d.ts +5 -0
- package/dist/utils/extract-command-messages.d.ts.map +1 -0
- package/dist/utils/extract-command-messages.js +140 -0
- package/dist/utils/extract-command-messages.js.map +1 -0
- package/dist/utils/extract-command-messages.repro.test.d.ts +2 -0
- package/dist/utils/extract-command-messages.repro.test.d.ts.map +1 -0
- package/dist/utils/extract-command-messages.repro.test.js +31 -0
- package/dist/utils/extract-command-messages.repro.test.js.map +1 -0
- package/dist/utils/extract-command-messages.test.js +57 -0
- package/dist/utils/message-buffer.d.ts +2 -0
- package/dist/utils/message-buffer.d.ts.map +1 -0
- package/dist/utils/message-buffer.js +15 -0
- package/dist/utils/message-buffer.js.map +1 -0
- package/dist/utils/message-buffer.test.d.ts +2 -0
- package/dist/utils/message-buffer.test.d.ts.map +1 -0
- package/dist/utils/message-buffer.test.js +17 -0
- package/dist/utils/message-buffer.test.js.map +1 -0
- package/dist/utils/output-trim.d.ts +31 -0
- package/dist/utils/output-trim.d.ts.map +1 -0
- package/dist/utils/output-trim.js +71 -0
- package/dist/utils/output-trim.js.map +1 -0
- package/dist/utils/provider-credentials.d.ts +10 -0
- package/dist/utils/provider-credentials.d.ts.map +1 -0
- package/dist/utils/provider-credentials.js +22 -0
- package/dist/utils/provider-credentials.js.map +1 -0
- package/dist/utils/settings-command.d.ts +13 -0
- package/dist/utils/settings-command.d.ts.map +1 -0
- package/dist/utils/settings-command.js +173 -0
- package/dist/utils/settings-command.js.map +1 -0
- package/dist/utils/ssh-config-parser.d.ts +21 -0
- package/dist/utils/ssh-config-parser.d.ts.map +1 -0
- package/dist/utils/ssh-config-parser.js +89 -0
- package/dist/utils/ssh-config-parser.js.map +1 -0
- package/dist/utils/ssh-config-parser.test.d.ts +2 -0
- package/dist/utils/ssh-config-parser.test.d.ts.map +1 -0
- package/dist/utils/ssh-config-parser.test.js +153 -0
- package/dist/utils/ssh-config-parser.test.js.map +1 -0
- package/dist/utils/streaming-updater.d.ts +7 -0
- package/dist/utils/streaming-updater.d.ts.map +1 -0
- package/dist/utils/streaming-updater.js +41 -0
- package/dist/utils/streaming-updater.js.map +1 -0
- package/dist/utils/throttle.d.ts +7 -0
- package/dist/utils/throttle.d.ts.map +1 -0
- package/dist/utils/throttle.js +49 -0
- package/dist/utils/throttle.js.map +1 -0
- package/package.json +108 -0
- package/readme.md +428 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import parse from 'bash-parser';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { loggingService } from '../services/logging-service.js';
|
|
4
|
+
// 1. CONSTANTS
|
|
5
|
+
// Note: 'sed' is useful for read-only transformations. We allow it by default
|
|
6
|
+
// but add guards below to prevent in-place edits (-i) and unapproved redirections.
|
|
7
|
+
const ALLOWED_COMMANDS = new Set([
|
|
8
|
+
'ls',
|
|
9
|
+
'pwd',
|
|
10
|
+
'grep',
|
|
11
|
+
'cat',
|
|
12
|
+
'echo',
|
|
13
|
+
'head',
|
|
14
|
+
'tail',
|
|
15
|
+
'sed',
|
|
16
|
+
'find',
|
|
17
|
+
]);
|
|
18
|
+
const BLOCKED_COMMANDS = new Set([
|
|
19
|
+
// Filesystem
|
|
20
|
+
'rm',
|
|
21
|
+
'rmdir',
|
|
22
|
+
'mkfs',
|
|
23
|
+
'dd',
|
|
24
|
+
'mv',
|
|
25
|
+
'cp',
|
|
26
|
+
// System
|
|
27
|
+
'sudo',
|
|
28
|
+
'su',
|
|
29
|
+
'chmod',
|
|
30
|
+
'chown',
|
|
31
|
+
'shutdown',
|
|
32
|
+
'reboot',
|
|
33
|
+
// Network/Web
|
|
34
|
+
'curl',
|
|
35
|
+
'wget',
|
|
36
|
+
'ssh',
|
|
37
|
+
'scp',
|
|
38
|
+
'netstat',
|
|
39
|
+
// Package Managers / installers
|
|
40
|
+
'apt',
|
|
41
|
+
'yum',
|
|
42
|
+
'npm',
|
|
43
|
+
'yarn',
|
|
44
|
+
'pnpm',
|
|
45
|
+
'pip',
|
|
46
|
+
'gem',
|
|
47
|
+
// Dangerous wrappers / misc
|
|
48
|
+
'eval',
|
|
49
|
+
'exec',
|
|
50
|
+
'kill',
|
|
51
|
+
'killall',
|
|
52
|
+
]);
|
|
53
|
+
/* legacy containsDangerousCommand removed — replaced by classifyCommand + path analysis */
|
|
54
|
+
/**
|
|
55
|
+
* Validate command safety using an AST parser.
|
|
56
|
+
* Returns true when a command requires user approval.
|
|
57
|
+
* Throws for invalid/empty inputs.
|
|
58
|
+
*/
|
|
59
|
+
export var SafetyStatus;
|
|
60
|
+
(function (SafetyStatus) {
|
|
61
|
+
SafetyStatus["GREEN"] = "GREEN";
|
|
62
|
+
SafetyStatus["YELLOW"] = "YELLOW";
|
|
63
|
+
SafetyStatus["RED"] = "RED";
|
|
64
|
+
})(SafetyStatus || (SafetyStatus = {}));
|
|
65
|
+
// Extract a best-effort string for a word/arg node, including expansions.
|
|
66
|
+
function extractWordText(word) {
|
|
67
|
+
if (!word)
|
|
68
|
+
return undefined;
|
|
69
|
+
if (typeof word === 'string')
|
|
70
|
+
return word;
|
|
71
|
+
if (typeof word.text === 'string')
|
|
72
|
+
return word.text;
|
|
73
|
+
if (typeof word.value === 'string')
|
|
74
|
+
return word.value;
|
|
75
|
+
if (typeof word.content === 'string')
|
|
76
|
+
return word.content;
|
|
77
|
+
if (word.parameter)
|
|
78
|
+
return `$${word.parameter}`;
|
|
79
|
+
if (Array.isArray(word.parts)) {
|
|
80
|
+
return word.parts
|
|
81
|
+
.map((part) => extractWordText(part) ?? '')
|
|
82
|
+
.join('');
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
// 2. FIND COMMAND HELPERS
|
|
87
|
+
/**
|
|
88
|
+
* Check if a find command has dangerous execution flags (-exec, -execdir, -ok, -okdir, -delete)
|
|
89
|
+
*/
|
|
90
|
+
function hasFindDangerousExecution(args) {
|
|
91
|
+
for (let i = 0; i < args.length; i++) {
|
|
92
|
+
const argText = extractWordText(args[i]);
|
|
93
|
+
if (!argText)
|
|
94
|
+
continue;
|
|
95
|
+
// Check for -delete flag
|
|
96
|
+
if (argText === '-delete') {
|
|
97
|
+
return { dangerous: true, reason: 'find -delete (destructive)' };
|
|
98
|
+
}
|
|
99
|
+
// Check for execution flags
|
|
100
|
+
const execFlags = ['-exec', '-execdir', '-ok', '-okdir'];
|
|
101
|
+
if (!execFlags.includes(argText))
|
|
102
|
+
continue;
|
|
103
|
+
// Found an exec flag - analyze the command it executes
|
|
104
|
+
// Find the terminator (; or +)
|
|
105
|
+
let terminatorIndex = -1;
|
|
106
|
+
for (let j = i + 1; j < args.length; j++) {
|
|
107
|
+
const term = extractWordText(args[j]);
|
|
108
|
+
if (term === ';' ||
|
|
109
|
+
term === '+' ||
|
|
110
|
+
term === '\\;' ||
|
|
111
|
+
term === '\\+') {
|
|
112
|
+
terminatorIndex = j;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (terminatorIndex === -1) {
|
|
117
|
+
// Malformed -exec (no terminator)
|
|
118
|
+
return {
|
|
119
|
+
dangerous: true,
|
|
120
|
+
reason: `find ${argText} without terminator`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Extract the command between exec flag and terminator
|
|
124
|
+
const execArgs = args.slice(i + 1, terminatorIndex);
|
|
125
|
+
// Check for redirects (which indicate shell operations)
|
|
126
|
+
const hasRedirect = execArgs.some((a) => a?.type === 'Redirect');
|
|
127
|
+
if (hasRedirect) {
|
|
128
|
+
return {
|
|
129
|
+
dangerous: true,
|
|
130
|
+
reason: `find ${argText} with shell redirection`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const execCommand = execArgs
|
|
134
|
+
.map(a => extractWordText(a))
|
|
135
|
+
.filter(Boolean);
|
|
136
|
+
if (execCommand.length === 0) {
|
|
137
|
+
return {
|
|
138
|
+
dangerous: true,
|
|
139
|
+
reason: `find ${argText} with empty command`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const cmdName = execCommand[0];
|
|
143
|
+
if (!cmdName) {
|
|
144
|
+
return {
|
|
145
|
+
dangerous: true,
|
|
146
|
+
reason: `find ${argText} with undefined command`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// Check if {} is the command itself (executing found files)
|
|
150
|
+
if (cmdName === '{}') {
|
|
151
|
+
return {
|
|
152
|
+
dangerous: true,
|
|
153
|
+
reason: `find ${argText} {} (executes found files directly)`,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Check for destructive commands
|
|
157
|
+
const destructiveCmds = [
|
|
158
|
+
'rm',
|
|
159
|
+
'shred',
|
|
160
|
+
'chmod',
|
|
161
|
+
'chown',
|
|
162
|
+
'mv',
|
|
163
|
+
'dd',
|
|
164
|
+
'mkfs',
|
|
165
|
+
'truncate',
|
|
166
|
+
'tee',
|
|
167
|
+
'cp',
|
|
168
|
+
'ln',
|
|
169
|
+
'install',
|
|
170
|
+
'rsync',
|
|
171
|
+
];
|
|
172
|
+
if (destructiveCmds.includes(cmdName)) {
|
|
173
|
+
return {
|
|
174
|
+
dangerous: true,
|
|
175
|
+
reason: `find ${argText} ${cmdName} (destructive)`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// Check for dangerous interpreters and meta-executors
|
|
179
|
+
// These can all invoke arbitrary commands or scripts
|
|
180
|
+
const dangerousInterpreters = [
|
|
181
|
+
// Shells
|
|
182
|
+
'sh',
|
|
183
|
+
'bash',
|
|
184
|
+
'zsh',
|
|
185
|
+
'ksh',
|
|
186
|
+
'dash',
|
|
187
|
+
'fish',
|
|
188
|
+
'tcsh',
|
|
189
|
+
'csh',
|
|
190
|
+
// Script interpreters
|
|
191
|
+
'perl',
|
|
192
|
+
'python',
|
|
193
|
+
'python2',
|
|
194
|
+
'python3',
|
|
195
|
+
'ruby',
|
|
196
|
+
'node',
|
|
197
|
+
'nodejs',
|
|
198
|
+
'php',
|
|
199
|
+
'lua',
|
|
200
|
+
// Meta-executors that can run commands
|
|
201
|
+
'env',
|
|
202
|
+
'xargs',
|
|
203
|
+
'parallel',
|
|
204
|
+
'nohup',
|
|
205
|
+
'nice',
|
|
206
|
+
'ionice',
|
|
207
|
+
'timeout',
|
|
208
|
+
'stdbuf',
|
|
209
|
+
'script',
|
|
210
|
+
'expect',
|
|
211
|
+
// Text processors that can execute
|
|
212
|
+
'awk',
|
|
213
|
+
'gawk',
|
|
214
|
+
'mawk',
|
|
215
|
+
'nawk',
|
|
216
|
+
'sed',
|
|
217
|
+
'ed',
|
|
218
|
+
// Editors that can run shell commands
|
|
219
|
+
'vim',
|
|
220
|
+
'nvim',
|
|
221
|
+
'emacs',
|
|
222
|
+
];
|
|
223
|
+
// Handle both bare names and full paths like /usr/bin/python
|
|
224
|
+
const isDangerousInterpreter = dangerousInterpreters.some(interp => cmdName === interp || cmdName.endsWith(`/${interp}`));
|
|
225
|
+
if (isDangerousInterpreter) {
|
|
226
|
+
return {
|
|
227
|
+
dangerous: true,
|
|
228
|
+
reason: `find ${argText} ${cmdName} (can execute commands)`,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// Check for shell metacharacters in command
|
|
232
|
+
const fullExecCmd = execCommand.join(' ');
|
|
233
|
+
if (/[|&;$`<>]/.test(fullExecCmd)) {
|
|
234
|
+
return {
|
|
235
|
+
dangerous: true,
|
|
236
|
+
reason: `find ${argText} with shell metacharacters`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { dangerous: false };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Check for suspicious find flags that warrant YELLOW classification
|
|
244
|
+
*/
|
|
245
|
+
function hasFindSuspiciousFlags(args) {
|
|
246
|
+
for (const arg of args) {
|
|
247
|
+
const argText = extractWordText(arg);
|
|
248
|
+
if (!argText)
|
|
249
|
+
continue;
|
|
250
|
+
// File output flags
|
|
251
|
+
if (['-fprint', '-fprint0', '-fprintf', '-fls'].some(flag => argText.startsWith(flag))) {
|
|
252
|
+
return {
|
|
253
|
+
suspicious: true,
|
|
254
|
+
reason: `find ${argText} (file output)`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
// Symlink following
|
|
258
|
+
if (['-L', '-follow', '-H'].includes(argText)) {
|
|
259
|
+
return {
|
|
260
|
+
suspicious: true,
|
|
261
|
+
reason: `find ${argText} (symlink following)`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// SUID/SGID permission searches
|
|
265
|
+
if (argText === '-perm') {
|
|
266
|
+
// Check the next argument for dangerous permission patterns
|
|
267
|
+
const nextIdx = args.indexOf(arg) + 1;
|
|
268
|
+
if (nextIdx < args.length) {
|
|
269
|
+
const permValue = extractWordText(args[nextIdx]);
|
|
270
|
+
if (permValue) {
|
|
271
|
+
// Numeric SUID/SGID patterns (e.g., -4000, /6000)
|
|
272
|
+
const hasNumericSuid = /[-\/]?[2467]000/.test(permValue);
|
|
273
|
+
// Symbolic SUID/SGID patterns (e.g., -u+s, /g+s, +s)
|
|
274
|
+
const hasSymbolicSuid = /[ug]?\+s/.test(permValue);
|
|
275
|
+
if (hasNumericSuid || hasSymbolicSuid) {
|
|
276
|
+
return {
|
|
277
|
+
suspicious: true,
|
|
278
|
+
reason: `find -perm ${permValue} (SUID/SGID search)`,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Inode-based searches (can bypass path restrictions)
|
|
285
|
+
if (argText === '-inum') {
|
|
286
|
+
return {
|
|
287
|
+
suspicious: true,
|
|
288
|
+
reason: 'find -inum (inode-based access bypasses path checks)',
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// Read-only exec (still suspicious, requires approval)
|
|
292
|
+
if (['-exec', '-execdir', '-ok', '-okdir'].includes(argText)) {
|
|
293
|
+
// If we reach here, hasFindDangerousExecution already passed (not RED)
|
|
294
|
+
// but any -exec usage should still be YELLOW
|
|
295
|
+
return {
|
|
296
|
+
suspicious: true,
|
|
297
|
+
reason: `find ${argText} (command execution)`,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return { suspicious: false };
|
|
302
|
+
}
|
|
303
|
+
// 3. PATH ANALYSIS HELPER
|
|
304
|
+
function analyzePathRisk(inputPath) {
|
|
305
|
+
const candidate = inputPath?.trim();
|
|
306
|
+
if (!candidate)
|
|
307
|
+
return SafetyStatus.GREEN;
|
|
308
|
+
// RED: Home directory and sensitive paths
|
|
309
|
+
// Check for various home directory representations
|
|
310
|
+
const homePatterns = [
|
|
311
|
+
/^~/, // Tilde
|
|
312
|
+
/^\$HOME/, // $HOME variable
|
|
313
|
+
/^\$\{HOME\}/, // ${HOME} variable
|
|
314
|
+
/^\$USER/, // $USER variable
|
|
315
|
+
/^\$LOGNAME/, // $LOGNAME variable
|
|
316
|
+
/^\$XDG_/, // XDG variables
|
|
317
|
+
/^\/home\//, // Linux home directories
|
|
318
|
+
/^\/Users\//, // macOS home directories
|
|
319
|
+
/^\/root($|\/)/, // Root's home
|
|
320
|
+
];
|
|
321
|
+
const isHomeRelated = homePatterns.some(pattern => pattern.test(candidate));
|
|
322
|
+
if (isHomeRelated) {
|
|
323
|
+
// Extract the path after home prefix for further analysis
|
|
324
|
+
const sliced = candidate
|
|
325
|
+
.replace(/^~/, '')
|
|
326
|
+
.replace(/^\$\{?HOME\}?/, '')
|
|
327
|
+
.replace(/^\$\{?USER\}?/, '')
|
|
328
|
+
.replace(/^\$\{?LOGNAME\}?/, '')
|
|
329
|
+
.replace(/^\/home\/[^/]+/, '')
|
|
330
|
+
.replace(/^\/Users\/[^/]+/, '')
|
|
331
|
+
.replace(/^\/root/, '');
|
|
332
|
+
// Plain home directory access without any suffix is RED
|
|
333
|
+
if (sliced === '' || sliced === '/') {
|
|
334
|
+
loggingService.security('Path risk: home directory access', {
|
|
335
|
+
path: candidate,
|
|
336
|
+
});
|
|
337
|
+
return SafetyStatus.RED;
|
|
338
|
+
}
|
|
339
|
+
// Check for sensitive dotfiles and directories
|
|
340
|
+
const sensitivePaths = [
|
|
341
|
+
'/.ssh',
|
|
342
|
+
'/.gnupg',
|
|
343
|
+
'/.aws',
|
|
344
|
+
'/.kube',
|
|
345
|
+
'/.env',
|
|
346
|
+
'/.git',
|
|
347
|
+
'/.config',
|
|
348
|
+
'/.bash_history',
|
|
349
|
+
'/.zsh_history',
|
|
350
|
+
];
|
|
351
|
+
if (/^\/\.\w+/.test(sliced) ||
|
|
352
|
+
sensitivePaths.some(sensitive => sliced.includes(sensitive))) {
|
|
353
|
+
loggingService.security('Path risk: home dotfile or config', {
|
|
354
|
+
path: candidate,
|
|
355
|
+
});
|
|
356
|
+
return SafetyStatus.RED;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// RED: Absolute System Paths
|
|
360
|
+
if (path.isAbsolute(candidate)) {
|
|
361
|
+
const SYSTEM_PATHS = [
|
|
362
|
+
'/etc',
|
|
363
|
+
'/dev',
|
|
364
|
+
'/proc',
|
|
365
|
+
'/var',
|
|
366
|
+
'/usr',
|
|
367
|
+
'/boot',
|
|
368
|
+
'/bin',
|
|
369
|
+
];
|
|
370
|
+
if (SYSTEM_PATHS.some(sys => candidate.startsWith(sys))) {
|
|
371
|
+
loggingService.security('Path risk: absolute system path', {
|
|
372
|
+
path: candidate,
|
|
373
|
+
});
|
|
374
|
+
return SafetyStatus.RED;
|
|
375
|
+
}
|
|
376
|
+
// Home dotfiles when absolute
|
|
377
|
+
if (/^\/(home|Users)\/[^/]+\/\.\w+/.test(candidate) ||
|
|
378
|
+
candidate.includes('/.ssh') ||
|
|
379
|
+
candidate.includes('/.gitconfig')) {
|
|
380
|
+
loggingService.security('Path risk: absolute home dotfile', {
|
|
381
|
+
path: candidate,
|
|
382
|
+
});
|
|
383
|
+
return SafetyStatus.RED;
|
|
384
|
+
}
|
|
385
|
+
// Other absolute paths are suspicious -> audit
|
|
386
|
+
loggingService.security('Path risk: absolute non-system path', {
|
|
387
|
+
path: candidate,
|
|
388
|
+
});
|
|
389
|
+
return SafetyStatus.YELLOW;
|
|
390
|
+
}
|
|
391
|
+
// RED: Directory Traversal
|
|
392
|
+
if (candidate.includes('..')) {
|
|
393
|
+
loggingService.security('Path risk: directory traversal detected', {
|
|
394
|
+
path: candidate,
|
|
395
|
+
});
|
|
396
|
+
return SafetyStatus.RED;
|
|
397
|
+
}
|
|
398
|
+
// Hidden files -> YELLOW
|
|
399
|
+
const filename = path.basename(candidate);
|
|
400
|
+
if (filename.startsWith('.')) {
|
|
401
|
+
loggingService.security('Path risk: hidden file', { path: candidate });
|
|
402
|
+
return SafetyStatus.YELLOW;
|
|
403
|
+
}
|
|
404
|
+
// Sensitive extensions
|
|
405
|
+
const SENSITIVE_EXTENSIONS = ['.env', '.pem', '.key', '.json'];
|
|
406
|
+
if (SENSITIVE_EXTENSIONS.some(ext => filename.endsWith(ext))) {
|
|
407
|
+
loggingService.security('Path risk: sensitive extension', {
|
|
408
|
+
path: candidate,
|
|
409
|
+
});
|
|
410
|
+
return SafetyStatus.YELLOW;
|
|
411
|
+
}
|
|
412
|
+
return SafetyStatus.GREEN;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Classify command into a SafetyStatus (GREEN/YELLOW/RED)
|
|
416
|
+
*/
|
|
417
|
+
export function classifyCommand(commandString) {
|
|
418
|
+
try {
|
|
419
|
+
const reasons = [];
|
|
420
|
+
const truncatedCommand = commandString.substring(0, 200);
|
|
421
|
+
loggingService.security('Classifying command safety', {
|
|
422
|
+
command: truncatedCommand,
|
|
423
|
+
});
|
|
424
|
+
const ast = parse(commandString, { mode: 'bash' });
|
|
425
|
+
let worstStatus = SafetyStatus.GREEN;
|
|
426
|
+
function upgradeStatus(s, reason) {
|
|
427
|
+
if (worstStatus === SafetyStatus.RED)
|
|
428
|
+
return;
|
|
429
|
+
if (s === SafetyStatus.RED)
|
|
430
|
+
worstStatus = SafetyStatus.RED;
|
|
431
|
+
else if (s === SafetyStatus.YELLOW &&
|
|
432
|
+
worstStatus === SafetyStatus.GREEN)
|
|
433
|
+
worstStatus = SafetyStatus.YELLOW;
|
|
434
|
+
if (reason)
|
|
435
|
+
reasons.push(`${s}: ${reason}`);
|
|
436
|
+
}
|
|
437
|
+
function traverse(node) {
|
|
438
|
+
if (!node)
|
|
439
|
+
return;
|
|
440
|
+
if (Array.isArray(node))
|
|
441
|
+
return node.forEach(traverse);
|
|
442
|
+
if (node.type === 'Command') {
|
|
443
|
+
const name = node.name?.text ||
|
|
444
|
+
(node.name &&
|
|
445
|
+
node.name.parts &&
|
|
446
|
+
node.name.parts.map((p) => p.text).join(''));
|
|
447
|
+
if (typeof name === 'string') {
|
|
448
|
+
if (BLOCKED_COMMANDS.has(name)) {
|
|
449
|
+
upgradeStatus(SafetyStatus.RED, `blocked command: ${name}`);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (!ALLOWED_COMMANDS.has(name)) {
|
|
453
|
+
upgradeStatus(SafetyStatus.YELLOW, `unknown or unlisted command: ${name}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const cmdName = typeof name === 'string' ? name : undefined;
|
|
457
|
+
// Special handling for find command
|
|
458
|
+
if (cmdName === 'find' && node.suffix) {
|
|
459
|
+
// Check for dangerous find operations first (RED)
|
|
460
|
+
const dangerResult = hasFindDangerousExecution(node.suffix);
|
|
461
|
+
if (dangerResult.dangerous) {
|
|
462
|
+
upgradeStatus(SafetyStatus.RED, dangerResult.reason || 'find with dangerous flags');
|
|
463
|
+
}
|
|
464
|
+
// Check for suspicious find flags (YELLOW)
|
|
465
|
+
if (!dangerResult.dangerous) {
|
|
466
|
+
const suspiciousResult = hasFindSuspiciousFlags(node.suffix);
|
|
467
|
+
if (suspiciousResult.suspicious) {
|
|
468
|
+
upgradeStatus(SafetyStatus.YELLOW, suspiciousResult.reason ||
|
|
469
|
+
'find with suspicious flags');
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
// Check path arguments for find
|
|
473
|
+
if (!dangerResult.dangerous) {
|
|
474
|
+
// Track if previous arg was a pattern flag like -name, -regex
|
|
475
|
+
let previousArgWasPatternFlag = false;
|
|
476
|
+
for (const arg of node.suffix) {
|
|
477
|
+
if (arg?.type === 'Redirect')
|
|
478
|
+
continue;
|
|
479
|
+
const argText = extractWordText(arg);
|
|
480
|
+
if (!argText)
|
|
481
|
+
continue;
|
|
482
|
+
// Track pattern flags
|
|
483
|
+
if ([
|
|
484
|
+
'-name',
|
|
485
|
+
'-iname',
|
|
486
|
+
'-path',
|
|
487
|
+
'-ipath',
|
|
488
|
+
'-regex',
|
|
489
|
+
'-iregex',
|
|
490
|
+
].includes(argText)) {
|
|
491
|
+
previousArgWasPatternFlag = true;
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
// Skip flags
|
|
495
|
+
if (argText.startsWith('-')) {
|
|
496
|
+
previousArgWasPatternFlag = false;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
// Skip pattern arguments (the values after -name, -regex, etc.)
|
|
500
|
+
if (previousArgWasPatternFlag) {
|
|
501
|
+
previousArgWasPatternFlag = false;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
// Skip glob patterns (contain wildcards)
|
|
505
|
+
if (/[*?[\]]/.test(argText))
|
|
506
|
+
continue;
|
|
507
|
+
// Skip safe relative paths (. and ./)
|
|
508
|
+
if (argText === '.' || argText === './')
|
|
509
|
+
continue;
|
|
510
|
+
// Skip patterns with backslashes (regex patterns)
|
|
511
|
+
if (argText.includes('\\'))
|
|
512
|
+
continue;
|
|
513
|
+
// Root traversal detection (DoS + information disclosure)
|
|
514
|
+
if (argText === '/' || argText === '//') {
|
|
515
|
+
upgradeStatus(SafetyStatus.YELLOW, 'find / (root traversal - resource intensive)');
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
// For find, analyzing paths is more lenient:
|
|
519
|
+
// - System paths like /etc are YELLOW (not RED)
|
|
520
|
+
// - Home directories and dotfiles are still RED
|
|
521
|
+
const pathStatus = analyzePathRisk(argText);
|
|
522
|
+
if (pathStatus === SafetyStatus.RED) {
|
|
523
|
+
// Keep RED for home directories, dotfiles, and traversal
|
|
524
|
+
// Downgrade system paths to YELLOW
|
|
525
|
+
const homeRelatedPatterns = [
|
|
526
|
+
/^~/, // Tilde
|
|
527
|
+
/^\$/, // Variables like $HOME, $USER
|
|
528
|
+
/^\/home\//, // Linux home
|
|
529
|
+
/^\/Users\//, // macOS home
|
|
530
|
+
/^\/root/, // Root's home
|
|
531
|
+
/\/\.ssh/, // SSH keys
|
|
532
|
+
/\/\.env/, // Environment files
|
|
533
|
+
/\/\.git/, // Git config
|
|
534
|
+
/\/\.aws/, // AWS credentials
|
|
535
|
+
/\/\.kube/, // Kubernetes config
|
|
536
|
+
/\/\.gnupg/, // GPG keys
|
|
537
|
+
/\.\./, // Directory traversal
|
|
538
|
+
];
|
|
539
|
+
const isHomeRelated = homeRelatedPatterns.some(pattern => pattern.test(argText));
|
|
540
|
+
if (isHomeRelated) {
|
|
541
|
+
upgradeStatus(SafetyStatus.RED, `find dangerous path: ${argText}`);
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
// System paths like /etc get downgraded to YELLOW
|
|
545
|
+
upgradeStatus(SafetyStatus.YELLOW, `find system path: ${argText}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
else if (pathStatus === SafetyStatus.YELLOW) {
|
|
549
|
+
upgradeStatus(pathStatus, `find path argument ${argText}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// Done with find-specific handling
|
|
554
|
+
// Don't process suffix generically
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (node.suffix) {
|
|
558
|
+
let hasOutputRedirect = false;
|
|
559
|
+
let hasInPlaceEdit = false;
|
|
560
|
+
// First pass: detect dangerous sed patterns
|
|
561
|
+
for (const arg of node.suffix) {
|
|
562
|
+
if (arg?.type === 'Redirect') {
|
|
563
|
+
// Check if it's an output redirect (>, >>)
|
|
564
|
+
const op = arg.op?.text || arg.op;
|
|
565
|
+
if (op === '>' || op === '>>') {
|
|
566
|
+
hasOutputRedirect = true;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
const argText = extractWordText(arg);
|
|
570
|
+
if (argText && argText.startsWith('-')) {
|
|
571
|
+
if (cmdName === 'sed' && argText.startsWith('-i')) {
|
|
572
|
+
hasInPlaceEdit = true;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// Second pass: classify arguments
|
|
577
|
+
for (const arg of node.suffix) {
|
|
578
|
+
// Redirects: analyze path risk. For `sed`, only mark output redirects as YELLOW
|
|
579
|
+
if (arg?.type === 'Redirect') {
|
|
580
|
+
const fileText = extractWordText(arg.file ?? arg);
|
|
581
|
+
const op = arg.op?.text || arg.op;
|
|
582
|
+
if (cmdName === 'sed' &&
|
|
583
|
+
(op === '>' || op === '>>')) {
|
|
584
|
+
upgradeStatus(SafetyStatus.YELLOW, `sed with output redirection to ${fileText ?? '<unknown>'}`);
|
|
585
|
+
}
|
|
586
|
+
const pathStatus = analyzePathRisk(fileText);
|
|
587
|
+
upgradeStatus(pathStatus, `redirect to ${fileText ?? '<unknown>'}`);
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
const argText = extractWordText(arg);
|
|
591
|
+
// Flags are normally ignored, but for `sed` the -i flag is dangerous
|
|
592
|
+
// because it performs in-place edits. Detect -i and variants (e.g. -i, -i.bak, -i'')
|
|
593
|
+
if (argText && argText.startsWith('-')) {
|
|
594
|
+
if (cmdName === 'sed' && argText.startsWith('-i')) {
|
|
595
|
+
upgradeStatus(SafetyStatus.RED, `sed in-place edit detected: ${argText}`);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
continue; // other flags ignored
|
|
599
|
+
}
|
|
600
|
+
const pathStatus = analyzePathRisk(argText);
|
|
601
|
+
// For `sed`, file arguments are only risky if combined with dangerous operations
|
|
602
|
+
if (cmdName === 'sed' && argText) {
|
|
603
|
+
// If there's an in-place edit or output redirect, path risk matters
|
|
604
|
+
// Otherwise, reading files with sed is safe (GREEN)
|
|
605
|
+
if (hasInPlaceEdit || hasOutputRedirect) {
|
|
606
|
+
if (pathStatus === SafetyStatus.RED)
|
|
607
|
+
upgradeStatus(pathStatus, `sed file argument ${argText}`);
|
|
608
|
+
else
|
|
609
|
+
upgradeStatus(SafetyStatus.YELLOW, `sed file argument ${argText}`);
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
// Read-only sed: only escalate if path itself is risky
|
|
613
|
+
if (pathStatus !== SafetyStatus.GREEN) {
|
|
614
|
+
upgradeStatus(pathStatus, `sed file argument ${argText}`);
|
|
615
|
+
}
|
|
616
|
+
// Otherwise GREEN - read-only sed is safe
|
|
617
|
+
}
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
// Unknown/opaque args fall back to YELLOW
|
|
621
|
+
if (!argText)
|
|
622
|
+
upgradeStatus(SafetyStatus.YELLOW, 'opaque or unparseable argument');
|
|
623
|
+
else
|
|
624
|
+
upgradeStatus(pathStatus, `argument ${argText}`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
// recurse common shapes
|
|
629
|
+
if (node.type === 'LogicalExpression') {
|
|
630
|
+
traverse(node.left);
|
|
631
|
+
traverse(node.right);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
if (node.type === 'Pipeline') {
|
|
635
|
+
(node.commands || []).forEach(traverse);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
if (node.type === 'Subshell') {
|
|
639
|
+
traverse(node.list);
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
if (node.type === 'CommandSubstitution') {
|
|
643
|
+
(node.commands || []).forEach(traverse);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (node.type === 'Script' || node.type === 'Program') {
|
|
647
|
+
(node.commands || []).forEach(traverse);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
for (const k of Object.keys(node)) {
|
|
651
|
+
const v = node[k];
|
|
652
|
+
if (v && typeof v === 'object')
|
|
653
|
+
traverse(v);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (ast && ast.commands) {
|
|
657
|
+
ast.commands.forEach(traverse);
|
|
658
|
+
}
|
|
659
|
+
loggingService.security('Command classification result', {
|
|
660
|
+
command: truncatedCommand,
|
|
661
|
+
status: worstStatus,
|
|
662
|
+
reasons,
|
|
663
|
+
});
|
|
664
|
+
return worstStatus;
|
|
665
|
+
}
|
|
666
|
+
catch (e) {
|
|
667
|
+
// Fail-safe: unparsable -> audit
|
|
668
|
+
loggingService.warn('Failed to parse command, classifying as YELLOW', {
|
|
669
|
+
command: commandString.substring(0, 200),
|
|
670
|
+
error: e instanceof Error ? e.message : String(e),
|
|
671
|
+
});
|
|
672
|
+
return SafetyStatus.YELLOW;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Validate command safety using an AST parser.
|
|
677
|
+
* Returns true when a command requires user approval.
|
|
678
|
+
* Throws for invalid/empty inputs OR hard-blocked RED classifications.
|
|
679
|
+
*/
|
|
680
|
+
export function validateCommandSafety(command) {
|
|
681
|
+
if (!command ||
|
|
682
|
+
typeof command !== 'string' ||
|
|
683
|
+
command.trim().length === 0) {
|
|
684
|
+
throw new Error('Command cannot be empty');
|
|
685
|
+
}
|
|
686
|
+
loggingService.security('Validating command safety', {
|
|
687
|
+
command: command.substring(0, 200),
|
|
688
|
+
});
|
|
689
|
+
const status = classifyCommand(command);
|
|
690
|
+
if (status === SafetyStatus.RED) {
|
|
691
|
+
loggingService.security('Command validation failed: RED (forbidden)', {
|
|
692
|
+
command: command.substring(0, 200),
|
|
693
|
+
});
|
|
694
|
+
throw new Error('Command classified as RED (forbidden)');
|
|
695
|
+
}
|
|
696
|
+
loggingService.security('Validation result', {
|
|
697
|
+
command: command.substring(0, 200),
|
|
698
|
+
status,
|
|
699
|
+
});
|
|
700
|
+
return status === SafetyStatus.YELLOW;
|
|
701
|
+
}
|
|
702
|
+
//# sourceMappingURL=command-safety.js.map
|