@shareai-lab/kode 1.1.12 → 1.1.14
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 +83 -57
- package/dist/ProjectOnboarding.js +99 -0
- package/dist/ProjectOnboarding.js.map +7 -0
- package/dist/Tool.js +1 -0
- package/dist/Tool.js.map +7 -0
- package/dist/commands/agents.js +2087 -0
- package/dist/commands/agents.js.map +7 -0
- package/dist/commands/approvedTools.js +36 -0
- package/dist/commands/approvedTools.js.map +7 -0
- package/dist/commands/bug.js +21 -0
- package/dist/commands/bug.js.map +7 -0
- package/dist/commands/clear.js +37 -0
- package/dist/commands/clear.js.map +7 -0
- package/dist/commands/compact.js +104 -0
- package/dist/commands/compact.js.map +7 -0
- package/dist/commands/config.js +20 -0
- package/dist/commands/config.js.map +7 -0
- package/dist/commands/cost.js +19 -0
- package/dist/commands/cost.js.map +7 -0
- package/dist/commands/ctx_viz.js +152 -0
- package/dist/commands/ctx_viz.js.map +7 -0
- package/dist/commands/doctor.js +25 -0
- package/dist/commands/doctor.js.map +7 -0
- package/dist/commands/help.js +20 -0
- package/dist/commands/help.js.map +7 -0
- package/dist/commands/init.js +38 -0
- package/dist/commands/init.js.map +7 -0
- package/dist/commands/listen.js +37 -0
- package/dist/commands/listen.js.map +7 -0
- package/dist/commands/login.js +37 -0
- package/dist/commands/login.js.map +7 -0
- package/dist/commands/logout.js +33 -0
- package/dist/commands/logout.js.map +7 -0
- package/dist/commands/mcp.js +34 -0
- package/dist/commands/mcp.js.map +7 -0
- package/dist/commands/model.js +41 -0
- package/dist/commands/model.js.map +7 -0
- package/dist/commands/modelstatus.js +21 -0
- package/dist/commands/modelstatus.js.map +7 -0
- package/dist/commands/onboarding.js +36 -0
- package/dist/commands/onboarding.js.map +7 -0
- package/dist/commands/pr_comments.js +61 -0
- package/dist/commands/pr_comments.js.map +7 -0
- package/dist/commands/refreshCommands.js +37 -0
- package/dist/commands/refreshCommands.js.map +7 -0
- package/dist/commands/release-notes.js +30 -0
- package/dist/commands/release-notes.js.map +7 -0
- package/dist/commands/resume.js +35 -0
- package/dist/commands/resume.js.map +7 -0
- package/dist/commands/review.js +51 -0
- package/dist/commands/review.js.map +7 -0
- package/dist/commands/terminalSetup.js +163 -0
- package/dist/commands/terminalSetup.js.map +7 -0
- package/dist/commands.js +84 -0
- package/dist/commands.js.map +7 -0
- package/dist/components/ApproveApiKey.js +74 -0
- package/dist/components/ApproveApiKey.js.map +7 -0
- package/dist/components/AsciiLogo.js +12 -0
- package/dist/components/AsciiLogo.js.map +7 -0
- package/dist/components/AutoUpdater.js +74 -0
- package/dist/components/AutoUpdater.js.map +7 -0
- package/dist/components/Bug.js +147 -0
- package/dist/components/Bug.js.map +7 -0
- package/dist/components/Config.js +166 -0
- package/dist/components/Config.js.map +7 -0
- package/dist/components/ConsoleOAuthFlow.js +188 -0
- package/dist/components/ConsoleOAuthFlow.js.map +7 -0
- package/dist/components/Cost.js +13 -0
- package/dist/components/Cost.js.map +7 -0
- package/dist/components/CostThresholdDialog.js +38 -0
- package/dist/components/CostThresholdDialog.js.map +7 -0
- package/dist/components/CustomSelect/option-map.js +32 -0
- package/dist/components/CustomSelect/option-map.js.map +7 -0
- package/dist/components/CustomSelect/select-option.js +34 -0
- package/dist/components/CustomSelect/select-option.js.map +7 -0
- package/dist/components/CustomSelect/select.js +64 -0
- package/dist/components/CustomSelect/select.js.map +7 -0
- package/dist/components/CustomSelect/theme.js +1 -0
- package/dist/components/CustomSelect/theme.js.map +7 -0
- package/dist/components/CustomSelect/use-select-state.js +220 -0
- package/dist/components/CustomSelect/use-select-state.js.map +7 -0
- package/dist/components/CustomSelect/use-select.js +21 -0
- package/dist/components/CustomSelect/use-select.js.map +7 -0
- package/dist/components/FallbackToolUseRejectedMessage.js +11 -0
- package/dist/components/FallbackToolUseRejectedMessage.js.map +7 -0
- package/dist/components/FileEditToolUpdatedMessage.js +31 -0
- package/dist/components/FileEditToolUpdatedMessage.js.map +7 -0
- package/dist/components/Help.js +41 -0
- package/dist/components/Help.js.map +7 -0
- package/dist/components/HighlightedCode.js +30 -0
- package/dist/components/HighlightedCode.js.map +7 -0
- package/dist/components/InvalidConfigDialog.js +83 -0
- package/dist/components/InvalidConfigDialog.js.map +7 -0
- package/dist/components/Link.js +18 -0
- package/dist/components/Link.js.map +7 -0
- package/dist/components/LogSelector.js +50 -0
- package/dist/components/LogSelector.js.map +7 -0
- package/dist/components/Logo.js +89 -0
- package/dist/components/Logo.js.map +7 -0
- package/dist/components/MCPServerApprovalDialog.js +79 -0
- package/dist/components/MCPServerApprovalDialog.js.map +7 -0
- package/dist/components/MCPServerDialogCopy.js +11 -0
- package/dist/components/MCPServerDialogCopy.js.map +7 -0
- package/dist/components/MCPServerMultiselectDialog.js +80 -0
- package/dist/components/MCPServerMultiselectDialog.js.map +7 -0
- package/dist/components/Message.js +146 -0
- package/dist/components/Message.js.map +7 -0
- package/dist/components/MessageResponse.js +9 -0
- package/dist/components/MessageResponse.js.map +7 -0
- package/dist/components/MessageSelector.js +133 -0
- package/dist/components/MessageSelector.js.map +7 -0
- package/dist/components/ModeIndicator.js +38 -0
- package/dist/components/ModeIndicator.js.map +7 -0
- package/dist/components/ModelConfig.js +208 -0
- package/dist/components/ModelConfig.js.map +7 -0
- package/dist/components/ModelListManager.js +140 -0
- package/dist/components/ModelListManager.js.map +7 -0
- package/dist/components/ModelSelector.js +1985 -0
- package/dist/components/ModelSelector.js.map +7 -0
- package/dist/components/ModelStatusDisplay.js +87 -0
- package/dist/components/ModelStatusDisplay.js.map +7 -0
- package/dist/components/Onboarding.js +153 -0
- package/dist/components/Onboarding.js.map +7 -0
- package/dist/components/PressEnterToContinue.js +10 -0
- package/dist/components/PressEnterToContinue.js.map +7 -0
- package/dist/components/PromptInput.js +501 -0
- package/dist/components/PromptInput.js.map +7 -0
- package/dist/components/SentryErrorBoundary.js +27 -0
- package/dist/components/SentryErrorBoundary.js.map +7 -0
- package/dist/components/Spinner.js +101 -0
- package/dist/components/Spinner.js.map +7 -0
- package/dist/components/StickerRequestForm.js +7 -0
- package/dist/components/StickerRequestForm.js.map +7 -0
- package/dist/components/StructuredDiff.js +148 -0
- package/dist/components/StructuredDiff.js.map +7 -0
- package/dist/components/TextInput.js +100 -0
- package/dist/components/TextInput.js.map +7 -0
- package/dist/components/TodoItem.js +35 -0
- package/dist/components/TodoItem.js.map +7 -0
- package/dist/components/TokenWarning.js +19 -0
- package/dist/components/TokenWarning.js.map +7 -0
- package/dist/components/ToolUseLoader.js +24 -0
- package/dist/components/ToolUseLoader.js.map +7 -0
- package/dist/components/TrustDialog.js +76 -0
- package/dist/components/TrustDialog.js.map +7 -0
- package/dist/components/binary-feedback/BinaryFeedback.js +50 -0
- package/dist/components/binary-feedback/BinaryFeedback.js.map +7 -0
- package/dist/components/binary-feedback/BinaryFeedbackOption.js +94 -0
- package/dist/components/binary-feedback/BinaryFeedbackOption.js.map +7 -0
- package/dist/components/binary-feedback/BinaryFeedbackView.js +139 -0
- package/dist/components/binary-feedback/BinaryFeedbackView.js.map +7 -0
- package/dist/components/binary-feedback/utils.js +161 -0
- package/dist/components/binary-feedback/utils.js.map +7 -0
- package/dist/components/messages/AssistantBashOutputMessage.js +23 -0
- package/dist/components/messages/AssistantBashOutputMessage.js.map +7 -0
- package/dist/components/messages/AssistantLocalCommandOutputMessage.js +36 -0
- package/dist/components/messages/AssistantLocalCommandOutputMessage.js.map +7 -0
- package/dist/components/messages/AssistantRedactedThinkingMessage.js +12 -0
- package/dist/components/messages/AssistantRedactedThinkingMessage.js.map +7 -0
- package/dist/components/messages/AssistantTextMessage.js +78 -0
- package/dist/components/messages/AssistantTextMessage.js.map +7 -0
- package/dist/components/messages/AssistantThinkingMessage.js +27 -0
- package/dist/components/messages/AssistantThinkingMessage.js.map +7 -0
- package/dist/components/messages/AssistantToolUseMessage.js +91 -0
- package/dist/components/messages/AssistantToolUseMessage.js.map +7 -0
- package/dist/components/messages/TaskProgressMessage.js +11 -0
- package/dist/components/messages/TaskProgressMessage.js.map +7 -0
- package/dist/components/messages/TaskToolMessage.js +39 -0
- package/dist/components/messages/TaskToolMessage.js.map +7 -0
- package/dist/components/messages/UserBashInputMessage.js +18 -0
- package/dist/components/messages/UserBashInputMessage.js.map +7 -0
- package/dist/components/messages/UserCommandMessage.js +20 -0
- package/dist/components/messages/UserCommandMessage.js.map +7 -0
- package/dist/components/messages/UserKodingInputMessage.js +18 -0
- package/dist/components/messages/UserKodingInputMessage.js.map +7 -0
- package/dist/components/messages/UserPromptMessage.js +20 -0
- package/dist/components/messages/UserPromptMessage.js.map +7 -0
- package/dist/components/messages/UserTextMessage.js +25 -0
- package/dist/components/messages/UserTextMessage.js.map +7 -0
- package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +10 -0
- package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js.map +7 -0
- package/dist/components/messages/UserToolResultMessage/UserToolErrorMessage.js +15 -0
- package/dist/components/messages/UserToolResultMessage/UserToolErrorMessage.js.map +7 -0
- package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +25 -0
- package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +7 -0
- package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +47 -0
- package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +7 -0
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +23 -0
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +7 -0
- package/dist/components/messages/UserToolResultMessage/utils.js +42 -0
- package/dist/components/messages/UserToolResultMessage/utils.js.map +7 -0
- package/dist/components/permissions/BashPermissionRequest/BashPermissionRequest.js +112 -0
- package/dist/components/permissions/BashPermissionRequest/BashPermissionRequest.js.map +7 -0
- package/dist/components/permissions/FallbackPermissionRequest.js +131 -0
- package/dist/components/permissions/FallbackPermissionRequest.js.map +7 -0
- package/dist/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.js +159 -0
- package/dist/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.js.map +7 -0
- package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js +58 -0
- package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js.map +7 -0
- package/dist/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.js +153 -0
- package/dist/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.js.map +7 -0
- package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js +70 -0
- package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js.map +7 -0
- package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +212 -0
- package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +7 -0
- package/dist/components/permissions/PermissionRequest.js +70 -0
- package/dist/components/permissions/PermissionRequest.js.map +7 -0
- package/dist/components/permissions/PermissionRequestTitle.js +52 -0
- package/dist/components/permissions/PermissionRequestTitle.js.map +7 -0
- package/dist/components/permissions/hooks.js +28 -0
- package/dist/components/permissions/hooks.js.map +7 -0
- package/dist/components/permissions/toolUseOptions.js +46 -0
- package/dist/components/permissions/toolUseOptions.js.map +7 -0
- package/dist/components/permissions/utils.js +21 -0
- package/dist/components/permissions/utils.js.map +7 -0
- package/dist/constants/betas.js +11 -0
- package/dist/constants/betas.js.map +7 -0
- package/dist/constants/claude-asterisk-ascii-art.js +242 -0
- package/dist/constants/claude-asterisk-ascii-art.js.map +7 -0
- package/dist/constants/figures.js +6 -0
- package/dist/constants/figures.js.map +7 -0
- package/dist/constants/keys.js +7 -0
- package/dist/constants/keys.js.map +7 -0
- package/dist/constants/macros.js +13 -0
- package/dist/constants/macros.js.map +7 -0
- package/dist/constants/modelCapabilities.js +154 -0
- package/dist/constants/modelCapabilities.js.map +7 -0
- package/dist/constants/models.js +1029 -0
- package/dist/constants/models.js.map +7 -0
- package/dist/constants/oauth.js +18 -0
- package/dist/constants/oauth.js.map +7 -0
- package/dist/constants/product.js +26 -0
- package/dist/constants/product.js.map +7 -0
- package/dist/constants/prompts.js +168 -0
- package/dist/constants/prompts.js.map +7 -0
- package/dist/constants/releaseNotes.js +9 -0
- package/dist/constants/releaseNotes.js.map +7 -0
- package/dist/context/PermissionContext.js +111 -0
- package/dist/context/PermissionContext.js.map +7 -0
- package/dist/context.js +259 -0
- package/dist/context.js.map +7 -0
- package/dist/cost-tracker.js +76 -0
- package/dist/cost-tracker.js.map +7 -0
- package/dist/entrypoints/cli.js +1101 -0
- package/dist/entrypoints/cli.js.map +7 -0
- package/dist/entrypoints/mcp.js +150 -0
- package/dist/entrypoints/mcp.js.map +7 -0
- package/dist/history.js +25 -0
- package/dist/history.js.map +7 -0
- package/dist/hooks/useApiKeyVerification.js +12 -0
- package/dist/hooks/useApiKeyVerification.js.map +7 -0
- package/dist/hooks/useArrowKeyHistory.js +50 -0
- package/dist/hooks/useArrowKeyHistory.js.map +7 -0
- package/dist/hooks/useCanUseTool.js +112 -0
- package/dist/hooks/useCanUseTool.js.map +7 -0
- package/dist/hooks/useCancelRequest.js +30 -0
- package/dist/hooks/useCancelRequest.js.map +7 -0
- package/dist/hooks/useDoublePress.js +31 -0
- package/dist/hooks/useDoublePress.js.map +7 -0
- package/dist/hooks/useExitOnCtrlCD.js +26 -0
- package/dist/hooks/useExitOnCtrlCD.js.map +7 -0
- package/dist/hooks/useInterval.js +18 -0
- package/dist/hooks/useInterval.js.map +7 -0
- package/dist/hooks/useLogMessages.js +14 -0
- package/dist/hooks/useLogMessages.js.map +7 -0
- package/dist/hooks/useLogStartupTime.js +15 -0
- package/dist/hooks/useLogStartupTime.js.map +7 -0
- package/dist/hooks/useNotifyAfterTimeout.js +42 -0
- package/dist/hooks/useNotifyAfterTimeout.js.map +7 -0
- package/dist/hooks/usePermissionRequestLogging.js +28 -0
- package/dist/hooks/usePermissionRequestLogging.js.map +7 -0
- package/dist/hooks/useTerminalSize.js +38 -0
- package/dist/hooks/useTerminalSize.js.map +7 -0
- package/dist/hooks/useTextInput.js +250 -0
- package/dist/hooks/useTextInput.js.map +7 -0
- package/dist/hooks/useUnifiedCompletion.js +929 -0
- package/dist/hooks/useUnifiedCompletion.js.map +7 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +7 -0
- package/dist/messages.js +33 -0
- package/dist/messages.js.map +7 -0
- package/dist/package.json +1 -0
- package/dist/permissions.js +194 -0
- package/dist/permissions.js.map +7 -0
- package/dist/query.js +492 -0
- package/dist/query.js.map +7 -0
- package/dist/screens/ConfigureNpmPrefix.js +128 -0
- package/dist/screens/ConfigureNpmPrefix.js.map +7 -0
- package/dist/screens/Doctor.js +143 -0
- package/dist/screens/Doctor.js.map +7 -0
- package/dist/screens/LogList.js +55 -0
- package/dist/screens/LogList.js.map +7 -0
- package/dist/screens/REPL.js +596 -0
- package/dist/screens/REPL.js.map +7 -0
- package/dist/screens/ResumeConversation.js +56 -0
- package/dist/screens/ResumeConversation.js.map +7 -0
- package/dist/services/adapters/base.js +29 -0
- package/dist/services/adapters/base.js.map +7 -0
- package/dist/services/adapters/chatCompletions.js +69 -0
- package/dist/services/adapters/chatCompletions.js.map +7 -0
- package/dist/services/adapters/responsesAPI.js +126 -0
- package/dist/services/adapters/responsesAPI.js.map +7 -0
- package/dist/services/browserMocks.js +48 -0
- package/dist/services/browserMocks.js.map +7 -0
- package/dist/services/claude.js +1605 -0
- package/dist/services/claude.js.map +7 -0
- package/dist/services/customCommands.js +359 -0
- package/dist/services/customCommands.js.map +7 -0
- package/dist/services/fileFreshness.js +280 -0
- package/dist/services/fileFreshness.js.map +7 -0
- package/dist/services/gpt5ConnectionTest.js +248 -0
- package/dist/services/gpt5ConnectionTest.js.map +7 -0
- package/dist/services/mcpClient.js +435 -0
- package/dist/services/mcpClient.js.map +7 -0
- package/dist/services/mcpServerApproval.js +55 -0
- package/dist/services/mcpServerApproval.js.map +7 -0
- package/dist/services/mentionProcessor.js +200 -0
- package/dist/services/mentionProcessor.js.map +7 -0
- package/dist/services/modelAdapterFactory.js +47 -0
- package/dist/services/modelAdapterFactory.js.map +7 -0
- package/dist/services/notifier.js +35 -0
- package/dist/services/notifier.js.map +7 -0
- package/dist/services/oauth.js +259 -0
- package/dist/services/oauth.js.map +7 -0
- package/dist/services/openai.js +998 -0
- package/dist/services/openai.js.map +7 -0
- package/dist/services/responseStateManager.js +68 -0
- package/dist/services/responseStateManager.js.map +7 -0
- package/dist/services/sentry.js +9 -0
- package/dist/services/sentry.js.map +7 -0
- package/dist/services/statsig.js +112 -0
- package/dist/services/statsig.js.map +7 -0
- package/dist/services/statsigStorage.js +75 -0
- package/dist/services/statsigStorage.js.map +7 -0
- package/dist/services/systemReminder.js +353 -0
- package/dist/services/systemReminder.js.map +7 -0
- package/dist/services/vcr.js +133 -0
- package/dist/services/vcr.js.map +7 -0
- package/dist/test/testAdapters.js +88 -0
- package/dist/test/testAdapters.js.map +1 -0
- package/dist/tools/ArchitectTool/ArchitectTool.js +119 -0
- package/dist/tools/ArchitectTool/ArchitectTool.js.map +7 -0
- package/dist/tools/ArchitectTool/prompt.js +18 -0
- package/dist/tools/ArchitectTool/prompt.js.map +7 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +423 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +7 -0
- package/dist/tools/BashTool/BashTool.js +188 -0
- package/dist/tools/BashTool/BashTool.js.map +7 -0
- package/dist/tools/BashTool/BashToolResultMessage.js +21 -0
- package/dist/tools/BashTool/BashToolResultMessage.js.map +7 -0
- package/dist/tools/BashTool/OutputLine.js +30 -0
- package/dist/tools/BashTool/OutputLine.js.map +7 -0
- package/dist/tools/BashTool/prompt.js +179 -0
- package/dist/tools/BashTool/prompt.js.map +7 -0
- package/dist/tools/BashTool/utils.js +51 -0
- package/dist/tools/BashTool/utils.js.map +7 -0
- package/dist/tools/FileEditTool/FileEditTool.js +228 -0
- package/dist/tools/FileEditTool/FileEditTool.js.map +7 -0
- package/dist/tools/FileEditTool/prompt.js +54 -0
- package/dist/tools/FileEditTool/prompt.js.map +7 -0
- package/dist/tools/FileEditTool/utils.js +42 -0
- package/dist/tools/FileEditTool/utils.js.map +7 -0
- package/dist/tools/FileReadTool/FileReadTool.js +272 -0
- package/dist/tools/FileReadTool/FileReadTool.js.map +7 -0
- package/dist/tools/FileReadTool/prompt.js +10 -0
- package/dist/tools/FileReadTool/prompt.js.map +7 -0
- package/dist/tools/FileWriteTool/FileWriteTool.js +204 -0
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +7 -0
- package/dist/tools/FileWriteTool/prompt.js +14 -0
- package/dist/tools/FileWriteTool/prompt.js.map +7 -0
- package/dist/tools/GlobTool/GlobTool.js +88 -0
- package/dist/tools/GlobTool/GlobTool.js.map +7 -0
- package/dist/tools/GlobTool/prompt.js +12 -0
- package/dist/tools/GlobTool/prompt.js.map +7 -0
- package/dist/tools/GrepTool/GrepTool.js +107 -0
- package/dist/tools/GrepTool/GrepTool.js.map +7 -0
- package/dist/tools/GrepTool/prompt.js +15 -0
- package/dist/tools/GrepTool/prompt.js.map +7 -0
- package/dist/tools/MCPTool/MCPTool.js +90 -0
- package/dist/tools/MCPTool/MCPTool.js.map +7 -0
- package/dist/tools/MCPTool/prompt.js +7 -0
- package/dist/tools/MCPTool/prompt.js.map +7 -0
- package/dist/tools/MemoryReadTool/MemoryReadTool.js +103 -0
- package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +7 -0
- package/dist/tools/MemoryReadTool/prompt.js +7 -0
- package/dist/tools/MemoryReadTool/prompt.js.map +7 -0
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +77 -0
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +7 -0
- package/dist/tools/MemoryWriteTool/prompt.js +7 -0
- package/dist/tools/MemoryWriteTool/prompt.js.map +7 -0
- package/dist/tools/MultiEditTool/MultiEditTool.js +293 -0
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +7 -0
- package/dist/tools/MultiEditTool/prompt.js +48 -0
- package/dist/tools/MultiEditTool/prompt.js.map +7 -0
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +238 -0
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +7 -0
- package/dist/tools/NotebookEditTool/prompt.js +7 -0
- package/dist/tools/NotebookEditTool/prompt.js.map +7 -0
- package/dist/tools/NotebookReadTool/NotebookReadTool.js +212 -0
- package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +7 -0
- package/dist/tools/NotebookReadTool/prompt.js +7 -0
- package/dist/tools/NotebookReadTool/prompt.js.map +7 -0
- package/dist/tools/StickerRequestTool/StickerRequestTool.js +86 -0
- package/dist/tools/StickerRequestTool/StickerRequestTool.js.map +7 -0
- package/dist/tools/StickerRequestTool/prompt.js +23 -0
- package/dist/tools/StickerRequestTool/prompt.js.map +7 -0
- package/dist/tools/TaskTool/TaskTool.js +308 -0
- package/dist/tools/TaskTool/TaskTool.js.map +7 -0
- package/dist/tools/TaskTool/constants.js +5 -0
- package/dist/tools/TaskTool/constants.js.map +7 -0
- package/dist/tools/TaskTool/prompt.js +82 -0
- package/dist/tools/TaskTool/prompt.js.map +7 -0
- package/dist/tools/ThinkTool/ThinkTool.js +48 -0
- package/dist/tools/ThinkTool/ThinkTool.js.map +7 -0
- package/dist/tools/ThinkTool/prompt.js +16 -0
- package/dist/tools/ThinkTool/prompt.js.map +7 -0
- package/dist/tools/TodoWriteTool/TodoWriteTool.js +216 -0
- package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +7 -0
- package/dist/tools/TodoWriteTool/prompt.js +66 -0
- package/dist/tools/TodoWriteTool/prompt.js.map +7 -0
- package/dist/tools/URLFetcherTool/URLFetcherTool.js +137 -0
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +7 -0
- package/dist/tools/URLFetcherTool/cache.js +45 -0
- package/dist/tools/URLFetcherTool/cache.js.map +7 -0
- package/dist/tools/URLFetcherTool/htmlToMarkdown.js +42 -0
- package/dist/tools/URLFetcherTool/htmlToMarkdown.js.map +7 -0
- package/dist/tools/URLFetcherTool/prompt.js +22 -0
- package/dist/tools/URLFetcherTool/prompt.js.map +7 -0
- package/dist/tools/WebSearchTool/WebSearchTool.js +86 -0
- package/dist/tools/WebSearchTool/WebSearchTool.js.map +7 -0
- package/dist/tools/WebSearchTool/prompt.js +17 -0
- package/dist/tools/WebSearchTool/prompt.js.map +7 -0
- package/dist/tools/WebSearchTool/searchProviders.js +48 -0
- package/dist/tools/WebSearchTool/searchProviders.js.map +7 -0
- package/dist/tools/lsTool/lsTool.js +201 -0
- package/dist/tools/lsTool/lsTool.js.map +7 -0
- package/dist/tools/lsTool/prompt.js +5 -0
- package/dist/tools/lsTool/prompt.js.map +7 -0
- package/dist/tools.js +64 -0
- package/dist/tools.js.map +7 -0
- package/dist/types/PermissionMode.js +82 -0
- package/dist/types/PermissionMode.js.map +7 -0
- package/dist/types/RequestContext.js +47 -0
- package/dist/types/RequestContext.js.map +7 -0
- package/dist/types/common.d.js +1 -0
- package/dist/types/common.d.js.map +7 -0
- package/dist/types/conversation.js +1 -0
- package/dist/types/conversation.js.map +7 -0
- package/dist/types/logs.js +1 -0
- package/dist/types/logs.js.map +7 -0
- package/dist/types/modelCapabilities.js +1 -0
- package/dist/types/modelCapabilities.js.map +7 -0
- package/dist/types/notebook.js +1 -0
- package/dist/types/notebook.js.map +7 -0
- package/dist/utils/Cursor.js +313 -0
- package/dist/utils/Cursor.js.map +7 -0
- package/dist/utils/PersistentShell.js +382 -0
- package/dist/utils/PersistentShell.js.map +7 -0
- package/dist/utils/advancedFuzzyMatcher.js +206 -0
- package/dist/utils/advancedFuzzyMatcher.js.map +7 -0
- package/dist/utils/agentLoader.js +199 -0
- package/dist/utils/agentLoader.js.map +7 -0
- package/dist/utils/agentStorage.js +59 -0
- package/dist/utils/agentStorage.js.map +7 -0
- package/dist/utils/array.js +7 -0
- package/dist/utils/array.js.map +7 -0
- package/dist/utils/ask.js +77 -0
- package/dist/utils/ask.js.map +7 -0
- package/dist/utils/auth.js +11 -0
- package/dist/utils/auth.js.map +7 -0
- package/dist/utils/autoCompactCore.js +149 -0
- package/dist/utils/autoCompactCore.js.map +7 -0
- package/dist/utils/autoUpdater.js +362 -0
- package/dist/utils/autoUpdater.js.map +7 -0
- package/dist/utils/betas.js +21 -0
- package/dist/utils/betas.js.map +7 -0
- package/dist/utils/browser.js +15 -0
- package/dist/utils/browser.js.map +7 -0
- package/dist/utils/cleanup.js +54 -0
- package/dist/utils/cleanup.js.map +7 -0
- package/dist/utils/commands.js +207 -0
- package/dist/utils/commands.js.map +7 -0
- package/dist/utils/commonUnixCommands.js +687 -0
- package/dist/utils/commonUnixCommands.js.map +7 -0
- package/dist/utils/config.js +655 -0
- package/dist/utils/config.js.map +7 -0
- package/dist/utils/conversationRecovery.js +35 -0
- package/dist/utils/conversationRecovery.js.map +7 -0
- package/dist/utils/debugLogger.js +891 -0
- package/dist/utils/debugLogger.js.map +7 -0
- package/dist/utils/diff.js +32 -0
- package/dist/utils/diff.js.map +7 -0
- package/dist/utils/env.js +44 -0
- package/dist/utils/env.js.map +7 -0
- package/dist/utils/errors.js +23 -0
- package/dist/utils/errors.js.map +7 -0
- package/dist/utils/exampleCommands.js +80 -0
- package/dist/utils/exampleCommands.js.map +7 -0
- package/dist/utils/execFileNoThrow.js +44 -0
- package/dist/utils/execFileNoThrow.js.map +7 -0
- package/dist/utils/expertChatStorage.js +78 -0
- package/dist/utils/expertChatStorage.js.map +7 -0
- package/dist/utils/file.js +282 -0
- package/dist/utils/file.js.map +7 -0
- package/dist/utils/fileRecoveryCore.js +41 -0
- package/dist/utils/fileRecoveryCore.js.map +7 -0
- package/dist/utils/format.js +41 -0
- package/dist/utils/format.js.map +7 -0
- package/dist/utils/fuzzyMatcher.js +252 -0
- package/dist/utils/fuzzyMatcher.js.map +7 -0
- package/dist/utils/generators.js +46 -0
- package/dist/utils/generators.js.map +7 -0
- package/dist/utils/git.js +83 -0
- package/dist/utils/git.js.map +7 -0
- package/dist/utils/globalLogger.js +54 -0
- package/dist/utils/globalLogger.js.map +7 -0
- package/dist/utils/http.js +7 -0
- package/dist/utils/http.js.map +7 -0
- package/dist/utils/imagePaste.js +29 -0
- package/dist/utils/imagePaste.js.map +7 -0
- package/dist/utils/json.js +16 -0
- package/dist/utils/json.js.map +7 -0
- package/dist/utils/log.js +298 -0
- package/dist/utils/log.js.map +7 -0
- package/dist/utils/markdown.js +187 -0
- package/dist/utils/markdown.js.map +7 -0
- package/dist/utils/messageContextManager.js +195 -0
- package/dist/utils/messageContextManager.js.map +7 -0
- package/dist/utils/messages.js +633 -0
- package/dist/utils/messages.js.map +7 -0
- package/dist/utils/model.js +687 -0
- package/dist/utils/model.js.map +7 -0
- package/dist/utils/permissions/filesystem.js +80 -0
- package/dist/utils/permissions/filesystem.js.map +7 -0
- package/dist/utils/responseState.js +20 -0
- package/dist/utils/responseState.js.map +7 -0
- package/dist/utils/ripgrep.js +131 -0
- package/dist/utils/ripgrep.js.map +7 -0
- package/dist/utils/secureFile.js +483 -0
- package/dist/utils/secureFile.js.map +7 -0
- package/dist/utils/sessionState.js +31 -0
- package/dist/utils/sessionState.js.map +7 -0
- package/dist/utils/state.js +24 -0
- package/dist/utils/state.js.map +7 -0
- package/dist/utils/style.js +31 -0
- package/dist/utils/style.js.map +7 -0
- package/dist/utils/terminal.js +43 -0
- package/dist/utils/terminal.js.map +7 -0
- package/dist/utils/theme.js +102 -0
- package/dist/utils/theme.js.map +7 -0
- package/dist/utils/thinking.js +103 -0
- package/dist/utils/thinking.js.map +7 -0
- package/dist/utils/todoStorage.js +291 -0
- package/dist/utils/todoStorage.js.map +7 -0
- package/dist/utils/tokens.js +30 -0
- package/dist/utils/tokens.js.map +7 -0
- package/dist/utils/toolExecutionController.js +109 -0
- package/dist/utils/toolExecutionController.js.map +7 -0
- package/dist/utils/unaryLogging.js +14 -0
- package/dist/utils/unaryLogging.js.map +7 -0
- package/dist/utils/user.js +40 -0
- package/dist/utils/user.js.map +7 -0
- package/dist/utils/validate.js +132 -0
- package/dist/utils/validate.js.map +7 -0
- package/dist/yoga.wasm +0 -0
- package/package.json +28 -7
- package/src/Tool.ts +4 -3
- package/src/commands/agents.tsx +10 -4
- package/src/components/messages/AssistantToolUseMessage.tsx +5 -6
- package/src/constants/macros.ts +5 -2
- package/src/entrypoints/cli.tsx +38 -19
- package/src/entrypoints/mcp.ts +1 -2
- package/src/hooks/useDoublePress.ts +0 -1
- package/src/hooks/useTextInput.ts +4 -5
- package/src/hooks/useUnifiedCompletion.ts +2 -2
- package/src/index.ts +34 -0
- package/src/query.ts +13 -8
- package/src/screens/Doctor.tsx +1 -1
- package/src/screens/REPL.tsx +13 -9
- package/src/services/openai.ts +25 -4
- package/src/tools/ArchitectTool/ArchitectTool.tsx +18 -5
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +21 -14
- package/src/tools/FileEditTool/FileEditTool.tsx +6 -2
- package/src/tools/FileWriteTool/FileWriteTool.tsx +7 -3
- package/src/tools/MultiEditTool/MultiEditTool.tsx +26 -4
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +1 -1
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +28 -14
- package/src/tools/TaskTool/TaskTool.tsx +8 -36
- package/src/types/common.d.ts +2 -0
- package/src/utils/generators.ts +1 -1
- package/src/utils/messageContextManager.ts +5 -0
- package/src/utils/messages.tsx +8 -2
- package/src/utils/thinking.ts +1 -1
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import shellquote from "shell-quote";
|
|
4
|
+
import { spawn, execSync } from "child_process";
|
|
5
|
+
import { isAbsolute, resolve, join } from "path";
|
|
6
|
+
import { logError } from "./log.js";
|
|
7
|
+
import * as os from "os";
|
|
8
|
+
import { logEvent } from "../services/statsig.js";
|
|
9
|
+
import { PRODUCT_COMMAND } from "../constants/product.js";
|
|
10
|
+
const TEMPFILE_PREFIX = os.tmpdir() + `/${PRODUCT_COMMAND}-`;
|
|
11
|
+
const DEFAULT_TIMEOUT = 30 * 60 * 1e3;
|
|
12
|
+
const SIGTERM_CODE = 143;
|
|
13
|
+
const FILE_SUFFIXES = {
|
|
14
|
+
STATUS: "-status",
|
|
15
|
+
STDOUT: "-stdout",
|
|
16
|
+
STDERR: "-stderr",
|
|
17
|
+
CWD: "-cwd"
|
|
18
|
+
};
|
|
19
|
+
const SHELL_CONFIGS = {
|
|
20
|
+
"/bin/bash": ".bashrc",
|
|
21
|
+
"/bin/zsh": ".zshrc"
|
|
22
|
+
};
|
|
23
|
+
function quoteForBash(str) {
|
|
24
|
+
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
25
|
+
}
|
|
26
|
+
function toBashPath(pathStr, type) {
|
|
27
|
+
if (pathStr.startsWith("/")) return pathStr;
|
|
28
|
+
if (type === "posix") return pathStr;
|
|
29
|
+
const normalized = pathStr.replace(/\\/g, "/").replace(/\\\\/g, "/");
|
|
30
|
+
const driveMatch = /^[A-Za-z]:/.exec(normalized);
|
|
31
|
+
if (driveMatch) {
|
|
32
|
+
const drive = normalized[0].toLowerCase();
|
|
33
|
+
const rest = normalized.slice(2);
|
|
34
|
+
if (type === "msys") {
|
|
35
|
+
return `/` + drive + (rest.startsWith("/") ? rest : `/${rest}`);
|
|
36
|
+
}
|
|
37
|
+
return `/mnt/` + drive + (rest.startsWith("/") ? rest : `/${rest}`);
|
|
38
|
+
}
|
|
39
|
+
return normalized;
|
|
40
|
+
}
|
|
41
|
+
function fileExists(p) {
|
|
42
|
+
return !!p && existsSync(p);
|
|
43
|
+
}
|
|
44
|
+
function splitPathEntries(pathEnv, platform) {
|
|
45
|
+
if (!pathEnv) return [];
|
|
46
|
+
if (platform !== "win32") {
|
|
47
|
+
return pathEnv.split(":").map((s) => s.trim().replace(/^"|"$/g, "")).filter(Boolean);
|
|
48
|
+
}
|
|
49
|
+
const entries = [];
|
|
50
|
+
let current = "";
|
|
51
|
+
const pushCurrent = () => {
|
|
52
|
+
const cleaned = current.trim().replace(/^"|"$/g, "");
|
|
53
|
+
if (cleaned) entries.push(cleaned);
|
|
54
|
+
current = "";
|
|
55
|
+
};
|
|
56
|
+
for (let i = 0; i < pathEnv.length; i++) {
|
|
57
|
+
const ch = pathEnv[i];
|
|
58
|
+
if (ch === ";") {
|
|
59
|
+
pushCurrent();
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (ch === ":") {
|
|
63
|
+
const segmentLength = current.length;
|
|
64
|
+
const firstChar = current[0];
|
|
65
|
+
const isDriveLetterPrefix = segmentLength === 1 && /[A-Za-z]/.test(firstChar || "");
|
|
66
|
+
if (!isDriveLetterPrefix) {
|
|
67
|
+
pushCurrent();
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
current += ch;
|
|
72
|
+
}
|
|
73
|
+
pushCurrent();
|
|
74
|
+
return entries;
|
|
75
|
+
}
|
|
76
|
+
function detectShell() {
|
|
77
|
+
const isWin = process.platform === "win32";
|
|
78
|
+
if (!isWin) {
|
|
79
|
+
const bin = process.env.SHELL || "/bin/bash";
|
|
80
|
+
return { bin, args: ["-l"], type: "posix" };
|
|
81
|
+
}
|
|
82
|
+
if (process.env.SHELL && /bash\.exe$/i.test(process.env.SHELL) && existsSync(process.env.SHELL)) {
|
|
83
|
+
return { bin: process.env.SHELL, args: ["-l"], type: "msys" };
|
|
84
|
+
}
|
|
85
|
+
if (process.env.KODE_BASH && existsSync(process.env.KODE_BASH)) {
|
|
86
|
+
return { bin: process.env.KODE_BASH, args: ["-l"], type: "msys" };
|
|
87
|
+
}
|
|
88
|
+
const programFiles = [
|
|
89
|
+
process.env["ProgramFiles"],
|
|
90
|
+
process.env["ProgramFiles(x86)"],
|
|
91
|
+
process.env["ProgramW6432"]
|
|
92
|
+
].filter(Boolean);
|
|
93
|
+
const localAppData = process.env["LocalAppData"];
|
|
94
|
+
const candidates = [];
|
|
95
|
+
for (const base of programFiles) {
|
|
96
|
+
candidates.push(
|
|
97
|
+
join(base, "Git", "bin", "bash.exe"),
|
|
98
|
+
join(base, "Git", "usr", "bin", "bash.exe")
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (localAppData) {
|
|
102
|
+
candidates.push(
|
|
103
|
+
join(localAppData, "Programs", "Git", "bin", "bash.exe"),
|
|
104
|
+
join(localAppData, "Programs", "Git", "usr", "bin", "bash.exe")
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
candidates.push("C:/msys64/usr/bin/bash.exe");
|
|
108
|
+
for (const c of candidates) {
|
|
109
|
+
if (existsSync(c)) {
|
|
110
|
+
return { bin: c, args: ["-l"], type: "msys" };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const pathEnv = process.env.PATH || process.env.Path || process.env.path || "";
|
|
114
|
+
const pathEntries = splitPathEntries(pathEnv, process.platform);
|
|
115
|
+
for (const p of pathEntries) {
|
|
116
|
+
const candidate = join(p, "bash.exe");
|
|
117
|
+
if (existsSync(candidate)) {
|
|
118
|
+
return { bin: candidate, args: ["-l"], type: "msys" };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
execSync('wsl.exe -e bash -lc "echo KODE_OK"', { stdio: "ignore", timeout: 1500 });
|
|
123
|
+
return { bin: "wsl.exe", args: ["-e", "bash", "-l"], type: "wsl" };
|
|
124
|
+
} catch {
|
|
125
|
+
}
|
|
126
|
+
const hint = [
|
|
127
|
+
"\u65E0\u6CD5\u627E\u5230\u53EF\u7528\u7684 bash\u3002\u8BF7\u5B89\u88C5 Git for Windows \u6216\u542F\u7528 WSL\u3002",
|
|
128
|
+
"\u63A8\u8350\u5B89\u88C5 Git: https://git-scm.com/download/win",
|
|
129
|
+
"\u6216\u542F\u7528 WSL \u5E76\u5B89\u88C5 Ubuntu: https://learn.microsoft.com/windows/wsl/install"
|
|
130
|
+
].join("\n");
|
|
131
|
+
throw new Error(hint);
|
|
132
|
+
}
|
|
133
|
+
class PersistentShell {
|
|
134
|
+
commandQueue = [];
|
|
135
|
+
isExecuting = false;
|
|
136
|
+
shell;
|
|
137
|
+
isAlive = true;
|
|
138
|
+
commandInterrupted = false;
|
|
139
|
+
statusFile;
|
|
140
|
+
stdoutFile;
|
|
141
|
+
stderrFile;
|
|
142
|
+
cwdFile;
|
|
143
|
+
cwd;
|
|
144
|
+
binShell;
|
|
145
|
+
shellArgs;
|
|
146
|
+
shellType;
|
|
147
|
+
statusFileBashPath;
|
|
148
|
+
stdoutFileBashPath;
|
|
149
|
+
stderrFileBashPath;
|
|
150
|
+
cwdFileBashPath;
|
|
151
|
+
constructor(cwd) {
|
|
152
|
+
const { bin, args, type } = detectShell();
|
|
153
|
+
this.binShell = bin;
|
|
154
|
+
this.shellArgs = args;
|
|
155
|
+
this.shellType = type;
|
|
156
|
+
this.shell = spawn(this.binShell, this.shellArgs, {
|
|
157
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
158
|
+
cwd,
|
|
159
|
+
env: {
|
|
160
|
+
...process.env,
|
|
161
|
+
GIT_EDITOR: "true"
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
this.cwd = cwd;
|
|
165
|
+
this.shell.on("exit", (code, signal) => {
|
|
166
|
+
if (code) {
|
|
167
|
+
logError(`Shell exited with code ${code} and signal ${signal}`);
|
|
168
|
+
logEvent("persistent_shell_exit", {
|
|
169
|
+
code: code?.toString() || "null",
|
|
170
|
+
signal: signal || "null"
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
for (const file of [
|
|
174
|
+
this.statusFile,
|
|
175
|
+
this.stdoutFile,
|
|
176
|
+
this.stderrFile,
|
|
177
|
+
this.cwdFile
|
|
178
|
+
]) {
|
|
179
|
+
if (fs.existsSync(file)) {
|
|
180
|
+
fs.unlinkSync(file);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
this.isAlive = false;
|
|
184
|
+
});
|
|
185
|
+
const id = Math.floor(Math.random() * 65536).toString(16).padStart(4, "0");
|
|
186
|
+
this.statusFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.STATUS;
|
|
187
|
+
this.stdoutFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.STDOUT;
|
|
188
|
+
this.stderrFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.STDERR;
|
|
189
|
+
this.cwdFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.CWD;
|
|
190
|
+
for (const file of [this.statusFile, this.stdoutFile, this.stderrFile]) {
|
|
191
|
+
fs.writeFileSync(file, "");
|
|
192
|
+
}
|
|
193
|
+
fs.writeFileSync(this.cwdFile, cwd);
|
|
194
|
+
this.statusFileBashPath = toBashPath(this.statusFile, this.shellType);
|
|
195
|
+
this.stdoutFileBashPath = toBashPath(this.stdoutFile, this.shellType);
|
|
196
|
+
this.stderrFileBashPath = toBashPath(this.stderrFile, this.shellType);
|
|
197
|
+
this.cwdFileBashPath = toBashPath(this.cwdFile, this.shellType);
|
|
198
|
+
this.sendToShell("[ -f ~/.bashrc ] && source ~/.bashrc || true");
|
|
199
|
+
}
|
|
200
|
+
static instance = null;
|
|
201
|
+
static restart() {
|
|
202
|
+
if (PersistentShell.instance) {
|
|
203
|
+
PersistentShell.instance.close();
|
|
204
|
+
PersistentShell.instance = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
static getInstance() {
|
|
208
|
+
if (!PersistentShell.instance || !PersistentShell.instance.isAlive) {
|
|
209
|
+
PersistentShell.instance = new PersistentShell(process.cwd());
|
|
210
|
+
}
|
|
211
|
+
return PersistentShell.instance;
|
|
212
|
+
}
|
|
213
|
+
killChildren() {
|
|
214
|
+
const parentPid = this.shell.pid;
|
|
215
|
+
try {
|
|
216
|
+
const childPids = execSync(`pgrep -P ${parentPid}`).toString().trim().split("\n").filter(Boolean);
|
|
217
|
+
if (childPids.length > 0) {
|
|
218
|
+
logEvent("persistent_shell_command_interrupted", {
|
|
219
|
+
numChildProcesses: childPids.length.toString()
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
childPids.forEach((pid) => {
|
|
223
|
+
try {
|
|
224
|
+
process.kill(Number(pid), "SIGTERM");
|
|
225
|
+
} catch (error) {
|
|
226
|
+
logError(`Failed to kill process ${pid}: ${error}`);
|
|
227
|
+
logEvent("persistent_shell_kill_process_error", {
|
|
228
|
+
error: error.message.substring(0, 10)
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
} catch {
|
|
233
|
+
} finally {
|
|
234
|
+
this.commandInterrupted = true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async processQueue() {
|
|
238
|
+
if (this.isExecuting || this.commandQueue.length === 0) return;
|
|
239
|
+
this.isExecuting = true;
|
|
240
|
+
const { command, abortSignal, timeout, resolve: resolve2, reject } = this.commandQueue.shift();
|
|
241
|
+
const killChildren = () => this.killChildren();
|
|
242
|
+
if (abortSignal) {
|
|
243
|
+
abortSignal.addEventListener("abort", killChildren);
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const result = await this.exec_(command, timeout);
|
|
247
|
+
resolve2(result);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
logEvent("persistent_shell_command_error", {
|
|
250
|
+
error: error.message.substring(0, 10)
|
|
251
|
+
});
|
|
252
|
+
reject(error);
|
|
253
|
+
} finally {
|
|
254
|
+
this.isExecuting = false;
|
|
255
|
+
if (abortSignal) {
|
|
256
|
+
abortSignal.removeEventListener("abort", killChildren);
|
|
257
|
+
}
|
|
258
|
+
this.processQueue();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async exec(command, abortSignal, timeout) {
|
|
262
|
+
return new Promise((resolve2, reject) => {
|
|
263
|
+
this.commandQueue.push({ command, abortSignal, timeout, resolve: resolve2, reject });
|
|
264
|
+
this.processQueue();
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
async exec_(command, timeout) {
|
|
268
|
+
const quotedCommand = shellquote.quote([command]);
|
|
269
|
+
try {
|
|
270
|
+
if (this.shellType === "wsl") {
|
|
271
|
+
execSync(`wsl.exe -e bash -n -c ${quotedCommand}`, {
|
|
272
|
+
stdio: "ignore",
|
|
273
|
+
timeout: 1e3
|
|
274
|
+
});
|
|
275
|
+
} else {
|
|
276
|
+
execSync(`${this.binShell} -n -c ${quotedCommand}`, {
|
|
277
|
+
stdio: "ignore",
|
|
278
|
+
timeout: 1e3
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
} catch (stderr) {
|
|
282
|
+
const errorStr = typeof stderr === "string" ? stderr : String(stderr || "");
|
|
283
|
+
logEvent("persistent_shell_syntax_error", {
|
|
284
|
+
error: errorStr.substring(0, 10)
|
|
285
|
+
});
|
|
286
|
+
return Promise.resolve({
|
|
287
|
+
stdout: "",
|
|
288
|
+
stderr: errorStr,
|
|
289
|
+
code: 128,
|
|
290
|
+
interrupted: false
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
const commandTimeout = timeout || DEFAULT_TIMEOUT;
|
|
294
|
+
this.commandInterrupted = false;
|
|
295
|
+
return new Promise((resolve2) => {
|
|
296
|
+
fs.writeFileSync(this.stdoutFile, "");
|
|
297
|
+
fs.writeFileSync(this.stderrFile, "");
|
|
298
|
+
fs.writeFileSync(this.statusFile, "");
|
|
299
|
+
const commandParts = [];
|
|
300
|
+
commandParts.push(
|
|
301
|
+
`eval ${quotedCommand} < /dev/null > ${quoteForBash(this.stdoutFileBashPath)} 2> ${quoteForBash(this.stderrFileBashPath)}`
|
|
302
|
+
);
|
|
303
|
+
commandParts.push(`EXEC_EXIT_CODE=$?`);
|
|
304
|
+
commandParts.push(`pwd > ${quoteForBash(this.cwdFileBashPath)}`);
|
|
305
|
+
commandParts.push(`echo $EXEC_EXIT_CODE > ${quoteForBash(this.statusFileBashPath)}`);
|
|
306
|
+
this.sendToShell(commandParts.join("\n"));
|
|
307
|
+
const start = Date.now();
|
|
308
|
+
const checkCompletion = setInterval(() => {
|
|
309
|
+
try {
|
|
310
|
+
let statusFileSize = 0;
|
|
311
|
+
if (fs.existsSync(this.statusFile)) {
|
|
312
|
+
statusFileSize = fs.statSync(this.statusFile).size;
|
|
313
|
+
}
|
|
314
|
+
if (statusFileSize > 0 || Date.now() - start > commandTimeout || this.commandInterrupted) {
|
|
315
|
+
clearInterval(checkCompletion);
|
|
316
|
+
const stdout = fs.existsSync(this.stdoutFile) ? fs.readFileSync(this.stdoutFile, "utf8") : "";
|
|
317
|
+
let stderr = fs.existsSync(this.stderrFile) ? fs.readFileSync(this.stderrFile, "utf8") : "";
|
|
318
|
+
let code;
|
|
319
|
+
if (statusFileSize) {
|
|
320
|
+
code = Number(fs.readFileSync(this.statusFile, "utf8"));
|
|
321
|
+
} else {
|
|
322
|
+
this.killChildren();
|
|
323
|
+
code = SIGTERM_CODE;
|
|
324
|
+
stderr += (stderr ? "\n" : "") + "Command execution timed out";
|
|
325
|
+
logEvent("persistent_shell_command_timeout", {
|
|
326
|
+
command: command.substring(0, 10),
|
|
327
|
+
timeout: commandTimeout.toString()
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
resolve2({
|
|
331
|
+
stdout,
|
|
332
|
+
stderr,
|
|
333
|
+
code,
|
|
334
|
+
interrupted: this.commandInterrupted
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
} catch {
|
|
338
|
+
}
|
|
339
|
+
}, 10);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
sendToShell(command) {
|
|
343
|
+
try {
|
|
344
|
+
this.shell.stdin.write(command + "\n");
|
|
345
|
+
} catch (error) {
|
|
346
|
+
const errorString = error instanceof Error ? error.message : String(error || "Unknown error");
|
|
347
|
+
logError(`Error in sendToShell: ${errorString}`);
|
|
348
|
+
logEvent("persistent_shell_write_error", {
|
|
349
|
+
error: errorString.substring(0, 100),
|
|
350
|
+
command: command.substring(0, 30)
|
|
351
|
+
});
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
pwd() {
|
|
356
|
+
try {
|
|
357
|
+
const newCwd = fs.readFileSync(this.cwdFile, "utf8").trim();
|
|
358
|
+
if (newCwd) {
|
|
359
|
+
this.cwd = newCwd;
|
|
360
|
+
}
|
|
361
|
+
} catch (error) {
|
|
362
|
+
logError(`Shell pwd error ${error}`);
|
|
363
|
+
}
|
|
364
|
+
return this.cwd;
|
|
365
|
+
}
|
|
366
|
+
async setCwd(cwd) {
|
|
367
|
+
const resolved = isAbsolute(cwd) ? cwd : resolve(process.cwd(), cwd);
|
|
368
|
+
if (!existsSync(resolved)) {
|
|
369
|
+
throw new Error(`Path "${resolved}" does not exist`);
|
|
370
|
+
}
|
|
371
|
+
const bashPath = toBashPath(resolved, this.shellType);
|
|
372
|
+
await this.exec(`cd ${quoteForBash(bashPath)}`);
|
|
373
|
+
}
|
|
374
|
+
close() {
|
|
375
|
+
this.shell.stdin.end();
|
|
376
|
+
this.shell.kill();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
export {
|
|
380
|
+
PersistentShell
|
|
381
|
+
};
|
|
382
|
+
//# sourceMappingURL=PersistentShell.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/PersistentShell.ts"],
|
|
4
|
+
"sourcesContent": ["import * as fs from 'fs'\nimport { homedir } from 'os'\nimport { existsSync } from 'fs'\nimport shellquote from 'shell-quote'\nimport { spawn, execSync, type ChildProcess } from 'child_process'\nimport { isAbsolute, resolve, join } from 'path'\nimport { logError } from './log'\nimport * as os from 'os'\nimport { logEvent } from '../services/statsig'\nimport { PRODUCT_COMMAND } from '../constants/product'\n\ntype ExecResult = {\n stdout: string\n stderr: string\n code: number\n interrupted: boolean\n}\ntype QueuedCommand = {\n command: string\n abortSignal?: AbortSignal\n timeout?: number\n resolve: (result: ExecResult) => void\n reject: (error: Error) => void\n}\n\nconst TEMPFILE_PREFIX = os.tmpdir() + `/${PRODUCT_COMMAND}-`\nconst DEFAULT_TIMEOUT = 30 * 60 * 1000\nconst SIGTERM_CODE = 143 // Standard exit code for SIGTERM\nconst FILE_SUFFIXES = {\n STATUS: '-status',\n STDOUT: '-stdout',\n STDERR: '-stderr',\n CWD: '-cwd',\n}\nconst SHELL_CONFIGS: Record<string, string> = {\n '/bin/bash': '.bashrc',\n '/bin/zsh': '.zshrc',\n}\n\ntype DetectedShell = {\n bin: string\n args: string[]\n type: 'posix' | 'msys' | 'wsl'\n}\n\nfunction quoteForBash(str: string): string {\n return `'${str.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction toBashPath(pathStr: string, type: 'posix' | 'msys' | 'wsl'): string {\n // Already POSIX absolute path\n if (pathStr.startsWith('/')) return pathStr\n if (type === 'posix') return pathStr\n\n // Normalize backslashes\n const normalized = pathStr.replace(/\\\\/g, '/').replace(/\\\\\\\\/g, '/')\n const driveMatch = /^[A-Za-z]:/.exec(normalized)\n if (driveMatch) {\n const drive = normalized[0].toLowerCase()\n const rest = normalized.slice(2)\n if (type === 'msys') {\n return `/` + drive + (rest.startsWith('/') ? rest : `/${rest}`)\n }\n // wsl\n return `/mnt/` + drive + (rest.startsWith('/') ? rest : `/${rest}`)\n }\n // Relative path: just convert slashes\n return normalized\n}\n\nfunction fileExists(p: string | undefined): p is string {\n return !!p && existsSync(p)\n}\n\n// Robust PATH splitter for Windows and POSIX\nfunction splitPathEntries(pathEnv: string, platform: NodeJS.Platform): string[] {\n if (!pathEnv) return []\n\n // POSIX: ':' is the separator\n if (platform !== 'win32') {\n return pathEnv\n .split(':')\n .map(s => s.trim().replace(/^\"|\"$/g, ''))\n .filter(Boolean)\n }\n\n // Windows: primarily ';', but some environments may use ':'\n // We must not split drive letters like 'C:\\\\' or 'D:foo\\\\bar'\n const entries: string[] = []\n let current = ''\n const pushCurrent = () => {\n const cleaned = current.trim().replace(/^\"|\"$/g, '')\n if (cleaned) entries.push(cleaned)\n current = ''\n }\n\n for (let i = 0; i < pathEnv.length; i++) {\n const ch = pathEnv[i]\n\n if (ch === ';') {\n pushCurrent()\n continue\n }\n\n if (ch === ':') {\n const segmentLength = current.length\n const firstChar = current[0]\n const isDriveLetterPrefix = segmentLength === 1 && /[A-Za-z]/.test(firstChar || '')\n // Treat ':' as separator only if it's NOT the drive letter colon\n if (!isDriveLetterPrefix) {\n pushCurrent()\n continue\n }\n }\n\n current += ch\n }\n\n // Flush the final segment\n pushCurrent()\n\n return entries\n}\n\nfunction detectShell(): DetectedShell {\n const isWin = process.platform === 'win32'\n if (!isWin) {\n const bin = process.env.SHELL || '/bin/bash'\n return { bin, args: ['-l'], type: 'posix' }\n }\n\n // 1) Respect SHELL if it points to a bash.exe that exists\n if (process.env.SHELL && /bash\\.exe$/i.test(process.env.SHELL) && existsSync(process.env.SHELL)) {\n return { bin: process.env.SHELL, args: ['-l'], type: 'msys' }\n }\n\n // 1.1) Explicit override\n if (process.env.KODE_BASH && existsSync(process.env.KODE_BASH)) {\n return { bin: process.env.KODE_BASH, args: ['-l'], type: 'msys' }\n }\n\n // 2) Common Git Bash/MSYS2 locations\n const programFiles = [\n process.env['ProgramFiles'],\n process.env['ProgramFiles(x86)'],\n process.env['ProgramW6432'],\n ].filter(Boolean) as string[]\n\n const localAppData = process.env['LocalAppData']\n\n const candidates: string[] = []\n for (const base of programFiles) {\n candidates.push(\n join(base, 'Git', 'bin', 'bash.exe'),\n join(base, 'Git', 'usr', 'bin', 'bash.exe'),\n )\n }\n if (localAppData) {\n candidates.push(\n join(localAppData, 'Programs', 'Git', 'bin', 'bash.exe'),\n join(localAppData, 'Programs', 'Git', 'usr', 'bin', 'bash.exe'),\n )\n }\n // MSYS2 default\n candidates.push('C:/msys64/usr/bin/bash.exe')\n\n for (const c of candidates) {\n if (existsSync(c)) {\n return { bin: c, args: ['-l'], type: 'msys' }\n }\n }\n\n // 2.1) Search in PATH for bash.exe\n const pathEnv = process.env.PATH || process.env.Path || process.env.path || ''\n const pathEntries = splitPathEntries(pathEnv, process.platform)\n for (const p of pathEntries) {\n const candidate = join(p, 'bash.exe')\n if (existsSync(candidate)) {\n return { bin: candidate, args: ['-l'], type: 'msys' }\n }\n }\n\n // 3) WSL\n try {\n // Quick probe to ensure WSL+bash exists\n execSync('wsl.exe -e bash -lc \"echo KODE_OK\"', { stdio: 'ignore', timeout: 1500 })\n return { bin: 'wsl.exe', args: ['-e', 'bash', '-l'], type: 'wsl' }\n } catch {}\n\n // 4) Last resort: meaningful error\n const hint = [\n '\u65E0\u6CD5\u627E\u5230\u53EF\u7528\u7684 bash\u3002\u8BF7\u5B89\u88C5 Git for Windows \u6216\u542F\u7528 WSL\u3002',\n '\u63A8\u8350\u5B89\u88C5 Git: https://git-scm.com/download/win',\n '\u6216\u542F\u7528 WSL \u5E76\u5B89\u88C5 Ubuntu: https://learn.microsoft.com/windows/wsl/install',\n ].join('\\n')\n throw new Error(hint)\n}\n\nexport class PersistentShell {\n private commandQueue: QueuedCommand[] = []\n private isExecuting: boolean = false\n private shell: ChildProcess\n private isAlive: boolean = true\n private commandInterrupted: boolean = false\n private statusFile: string\n private stdoutFile: string\n private stderrFile: string\n private cwdFile: string\n private cwd: string\n private binShell: string\n private shellArgs: string[]\n private shellType: 'posix' | 'msys' | 'wsl'\n private statusFileBashPath: string\n private stdoutFileBashPath: string\n private stderrFileBashPath: string\n private cwdFileBashPath: string\n\n constructor(cwd: string) {\n const { bin, args, type } = detectShell()\n this.binShell = bin\n this.shellArgs = args\n this.shellType = type\n\n this.shell = spawn(this.binShell, this.shellArgs, {\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd,\n env: {\n ...process.env,\n GIT_EDITOR: 'true',\n },\n })\n\n this.cwd = cwd\n\n this.shell.on('exit', (code, signal) => {\n if (code) {\n // TODO: It would be nice to alert the user that shell crashed\n logError(`Shell exited with code ${code} and signal ${signal}`)\n logEvent('persistent_shell_exit', {\n code: code?.toString() || 'null',\n signal: signal || 'null',\n })\n }\n for (const file of [\n this.statusFile,\n this.stdoutFile,\n this.stderrFile,\n this.cwdFile,\n ]) {\n if (fs.existsSync(file)) {\n fs.unlinkSync(file)\n }\n }\n this.isAlive = false\n })\n\n const id = Math.floor(Math.random() * 0x10000)\n .toString(16)\n .padStart(4, '0')\n\n this.statusFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.STATUS\n this.stdoutFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.STDOUT\n this.stderrFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.STDERR\n this.cwdFile = TEMPFILE_PREFIX + id + FILE_SUFFIXES.CWD\n for (const file of [this.statusFile, this.stdoutFile, this.stderrFile]) {\n fs.writeFileSync(file, '')\n }\n // Initialize CWD file with initial directory\n fs.writeFileSync(this.cwdFile, cwd)\n\n // Compute bash-visible paths for redirections\n this.statusFileBashPath = toBashPath(this.statusFile, this.shellType)\n this.stdoutFileBashPath = toBashPath(this.stdoutFile, this.shellType)\n this.stderrFileBashPath = toBashPath(this.stderrFile, this.shellType)\n this.cwdFileBashPath = toBashPath(this.cwdFile, this.shellType)\n\n // Source ~/.bashrc when available (works for bash on POSIX/MSYS/WSL)\n this.sendToShell('[ -f ~/.bashrc ] && source ~/.bashrc || true')\n }\n\n private static instance: PersistentShell | null = null\n\n static restart() {\n if (PersistentShell.instance) {\n PersistentShell.instance.close()\n PersistentShell.instance = null\n }\n }\n\n static getInstance(): PersistentShell {\n if (!PersistentShell.instance || !PersistentShell.instance.isAlive) {\n PersistentShell.instance = new PersistentShell(process.cwd())\n }\n return PersistentShell.instance\n }\n\n killChildren() {\n const parentPid = this.shell.pid\n try {\n const childPids = execSync(`pgrep -P ${parentPid}`)\n .toString()\n .trim()\n .split('\\n')\n .filter(Boolean) // Filter out empty strings\n\n if (childPids.length > 0) {\n logEvent('persistent_shell_command_interrupted', {\n numChildProcesses: childPids.length.toString(),\n })\n }\n\n childPids.forEach(pid => {\n try {\n process.kill(Number(pid), 'SIGTERM')\n } catch (error) {\n logError(`Failed to kill process ${pid}: ${error}`)\n logEvent('persistent_shell_kill_process_error', {\n error: (error as Error).message.substring(0, 10),\n })\n }\n })\n } catch {\n // pgrep returns non-zero when no processes are found - this is expected\n } finally {\n this.commandInterrupted = true\n }\n }\n\n private async processQueue() {\n /**\n * Processes commands from the queue one at a time.\n * Concurrency invariants:\n * - Only one instance runs at a time (controlled by isExecuting)\n * - Is the only caller of updateCwd() in the system\n * - Calls updateCwd() after each command completes\n * - Ensures commands execute serially via the queue\n * - Handles interruption via abortSignal by calling killChildren()\n * - Cleans up abortSignal listeners after command completion or interruption\n */\n if (this.isExecuting || this.commandQueue.length === 0) return\n\n this.isExecuting = true\n const { command, abortSignal, timeout, resolve, reject } =\n this.commandQueue.shift()!\n\n const killChildren = () => this.killChildren()\n if (abortSignal) {\n abortSignal.addEventListener('abort', killChildren)\n }\n\n try {\n const result = await this.exec_(command, timeout)\n\n // No need to update cwd - it's handled in exec_ via the CWD file\n\n resolve(result)\n } catch (error) {\n logEvent('persistent_shell_command_error', {\n error: (error as Error).message.substring(0, 10),\n })\n reject(error as Error)\n } finally {\n this.isExecuting = false\n if (abortSignal) {\n abortSignal.removeEventListener('abort', killChildren)\n }\n // Process next command in queue\n this.processQueue()\n }\n }\n\n async exec(\n command: string,\n abortSignal?: AbortSignal,\n timeout?: number,\n ): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n this.commandQueue.push({ command, abortSignal, timeout, resolve, reject })\n this.processQueue()\n })\n }\n\n private async exec_(command: string, timeout?: number): Promise<ExecResult> {\n /**\n * Direct command execution without going through the queue.\n * Concurrency invariants:\n * - Not safe for concurrent calls (uses shared files)\n * - Called only when queue is idle\n * - Relies on file-based IPC to handle shell interaction\n * - Does not modify the command queue state\n * - Tracks interruption state via commandInterrupted flag\n * - Resets interruption state at start of new command\n * - Reports interruption status in result object\n *\n * Exit Code & CWD Handling:\n * - Executes command and immediately captures its exit code into a shell variable\n * - Updates the CWD file with the working directory after capturing exit code\n * - Writes the preserved exit code to the status file as the final step\n * - This sequence eliminates race conditions between exit code capture and CWD updates\n * - The pwd() method reads the CWD file directly for current directory info\n */\n const quotedCommand = shellquote.quote([command])\n\n // Check the syntax of the command\n try {\n if (this.shellType === 'wsl') {\n execSync(`wsl.exe -e bash -n -c ${quotedCommand}`, {\n stdio: 'ignore',\n timeout: 1000,\n })\n } else {\n execSync(`${this.binShell} -n -c ${quotedCommand}`, {\n stdio: 'ignore',\n timeout: 1000,\n })\n }\n } catch (stderr) {\n // If there's a syntax error, return an error and log it\n const errorStr =\n typeof stderr === 'string' ? stderr : String(stderr || '')\n logEvent('persistent_shell_syntax_error', {\n error: errorStr.substring(0, 10),\n })\n return Promise.resolve({\n stdout: '',\n stderr: errorStr,\n code: 128,\n interrupted: false,\n })\n }\n\n const commandTimeout = timeout || DEFAULT_TIMEOUT\n // Reset interrupted state for new command\n this.commandInterrupted = false\n return new Promise<ExecResult>(resolve => {\n // Truncate output files\n fs.writeFileSync(this.stdoutFile, '')\n fs.writeFileSync(this.stderrFile, '')\n fs.writeFileSync(this.statusFile, '')\n // Break up the command sequence for clarity using an array of commands\n const commandParts = []\n\n // 1. Execute the main command with redirections\n commandParts.push(\n `eval ${quotedCommand} < /dev/null > ${quoteForBash(this.stdoutFileBashPath)} 2> ${quoteForBash(this.stderrFileBashPath)}`,\n )\n\n // 2. Capture exit code immediately after command execution to avoid losing it\n commandParts.push(`EXEC_EXIT_CODE=$?`)\n\n // 3. Update CWD file\n commandParts.push(`pwd > ${quoteForBash(this.cwdFileBashPath)}`)\n\n // 4. Write the preserved exit code to status file to avoid race with pwd\n commandParts.push(`echo $EXEC_EXIT_CODE > ${quoteForBash(this.statusFileBashPath)}`)\n\n // Send the combined commands as a single operation to maintain atomicity\n this.sendToShell(commandParts.join('\\n'))\n\n // Check for command completion or timeout\n const start = Date.now()\n const checkCompletion = setInterval(() => {\n try {\n let statusFileSize = 0\n if (fs.existsSync(this.statusFile)) {\n statusFileSize = fs.statSync(this.statusFile).size\n }\n\n if (\n statusFileSize > 0 ||\n Date.now() - start > commandTimeout ||\n this.commandInterrupted\n ) {\n clearInterval(checkCompletion)\n const stdout = fs.existsSync(this.stdoutFile)\n ? fs.readFileSync(this.stdoutFile, 'utf8')\n : ''\n let stderr = fs.existsSync(this.stderrFile)\n ? fs.readFileSync(this.stderrFile, 'utf8')\n : ''\n let code: number\n if (statusFileSize) {\n code = Number(fs.readFileSync(this.statusFile, 'utf8'))\n } else {\n // Timeout occurred - kill any running processes\n this.killChildren()\n code = SIGTERM_CODE\n stderr += (stderr ? '\\n' : '') + 'Command execution timed out'\n logEvent('persistent_shell_command_timeout', {\n command: command.substring(0, 10),\n timeout: commandTimeout.toString(),\n })\n }\n resolve({\n stdout,\n stderr,\n code,\n interrupted: this.commandInterrupted,\n })\n }\n } catch {\n // Ignore file system errors during polling - they are expected\n // as we check for completion before files exist\n }\n }, 10) // increasing this will introduce latency\n })\n }\n\n private sendToShell(command: string) {\n try {\n this.shell!.stdin!.write(command + '\\n')\n } catch (error) {\n const errorString =\n error instanceof Error\n ? error.message\n : String(error || 'Unknown error')\n logError(`Error in sendToShell: ${errorString}`)\n logEvent('persistent_shell_write_error', {\n error: errorString.substring(0, 100),\n command: command.substring(0, 30),\n })\n throw error\n }\n }\n\n pwd(): string {\n try {\n const newCwd = fs.readFileSync(this.cwdFile, 'utf8').trim()\n if (newCwd) {\n this.cwd = newCwd\n }\n } catch (error) {\n logError(`Shell pwd error ${error}`)\n }\n // Always return the cached value\n return this.cwd\n }\n\n async setCwd(cwd: string) {\n const resolved = isAbsolute(cwd) ? cwd : resolve(process.cwd(), cwd)\n if (!existsSync(resolved)) {\n throw new Error(`Path \"${resolved}\" does not exist`)\n }\n const bashPath = toBashPath(resolved, this.shellType)\n await this.exec(`cd ${quoteForBash(bashPath)}`)\n }\n\n close(): void {\n this.shell!.stdin!.end()\n this.shell.kill()\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["resolve"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
class AdvancedFuzzyMatcher {
|
|
2
|
+
/**
|
|
3
|
+
* Main matching function - combines multiple algorithms
|
|
4
|
+
*/
|
|
5
|
+
match(candidate, query) {
|
|
6
|
+
const text = candidate.toLowerCase();
|
|
7
|
+
const pattern = query.toLowerCase();
|
|
8
|
+
if (text === pattern) {
|
|
9
|
+
return { score: 1e4, matched: true, algorithm: "exact" };
|
|
10
|
+
}
|
|
11
|
+
const algorithms = [
|
|
12
|
+
this.exactPrefixMatch(text, pattern),
|
|
13
|
+
this.hyphenAwareMatch(text, pattern),
|
|
14
|
+
this.wordBoundaryMatch(text, pattern),
|
|
15
|
+
this.abbreviationMatch(text, pattern),
|
|
16
|
+
this.numericSuffixMatch(text, pattern),
|
|
17
|
+
this.subsequenceMatch(text, pattern),
|
|
18
|
+
this.fuzzySegmentMatch(text, pattern)
|
|
19
|
+
];
|
|
20
|
+
let bestScore = 0;
|
|
21
|
+
let bestAlgorithm = "none";
|
|
22
|
+
for (const result of algorithms) {
|
|
23
|
+
if (result.score > bestScore) {
|
|
24
|
+
bestScore = result.score;
|
|
25
|
+
bestAlgorithm = result.algorithm;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
score: bestScore,
|
|
30
|
+
matched: bestScore > 10,
|
|
31
|
+
algorithm: bestAlgorithm
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Exact prefix matching
|
|
36
|
+
*/
|
|
37
|
+
exactPrefixMatch(text, pattern) {
|
|
38
|
+
if (text.startsWith(pattern)) {
|
|
39
|
+
const coverage = pattern.length / text.length;
|
|
40
|
+
return { score: 1e3 + coverage * 500, algorithm: "prefix" };
|
|
41
|
+
}
|
|
42
|
+
return { score: 0, algorithm: "prefix" };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Hyphen-aware matching (dao → dao-qi-harmony-designer)
|
|
46
|
+
* Treats hyphens as optional word boundaries
|
|
47
|
+
*/
|
|
48
|
+
hyphenAwareMatch(text, pattern) {
|
|
49
|
+
const words = text.split("-");
|
|
50
|
+
if (words[0].startsWith(pattern)) {
|
|
51
|
+
const coverage = pattern.length / words[0].length;
|
|
52
|
+
return { score: 300 + coverage * 100, algorithm: "hyphen-prefix" };
|
|
53
|
+
}
|
|
54
|
+
const concatenated = words.join("");
|
|
55
|
+
if (concatenated.startsWith(pattern)) {
|
|
56
|
+
const coverage = pattern.length / concatenated.length;
|
|
57
|
+
return { score: 250 + coverage * 100, algorithm: "hyphen-concat" };
|
|
58
|
+
}
|
|
59
|
+
for (let i = 0; i < words.length; i++) {
|
|
60
|
+
if (words[i].startsWith(pattern)) {
|
|
61
|
+
return { score: 200 - i * 10, algorithm: "hyphen-word" };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { score: 0, algorithm: "hyphen" };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Word boundary matching (dq → dao-qi)
|
|
68
|
+
* Matches characters at word boundaries
|
|
69
|
+
*/
|
|
70
|
+
wordBoundaryMatch(text, pattern) {
|
|
71
|
+
const words = text.split(/[-_\s]+/);
|
|
72
|
+
let patternIdx = 0;
|
|
73
|
+
let score = 0;
|
|
74
|
+
let matched = false;
|
|
75
|
+
for (const word of words) {
|
|
76
|
+
if (patternIdx >= pattern.length) break;
|
|
77
|
+
if (word[0] === pattern[patternIdx]) {
|
|
78
|
+
score += 50;
|
|
79
|
+
patternIdx++;
|
|
80
|
+
matched = true;
|
|
81
|
+
for (let i = 1; i < word.length && patternIdx < pattern.length; i++) {
|
|
82
|
+
if (word[i] === pattern[patternIdx]) {
|
|
83
|
+
score += 20;
|
|
84
|
+
patternIdx++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (matched && patternIdx === pattern.length) {
|
|
90
|
+
return { score, algorithm: "word-boundary" };
|
|
91
|
+
}
|
|
92
|
+
return { score: 0, algorithm: "word-boundary" };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Abbreviation matching (nde → node, daoqi → dao-qi)
|
|
96
|
+
*/
|
|
97
|
+
abbreviationMatch(text, pattern) {
|
|
98
|
+
let textIdx = 0;
|
|
99
|
+
let patternIdx = 0;
|
|
100
|
+
let score = 0;
|
|
101
|
+
let lastMatchIdx = -1;
|
|
102
|
+
while (patternIdx < pattern.length && textIdx < text.length) {
|
|
103
|
+
if (text[textIdx] === pattern[patternIdx]) {
|
|
104
|
+
const gap = lastMatchIdx === -1 ? 0 : textIdx - lastMatchIdx - 1;
|
|
105
|
+
if (textIdx === 0) {
|
|
106
|
+
score += 50;
|
|
107
|
+
} else if (lastMatchIdx >= 0 && gap === 0) {
|
|
108
|
+
score += 30;
|
|
109
|
+
} else if (text[textIdx - 1] === "-" || text[textIdx - 1] === "_") {
|
|
110
|
+
score += 40;
|
|
111
|
+
} else {
|
|
112
|
+
score += Math.max(5, 20 - gap * 2);
|
|
113
|
+
}
|
|
114
|
+
lastMatchIdx = textIdx;
|
|
115
|
+
patternIdx++;
|
|
116
|
+
}
|
|
117
|
+
textIdx++;
|
|
118
|
+
}
|
|
119
|
+
if (patternIdx === pattern.length) {
|
|
120
|
+
const spread = lastMatchIdx / pattern.length;
|
|
121
|
+
if (spread <= 3) score += 50;
|
|
122
|
+
else if (spread <= 5) score += 30;
|
|
123
|
+
return { score, algorithm: "abbreviation" };
|
|
124
|
+
}
|
|
125
|
+
return { score: 0, algorithm: "abbreviation" };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Numeric suffix matching (py3 → python3, np18 → node18)
|
|
129
|
+
*/
|
|
130
|
+
numericSuffixMatch(text, pattern) {
|
|
131
|
+
const patternMatch = pattern.match(/^(.+?)(\d+)$/);
|
|
132
|
+
if (!patternMatch) return { score: 0, algorithm: "numeric" };
|
|
133
|
+
const [, prefix, suffix] = patternMatch;
|
|
134
|
+
if (!text.endsWith(suffix)) return { score: 0, algorithm: "numeric" };
|
|
135
|
+
const textWithoutSuffix = text.slice(0, -suffix.length);
|
|
136
|
+
if (textWithoutSuffix.startsWith(prefix)) {
|
|
137
|
+
const coverage = prefix.length / textWithoutSuffix.length;
|
|
138
|
+
return { score: 200 + coverage * 100, algorithm: "numeric-suffix" };
|
|
139
|
+
}
|
|
140
|
+
const abbrevResult = this.abbreviationMatch(textWithoutSuffix, prefix);
|
|
141
|
+
if (abbrevResult.score > 0) {
|
|
142
|
+
return { score: abbrevResult.score + 50, algorithm: "numeric-abbrev" };
|
|
143
|
+
}
|
|
144
|
+
return { score: 0, algorithm: "numeric" };
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Subsequence matching - characters appear in order
|
|
148
|
+
*/
|
|
149
|
+
subsequenceMatch(text, pattern) {
|
|
150
|
+
let textIdx = 0;
|
|
151
|
+
let patternIdx = 0;
|
|
152
|
+
let score = 0;
|
|
153
|
+
while (patternIdx < pattern.length && textIdx < text.length) {
|
|
154
|
+
if (text[textIdx] === pattern[patternIdx]) {
|
|
155
|
+
score += 10;
|
|
156
|
+
patternIdx++;
|
|
157
|
+
}
|
|
158
|
+
textIdx++;
|
|
159
|
+
}
|
|
160
|
+
if (patternIdx === pattern.length) {
|
|
161
|
+
const spread = textIdx / pattern.length;
|
|
162
|
+
score = Math.max(10, score - spread * 5);
|
|
163
|
+
return { score, algorithm: "subsequence" };
|
|
164
|
+
}
|
|
165
|
+
return { score: 0, algorithm: "subsequence" };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Fuzzy segment matching (dao → dao-qi-harmony)
|
|
169
|
+
* Matches segments flexibly
|
|
170
|
+
*/
|
|
171
|
+
fuzzySegmentMatch(text, pattern) {
|
|
172
|
+
const cleanText = text.replace(/[-_]/g, "");
|
|
173
|
+
const cleanPattern = pattern.replace(/[-_]/g, "");
|
|
174
|
+
if (cleanText.startsWith(cleanPattern)) {
|
|
175
|
+
const coverage = cleanPattern.length / cleanText.length;
|
|
176
|
+
return { score: 150 + coverage * 100, algorithm: "fuzzy-segment" };
|
|
177
|
+
}
|
|
178
|
+
const index = cleanText.indexOf(cleanPattern);
|
|
179
|
+
if (index !== -1) {
|
|
180
|
+
const positionPenalty = index * 5;
|
|
181
|
+
return { score: Math.max(50, 100 - positionPenalty), algorithm: "fuzzy-contains" };
|
|
182
|
+
}
|
|
183
|
+
return { score: 0, algorithm: "fuzzy-segment" };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const advancedMatcher = new AdvancedFuzzyMatcher();
|
|
187
|
+
function matchAdvanced(candidate, query) {
|
|
188
|
+
return advancedMatcher.match(candidate, query);
|
|
189
|
+
}
|
|
190
|
+
function matchManyAdvanced(candidates, query, minScore = 10) {
|
|
191
|
+
return candidates.map((candidate) => {
|
|
192
|
+
const result = advancedMatcher.match(candidate, query);
|
|
193
|
+
return {
|
|
194
|
+
candidate,
|
|
195
|
+
score: result.score,
|
|
196
|
+
algorithm: result.algorithm
|
|
197
|
+
};
|
|
198
|
+
}).filter((item) => item.score >= minScore).sort((a, b) => b.score - a.score);
|
|
199
|
+
}
|
|
200
|
+
export {
|
|
201
|
+
AdvancedFuzzyMatcher,
|
|
202
|
+
advancedMatcher,
|
|
203
|
+
matchAdvanced,
|
|
204
|
+
matchManyAdvanced
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=advancedFuzzyMatcher.js.map
|