@within-7/minto 0.1.7 → 0.3.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/cli.js +155 -37
- package/dist/Tool.js +38 -0
- package/dist/Tool.js.map +3 -3
- package/dist/commands/agents/AgentsCommand.js +73 -49
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/constants.js +1 -1
- package/dist/commands/agents/constants.js.map +1 -1
- package/dist/commands/agents/index.js +1 -1
- package/dist/commands/bug.js +74 -7
- package/dist/commands/bug.js.map +3 -3
- package/dist/commands/clear.js +3 -0
- package/dist/commands/clear.js.map +2 -2
- package/dist/commands/compact.js +37 -0
- package/dist/commands/compact.js.map +2 -2
- package/dist/commands/context.js +85 -0
- package/dist/commands/context.js.map +7 -0
- package/dist/commands/ctx_viz.js +18 -10
- package/dist/commands/ctx_viz.js.map +2 -2
- package/dist/commands/doctor.js +158 -12
- package/dist/commands/doctor.js.map +2 -2
- package/dist/commands/export.js +157 -0
- package/dist/commands/export.js.map +7 -0
- package/dist/commands/mcp-interactive.js +28 -18
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +9 -7
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/permissions.js +87 -0
- package/dist/commands/permissions.js.map +7 -0
- package/dist/commands/plugin/AddMarketplaceForm.js +3 -2
- package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
- package/dist/commands/plugin/ConfirmDialog.js +2 -1
- package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
- package/dist/commands/plugin/ErrorView.js +2 -1
- package/dist/commands/plugin/ErrorView.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js +5 -4
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsManager.js +5 -4
- package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
- package/dist/commands/plugin/MainMenu.js +2 -1
- package/dist/commands/plugin/MainMenu.js.map +2 -2
- package/dist/commands/plugin/MarketplaceManager.js +5 -4
- package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
- package/dist/commands/plugin/MarketplaceSelector.js +4 -3
- package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
- package/dist/commands/plugin/PlaceholderScreen.js +3 -2
- package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
- package/dist/commands/plugin/PluginBrowser.js +6 -5
- package/dist/commands/plugin/PluginBrowser.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsInstall.js +5 -4
- package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsManage.js +4 -3
- package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
- package/dist/commands/plugin.js +16 -15
- package/dist/commands/plugin.js.map +2 -2
- package/dist/commands/quit.js +3 -1
- package/dist/commands/quit.js.map +2 -2
- package/dist/commands/sandbox.js +105 -0
- package/dist/commands/sandbox.js.map +7 -0
- package/dist/commands/setup.js +2 -1
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/status.js +59 -0
- package/dist/commands/status.js.map +7 -0
- package/dist/commands/tasks.js +108 -0
- package/dist/commands/tasks.js.map +7 -0
- package/dist/commands/todos.js +123 -0
- package/dist/commands/todos.js.map +7 -0
- package/dist/commands/undo.js +245 -0
- package/dist/commands/undo.js.map +7 -0
- package/dist/commands.js +22 -2
- package/dist/commands.js.map +2 -2
- package/dist/components/AgentThinkingBlock.js +10 -18
- package/dist/components/AgentThinkingBlock.js.map +2 -2
- package/dist/components/AsciiLogo.js +7 -8
- package/dist/components/AsciiLogo.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/QuestionView.js +2 -1
- package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
- package/dist/components/BackgroundTasksPanel.js +78 -29
- package/dist/components/BackgroundTasksPanel.js.map +2 -2
- package/dist/components/BashStreamingProgress.js +24 -0
- package/dist/components/BashStreamingProgress.js.map +7 -0
- package/dist/components/CollapsibleHint.js +15 -0
- package/dist/components/CollapsibleHint.js.map +7 -0
- package/dist/components/Config.js +3 -2
- package/dist/components/Config.js.map +2 -2
- package/dist/components/ConsoleOAuthFlow.js +2 -1
- package/dist/components/ConsoleOAuthFlow.js.map +2 -2
- package/dist/components/Cost.js +2 -1
- package/dist/components/Cost.js.map +2 -2
- package/dist/components/FileEditToolUpdatedMessage.js +1 -1
- package/dist/components/FileEditToolUpdatedMessage.js.map +2 -2
- package/dist/components/HeaderBar.js +13 -8
- package/dist/components/HeaderBar.js.map +2 -2
- package/dist/components/HistorySearchOverlay.js +4 -3
- package/dist/components/HistorySearchOverlay.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +134 -0
- package/dist/components/HotkeyHelpPanel.js.map +7 -0
- package/dist/components/InvalidConfigDialog.js +2 -1
- package/dist/components/InvalidConfigDialog.js.map +2 -2
- package/dist/components/Logo.js +24 -68
- package/dist/components/Logo.js.map +2 -2
- package/dist/components/MCPServerApprovalDialog.js +2 -1
- package/dist/components/MCPServerApprovalDialog.js.map +2 -2
- package/dist/components/MCPServerDialogCopy.js +2 -1
- package/dist/components/MCPServerDialogCopy.js.map +2 -2
- package/dist/components/MCPServerMultiselectDialog.js +2 -1
- package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
- package/dist/components/Message.js +23 -7
- package/dist/components/Message.js.map +3 -3
- package/dist/components/MessageSelector.js +4 -3
- package/dist/components/MessageSelector.js.map +2 -2
- package/dist/components/ModeIndicator.js +2 -1
- package/dist/components/ModeIndicator.js.map +2 -2
- package/dist/components/ModelConfig.js +20 -6
- package/dist/components/ModelConfig.js.map +2 -2
- package/dist/components/ModelListManager.js +7 -6
- package/dist/components/ModelListManager.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +27 -14
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/Onboarding.js +22 -16
- package/dist/components/Onboarding.js.map +2 -2
- package/dist/components/OperationSummary.js +130 -0
- package/dist/components/OperationSummary.js.map +7 -0
- package/dist/components/ProgressBar.js +74 -0
- package/dist/components/ProgressBar.js.map +7 -0
- package/dist/components/PromptInput.js +210 -87
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/RequestStatusIndicator.js +194 -0
- package/dist/components/RequestStatusIndicator.js.map +7 -0
- package/dist/components/SensitiveFileWarning.js +31 -0
- package/dist/components/SensitiveFileWarning.js.map +7 -0
- package/dist/components/Spinner.js +141 -27
- package/dist/components/Spinner.js.map +2 -2
- package/dist/components/SpinnerSymbol.js +21 -27
- package/dist/components/SpinnerSymbol.js.map +2 -2
- package/dist/components/StreamingBashOutput.js +9 -8
- package/dist/components/StreamingBashOutput.js.map +2 -2
- package/dist/components/StructuredDiff.js +6 -8
- package/dist/components/StructuredDiff.js.map +2 -2
- package/dist/components/SubagentBlock.js +5 -3
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/SubagentProgress.js +17 -15
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TaskCard.js +30 -24
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TextInput.js +9 -1
- package/dist/components/TextInput.js.map +2 -2
- package/dist/components/TodoChangeBlock.js +1 -1
- package/dist/components/TodoChangeBlock.js.map +2 -2
- package/dist/components/TodoPanel.js +140 -31
- package/dist/components/TodoPanel.js.map +3 -3
- package/dist/components/TokenCounter.js +74 -0
- package/dist/components/TokenCounter.js.map +7 -0
- package/dist/components/TokenWarning.js +2 -1
- package/dist/components/TokenWarning.js.map +2 -2
- package/dist/components/ToolUseLoader.js +2 -2
- package/dist/components/ToolUseLoader.js.map +2 -2
- package/dist/components/TreeConnector.js +26 -0
- package/dist/components/TreeConnector.js.map +7 -0
- package/dist/components/TrustDialog.js +2 -1
- package/dist/components/TrustDialog.js.map +2 -2
- package/dist/components/TurnCompletionIndicator.js +18 -0
- package/dist/components/TurnCompletionIndicator.js.map +7 -0
- package/dist/components/binary-feedback/BinaryFeedbackView.js +2 -1
- package/dist/components/binary-feedback/BinaryFeedbackView.js.map +2 -2
- package/dist/components/messages/AssistantTextMessage.js +20 -9
- package/dist/components/messages/AssistantTextMessage.js.map +2 -2
- package/dist/components/messages/AssistantThinkingMessage.js +18 -3
- package/dist/components/messages/AssistantThinkingMessage.js.map +2 -2
- package/dist/components/messages/AssistantToolUseMessage.js +17 -10
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/GroupRenderer.js +54 -0
- package/dist/components/messages/GroupRenderer.js.map +7 -0
- package/dist/components/messages/NestedTasksPreview.js +24 -0
- package/dist/components/messages/NestedTasksPreview.js.map +7 -0
- package/dist/components/messages/ParallelTasksGroupView.js +93 -0
- package/dist/components/messages/ParallelTasksGroupView.js.map +7 -0
- package/dist/components/messages/TaskInModuleView.js +218 -0
- package/dist/components/messages/TaskInModuleView.js.map +7 -0
- package/dist/components/messages/TaskOutputContent.js +56 -0
- package/dist/components/messages/TaskOutputContent.js.map +7 -0
- package/dist/components/messages/UserPromptMessage.js +2 -2
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +2 -3
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
- package/dist/components/permissions/FallbackPermissionRequest.js +4 -4
- package/dist/components/permissions/FallbackPermissionRequest.js.map +2 -2
- package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +4 -4
- package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +2 -2
- package/dist/constants/colors.js +120 -54
- package/dist/constants/colors.js.map +2 -2
- package/dist/constants/formatRules.js +102 -0
- package/dist/constants/formatRules.js.map +7 -0
- package/dist/constants/prompts.js +12 -34
- package/dist/constants/prompts.js.map +2 -2
- package/dist/constants/symbols.js +64 -6
- package/dist/constants/symbols.js.map +2 -2
- package/dist/constants/timing.js +5 -0
- package/dist/constants/timing.js.map +2 -2
- package/dist/constants/toolInputExamples.js +84 -0
- package/dist/constants/toolInputExamples.js.map +7 -0
- package/dist/core/backupManager.js +321 -0
- package/dist/core/backupManager.js.map +7 -0
- package/dist/core/config/defaults.js +84 -0
- package/dist/core/config/defaults.js.map +7 -0
- package/dist/core/config/index.js +111 -0
- package/dist/core/config/index.js.map +7 -0
- package/dist/core/config/loader.js +221 -0
- package/dist/core/config/loader.js.map +7 -0
- package/dist/core/config/migrations.js +128 -0
- package/dist/core/config/migrations.js.map +7 -0
- package/dist/core/config/schema.js +178 -0
- package/dist/core/config/schema.js.map +7 -0
- package/dist/core/costTracker.js +129 -0
- package/dist/core/costTracker.js.map +7 -0
- package/dist/core/gitAutoCommit.js +287 -0
- package/dist/core/gitAutoCommit.js.map +7 -0
- package/dist/core/index.js +8 -0
- package/dist/core/index.js.map +7 -0
- package/dist/core/operationTracker.js +212 -0
- package/dist/core/operationTracker.js.map +7 -0
- package/dist/core/permissions/auditLog.js +204 -0
- package/dist/core/permissions/auditLog.js.map +7 -0
- package/dist/core/permissions/engine/index.js +3 -0
- package/dist/core/permissions/engine/index.js.map +7 -0
- package/dist/core/permissions/engine/permissionEngine.js +106 -0
- package/dist/core/permissions/engine/permissionEngine.js.map +7 -0
- package/dist/core/permissions/engine/types.js +1 -0
- package/dist/core/permissions/engine/types.js.map +7 -0
- package/dist/core/permissions/index.js +84 -0
- package/dist/core/permissions/index.js.map +7 -0
- package/dist/core/permissions/ruleEngine.js +259 -0
- package/dist/core/permissions/ruleEngine.js.map +7 -0
- package/dist/core/permissions/rules/allowedToolsRule.js +62 -0
- package/dist/core/permissions/rules/allowedToolsRule.js.map +7 -0
- package/dist/core/permissions/rules/autoEscalationRule.js +296 -0
- package/dist/core/permissions/rules/autoEscalationRule.js.map +7 -0
- package/dist/core/permissions/rules/index.js +46 -0
- package/dist/core/permissions/rules/index.js.map +7 -0
- package/dist/core/permissions/rules/planModeRule.js +55 -0
- package/dist/core/permissions/rules/planModeRule.js.map +7 -0
- package/dist/core/permissions/rules/projectBoundaryRule.js +173 -0
- package/dist/core/permissions/rules/projectBoundaryRule.js.map +7 -0
- package/dist/core/permissions/rules/safeModeRule.js +65 -0
- package/dist/core/permissions/rules/safeModeRule.js.map +7 -0
- package/dist/core/permissions/rules/sensitivePathsRule.js +345 -0
- package/dist/core/permissions/rules/sensitivePathsRule.js.map +7 -0
- package/dist/core/permissions/types.js +127 -0
- package/dist/core/permissions/types.js.map +7 -0
- package/dist/core/tokenStats.js +9 -0
- package/dist/core/tokenStats.js.map +7 -0
- package/dist/core/tokenStatsManager.js +331 -0
- package/dist/core/tokenStatsManager.js.map +7 -0
- package/dist/core/tools/executor.js +143 -0
- package/dist/core/tools/executor.js.map +7 -0
- package/dist/core/tools/index.js +15 -0
- package/dist/core/tools/index.js.map +7 -0
- package/dist/core/tools/registry.js +183 -0
- package/dist/core/tools/registry.js.map +7 -0
- package/dist/core/tools/types.js +1 -0
- package/dist/core/tools/types.js.map +7 -0
- package/dist/cost-tracker.js +23 -15
- package/dist/cost-tracker.js.map +2 -2
- package/dist/entrypoints/cli.js +158 -130
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/entrypoints/mcp.js +12 -4
- package/dist/entrypoints/mcp.js.map +2 -2
- package/dist/history.js +14 -3
- package/dist/history.js.map +2 -2
- package/dist/hooks/useAgentTokenStats.js +72 -0
- package/dist/hooks/useAgentTokenStats.js.map +7 -0
- package/dist/hooks/useAgentTranscripts.js +140 -0
- package/dist/hooks/useAgentTranscripts.js.map +7 -0
- package/dist/hooks/useAnimationSync.js +53 -0
- package/dist/hooks/useAnimationSync.js.map +7 -0
- package/dist/hooks/useArrowKeyHistory.js +4 -2
- package/dist/hooks/useArrowKeyHistory.js.map +2 -2
- package/dist/hooks/useCanUseTool.js +3 -1
- package/dist/hooks/useCanUseTool.js.map +2 -2
- package/dist/hooks/useExitOnCtrlCD.js +9 -5
- package/dist/hooks/useExitOnCtrlCD.js.map +2 -2
- package/dist/hooks/useHookStatus.js +40 -0
- package/dist/hooks/useHookStatus.js.map +7 -0
- package/dist/hooks/useLogMessages.js +29 -2
- package/dist/hooks/useLogMessages.js.map +2 -2
- package/dist/hooks/useMessageGroups.js +43 -0
- package/dist/hooks/useMessageGroups.js.map +7 -0
- package/dist/hooks/useTerminalSize.js +62 -6
- package/dist/hooks/useTerminalSize.js.map +2 -2
- package/dist/hooks/useUnifiedCompletion.js +69 -0
- package/dist/hooks/useUnifiedCompletion.js.map +2 -2
- package/dist/i18n/index.js +109 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/locales/en.js +348 -0
- package/dist/i18n/locales/en.js.map +7 -0
- package/dist/i18n/locales/index.js +7 -0
- package/dist/i18n/locales/index.js.map +7 -0
- package/dist/i18n/locales/zh-CN.js +348 -0
- package/dist/i18n/locales/zh-CN.js.map +7 -0
- package/dist/i18n/types.js +8 -0
- package/dist/i18n/types.js.map +7 -0
- package/dist/permissions.js +28 -1
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +253 -21
- package/dist/query.js.map +3 -3
- package/dist/screens/REPL.js +523 -194
- package/dist/screens/REPL.js.map +3 -3
- package/dist/services/adapters/chatCompletions.js +3 -1
- package/dist/services/adapters/chatCompletions.js.map +2 -2
- package/dist/services/adapters/messageNormalizer.js +354 -0
- package/dist/services/adapters/messageNormalizer.js.map +7 -0
- package/dist/services/adapters/responsesAPI.js +6 -3
- package/dist/services/adapters/responsesAPI.js.map +2 -2
- package/dist/services/checkpointManager.js +386 -0
- package/dist/services/checkpointManager.js.map +7 -0
- package/dist/services/claude.js +192 -14
- package/dist/services/claude.js.map +3 -3
- package/dist/services/compressionService.js +50 -1
- package/dist/services/compressionService.js.map +2 -2
- package/dist/services/contextMonitor.js +162 -0
- package/dist/services/contextMonitor.js.map +7 -0
- package/dist/services/customCommands.js +60 -41
- package/dist/services/customCommands.js.map +2 -2
- package/dist/services/hookExecutor.js +173 -1
- package/dist/services/hookExecutor.js.map +2 -2
- package/dist/services/intelligentCompactor.js +281 -0
- package/dist/services/intelligentCompactor.js.map +7 -0
- package/dist/services/lspConfig.js +109 -0
- package/dist/services/lspConfig.js.map +7 -0
- package/dist/services/mcpClient.js +338 -43
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/modelOrchestrator.js +310 -0
- package/dist/services/modelOrchestrator.js.map +7 -0
- package/dist/services/openai.js +8 -1
- package/dist/services/openai.js.map +2 -2
- package/dist/services/outputStyles.js +138 -0
- package/dist/services/outputStyles.js.map +7 -0
- package/dist/services/plugins/index.js +5 -0
- package/dist/services/plugins/index.js.map +7 -0
- package/dist/services/plugins/lspServers.js +188 -0
- package/dist/services/plugins/lspServers.js.map +7 -0
- package/dist/services/plugins/pluginRuntime.js +229 -0
- package/dist/services/plugins/pluginRuntime.js.map +7 -0
- package/dist/services/plugins/pluginValidation.js +219 -0
- package/dist/services/plugins/pluginValidation.js.map +7 -0
- package/dist/services/plugins/skillMarketplace.js +556 -0
- package/dist/services/plugins/skillMarketplace.js.map +7 -0
- package/dist/services/responseStateManager.js +37 -3
- package/dist/services/responseStateManager.js.map +2 -2
- package/dist/services/sandbox/filesystemBoundary.js +341 -0
- package/dist/services/sandbox/filesystemBoundary.js.map +7 -0
- package/dist/services/sandbox/index.js +14 -0
- package/dist/services/sandbox/index.js.map +7 -0
- package/dist/services/sandbox/networkProxy.js +293 -0
- package/dist/services/sandbox/networkProxy.js.map +7 -0
- package/dist/services/sandbox/sandboxController.js +574 -0
- package/dist/services/sandbox/sandboxController.js.map +7 -0
- package/dist/services/sandbox/types.js +50 -0
- package/dist/services/sandbox/types.js.map +7 -0
- package/dist/services/sessionMemory.js +266 -0
- package/dist/services/sessionMemory.js.map +7 -0
- package/dist/services/taskRouter.js +324 -0
- package/dist/services/taskRouter.js.map +7 -0
- package/dist/tools/ArchitectTool/ArchitectTool.js +7 -1
- package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +6 -2
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +2 -1
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
- package/dist/tools/BaseTool.js +72 -0
- package/dist/tools/BaseTool.js.map +7 -0
- package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js +3 -0
- package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +79 -3
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/BashToolResultMessage.js +3 -0
- package/dist/tools/BashTool/BashToolResultMessage.js.map +2 -2
- package/dist/tools/BashTool/OutputLine.js +54 -0
- package/dist/tools/BashTool/OutputLine.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +336 -3
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +29 -4
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileEditTool/prompt.js +6 -3
- package/dist/tools/FileEditTool/prompt.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +5 -5
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
- package/dist/tools/FileWriteTool/prompt.js +4 -2
- package/dist/tools/FileWriteTool/prompt.js.map +2 -2
- package/dist/tools/GlobTool/GlobTool.js +4 -2
- package/dist/tools/GlobTool/GlobTool.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +36 -7
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/KillShellTool/KillShellToolResultMessage.js +3 -0
- package/dist/tools/KillShellTool/KillShellToolResultMessage.js.map +2 -2
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +109 -0
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +7 -0
- package/dist/tools/ListMcpResourcesTool/prompt.js +19 -0
- package/dist/tools/ListMcpResourcesTool/prompt.js.map +7 -0
- package/dist/tools/LspTool/LspTool.js +664 -0
- package/dist/tools/LspTool/LspTool.js.map +7 -0
- package/dist/tools/LspTool/prompt.js +27 -0
- package/dist/tools/LspTool/prompt.js.map +7 -0
- package/dist/tools/MCPTool/MCPTool.js +9 -1
- package/dist/tools/MCPTool/MCPTool.js.map +2 -2
- package/dist/tools/MemoryReadTool/MemoryReadTool.js +19 -6
- package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +6 -6
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js +19 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
- package/dist/tools/MultiEditTool/prompt.js +5 -3
- package/dist/tools/MultiEditTool/prompt.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +7 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +75 -0
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +7 -0
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +109 -0
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +7 -0
- package/dist/tools/PlanModeTool/prompt.js +94 -0
- package/dist/tools/PlanModeTool/prompt.js.map +7 -0
- package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +130 -0
- package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +7 -0
- package/dist/tools/ReadMcpResourceTool/prompt.js +17 -0
- package/dist/tools/ReadMcpResourceTool/prompt.js.map +7 -0
- package/dist/tools/SkillTool/SkillTool.js +10 -4
- package/dist/tools/SkillTool/SkillTool.js.map +2 -2
- package/dist/tools/SkillTool/prompt.js +1 -1
- package/dist/tools/SkillTool/prompt.js.map +1 -1
- package/dist/tools/SlashCommandTool/SlashCommandTool.js +260 -0
- package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +7 -0
- package/dist/tools/SlashCommandTool/prompt.js +35 -0
- package/dist/tools/SlashCommandTool/prompt.js.map +7 -0
- package/dist/tools/TaskOutputTool/TaskOutputTool.js +190 -0
- package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +7 -0
- package/dist/tools/TaskOutputTool/prompt.js +15 -0
- package/dist/tools/TaskOutputTool/prompt.js.map +7 -0
- package/dist/tools/TaskTool/TaskTool.js +310 -104
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskTool/prompt.js.map +2 -2
- package/dist/tools/TodoWriteTool/TodoWriteTool.js +42 -77
- package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/URLFetcherTool.js +4 -1
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/cache.js +55 -8
- package/dist/tools/URLFetcherTool/cache.js.map +2 -2
- package/dist/tools.js +31 -2
- package/dist/tools.js.map +2 -2
- package/dist/types/hooks.js +4 -0
- package/dist/types/hooks.js.map +2 -2
- package/dist/types/marketplace.js.map +2 -2
- package/dist/types/messageGroup.js +36 -0
- package/dist/types/messageGroup.js.map +7 -0
- package/dist/types/plugin.js.map +2 -2
- package/dist/types/thinking.js +1 -0
- package/dist/types/thinking.js.map +7 -0
- package/dist/utils/BackgroundShellManager.js +136 -39
- package/dist/utils/BackgroundShellManager.js.map +2 -2
- package/dist/utils/CircuitBreaker.js +242 -0
- package/dist/utils/CircuitBreaker.js.map +7 -0
- package/dist/utils/MessageBatchBuffer.js +102 -0
- package/dist/utils/MessageBatchBuffer.js.map +7 -0
- package/dist/utils/PersistentShell.js +151 -1
- package/dist/utils/PersistentShell.js.map +2 -2
- package/dist/utils/agentLoader.js +1 -23
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/agentTranscripts.js +641 -0
- package/dist/utils/agentTranscripts.js.map +7 -0
- package/dist/utils/animationManager.js +213 -0
- package/dist/utils/animationManager.js.map +7 -0
- package/dist/utils/animationSync.js +110 -0
- package/dist/utils/animationSync.js.map +7 -0
- package/dist/utils/ask.js +2 -0
- package/dist/utils/ask.js.map +2 -2
- package/dist/utils/asyncFile.js +215 -0
- package/dist/utils/asyncFile.js.map +7 -0
- package/dist/utils/backgroundAgentManager.js +231 -0
- package/dist/utils/backgroundAgentManager.js.map +7 -0
- package/dist/utils/config.js +108 -10
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/conversationRecovery.js +19 -0
- package/dist/utils/conversationRecovery.js.map +2 -2
- package/dist/utils/credentials/CredentialStore.js +1 -0
- package/dist/utils/credentials/CredentialStore.js.map +7 -0
- package/dist/utils/credentials/EncryptedFileStore.js +157 -0
- package/dist/utils/credentials/EncryptedFileStore.js.map +7 -0
- package/dist/utils/credentials/index.js +37 -0
- package/dist/utils/credentials/index.js.map +7 -0
- package/dist/utils/credentials/migration.js +82 -0
- package/dist/utils/credentials/migration.js.map +7 -0
- package/dist/utils/exit.js +73 -0
- package/dist/utils/exit.js.map +7 -0
- package/dist/utils/format.js +73 -5
- package/dist/utils/format.js.map +2 -2
- package/dist/utils/generators.js +76 -6
- package/dist/utils/generators.js.map +2 -2
- package/dist/utils/globalErrorHandler.js +149 -0
- package/dist/utils/globalErrorHandler.js.map +7 -0
- package/dist/utils/groupHandlers/index.js +8 -0
- package/dist/utils/groupHandlers/index.js.map +7 -0
- package/dist/utils/groupHandlers/parallelTasksHandler.js +140 -0
- package/dist/utils/groupHandlers/parallelTasksHandler.js.map +7 -0
- package/dist/utils/groupHandlers/taskHandler.js +104 -0
- package/dist/utils/groupHandlers/taskHandler.js.map +7 -0
- package/dist/utils/groupHandlers/types.js +1 -0
- package/dist/utils/groupHandlers/types.js.map +7 -0
- package/dist/utils/logRotation.js +224 -0
- package/dist/utils/logRotation.js.map +7 -0
- package/dist/utils/markdown.js +13 -1
- package/dist/utils/markdown.js.map +2 -2
- package/dist/utils/marketplaceManager.js +3 -5
- package/dist/utils/marketplaceManager.js.map +2 -2
- package/dist/utils/memSafety.js +264 -0
- package/dist/utils/memSafety.js.map +7 -0
- package/dist/utils/messageGroupManager.js +274 -0
- package/dist/utils/messageGroupManager.js.map +7 -0
- package/dist/utils/messages.js +13 -4
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/model.js +119 -15
- package/dist/utils/model.js.map +3 -3
- package/dist/utils/permissions/filesystem.js +162 -6
- package/dist/utils/permissions/filesystem.js.map +2 -2
- package/dist/utils/plan/planMode.js +143 -0
- package/dist/utils/plan/planMode.js.map +7 -0
- package/dist/utils/pluginLoader.js +17 -21
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/ripgrep.js +55 -2
- package/dist/utils/ripgrep.js.map +2 -2
- package/dist/utils/safePath.js +132 -0
- package/dist/utils/safePath.js.map +7 -0
- package/dist/utils/sanitizeInput.js +32 -0
- package/dist/utils/sanitizeInput.js.map +7 -0
- package/dist/utils/secureKeyStorage.js +312 -0
- package/dist/utils/secureKeyStorage.js.map +7 -0
- package/dist/utils/sensitiveFiles.js +125 -0
- package/dist/utils/sensitiveFiles.js.map +7 -0
- package/dist/utils/session/sessionPlugins.js +67 -0
- package/dist/utils/session/sessionPlugins.js.map +7 -0
- package/dist/utils/taskDisplayUtils.js +257 -0
- package/dist/utils/taskDisplayUtils.js.map +7 -0
- package/dist/utils/teamConfig.js +2 -1
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/theme.js +6 -6
- package/dist/utils/theme.js.map +1 -1
- package/dist/utils/todoStorage.js +92 -2
- package/dist/utils/todoStorage.js.map +2 -2
- package/dist/utils/toolRiskClassification.js +207 -0
- package/dist/utils/toolRiskClassification.js.map +7 -0
- package/dist/utils/toolTimeout.js +136 -0
- package/dist/utils/toolTimeout.js.map +7 -0
- package/dist/utils/tooling/safeRender.js +116 -0
- package/dist/utils/tooling/safeRender.js.map +7 -0
- package/dist/utils/userFriendlyError.js +346 -0
- package/dist/utils/userFriendlyError.js.map +7 -0
- package/dist/utils/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +17 -5
- package/scripts/postinstall.js +128 -38
- package/dist/commands/agents.js +0 -2086
- package/dist/commands/agents.js.map +0 -7
- package/dist/commands/build.js +0 -74
- package/dist/commands/build.js.map +0 -7
- package/dist/commands/compression.js +0 -57
- package/dist/commands/compression.js.map +0 -7
- package/dist/commands/listen.js +0 -37
- package/dist/commands/listen.js.map +0 -7
- package/dist/commands/login.js +0 -37
- package/dist/commands/login.js.map +0 -7
- package/dist/commands/logout.js +0 -33
- package/dist/commands/logout.js.map +0 -7
- package/dist/commands/mcp.js +0 -40
- package/dist/commands/mcp.js.map +0 -7
- package/dist/commands/mcp_refresh.js +0 -40
- package/dist/commands/mcp_refresh.js.map +0 -7
- package/dist/commands/modelstatus.js +0 -21
- package/dist/commands/modelstatus.js.map +0 -7
- package/dist/commands/onboarding.js +0 -36
- package/dist/commands/onboarding.js.map +0 -7
- package/dist/commands/plugin-interactive.js +0 -446
- package/dist/commands/plugin-interactive.js.map +0 -7
- package/dist/commands/pr_comments.js +0 -61
- package/dist/commands/pr_comments.js.map +0 -7
- package/dist/commands/release-notes.js +0 -30
- package/dist/commands/release-notes.js.map +0 -7
- package/dist/commands/review.js +0 -51
- package/dist/commands/review.js.map +0 -7
- package/dist/components/Bug.js +0 -147
- package/dist/components/Bug.js.map +0 -7
- package/dist/components/ModelSelector.js +0 -2062
- package/dist/components/ModelSelector.js.map +0 -7
- package/dist/components/ModelStatusDisplay.js +0 -87
- package/dist/components/ModelStatusDisplay.js.map +0 -7
- package/dist/entrypoints/cli-wrapper.js +0 -61
- package/dist/entrypoints/cli-wrapper.js.map +0 -7
- package/dist/hooks/useCancelRequest.js +0 -28
- package/dist/hooks/useCancelRequest.js.map +0 -7
- package/dist/screens/Doctor.js +0 -22
- package/dist/screens/Doctor.js.map +0 -7
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { realpathSync, existsSync, lstatSync } from "fs";
|
|
2
|
+
import { resolve, isAbsolute, relative, sep, join } from "path";
|
|
3
|
+
function safeResolvePath(inputPath, cwd, allowedRoot) {
|
|
4
|
+
try {
|
|
5
|
+
const absolutePath = isAbsolute(inputPath) ? resolve(inputPath) : resolve(cwd, inputPath);
|
|
6
|
+
let isSymlink = false;
|
|
7
|
+
let realPath = absolutePath;
|
|
8
|
+
if (existsSync(absolutePath)) {
|
|
9
|
+
try {
|
|
10
|
+
isSymlink = lstatSync(absolutePath).isSymbolicLink();
|
|
11
|
+
realPath = realpathSync(absolutePath);
|
|
12
|
+
} catch (e) {
|
|
13
|
+
realPath = absolutePath;
|
|
14
|
+
}
|
|
15
|
+
} else {
|
|
16
|
+
realPath = findRealPathForNonexistent(absolutePath);
|
|
17
|
+
}
|
|
18
|
+
return validateBoundary(realPath, allowedRoot, isSymlink);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return {
|
|
21
|
+
valid: false,
|
|
22
|
+
resolvedPath: inputPath,
|
|
23
|
+
isSymlink: false,
|
|
24
|
+
error: `Failed to validate path: ${e instanceof Error ? e.message : String(e)}`
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function findRealPathForNonexistent(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
let currentPath = filePath;
|
|
31
|
+
let depth = 0;
|
|
32
|
+
const maxDepth = 50;
|
|
33
|
+
while (!existsSync(currentPath) && depth < maxDepth) {
|
|
34
|
+
const parent = resolve(currentPath, "..");
|
|
35
|
+
if (parent === currentPath) break;
|
|
36
|
+
currentPath = parent;
|
|
37
|
+
depth++;
|
|
38
|
+
}
|
|
39
|
+
if (existsSync(currentPath)) {
|
|
40
|
+
const realParent = realpathSync(currentPath);
|
|
41
|
+
let remaining = filePath.slice(currentPath.length);
|
|
42
|
+
if (remaining.startsWith(sep)) {
|
|
43
|
+
remaining = remaining.slice(1);
|
|
44
|
+
}
|
|
45
|
+
return remaining ? join(realParent, remaining) : realParent;
|
|
46
|
+
}
|
|
47
|
+
return resolve(filePath);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
return resolve(filePath);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function validateBoundary(resolvedPath, allowedRoot, isSymlink) {
|
|
53
|
+
let normalizedRoot;
|
|
54
|
+
try {
|
|
55
|
+
if (existsSync(allowedRoot)) {
|
|
56
|
+
normalizedRoot = realpathSync(allowedRoot);
|
|
57
|
+
} else {
|
|
58
|
+
normalizedRoot = resolve(allowedRoot);
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
normalizedRoot = resolve(allowedRoot);
|
|
62
|
+
}
|
|
63
|
+
normalizedRoot = normalizePath(normalizedRoot);
|
|
64
|
+
const normalizedResolved = normalizePath(resolvedPath);
|
|
65
|
+
const rel = relative(normalizedRoot, normalizedResolved);
|
|
66
|
+
if (rel.startsWith("..")) {
|
|
67
|
+
return {
|
|
68
|
+
valid: false,
|
|
69
|
+
resolvedPath,
|
|
70
|
+
isSymlink,
|
|
71
|
+
error: `Path escapes sandbox boundary: ${resolvedPath} is outside ${normalizedRoot}`
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (isAbsolute(rel)) {
|
|
75
|
+
return {
|
|
76
|
+
valid: false,
|
|
77
|
+
resolvedPath,
|
|
78
|
+
isSymlink,
|
|
79
|
+
error: `Path is on different drive or root: ${resolvedPath}`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
valid: true,
|
|
84
|
+
resolvedPath,
|
|
85
|
+
isSymlink
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function normalizePath(p) {
|
|
89
|
+
const resolved = resolve(p);
|
|
90
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
91
|
+
}
|
|
92
|
+
function hasSymlinksInPath(filePath) {
|
|
93
|
+
try {
|
|
94
|
+
const absolutePath = isAbsolute(filePath) ? filePath : resolve(filePath);
|
|
95
|
+
const parts = absolutePath.split(sep).filter((p) => p);
|
|
96
|
+
let currentPath = "";
|
|
97
|
+
for (const part of parts) {
|
|
98
|
+
if (currentPath) {
|
|
99
|
+
currentPath = resolve(currentPath, part);
|
|
100
|
+
} else {
|
|
101
|
+
currentPath = sep === "\\" ? `${part}\\` : `/${part}`;
|
|
102
|
+
}
|
|
103
|
+
if (!existsSync(currentPath)) break;
|
|
104
|
+
try {
|
|
105
|
+
if (lstatSync(currentPath).isSymbolicLink()) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
} catch (e) {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
} catch (e) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function getRealPath(filePath) {
|
|
117
|
+
try {
|
|
118
|
+
const absolutePath = isAbsolute(filePath) ? filePath : resolve(filePath);
|
|
119
|
+
if (existsSync(absolutePath)) {
|
|
120
|
+
return realpathSync(absolutePath);
|
|
121
|
+
}
|
|
122
|
+
return absolutePath;
|
|
123
|
+
} catch (e) {
|
|
124
|
+
return filePath;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
getRealPath,
|
|
129
|
+
hasSymlinksInPath,
|
|
130
|
+
safeResolvePath
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=safePath.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/safePath.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Safe Path Resolution Utility\n *\n * Provides secure path resolution with symbolic link tracking and boundary validation.\n * Prevents attackers from escaping sandbox boundaries using symlinks.\n */\n\nimport { realpathSync, existsSync, lstatSync } from 'fs'\nimport { resolve, isAbsolute, relative, sep, join } from 'path'\n\n/**\n * Result of a path validation operation\n */\nexport interface PathValidationResult {\n /** Whether the path is valid and within boundaries */\n valid: boolean\n /** The resolved real path (after following symlinks) */\n resolvedPath: string\n /** Whether the path itself is a symbolic link */\n isSymlink: boolean\n /** Error message if validation failed */\n error?: string\n}\n\n/**\n * Safely resolves a path to its real location, tracking symbolic links.\n * Validates that the final resolved path stays within the allowed boundary.\n *\n * @param inputPath The path to resolve (relative or absolute)\n * @param cwd Current working directory for relative path resolution\n * @param allowedRoot The root directory boundary that must not be escaped\n * @returns PathValidationResult with validation status and resolved path\n *\n * @example\n * const result = safeResolvePath('./file.txt', '/project', '/project')\n * if (result.valid) {\n * // Path is valid and doesn't escape boundary\n * console.log(result.resolvedPath)\n * }\n */\nexport function safeResolvePath(\n inputPath: string,\n cwd: string,\n allowedRoot: string,\n): PathValidationResult {\n try {\n // 1. Resolve to absolute path\n const absolutePath = isAbsolute(inputPath)\n ? resolve(inputPath)\n : resolve(cwd, inputPath)\n\n // 2. Determine if path is a symlink and get real path\n let isSymlink = false\n let realPath = absolutePath\n\n if (existsSync(absolutePath)) {\n // Path exists - check if it's a symlink and follow to real location\n try {\n isSymlink = lstatSync(absolutePath).isSymbolicLink()\n realPath = realpathSync(absolutePath)\n } catch (e) {\n // If stat/realpath fails, use absolute path\n realPath = absolutePath\n }\n } else {\n // Path doesn't exist - try to resolve via parents to detect symlink escapes\n realPath = findRealPathForNonexistent(absolutePath)\n }\n\n // 3. Validate that realPath is within allowed boundary\n return validateBoundary(realPath, allowedRoot, isSymlink)\n } catch (e) {\n return {\n valid: false,\n resolvedPath: inputPath,\n isSymlink: false,\n error: `Failed to validate path: ${e instanceof Error ? e.message : String(e)}`,\n }\n }\n}\n\n/**\n * Attempts to resolve a non-existent path by resolving existing parents.\n * This helps detect symlink escapes for paths that don't yet exist.\n */\nfunction findRealPathForNonexistent(filePath: string): string {\n try {\n // Walk up the path to find the first existing parent\n let currentPath = filePath\n let depth = 0\n const maxDepth = 50 // Prevent infinite loops\n\n while (!existsSync(currentPath) && depth < maxDepth) {\n const parent = resolve(currentPath, '..')\n if (parent === currentPath) break // Reached filesystem root\n currentPath = parent\n depth++\n }\n\n // If we found an existing path, resolve it and reconstruct\n if (existsSync(currentPath)) {\n const realParent = realpathSync(currentPath)\n // Remove the parent path and any leading separator from the remaining portion\n let remaining = filePath.slice(currentPath.length)\n if (remaining.startsWith(sep)) {\n remaining = remaining.slice(1)\n }\n return remaining ? join(realParent, remaining) : realParent\n }\n\n // Fallback: just return resolved path\n return resolve(filePath)\n } catch (e) {\n return resolve(filePath)\n }\n}\n\n/**\n * Validates that a resolved path stays within the allowed boundary.\n *\n * @param resolvedPath The absolute path to validate\n * @param allowedRoot The boundary root directory\n * @param isSymlink Whether the original path was a symlink\n * @returns PathValidationResult indicating if boundary is respected\n */\nfunction validateBoundary(\n resolvedPath: string,\n allowedRoot: string,\n isSymlink: boolean,\n): PathValidationResult {\n let normalizedRoot: string\n\n try {\n // Resolve the boundary root to its real path\n if (existsSync(allowedRoot)) {\n normalizedRoot = realpathSync(allowedRoot)\n } else {\n normalizedRoot = resolve(allowedRoot)\n }\n } catch (e) {\n normalizedRoot = resolve(allowedRoot)\n }\n\n // Normalize both paths for comparison (handle case sensitivity)\n normalizedRoot = normalizePath(normalizedRoot)\n const normalizedResolved = normalizePath(resolvedPath)\n\n // Check if the resolved path is within the boundary\n const rel = relative(normalizedRoot, normalizedResolved)\n\n // Validation fails if:\n // 1. Path goes up to parent directory (..)\n if (rel.startsWith('..')) {\n return {\n valid: false,\n resolvedPath,\n isSymlink,\n error: `Path escapes sandbox boundary: ${resolvedPath} is outside ${normalizedRoot}`,\n }\n }\n\n // 2. Relative path is absolute (different drive on Windows)\n if (isAbsolute(rel)) {\n return {\n valid: false,\n resolvedPath,\n isSymlink,\n error: `Path is on different drive or root: ${resolvedPath}`,\n }\n }\n\n return {\n valid: true,\n resolvedPath,\n isSymlink,\n }\n}\n\n/**\n * Normalizes a path for platform-consistent comparison.\n * On Windows, converts to lowercase for case-insensitive comparison.\n *\n * @param p The path to normalize\n * @returns Normalized path string\n */\nfunction normalizePath(p: string): string {\n const resolved = resolve(p)\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved\n}\n\n/**\n * Checks if a path contains any symlinks in its chain.\n * This is useful for detecting potential symlink attacks.\n *\n * @param filePath The path to check\n * @returns true if any component in the path is a symlink, false otherwise\n *\n * @example\n * const hasSymlinks = hasSymlinksInPath('/path/to/file')\n * if (hasSymlinks) {\n * console.log('Path contains one or more symlinks')\n * }\n */\nexport function hasSymlinksInPath(filePath: string): boolean {\n try {\n const absolutePath = isAbsolute(filePath) ? filePath : resolve(filePath)\n const parts = absolutePath.split(sep).filter(p => p)\n let currentPath = ''\n\n for (const part of parts) {\n if (currentPath) {\n currentPath = resolve(currentPath, part)\n } else {\n // Handle root directory\n currentPath = sep === '\\\\' ? `${part}\\\\` : `/${part}`\n }\n\n if (!existsSync(currentPath)) break\n\n try {\n if (lstatSync(currentPath).isSymbolicLink()) {\n return true\n }\n } catch (e) {\n // If we can't stat it, continue\n }\n }\n\n return false\n } catch (e) {\n return false\n }\n}\n\n/**\n * Gets the real path of a file, following symlinks.\n * Returns the original path if it can't be resolved.\n *\n * @param filePath The path to resolve\n * @returns The real path, or the input path if resolution fails\n */\nexport function getRealPath(filePath: string): string {\n try {\n const absolutePath = isAbsolute(filePath) ? filePath : resolve(filePath)\n if (existsSync(absolutePath)) {\n return realpathSync(absolutePath)\n }\n return absolutePath\n } catch (e) {\n return filePath\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
function sanitizeInput(input) {
|
|
2
|
+
if (!input) return input;
|
|
3
|
+
let sanitized = input;
|
|
4
|
+
sanitized = sanitized.replace(/\x1b{2,}/g, "");
|
|
5
|
+
sanitized = sanitized.replace(/\x1b[c78#]/g, "");
|
|
6
|
+
sanitized = sanitized.replace(
|
|
7
|
+
/\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g,
|
|
8
|
+
""
|
|
9
|
+
);
|
|
10
|
+
sanitized = sanitized.replace(/\x1b\].*?(?:\x1b\\|\x07|\x9c)/g, "");
|
|
11
|
+
sanitized = sanitized.replace(/\x1bP.*?(?:\x1b\\|\x9c)/g, "");
|
|
12
|
+
sanitized = sanitized.replace(/\x1b\^.*?(?:\x1b\\|\x9c)/g, "");
|
|
13
|
+
sanitized = sanitized.replace(/\x1b_.*?(?:\x1b\\|\x9c)/g, "");
|
|
14
|
+
sanitized = sanitized.replace(/\x1bX.*?(?:\x1b\\|\x9c)/g, "");
|
|
15
|
+
sanitized = sanitized.replace(/\x1b(?![[\]PO^_X])/g, "");
|
|
16
|
+
sanitized = sanitized.replace(
|
|
17
|
+
/[\x00-\x08\x0B\x0C\x0E-\x1A\x1C-\x1F\x7F]/g,
|
|
18
|
+
""
|
|
19
|
+
);
|
|
20
|
+
return sanitized;
|
|
21
|
+
}
|
|
22
|
+
function containsDangerousSequences(input) {
|
|
23
|
+
if (!input) return false;
|
|
24
|
+
if (input.includes("\x1B")) return true;
|
|
25
|
+
if (/[\x00-\x08\x0B\x0C\x0E-\x1A\x1C-\x1F\x7F]/.test(input)) return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
containsDangerousSequences,
|
|
30
|
+
sanitizeInput
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=sanitizeInput.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/sanitizeInput.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Sanitize input text to remove dangerous ANSI escape sequences\n * that could affect terminal rendering or cause unexpected behavior.\n *\n * This is particularly important for:\n * - History entries loaded from storage (may contain corrupted data)\n * - User input that might accidentally contain escape sequences\n *\n * Dangerous sequences include:\n * - ESC c (0x1B 0x63): RIS - Reset Initial State (clears screen, resets terminal)\n * - ESC [ ... sequences that could manipulate cursor/screen\n */\n\n/**\n * Remove dangerous ANSI escape sequences from input text.\n * Preserves normal text content while stripping control sequences.\n *\n * @param input - The input string to sanitize\n * @returns Sanitized string with dangerous escape sequences removed\n */\nexport function sanitizeInput(input: string): string {\n if (!input) return input\n\n // Remove ESC character (0x1B) sequences that are dangerous\n // Pattern matches:\n // - ESC followed by any single character (like ESC c for RIS)\n // - ESC [ followed by any CSI sequence (control sequence introducer)\n // - ESC ] followed by OSC sequence (operating system command)\n // - ESC ( or ESC ) for character set selection\n // - Multiple consecutive ESC characters\n let sanitized = input\n\n // Remove multiple consecutive ESC characters (often accidental)\n sanitized = sanitized.replace(/\\x1b{2,}/g, '')\n\n // Remove dangerous single-character escape sequences\n // ESC c = RIS (Reset Initial State) - THIS IS THE BUG CAUSE\n // ESC 7 = DECSC (save cursor)\n // ESC 8 = DECRC (restore cursor)\n // ESC # followed by digit for line attributes\n sanitized = sanitized.replace(/\\x1b[c78#]/g, '')\n\n // Remove CSI (Control Sequence Introducer) sequences: ESC [ ... final_byte\n // These can manipulate cursor, erase screen, change colors, etc.\n // Final byte is in range 0x40-0x7E (@ through ~)\n sanitized = sanitized.replace(\n /\\x1b\\[[\\x30-\\x3f]*[\\x20-\\x2f]*[\\x40-\\x7e]/g,\n '',\n )\n\n // Remove OSC (Operating System Command) sequences: ESC ] ... ST or BEL\n // ST (String Terminator) is ESC \\ or 0x9C\n // BEL is 0x07\n sanitized = sanitized.replace(/\\x1b\\].*?(?:\\x1b\\\\|\\x07|\\x9c)/g, '')\n\n // Remove DCS (Device Control String): ESC P ... ST\n sanitized = sanitized.replace(/\\x1bP.*?(?:\\x1b\\\\|\\x9c)/g, '')\n\n // Remove PM (Privacy Message): ESC ^ ... ST\n sanitized = sanitized.replace(/\\x1b\\^.*?(?:\\x1b\\\\|\\x9c)/g, '')\n\n // Remove APC (Application Program Command): ESC _ ... ST\n sanitized = sanitized.replace(/\\x1b_.*?(?:\\x1b\\\\|\\x9c)/g, '')\n\n // Remove SOS (Start of String): ESC X ... ST\n sanitized = sanitized.replace(/\\x1bX.*?(?:\\x1b\\\\|\\x9c)/g, '')\n\n // Remove any remaining standalone ESC characters\n // that don't form a recognized sequence\n sanitized = sanitized.replace(/\\x1b(?![[\\]PO^_X])/g, '')\n\n // Remove other control characters that shouldn't be in user input\n // Keep common ones: tab (0x09), newline (0x0A), carriage return (0x0D)\n sanitized = sanitized.replace(\n /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1A\\x1C-\\x1F\\x7F]/g,\n '',\n )\n\n return sanitized\n}\n\n/**\n * Check if input contains potentially dangerous escape sequences\n *\n * @param input - The input string to check\n * @returns true if input contains dangerous sequences\n */\nexport function containsDangerousSequences(input: string): boolean {\n if (!input) return false\n\n // Check for ESC character\n if (input.includes('\\x1b')) return true\n\n // Check for other control characters (excluding tab, newline, CR)\n if (/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1A\\x1C-\\x1F\\x7F]/.test(input)) return true\n\n return false\n}\n"],
|
|
5
|
+
"mappings": "AAoBO,SAAS,cAAc,OAAuB;AACnD,MAAI,CAAC,MAAO,QAAO;AASnB,MAAI,YAAY;AAGhB,cAAY,UAAU,QAAQ,aAAa,EAAE;AAO7C,cAAY,UAAU,QAAQ,eAAe,EAAE;AAK/C,cAAY,UAAU;AAAA,IACpB;AAAA,IACA;AAAA,EACF;AAKA,cAAY,UAAU,QAAQ,kCAAkC,EAAE;AAGlE,cAAY,UAAU,QAAQ,4BAA4B,EAAE;AAG5D,cAAY,UAAU,QAAQ,6BAA6B,EAAE;AAG7D,cAAY,UAAU,QAAQ,4BAA4B,EAAE;AAG5D,cAAY,UAAU,QAAQ,4BAA4B,EAAE;AAI5D,cAAY,UAAU,QAAQ,uBAAuB,EAAE;AAIvD,cAAY,UAAU;AAAA,IACpB;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,2BAA2B,OAAwB;AACjE,MAAI,CAAC,MAAO,QAAO;AAGnB,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AAGnC,MAAI,4CAA4C,KAAK,KAAK,EAAG,QAAO;AAEpE,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { spawnSync } from "child_process";
|
|
2
|
+
import {
|
|
3
|
+
existsSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
unlinkSync
|
|
8
|
+
} from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { homedir, hostname, platform } from "os";
|
|
11
|
+
import {
|
|
12
|
+
createCipheriv,
|
|
13
|
+
createDecipheriv,
|
|
14
|
+
randomBytes,
|
|
15
|
+
scryptSync,
|
|
16
|
+
createHash
|
|
17
|
+
} from "crypto";
|
|
18
|
+
const SERVICE_NAME = "com.minto.cli";
|
|
19
|
+
const ENCRYPTED_KEYS_DIR = join(homedir(), ".minto", "secure");
|
|
20
|
+
const ENCRYPTED_KEYS_FILE = join(ENCRYPTED_KEYS_DIR, "keys.enc");
|
|
21
|
+
function isMacOSWithKeychain() {
|
|
22
|
+
if (platform() !== "darwin") return false;
|
|
23
|
+
try {
|
|
24
|
+
const result = spawnSync("security", ["help"], {
|
|
25
|
+
encoding: "utf-8",
|
|
26
|
+
timeout: 5e3
|
|
27
|
+
});
|
|
28
|
+
return result.status === 0 || result.status === 1;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function getMachineKey() {
|
|
34
|
+
const machineId = getMachineId();
|
|
35
|
+
const combined = `${hostname()}-${machineId}-minto-secure-storage`;
|
|
36
|
+
return createHash("sha256").update(combined).digest();
|
|
37
|
+
}
|
|
38
|
+
function getMachineId() {
|
|
39
|
+
const sources = [
|
|
40
|
+
// macOS - use spawnSync instead of execSync for safety
|
|
41
|
+
() => {
|
|
42
|
+
if (platform() === "darwin") {
|
|
43
|
+
try {
|
|
44
|
+
const result = spawnSync(
|
|
45
|
+
"ioreg",
|
|
46
|
+
["-rd1", "-c", "IOPlatformExpertDevice"],
|
|
47
|
+
{
|
|
48
|
+
encoding: "utf-8",
|
|
49
|
+
timeout: 5e3
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
if (result.status === 0 && result.stdout) {
|
|
53
|
+
const match = result.stdout.match(
|
|
54
|
+
/"IOPlatformUUID"\s*=\s*"([^"]+)"/
|
|
55
|
+
);
|
|
56
|
+
if (match) return match[1];
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
},
|
|
63
|
+
// Linux - read from file directly (no shell needed)
|
|
64
|
+
() => {
|
|
65
|
+
if (platform() === "linux") {
|
|
66
|
+
try {
|
|
67
|
+
if (existsSync("/etc/machine-id")) {
|
|
68
|
+
return readFileSync("/etc/machine-id", "utf-8").trim();
|
|
69
|
+
}
|
|
70
|
+
if (existsSync("/var/lib/dbus/machine-id")) {
|
|
71
|
+
return readFileSync("/var/lib/dbus/machine-id", "utf-8").trim();
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
},
|
|
78
|
+
// Fallback: use hostname hash
|
|
79
|
+
() => {
|
|
80
|
+
return createHash("sha256").update(hostname()).digest("hex").slice(0, 32);
|
|
81
|
+
}
|
|
82
|
+
];
|
|
83
|
+
for (const source of sources) {
|
|
84
|
+
const id = source();
|
|
85
|
+
if (id) return id;
|
|
86
|
+
}
|
|
87
|
+
return "minto-default-machine-id";
|
|
88
|
+
}
|
|
89
|
+
function encrypt(data, key) {
|
|
90
|
+
const iv = randomBytes(16);
|
|
91
|
+
const salt = randomBytes(32);
|
|
92
|
+
const derivedKey = scryptSync(key, salt, 32);
|
|
93
|
+
const cipher = createCipheriv("aes-256-gcm", derivedKey, iv);
|
|
94
|
+
const encrypted = Buffer.concat([
|
|
95
|
+
cipher.update(data, "utf-8"),
|
|
96
|
+
cipher.final()
|
|
97
|
+
]);
|
|
98
|
+
const authTag = cipher.getAuthTag();
|
|
99
|
+
return [
|
|
100
|
+
salt.toString("base64"),
|
|
101
|
+
iv.toString("base64"),
|
|
102
|
+
authTag.toString("base64"),
|
|
103
|
+
encrypted.toString("base64")
|
|
104
|
+
].join(":");
|
|
105
|
+
}
|
|
106
|
+
function decrypt(encryptedData, key) {
|
|
107
|
+
const parts = encryptedData.split(":");
|
|
108
|
+
if (parts.length !== 4) {
|
|
109
|
+
throw new Error("Invalid encrypted data format");
|
|
110
|
+
}
|
|
111
|
+
const [saltB64, ivB64, authTagB64, encryptedB64] = parts;
|
|
112
|
+
const salt = Buffer.from(saltB64, "base64");
|
|
113
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
114
|
+
const authTag = Buffer.from(authTagB64, "base64");
|
|
115
|
+
const encrypted = Buffer.from(encryptedB64, "base64");
|
|
116
|
+
const derivedKey = scryptSync(key, salt, 32);
|
|
117
|
+
const decipher = createDecipheriv("aes-256-gcm", derivedKey, iv);
|
|
118
|
+
decipher.setAuthTag(authTag);
|
|
119
|
+
return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString(
|
|
120
|
+
"utf-8"
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
function storeInKeychain(keyName, value) {
|
|
124
|
+
try {
|
|
125
|
+
spawnSync(
|
|
126
|
+
"security",
|
|
127
|
+
["delete-generic-password", "-s", SERVICE_NAME, "-a", keyName],
|
|
128
|
+
{ timeout: 5e3 }
|
|
129
|
+
);
|
|
130
|
+
const result = spawnSync(
|
|
131
|
+
"security",
|
|
132
|
+
[
|
|
133
|
+
"add-generic-password",
|
|
134
|
+
"-s",
|
|
135
|
+
SERVICE_NAME,
|
|
136
|
+
"-a",
|
|
137
|
+
keyName,
|
|
138
|
+
"-w",
|
|
139
|
+
value,
|
|
140
|
+
"-U"
|
|
141
|
+
// Update if exists
|
|
142
|
+
],
|
|
143
|
+
{ timeout: 5e3 }
|
|
144
|
+
);
|
|
145
|
+
return result.status === 0;
|
|
146
|
+
} catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function getFromKeychain(keyName) {
|
|
151
|
+
try {
|
|
152
|
+
const result = spawnSync(
|
|
153
|
+
"security",
|
|
154
|
+
[
|
|
155
|
+
"find-generic-password",
|
|
156
|
+
"-s",
|
|
157
|
+
SERVICE_NAME,
|
|
158
|
+
"-a",
|
|
159
|
+
keyName,
|
|
160
|
+
"-w"
|
|
161
|
+
// Output password only
|
|
162
|
+
],
|
|
163
|
+
{
|
|
164
|
+
encoding: "utf-8",
|
|
165
|
+
timeout: 5e3
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
if (result.status === 0 && result.stdout) {
|
|
169
|
+
return result.stdout.trim();
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function deleteFromKeychain(keyName) {
|
|
177
|
+
try {
|
|
178
|
+
const result = spawnSync(
|
|
179
|
+
"security",
|
|
180
|
+
["delete-generic-password", "-s", SERVICE_NAME, "-a", keyName],
|
|
181
|
+
{ timeout: 5e3 }
|
|
182
|
+
);
|
|
183
|
+
return result.status === 0;
|
|
184
|
+
} catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function loadEncryptedKeys() {
|
|
189
|
+
if (!existsSync(ENCRYPTED_KEYS_FILE)) {
|
|
190
|
+
return {};
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const encryptedContent = readFileSync(ENCRYPTED_KEYS_FILE, "utf-8");
|
|
194
|
+
const machineKey = getMachineKey();
|
|
195
|
+
const decrypted = decrypt(encryptedContent, machineKey);
|
|
196
|
+
return JSON.parse(decrypted);
|
|
197
|
+
} catch {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function saveEncryptedKeys(keys) {
|
|
202
|
+
if (!existsSync(ENCRYPTED_KEYS_DIR)) {
|
|
203
|
+
mkdirSync(ENCRYPTED_KEYS_DIR, { recursive: true, mode: 448 });
|
|
204
|
+
}
|
|
205
|
+
const machineKey = getMachineKey();
|
|
206
|
+
const encrypted = encrypt(JSON.stringify(keys), machineKey);
|
|
207
|
+
writeFileSync(ENCRYPTED_KEYS_FILE, encrypted, { mode: 384 });
|
|
208
|
+
}
|
|
209
|
+
function storeApiKey(keyName, value) {
|
|
210
|
+
if (!keyName || !value) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
if (isMacOSWithKeychain()) {
|
|
214
|
+
if (storeInKeychain(keyName, value)) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
const keys = loadEncryptedKeys();
|
|
220
|
+
keys[keyName] = value;
|
|
221
|
+
saveEncryptedKeys(keys);
|
|
222
|
+
return true;
|
|
223
|
+
} catch {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function getApiKey(keyName) {
|
|
228
|
+
if (!keyName) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
if (isMacOSWithKeychain()) {
|
|
232
|
+
const value = getFromKeychain(keyName);
|
|
233
|
+
if (value) {
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const keys = loadEncryptedKeys();
|
|
239
|
+
return keys[keyName] || null;
|
|
240
|
+
} catch {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function deleteApiKey(keyName) {
|
|
245
|
+
if (!keyName) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
let success = false;
|
|
249
|
+
if (isMacOSWithKeychain()) {
|
|
250
|
+
if (deleteFromKeychain(keyName)) {
|
|
251
|
+
success = true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const keys = loadEncryptedKeys();
|
|
256
|
+
if (keys[keyName]) {
|
|
257
|
+
delete keys[keyName];
|
|
258
|
+
saveEncryptedKeys(keys);
|
|
259
|
+
success = true;
|
|
260
|
+
}
|
|
261
|
+
} catch {
|
|
262
|
+
}
|
|
263
|
+
return success;
|
|
264
|
+
}
|
|
265
|
+
function hasApiKey(keyName) {
|
|
266
|
+
return getApiKey(keyName) !== null;
|
|
267
|
+
}
|
|
268
|
+
function listApiKeyNames() {
|
|
269
|
+
const names = /* @__PURE__ */ new Set();
|
|
270
|
+
try {
|
|
271
|
+
const keys = loadEncryptedKeys();
|
|
272
|
+
for (const name of Object.keys(keys)) {
|
|
273
|
+
names.add(name);
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
return Array.from(names);
|
|
278
|
+
}
|
|
279
|
+
function migrateApiKeyToSecure(keyName, plainTextValue) {
|
|
280
|
+
if (!plainTextValue) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
if (storeApiKey(keyName, plainTextValue)) {
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function getStorageBackendInfo() {
|
|
289
|
+
if (isMacOSWithKeychain()) {
|
|
290
|
+
return { backend: "keychain", available: true };
|
|
291
|
+
}
|
|
292
|
+
return { backend: "encrypted-file", available: true };
|
|
293
|
+
}
|
|
294
|
+
function clearAllApiKeys() {
|
|
295
|
+
if (existsSync(ENCRYPTED_KEYS_FILE)) {
|
|
296
|
+
try {
|
|
297
|
+
unlinkSync(ENCRYPTED_KEYS_FILE);
|
|
298
|
+
} catch {
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
export {
|
|
303
|
+
clearAllApiKeys,
|
|
304
|
+
deleteApiKey,
|
|
305
|
+
getApiKey,
|
|
306
|
+
getStorageBackendInfo,
|
|
307
|
+
hasApiKey,
|
|
308
|
+
listApiKeyNames,
|
|
309
|
+
migrateApiKeyToSecure,
|
|
310
|
+
storeApiKey
|
|
311
|
+
};
|
|
312
|
+
//# sourceMappingURL=secureKeyStorage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/secureKeyStorage.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Secure Key Storage\n *\n * Provides secure storage for API keys using system keychain on macOS\n * and encrypted file storage on other platforms.\n *\n * Security features:\n * - Uses macOS Keychain via `security` command when available\n * - Falls back to AES-256-GCM encrypted file storage\n * - Encryption key derived from machine-specific data\n * - Keys never stored in plain text in config files\n */\n\nimport { spawnSync } from 'child_process'\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n mkdirSync,\n unlinkSync,\n} from 'fs'\nimport { join } from 'path'\nimport { homedir, hostname, platform } from 'os'\nimport {\n createCipheriv,\n createDecipheriv,\n randomBytes,\n scryptSync,\n createHash,\n} from 'crypto'\n\nconst SERVICE_NAME = 'com.minto.cli'\nconst ENCRYPTED_KEYS_DIR = join(homedir(), '.minto', 'secure')\nconst ENCRYPTED_KEYS_FILE = join(ENCRYPTED_KEYS_DIR, 'keys.enc')\n\n/**\n * Check if we're running on macOS with Keychain available\n */\nfunction isMacOSWithKeychain(): boolean {\n if (platform() !== 'darwin') return false\n\n try {\n const result = spawnSync('security', ['help'], {\n encoding: 'utf-8',\n timeout: 5000,\n })\n return result.status === 0 || result.status === 1 // security help returns 1\n } catch {\n return false\n }\n}\n\n/**\n * Get machine-specific key for encryption\n * Combines hostname and a stable machine identifier\n */\nfunction getMachineKey(): Buffer {\n const machineId = getMachineId()\n const combined = `${hostname()}-${machineId}-minto-secure-storage`\n return createHash('sha256').update(combined).digest()\n}\n\n/**\n * Get a stable machine identifier using safe methods only\n */\nfunction getMachineId(): string {\n // Try to get machine ID from various sources\n const sources = [\n // macOS - use spawnSync instead of execSync for safety\n () => {\n if (platform() === 'darwin') {\n try {\n const result = spawnSync(\n 'ioreg',\n ['-rd1', '-c', 'IOPlatformExpertDevice'],\n {\n encoding: 'utf-8',\n timeout: 5000,\n },\n )\n if (result.status === 0 && result.stdout) {\n const match = result.stdout.match(\n /\"IOPlatformUUID\"\\s*=\\s*\"([^\"]+)\"/,\n )\n if (match) return match[1]\n }\n } catch {}\n }\n return null\n },\n // Linux - read from file directly (no shell needed)\n () => {\n if (platform() === 'linux') {\n try {\n if (existsSync('/etc/machine-id')) {\n return readFileSync('/etc/machine-id', 'utf-8').trim()\n }\n if (existsSync('/var/lib/dbus/machine-id')) {\n return readFileSync('/var/lib/dbus/machine-id', 'utf-8').trim()\n }\n } catch {}\n }\n return null\n },\n // Fallback: use hostname hash\n () => {\n return createHash('sha256').update(hostname()).digest('hex').slice(0, 32)\n },\n ]\n\n for (const source of sources) {\n const id = source()\n if (id) return id\n }\n\n // Should never reach here due to fallback\n return 'minto-default-machine-id'\n}\n\n/**\n * Encrypt data using AES-256-GCM\n */\nfunction encrypt(data: string, key: Buffer): string {\n const iv = randomBytes(16)\n const salt = randomBytes(32)\n const derivedKey = scryptSync(key, salt, 32)\n\n const cipher = createCipheriv('aes-256-gcm', derivedKey, iv)\n const encrypted = Buffer.concat([\n cipher.update(data, 'utf-8'),\n cipher.final(),\n ])\n const authTag = cipher.getAuthTag()\n\n // Format: salt:iv:authTag:encrypted (all base64)\n return [\n salt.toString('base64'),\n iv.toString('base64'),\n authTag.toString('base64'),\n encrypted.toString('base64'),\n ].join(':')\n}\n\n/**\n * Decrypt data using AES-256-GCM\n */\nfunction decrypt(encryptedData: string, key: Buffer): string {\n const parts = encryptedData.split(':')\n if (parts.length !== 4) {\n throw new Error('Invalid encrypted data format')\n }\n\n const [saltB64, ivB64, authTagB64, encryptedB64] = parts\n const salt = Buffer.from(saltB64, 'base64')\n const iv = Buffer.from(ivB64, 'base64')\n const authTag = Buffer.from(authTagB64, 'base64')\n const encrypted = Buffer.from(encryptedB64, 'base64')\n\n const derivedKey = scryptSync(key, salt, 32)\n const decipher = createDecipheriv('aes-256-gcm', derivedKey, iv)\n decipher.setAuthTag(authTag)\n\n return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString(\n 'utf-8',\n )\n}\n\n/**\n * Store API key in macOS Keychain\n */\nfunction storeInKeychain(keyName: string, value: string): boolean {\n try {\n // First try to delete existing entry\n spawnSync(\n 'security',\n ['delete-generic-password', '-s', SERVICE_NAME, '-a', keyName],\n { timeout: 5000 },\n )\n\n // Add new entry\n const result = spawnSync(\n 'security',\n [\n 'add-generic-password',\n '-s',\n SERVICE_NAME,\n '-a',\n keyName,\n '-w',\n value,\n '-U', // Update if exists\n ],\n { timeout: 5000 },\n )\n\n return result.status === 0\n } catch {\n return false\n }\n}\n\n/**\n * Retrieve API key from macOS Keychain\n */\nfunction getFromKeychain(keyName: string): string | null {\n try {\n const result = spawnSync(\n 'security',\n [\n 'find-generic-password',\n '-s',\n SERVICE_NAME,\n '-a',\n keyName,\n '-w', // Output password only\n ],\n {\n encoding: 'utf-8',\n timeout: 5000,\n },\n )\n\n if (result.status === 0 && result.stdout) {\n return result.stdout.trim()\n }\n return null\n } catch {\n return null\n }\n}\n\n/**\n * Delete API key from macOS Keychain\n */\nfunction deleteFromKeychain(keyName: string): boolean {\n try {\n const result = spawnSync(\n 'security',\n ['delete-generic-password', '-s', SERVICE_NAME, '-a', keyName],\n { timeout: 5000 },\n )\n\n return result.status === 0\n } catch {\n return false\n }\n}\n\n/**\n * Load encrypted keys from file\n */\nfunction loadEncryptedKeys(): Record<string, string> {\n if (!existsSync(ENCRYPTED_KEYS_FILE)) {\n return {}\n }\n\n try {\n const encryptedContent = readFileSync(ENCRYPTED_KEYS_FILE, 'utf-8')\n const machineKey = getMachineKey()\n const decrypted = decrypt(encryptedContent, machineKey)\n return JSON.parse(decrypted)\n } catch {\n // If decryption fails (e.g., machine key changed), return empty\n return {}\n }\n}\n\n/**\n * Save encrypted keys to file\n */\nfunction saveEncryptedKeys(keys: Record<string, string>): void {\n // Ensure directory exists\n if (!existsSync(ENCRYPTED_KEYS_DIR)) {\n mkdirSync(ENCRYPTED_KEYS_DIR, { recursive: true, mode: 0o700 })\n }\n\n const machineKey = getMachineKey()\n const encrypted = encrypt(JSON.stringify(keys), machineKey)\n writeFileSync(ENCRYPTED_KEYS_FILE, encrypted, { mode: 0o600 })\n}\n\n/**\n * Store an API key securely\n */\nexport function storeApiKey(keyName: string, value: string): boolean {\n // Validate input\n if (!keyName || !value) {\n return false\n }\n\n // Try macOS Keychain first\n if (isMacOSWithKeychain()) {\n if (storeInKeychain(keyName, value)) {\n return true\n }\n }\n\n // Fall back to encrypted file storage\n try {\n const keys = loadEncryptedKeys()\n keys[keyName] = value\n saveEncryptedKeys(keys)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Retrieve an API key securely\n */\nexport function getApiKey(keyName: string): string | null {\n if (!keyName) {\n return null\n }\n\n // Try macOS Keychain first\n if (isMacOSWithKeychain()) {\n const value = getFromKeychain(keyName)\n if (value) {\n return value\n }\n }\n\n // Fall back to encrypted file storage\n try {\n const keys = loadEncryptedKeys()\n return keys[keyName] || null\n } catch {\n return null\n }\n}\n\n/**\n * Delete an API key\n */\nexport function deleteApiKey(keyName: string): boolean {\n if (!keyName) {\n return false\n }\n\n let success = false\n\n // Try macOS Keychain\n if (isMacOSWithKeychain()) {\n if (deleteFromKeychain(keyName)) {\n success = true\n }\n }\n\n // Also remove from encrypted file\n try {\n const keys = loadEncryptedKeys()\n if (keys[keyName]) {\n delete keys[keyName]\n saveEncryptedKeys(keys)\n success = true\n }\n } catch {}\n\n return success\n}\n\n/**\n * Check if an API key exists\n */\nexport function hasApiKey(keyName: string): boolean {\n return getApiKey(keyName) !== null\n}\n\n/**\n * List all stored API key names (not values)\n */\nexport function listApiKeyNames(): string[] {\n const names = new Set<string>()\n\n // From encrypted file\n try {\n const keys = loadEncryptedKeys()\n for (const name of Object.keys(keys)) {\n names.add(name)\n }\n } catch {}\n\n return Array.from(names)\n}\n\n/**\n * Migrate API key from plain text config to secure storage\n * Returns true if migration was successful or key was already secure\n */\nexport function migrateApiKeyToSecure(\n keyName: string,\n plainTextValue: string,\n): boolean {\n if (!plainTextValue) {\n return false\n }\n\n // Store in secure storage\n if (storeApiKey(keyName, plainTextValue)) {\n return true\n }\n\n return false\n}\n\n/**\n * Get storage backend info (for debugging)\n */\nexport function getStorageBackendInfo(): {\n backend: 'keychain' | 'encrypted-file'\n available: boolean\n} {\n if (isMacOSWithKeychain()) {\n return { backend: 'keychain', available: true }\n }\n return { backend: 'encrypted-file', available: true }\n}\n\n/**\n * Clear all stored API keys (use with caution)\n */\nexport function clearAllApiKeys(): void {\n // Clear encrypted file\n if (existsSync(ENCRYPTED_KEYS_FILE)) {\n try {\n unlinkSync(ENCRYPTED_KEYS_FILE)\n } catch {}\n }\n\n // Note: We don't clear Keychain entries automatically\n // as that could affect other applications\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|