@shareai-lab/kode 1.1.12 → 1.1.13

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.
Files changed (593) hide show
  1. package/cli.js +44 -23
  2. package/dist/ProjectOnboarding.js +99 -0
  3. package/dist/ProjectOnboarding.js.map +7 -0
  4. package/dist/Tool.js +1 -0
  5. package/dist/Tool.js.map +7 -0
  6. package/dist/commands/agents.js +2087 -0
  7. package/dist/commands/agents.js.map +7 -0
  8. package/dist/commands/approvedTools.js +36 -0
  9. package/dist/commands/approvedTools.js.map +7 -0
  10. package/dist/commands/bug.js +21 -0
  11. package/dist/commands/bug.js.map +7 -0
  12. package/dist/commands/clear.js +37 -0
  13. package/dist/commands/clear.js.map +7 -0
  14. package/dist/commands/compact.js +104 -0
  15. package/dist/commands/compact.js.map +7 -0
  16. package/dist/commands/config.js +20 -0
  17. package/dist/commands/config.js.map +7 -0
  18. package/dist/commands/cost.js +19 -0
  19. package/dist/commands/cost.js.map +7 -0
  20. package/dist/commands/ctx_viz.js +152 -0
  21. package/dist/commands/ctx_viz.js.map +7 -0
  22. package/dist/commands/doctor.js +25 -0
  23. package/dist/commands/doctor.js.map +7 -0
  24. package/dist/commands/help.js +20 -0
  25. package/dist/commands/help.js.map +7 -0
  26. package/dist/commands/init.js +38 -0
  27. package/dist/commands/init.js.map +7 -0
  28. package/dist/commands/listen.js +37 -0
  29. package/dist/commands/listen.js.map +7 -0
  30. package/dist/commands/login.js +37 -0
  31. package/dist/commands/login.js.map +7 -0
  32. package/dist/commands/logout.js +33 -0
  33. package/dist/commands/logout.js.map +7 -0
  34. package/dist/commands/mcp.js +34 -0
  35. package/dist/commands/mcp.js.map +7 -0
  36. package/dist/commands/model.js +41 -0
  37. package/dist/commands/model.js.map +7 -0
  38. package/dist/commands/modelstatus.js +21 -0
  39. package/dist/commands/modelstatus.js.map +7 -0
  40. package/dist/commands/onboarding.js +36 -0
  41. package/dist/commands/onboarding.js.map +7 -0
  42. package/dist/commands/pr_comments.js +61 -0
  43. package/dist/commands/pr_comments.js.map +7 -0
  44. package/dist/commands/refreshCommands.js +37 -0
  45. package/dist/commands/refreshCommands.js.map +7 -0
  46. package/dist/commands/release-notes.js +30 -0
  47. package/dist/commands/release-notes.js.map +7 -0
  48. package/dist/commands/resume.js +35 -0
  49. package/dist/commands/resume.js.map +7 -0
  50. package/dist/commands/review.js +51 -0
  51. package/dist/commands/review.js.map +7 -0
  52. package/dist/commands/terminalSetup.js +163 -0
  53. package/dist/commands/terminalSetup.js.map +7 -0
  54. package/dist/commands.js +84 -0
  55. package/dist/commands.js.map +7 -0
  56. package/dist/components/ApproveApiKey.js +74 -0
  57. package/dist/components/ApproveApiKey.js.map +7 -0
  58. package/dist/components/AsciiLogo.js +12 -0
  59. package/dist/components/AsciiLogo.js.map +7 -0
  60. package/dist/components/AutoUpdater.js +74 -0
  61. package/dist/components/AutoUpdater.js.map +7 -0
  62. package/dist/components/Bug.js +147 -0
  63. package/dist/components/Bug.js.map +7 -0
  64. package/dist/components/Config.js +166 -0
  65. package/dist/components/Config.js.map +7 -0
  66. package/dist/components/ConsoleOAuthFlow.js +188 -0
  67. package/dist/components/ConsoleOAuthFlow.js.map +7 -0
  68. package/dist/components/Cost.js +13 -0
  69. package/dist/components/Cost.js.map +7 -0
  70. package/dist/components/CostThresholdDialog.js +38 -0
  71. package/dist/components/CostThresholdDialog.js.map +7 -0
  72. package/dist/components/CustomSelect/option-map.js +32 -0
  73. package/dist/components/CustomSelect/option-map.js.map +7 -0
  74. package/dist/components/CustomSelect/select-option.js +34 -0
  75. package/dist/components/CustomSelect/select-option.js.map +7 -0
  76. package/dist/components/CustomSelect/select.js +64 -0
  77. package/dist/components/CustomSelect/select.js.map +7 -0
  78. package/dist/components/CustomSelect/theme.js +1 -0
  79. package/dist/components/CustomSelect/theme.js.map +7 -0
  80. package/dist/components/CustomSelect/use-select-state.js +220 -0
  81. package/dist/components/CustomSelect/use-select-state.js.map +7 -0
  82. package/dist/components/CustomSelect/use-select.js +21 -0
  83. package/dist/components/CustomSelect/use-select.js.map +7 -0
  84. package/dist/components/FallbackToolUseRejectedMessage.js +11 -0
  85. package/dist/components/FallbackToolUseRejectedMessage.js.map +7 -0
  86. package/dist/components/FileEditToolUpdatedMessage.js +31 -0
  87. package/dist/components/FileEditToolUpdatedMessage.js.map +7 -0
  88. package/dist/components/Help.js +41 -0
  89. package/dist/components/Help.js.map +7 -0
  90. package/dist/components/HighlightedCode.js +30 -0
  91. package/dist/components/HighlightedCode.js.map +7 -0
  92. package/dist/components/InvalidConfigDialog.js +83 -0
  93. package/dist/components/InvalidConfigDialog.js.map +7 -0
  94. package/dist/components/Link.js +18 -0
  95. package/dist/components/Link.js.map +7 -0
  96. package/dist/components/LogSelector.js +50 -0
  97. package/dist/components/LogSelector.js.map +7 -0
  98. package/dist/components/Logo.js +89 -0
  99. package/dist/components/Logo.js.map +7 -0
  100. package/dist/components/MCPServerApprovalDialog.js +79 -0
  101. package/dist/components/MCPServerApprovalDialog.js.map +7 -0
  102. package/dist/components/MCPServerDialogCopy.js +11 -0
  103. package/dist/components/MCPServerDialogCopy.js.map +7 -0
  104. package/dist/components/MCPServerMultiselectDialog.js +80 -0
  105. package/dist/components/MCPServerMultiselectDialog.js.map +7 -0
  106. package/dist/components/Message.js +146 -0
  107. package/dist/components/Message.js.map +7 -0
  108. package/dist/components/MessageResponse.js +9 -0
  109. package/dist/components/MessageResponse.js.map +7 -0
  110. package/dist/components/MessageSelector.js +133 -0
  111. package/dist/components/MessageSelector.js.map +7 -0
  112. package/dist/components/ModeIndicator.js +38 -0
  113. package/dist/components/ModeIndicator.js.map +7 -0
  114. package/dist/components/ModelConfig.js +208 -0
  115. package/dist/components/ModelConfig.js.map +7 -0
  116. package/dist/components/ModelListManager.js +140 -0
  117. package/dist/components/ModelListManager.js.map +7 -0
  118. package/dist/components/ModelSelector.js +1985 -0
  119. package/dist/components/ModelSelector.js.map +7 -0
  120. package/dist/components/ModelStatusDisplay.js +87 -0
  121. package/dist/components/ModelStatusDisplay.js.map +7 -0
  122. package/dist/components/Onboarding.js +153 -0
  123. package/dist/components/Onboarding.js.map +7 -0
  124. package/dist/components/PressEnterToContinue.js +10 -0
  125. package/dist/components/PressEnterToContinue.js.map +7 -0
  126. package/dist/components/PromptInput.js +501 -0
  127. package/dist/components/PromptInput.js.map +7 -0
  128. package/dist/components/SentryErrorBoundary.js +27 -0
  129. package/dist/components/SentryErrorBoundary.js.map +7 -0
  130. package/dist/components/Spinner.js +101 -0
  131. package/dist/components/Spinner.js.map +7 -0
  132. package/dist/components/StickerRequestForm.js +7 -0
  133. package/dist/components/StickerRequestForm.js.map +7 -0
  134. package/dist/components/StructuredDiff.js +148 -0
  135. package/dist/components/StructuredDiff.js.map +7 -0
  136. package/dist/components/TextInput.js +100 -0
  137. package/dist/components/TextInput.js.map +7 -0
  138. package/dist/components/TodoItem.js +35 -0
  139. package/dist/components/TodoItem.js.map +7 -0
  140. package/dist/components/TokenWarning.js +19 -0
  141. package/dist/components/TokenWarning.js.map +7 -0
  142. package/dist/components/ToolUseLoader.js +24 -0
  143. package/dist/components/ToolUseLoader.js.map +7 -0
  144. package/dist/components/TrustDialog.js +76 -0
  145. package/dist/components/TrustDialog.js.map +7 -0
  146. package/dist/components/binary-feedback/BinaryFeedback.js +50 -0
  147. package/dist/components/binary-feedback/BinaryFeedback.js.map +7 -0
  148. package/dist/components/binary-feedback/BinaryFeedbackOption.js +94 -0
  149. package/dist/components/binary-feedback/BinaryFeedbackOption.js.map +7 -0
  150. package/dist/components/binary-feedback/BinaryFeedbackView.js +139 -0
  151. package/dist/components/binary-feedback/BinaryFeedbackView.js.map +7 -0
  152. package/dist/components/binary-feedback/utils.js +161 -0
  153. package/dist/components/binary-feedback/utils.js.map +7 -0
  154. package/dist/components/messages/AssistantBashOutputMessage.js +23 -0
  155. package/dist/components/messages/AssistantBashOutputMessage.js.map +7 -0
  156. package/dist/components/messages/AssistantLocalCommandOutputMessage.js +36 -0
  157. package/dist/components/messages/AssistantLocalCommandOutputMessage.js.map +7 -0
  158. package/dist/components/messages/AssistantRedactedThinkingMessage.js +12 -0
  159. package/dist/components/messages/AssistantRedactedThinkingMessage.js.map +7 -0
  160. package/dist/components/messages/AssistantTextMessage.js +78 -0
  161. package/dist/components/messages/AssistantTextMessage.js.map +7 -0
  162. package/dist/components/messages/AssistantThinkingMessage.js +27 -0
  163. package/dist/components/messages/AssistantThinkingMessage.js.map +7 -0
  164. package/dist/components/messages/AssistantToolUseMessage.js +91 -0
  165. package/dist/components/messages/AssistantToolUseMessage.js.map +7 -0
  166. package/dist/components/messages/TaskProgressMessage.js +11 -0
  167. package/dist/components/messages/TaskProgressMessage.js.map +7 -0
  168. package/dist/components/messages/TaskToolMessage.js +39 -0
  169. package/dist/components/messages/TaskToolMessage.js.map +7 -0
  170. package/dist/components/messages/UserBashInputMessage.js +18 -0
  171. package/dist/components/messages/UserBashInputMessage.js.map +7 -0
  172. package/dist/components/messages/UserCommandMessage.js +20 -0
  173. package/dist/components/messages/UserCommandMessage.js.map +7 -0
  174. package/dist/components/messages/UserKodingInputMessage.js +18 -0
  175. package/dist/components/messages/UserKodingInputMessage.js.map +7 -0
  176. package/dist/components/messages/UserPromptMessage.js +20 -0
  177. package/dist/components/messages/UserPromptMessage.js.map +7 -0
  178. package/dist/components/messages/UserTextMessage.js +25 -0
  179. package/dist/components/messages/UserTextMessage.js.map +7 -0
  180. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +10 -0
  181. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js.map +7 -0
  182. package/dist/components/messages/UserToolResultMessage/UserToolErrorMessage.js +15 -0
  183. package/dist/components/messages/UserToolResultMessage/UserToolErrorMessage.js.map +7 -0
  184. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +25 -0
  185. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +7 -0
  186. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +47 -0
  187. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +7 -0
  188. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +23 -0
  189. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +7 -0
  190. package/dist/components/messages/UserToolResultMessage/utils.js +42 -0
  191. package/dist/components/messages/UserToolResultMessage/utils.js.map +7 -0
  192. package/dist/components/permissions/BashPermissionRequest/BashPermissionRequest.js +112 -0
  193. package/dist/components/permissions/BashPermissionRequest/BashPermissionRequest.js.map +7 -0
  194. package/dist/components/permissions/FallbackPermissionRequest.js +131 -0
  195. package/dist/components/permissions/FallbackPermissionRequest.js.map +7 -0
  196. package/dist/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.js +159 -0
  197. package/dist/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.js.map +7 -0
  198. package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js +58 -0
  199. package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js.map +7 -0
  200. package/dist/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.js +153 -0
  201. package/dist/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.js.map +7 -0
  202. package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js +70 -0
  203. package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js.map +7 -0
  204. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +212 -0
  205. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +7 -0
  206. package/dist/components/permissions/PermissionRequest.js +70 -0
  207. package/dist/components/permissions/PermissionRequest.js.map +7 -0
  208. package/dist/components/permissions/PermissionRequestTitle.js +52 -0
  209. package/dist/components/permissions/PermissionRequestTitle.js.map +7 -0
  210. package/dist/components/permissions/hooks.js +28 -0
  211. package/dist/components/permissions/hooks.js.map +7 -0
  212. package/dist/components/permissions/toolUseOptions.js +46 -0
  213. package/dist/components/permissions/toolUseOptions.js.map +7 -0
  214. package/dist/components/permissions/utils.js +21 -0
  215. package/dist/components/permissions/utils.js.map +7 -0
  216. package/dist/constants/betas.js +11 -0
  217. package/dist/constants/betas.js.map +7 -0
  218. package/dist/constants/claude-asterisk-ascii-art.js +242 -0
  219. package/dist/constants/claude-asterisk-ascii-art.js.map +7 -0
  220. package/dist/constants/figures.js +6 -0
  221. package/dist/constants/figures.js.map +7 -0
  222. package/dist/constants/keys.js +7 -0
  223. package/dist/constants/keys.js.map +7 -0
  224. package/dist/constants/macros.js +13 -0
  225. package/dist/constants/macros.js.map +7 -0
  226. package/dist/constants/modelCapabilities.js +154 -0
  227. package/dist/constants/modelCapabilities.js.map +7 -0
  228. package/dist/constants/models.js +1029 -0
  229. package/dist/constants/models.js.map +7 -0
  230. package/dist/constants/oauth.js +18 -0
  231. package/dist/constants/oauth.js.map +7 -0
  232. package/dist/constants/product.js +26 -0
  233. package/dist/constants/product.js.map +7 -0
  234. package/dist/constants/prompts.js +168 -0
  235. package/dist/constants/prompts.js.map +7 -0
  236. package/dist/constants/releaseNotes.js +9 -0
  237. package/dist/constants/releaseNotes.js.map +7 -0
  238. package/dist/context/PermissionContext.js +111 -0
  239. package/dist/context/PermissionContext.js.map +7 -0
  240. package/dist/context.js +259 -0
  241. package/dist/context.js.map +7 -0
  242. package/dist/cost-tracker.js +76 -0
  243. package/dist/cost-tracker.js.map +7 -0
  244. package/dist/entrypoints/cli.js +1101 -0
  245. package/dist/entrypoints/cli.js.map +7 -0
  246. package/dist/entrypoints/mcp.js +150 -0
  247. package/dist/entrypoints/mcp.js.map +7 -0
  248. package/dist/history.js +25 -0
  249. package/dist/history.js.map +7 -0
  250. package/dist/hooks/useApiKeyVerification.js +12 -0
  251. package/dist/hooks/useApiKeyVerification.js.map +7 -0
  252. package/dist/hooks/useArrowKeyHistory.js +50 -0
  253. package/dist/hooks/useArrowKeyHistory.js.map +7 -0
  254. package/dist/hooks/useCanUseTool.js +112 -0
  255. package/dist/hooks/useCanUseTool.js.map +7 -0
  256. package/dist/hooks/useCancelRequest.js +30 -0
  257. package/dist/hooks/useCancelRequest.js.map +7 -0
  258. package/dist/hooks/useDoublePress.js +31 -0
  259. package/dist/hooks/useDoublePress.js.map +7 -0
  260. package/dist/hooks/useExitOnCtrlCD.js +26 -0
  261. package/dist/hooks/useExitOnCtrlCD.js.map +7 -0
  262. package/dist/hooks/useInterval.js +18 -0
  263. package/dist/hooks/useInterval.js.map +7 -0
  264. package/dist/hooks/useLogMessages.js +14 -0
  265. package/dist/hooks/useLogMessages.js.map +7 -0
  266. package/dist/hooks/useLogStartupTime.js +15 -0
  267. package/dist/hooks/useLogStartupTime.js.map +7 -0
  268. package/dist/hooks/useNotifyAfterTimeout.js +42 -0
  269. package/dist/hooks/useNotifyAfterTimeout.js.map +7 -0
  270. package/dist/hooks/usePermissionRequestLogging.js +28 -0
  271. package/dist/hooks/usePermissionRequestLogging.js.map +7 -0
  272. package/dist/hooks/useTerminalSize.js +38 -0
  273. package/dist/hooks/useTerminalSize.js.map +7 -0
  274. package/dist/hooks/useTextInput.js +250 -0
  275. package/dist/hooks/useTextInput.js.map +7 -0
  276. package/dist/hooks/useUnifiedCompletion.js +929 -0
  277. package/dist/hooks/useUnifiedCompletion.js.map +7 -0
  278. package/dist/index.js +26 -0
  279. package/dist/index.js.map +7 -0
  280. package/dist/messages.js +33 -0
  281. package/dist/messages.js.map +7 -0
  282. package/dist/package.json +1 -0
  283. package/dist/permissions.js +194 -0
  284. package/dist/permissions.js.map +7 -0
  285. package/dist/query.js +492 -0
  286. package/dist/query.js.map +7 -0
  287. package/dist/screens/ConfigureNpmPrefix.js +128 -0
  288. package/dist/screens/ConfigureNpmPrefix.js.map +7 -0
  289. package/dist/screens/Doctor.js +143 -0
  290. package/dist/screens/Doctor.js.map +7 -0
  291. package/dist/screens/LogList.js +55 -0
  292. package/dist/screens/LogList.js.map +7 -0
  293. package/dist/screens/REPL.js +596 -0
  294. package/dist/screens/REPL.js.map +7 -0
  295. package/dist/screens/ResumeConversation.js +56 -0
  296. package/dist/screens/ResumeConversation.js.map +7 -0
  297. package/dist/services/adapters/base.js +29 -0
  298. package/dist/services/adapters/base.js.map +7 -0
  299. package/dist/services/adapters/chatCompletions.js +69 -0
  300. package/dist/services/adapters/chatCompletions.js.map +7 -0
  301. package/dist/services/adapters/responsesAPI.js +126 -0
  302. package/dist/services/adapters/responsesAPI.js.map +7 -0
  303. package/dist/services/browserMocks.js +48 -0
  304. package/dist/services/browserMocks.js.map +7 -0
  305. package/dist/services/claude.js +1605 -0
  306. package/dist/services/claude.js.map +7 -0
  307. package/dist/services/customCommands.js +359 -0
  308. package/dist/services/customCommands.js.map +7 -0
  309. package/dist/services/fileFreshness.js +280 -0
  310. package/dist/services/fileFreshness.js.map +7 -0
  311. package/dist/services/gpt5ConnectionTest.js +248 -0
  312. package/dist/services/gpt5ConnectionTest.js.map +7 -0
  313. package/dist/services/mcpClient.js +435 -0
  314. package/dist/services/mcpClient.js.map +7 -0
  315. package/dist/services/mcpServerApproval.js +55 -0
  316. package/dist/services/mcpServerApproval.js.map +7 -0
  317. package/dist/services/mentionProcessor.js +200 -0
  318. package/dist/services/mentionProcessor.js.map +7 -0
  319. package/dist/services/modelAdapterFactory.js +47 -0
  320. package/dist/services/modelAdapterFactory.js.map +7 -0
  321. package/dist/services/notifier.js +35 -0
  322. package/dist/services/notifier.js.map +7 -0
  323. package/dist/services/oauth.js +259 -0
  324. package/dist/services/oauth.js.map +7 -0
  325. package/dist/services/openai.js +998 -0
  326. package/dist/services/openai.js.map +7 -0
  327. package/dist/services/responseStateManager.js +68 -0
  328. package/dist/services/responseStateManager.js.map +7 -0
  329. package/dist/services/sentry.js +9 -0
  330. package/dist/services/sentry.js.map +7 -0
  331. package/dist/services/statsig.js +112 -0
  332. package/dist/services/statsig.js.map +7 -0
  333. package/dist/services/statsigStorage.js +75 -0
  334. package/dist/services/statsigStorage.js.map +7 -0
  335. package/dist/services/systemReminder.js +353 -0
  336. package/dist/services/systemReminder.js.map +7 -0
  337. package/dist/services/vcr.js +133 -0
  338. package/dist/services/vcr.js.map +7 -0
  339. package/dist/test/testAdapters.js +88 -0
  340. package/dist/test/testAdapters.js.map +1 -0
  341. package/dist/tools/ArchitectTool/ArchitectTool.js +119 -0
  342. package/dist/tools/ArchitectTool/ArchitectTool.js.map +7 -0
  343. package/dist/tools/ArchitectTool/prompt.js +18 -0
  344. package/dist/tools/ArchitectTool/prompt.js.map +7 -0
  345. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +423 -0
  346. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +7 -0
  347. package/dist/tools/BashTool/BashTool.js +188 -0
  348. package/dist/tools/BashTool/BashTool.js.map +7 -0
  349. package/dist/tools/BashTool/BashToolResultMessage.js +21 -0
  350. package/dist/tools/BashTool/BashToolResultMessage.js.map +7 -0
  351. package/dist/tools/BashTool/OutputLine.js +30 -0
  352. package/dist/tools/BashTool/OutputLine.js.map +7 -0
  353. package/dist/tools/BashTool/prompt.js +179 -0
  354. package/dist/tools/BashTool/prompt.js.map +7 -0
  355. package/dist/tools/BashTool/utils.js +51 -0
  356. package/dist/tools/BashTool/utils.js.map +7 -0
  357. package/dist/tools/FileEditTool/FileEditTool.js +228 -0
  358. package/dist/tools/FileEditTool/FileEditTool.js.map +7 -0
  359. package/dist/tools/FileEditTool/prompt.js +54 -0
  360. package/dist/tools/FileEditTool/prompt.js.map +7 -0
  361. package/dist/tools/FileEditTool/utils.js +42 -0
  362. package/dist/tools/FileEditTool/utils.js.map +7 -0
  363. package/dist/tools/FileReadTool/FileReadTool.js +272 -0
  364. package/dist/tools/FileReadTool/FileReadTool.js.map +7 -0
  365. package/dist/tools/FileReadTool/prompt.js +10 -0
  366. package/dist/tools/FileReadTool/prompt.js.map +7 -0
  367. package/dist/tools/FileWriteTool/FileWriteTool.js +204 -0
  368. package/dist/tools/FileWriteTool/FileWriteTool.js.map +7 -0
  369. package/dist/tools/FileWriteTool/prompt.js +14 -0
  370. package/dist/tools/FileWriteTool/prompt.js.map +7 -0
  371. package/dist/tools/GlobTool/GlobTool.js +88 -0
  372. package/dist/tools/GlobTool/GlobTool.js.map +7 -0
  373. package/dist/tools/GlobTool/prompt.js +12 -0
  374. package/dist/tools/GlobTool/prompt.js.map +7 -0
  375. package/dist/tools/GrepTool/GrepTool.js +107 -0
  376. package/dist/tools/GrepTool/GrepTool.js.map +7 -0
  377. package/dist/tools/GrepTool/prompt.js +15 -0
  378. package/dist/tools/GrepTool/prompt.js.map +7 -0
  379. package/dist/tools/MCPTool/MCPTool.js +90 -0
  380. package/dist/tools/MCPTool/MCPTool.js.map +7 -0
  381. package/dist/tools/MCPTool/prompt.js +7 -0
  382. package/dist/tools/MCPTool/prompt.js.map +7 -0
  383. package/dist/tools/MemoryReadTool/MemoryReadTool.js +103 -0
  384. package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +7 -0
  385. package/dist/tools/MemoryReadTool/prompt.js +7 -0
  386. package/dist/tools/MemoryReadTool/prompt.js.map +7 -0
  387. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +77 -0
  388. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +7 -0
  389. package/dist/tools/MemoryWriteTool/prompt.js +7 -0
  390. package/dist/tools/MemoryWriteTool/prompt.js.map +7 -0
  391. package/dist/tools/MultiEditTool/MultiEditTool.js +293 -0
  392. package/dist/tools/MultiEditTool/MultiEditTool.js.map +7 -0
  393. package/dist/tools/MultiEditTool/prompt.js +48 -0
  394. package/dist/tools/MultiEditTool/prompt.js.map +7 -0
  395. package/dist/tools/NotebookEditTool/NotebookEditTool.js +238 -0
  396. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +7 -0
  397. package/dist/tools/NotebookEditTool/prompt.js +7 -0
  398. package/dist/tools/NotebookEditTool/prompt.js.map +7 -0
  399. package/dist/tools/NotebookReadTool/NotebookReadTool.js +212 -0
  400. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +7 -0
  401. package/dist/tools/NotebookReadTool/prompt.js +7 -0
  402. package/dist/tools/NotebookReadTool/prompt.js.map +7 -0
  403. package/dist/tools/StickerRequestTool/StickerRequestTool.js +86 -0
  404. package/dist/tools/StickerRequestTool/StickerRequestTool.js.map +7 -0
  405. package/dist/tools/StickerRequestTool/prompt.js +23 -0
  406. package/dist/tools/StickerRequestTool/prompt.js.map +7 -0
  407. package/dist/tools/TaskTool/TaskTool.js +308 -0
  408. package/dist/tools/TaskTool/TaskTool.js.map +7 -0
  409. package/dist/tools/TaskTool/constants.js +5 -0
  410. package/dist/tools/TaskTool/constants.js.map +7 -0
  411. package/dist/tools/TaskTool/prompt.js +82 -0
  412. package/dist/tools/TaskTool/prompt.js.map +7 -0
  413. package/dist/tools/ThinkTool/ThinkTool.js +48 -0
  414. package/dist/tools/ThinkTool/ThinkTool.js.map +7 -0
  415. package/dist/tools/ThinkTool/prompt.js +16 -0
  416. package/dist/tools/ThinkTool/prompt.js.map +7 -0
  417. package/dist/tools/TodoWriteTool/TodoWriteTool.js +216 -0
  418. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +7 -0
  419. package/dist/tools/TodoWriteTool/prompt.js +66 -0
  420. package/dist/tools/TodoWriteTool/prompt.js.map +7 -0
  421. package/dist/tools/URLFetcherTool/URLFetcherTool.js +137 -0
  422. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +7 -0
  423. package/dist/tools/URLFetcherTool/cache.js +45 -0
  424. package/dist/tools/URLFetcherTool/cache.js.map +7 -0
  425. package/dist/tools/URLFetcherTool/htmlToMarkdown.js +42 -0
  426. package/dist/tools/URLFetcherTool/htmlToMarkdown.js.map +7 -0
  427. package/dist/tools/URLFetcherTool/prompt.js +22 -0
  428. package/dist/tools/URLFetcherTool/prompt.js.map +7 -0
  429. package/dist/tools/WebSearchTool/WebSearchTool.js +86 -0
  430. package/dist/tools/WebSearchTool/WebSearchTool.js.map +7 -0
  431. package/dist/tools/WebSearchTool/prompt.js +17 -0
  432. package/dist/tools/WebSearchTool/prompt.js.map +7 -0
  433. package/dist/tools/WebSearchTool/searchProviders.js +48 -0
  434. package/dist/tools/WebSearchTool/searchProviders.js.map +7 -0
  435. package/dist/tools/lsTool/lsTool.js +201 -0
  436. package/dist/tools/lsTool/lsTool.js.map +7 -0
  437. package/dist/tools/lsTool/prompt.js +5 -0
  438. package/dist/tools/lsTool/prompt.js.map +7 -0
  439. package/dist/tools.js +64 -0
  440. package/dist/tools.js.map +7 -0
  441. package/dist/types/PermissionMode.js +82 -0
  442. package/dist/types/PermissionMode.js.map +7 -0
  443. package/dist/types/RequestContext.js +47 -0
  444. package/dist/types/RequestContext.js.map +7 -0
  445. package/dist/types/common.d.js +1 -0
  446. package/dist/types/common.d.js.map +7 -0
  447. package/dist/types/conversation.js +1 -0
  448. package/dist/types/conversation.js.map +7 -0
  449. package/dist/types/logs.js +1 -0
  450. package/dist/types/logs.js.map +7 -0
  451. package/dist/types/modelCapabilities.js +1 -0
  452. package/dist/types/modelCapabilities.js.map +7 -0
  453. package/dist/types/notebook.js +1 -0
  454. package/dist/types/notebook.js.map +7 -0
  455. package/dist/utils/Cursor.js +313 -0
  456. package/dist/utils/Cursor.js.map +7 -0
  457. package/dist/utils/PersistentShell.js +382 -0
  458. package/dist/utils/PersistentShell.js.map +7 -0
  459. package/dist/utils/advancedFuzzyMatcher.js +206 -0
  460. package/dist/utils/advancedFuzzyMatcher.js.map +7 -0
  461. package/dist/utils/agentLoader.js +199 -0
  462. package/dist/utils/agentLoader.js.map +7 -0
  463. package/dist/utils/agentStorage.js +59 -0
  464. package/dist/utils/agentStorage.js.map +7 -0
  465. package/dist/utils/array.js +7 -0
  466. package/dist/utils/array.js.map +7 -0
  467. package/dist/utils/ask.js +77 -0
  468. package/dist/utils/ask.js.map +7 -0
  469. package/dist/utils/auth.js +11 -0
  470. package/dist/utils/auth.js.map +7 -0
  471. package/dist/utils/autoCompactCore.js +149 -0
  472. package/dist/utils/autoCompactCore.js.map +7 -0
  473. package/dist/utils/autoUpdater.js +362 -0
  474. package/dist/utils/autoUpdater.js.map +7 -0
  475. package/dist/utils/betas.js +21 -0
  476. package/dist/utils/betas.js.map +7 -0
  477. package/dist/utils/browser.js +15 -0
  478. package/dist/utils/browser.js.map +7 -0
  479. package/dist/utils/cleanup.js +54 -0
  480. package/dist/utils/cleanup.js.map +7 -0
  481. package/dist/utils/commands.js +207 -0
  482. package/dist/utils/commands.js.map +7 -0
  483. package/dist/utils/commonUnixCommands.js +687 -0
  484. package/dist/utils/commonUnixCommands.js.map +7 -0
  485. package/dist/utils/config.js +655 -0
  486. package/dist/utils/config.js.map +7 -0
  487. package/dist/utils/conversationRecovery.js +35 -0
  488. package/dist/utils/conversationRecovery.js.map +7 -0
  489. package/dist/utils/debugLogger.js +891 -0
  490. package/dist/utils/debugLogger.js.map +7 -0
  491. package/dist/utils/diff.js +32 -0
  492. package/dist/utils/diff.js.map +7 -0
  493. package/dist/utils/env.js +44 -0
  494. package/dist/utils/env.js.map +7 -0
  495. package/dist/utils/errors.js +23 -0
  496. package/dist/utils/errors.js.map +7 -0
  497. package/dist/utils/exampleCommands.js +80 -0
  498. package/dist/utils/exampleCommands.js.map +7 -0
  499. package/dist/utils/execFileNoThrow.js +44 -0
  500. package/dist/utils/execFileNoThrow.js.map +7 -0
  501. package/dist/utils/expertChatStorage.js +78 -0
  502. package/dist/utils/expertChatStorage.js.map +7 -0
  503. package/dist/utils/file.js +282 -0
  504. package/dist/utils/file.js.map +7 -0
  505. package/dist/utils/fileRecoveryCore.js +41 -0
  506. package/dist/utils/fileRecoveryCore.js.map +7 -0
  507. package/dist/utils/format.js +41 -0
  508. package/dist/utils/format.js.map +7 -0
  509. package/dist/utils/fuzzyMatcher.js +252 -0
  510. package/dist/utils/fuzzyMatcher.js.map +7 -0
  511. package/dist/utils/generators.js +46 -0
  512. package/dist/utils/generators.js.map +7 -0
  513. package/dist/utils/git.js +83 -0
  514. package/dist/utils/git.js.map +7 -0
  515. package/dist/utils/globalLogger.js +54 -0
  516. package/dist/utils/globalLogger.js.map +7 -0
  517. package/dist/utils/http.js +7 -0
  518. package/dist/utils/http.js.map +7 -0
  519. package/dist/utils/imagePaste.js +29 -0
  520. package/dist/utils/imagePaste.js.map +7 -0
  521. package/dist/utils/json.js +16 -0
  522. package/dist/utils/json.js.map +7 -0
  523. package/dist/utils/log.js +298 -0
  524. package/dist/utils/log.js.map +7 -0
  525. package/dist/utils/markdown.js +187 -0
  526. package/dist/utils/markdown.js.map +7 -0
  527. package/dist/utils/messageContextManager.js +195 -0
  528. package/dist/utils/messageContextManager.js.map +7 -0
  529. package/dist/utils/messages.js +633 -0
  530. package/dist/utils/messages.js.map +7 -0
  531. package/dist/utils/model.js +687 -0
  532. package/dist/utils/model.js.map +7 -0
  533. package/dist/utils/permissions/filesystem.js +80 -0
  534. package/dist/utils/permissions/filesystem.js.map +7 -0
  535. package/dist/utils/responseState.js +20 -0
  536. package/dist/utils/responseState.js.map +7 -0
  537. package/dist/utils/ripgrep.js +131 -0
  538. package/dist/utils/ripgrep.js.map +7 -0
  539. package/dist/utils/secureFile.js +483 -0
  540. package/dist/utils/secureFile.js.map +7 -0
  541. package/dist/utils/sessionState.js +31 -0
  542. package/dist/utils/sessionState.js.map +7 -0
  543. package/dist/utils/state.js +24 -0
  544. package/dist/utils/state.js.map +7 -0
  545. package/dist/utils/style.js +31 -0
  546. package/dist/utils/style.js.map +7 -0
  547. package/dist/utils/terminal.js +43 -0
  548. package/dist/utils/terminal.js.map +7 -0
  549. package/dist/utils/theme.js +102 -0
  550. package/dist/utils/theme.js.map +7 -0
  551. package/dist/utils/thinking.js +103 -0
  552. package/dist/utils/thinking.js.map +7 -0
  553. package/dist/utils/todoStorage.js +291 -0
  554. package/dist/utils/todoStorage.js.map +7 -0
  555. package/dist/utils/tokens.js +30 -0
  556. package/dist/utils/tokens.js.map +7 -0
  557. package/dist/utils/toolExecutionController.js +109 -0
  558. package/dist/utils/toolExecutionController.js.map +7 -0
  559. package/dist/utils/unaryLogging.js +14 -0
  560. package/dist/utils/unaryLogging.js.map +7 -0
  561. package/dist/utils/user.js +40 -0
  562. package/dist/utils/user.js.map +7 -0
  563. package/dist/utils/validate.js +132 -0
  564. package/dist/utils/validate.js.map +7 -0
  565. package/dist/yoga.wasm +0 -0
  566. package/package.json +28 -7
  567. package/src/Tool.ts +4 -3
  568. package/src/commands/agents.tsx +10 -4
  569. package/src/components/messages/AssistantToolUseMessage.tsx +5 -6
  570. package/src/constants/macros.ts +5 -2
  571. package/src/entrypoints/cli.tsx +38 -19
  572. package/src/entrypoints/mcp.ts +1 -2
  573. package/src/hooks/useDoublePress.ts +0 -1
  574. package/src/hooks/useTextInput.ts +4 -5
  575. package/src/hooks/useUnifiedCompletion.ts +2 -2
  576. package/src/index.ts +34 -0
  577. package/src/query.ts +13 -8
  578. package/src/screens/Doctor.tsx +1 -1
  579. package/src/screens/REPL.tsx +13 -9
  580. package/src/services/openai.ts +25 -4
  581. package/src/tools/ArchitectTool/ArchitectTool.tsx +18 -5
  582. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +21 -14
  583. package/src/tools/FileEditTool/FileEditTool.tsx +6 -2
  584. package/src/tools/FileWriteTool/FileWriteTool.tsx +7 -3
  585. package/src/tools/MultiEditTool/MultiEditTool.tsx +26 -4
  586. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +1 -1
  587. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +28 -14
  588. package/src/tools/TaskTool/TaskTool.tsx +8 -36
  589. package/src/types/common.d.ts +2 -0
  590. package/src/utils/generators.ts +1 -1
  591. package/src/utils/messageContextManager.ts +5 -0
  592. package/src/utils/messages.tsx +8 -2
  593. 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