@within-7/minto 0.1.5 → 0.1.7

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 (273) hide show
  1. package/dist/commands/agents/AgentsCommand.js +2342 -0
  2. package/dist/commands/agents/AgentsCommand.js.map +7 -0
  3. package/dist/commands/agents/constants.js +58 -0
  4. package/dist/commands/agents/constants.js.map +7 -0
  5. package/dist/commands/agents/index.js +37 -0
  6. package/dist/commands/agents/index.js.map +7 -0
  7. package/dist/commands/agents/types.js +10 -0
  8. package/dist/commands/agents/types.js.map +7 -0
  9. package/dist/commands/agents/utils/fileOperations.js +185 -0
  10. package/dist/commands/agents/utils/fileOperations.js.map +7 -0
  11. package/dist/commands/agents/utils/index.js +21 -0
  12. package/dist/commands/agents/utils/index.js.map +7 -0
  13. package/dist/commands/bug.js +2 -2
  14. package/dist/commands/bug.js.map +2 -2
  15. package/dist/commands/compact.js +5 -5
  16. package/dist/commands/compact.js.map +2 -2
  17. package/dist/commands/ctx_viz.js +55 -22
  18. package/dist/commands/ctx_viz.js.map +2 -2
  19. package/dist/commands/mcp-interactive.js +11 -11
  20. package/dist/commands/mcp-interactive.js.map +2 -2
  21. package/dist/commands/model.js +94 -32
  22. package/dist/commands/model.js.map +3 -3
  23. package/dist/commands/plugin/AddMarketplaceForm.js +49 -21
  24. package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
  25. package/dist/commands/plugin/ConfirmDialog.js +38 -26
  26. package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
  27. package/dist/commands/plugin/InstalledPluginsByMarketplace.js +24 -8
  28. package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
  29. package/dist/commands/plugin/InstalledPluginsManager.js +3 -1
  30. package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
  31. package/dist/commands/plugin/MainMenu.js +16 -7
  32. package/dist/commands/plugin/MainMenu.js.map +2 -2
  33. package/dist/commands/plugin/MarketplaceManager.js +84 -39
  34. package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
  35. package/dist/commands/plugin/MarketplaceSelector.js +7 -3
  36. package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
  37. package/dist/commands/plugin/PlaceholderScreen.js +16 -2
  38. package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
  39. package/dist/commands/plugin/PluginBrowser.js +4 -2
  40. package/dist/commands/plugin/PluginBrowser.js.map +2 -2
  41. package/dist/commands/plugin/PluginDetailsInstall.js +12 -6
  42. package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
  43. package/dist/commands/plugin/PluginDetailsManage.js +14 -5
  44. package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
  45. package/dist/commands/plugin/example-usage.js.map +2 -2
  46. package/dist/commands/plugin/utils.js.map +2 -2
  47. package/dist/commands/plugin.js +226 -46
  48. package/dist/commands/plugin.js.map +2 -2
  49. package/dist/commands/refreshCommands.js +6 -3
  50. package/dist/commands/refreshCommands.js.map +2 -2
  51. package/dist/commands/resume.js +2 -1
  52. package/dist/commands/resume.js.map +2 -2
  53. package/dist/commands/setup.js +19 -5
  54. package/dist/commands/setup.js.map +2 -2
  55. package/dist/commands/terminalSetup.js +2 -2
  56. package/dist/commands/terminalSetup.js.map +1 -1
  57. package/dist/commands.js +14 -30
  58. package/dist/commands.js.map +2 -2
  59. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  60. package/dist/components/AskUserQuestionDialog/QuestionView.js +10 -1
  61. package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
  62. package/dist/components/BackgroundTasksPanel.js +5 -1
  63. package/dist/components/BackgroundTasksPanel.js.map +2 -2
  64. package/dist/components/Config.js +17 -4
  65. package/dist/components/Config.js.map +2 -2
  66. package/dist/components/ConsoleOAuthFlow.js.map +2 -2
  67. package/dist/components/CustomSelect/select-option.js +4 -1
  68. package/dist/components/CustomSelect/select-option.js.map +2 -2
  69. package/dist/components/Help.js +6 -8
  70. package/dist/components/Help.js.map +2 -2
  71. package/dist/components/Logo.js +1 -1
  72. package/dist/components/Logo.js.map +2 -2
  73. package/dist/components/ModelListManager.js.map +2 -2
  74. package/dist/components/ModelSelector/ModelSelector.js +2030 -0
  75. package/dist/components/ModelSelector/ModelSelector.js.map +7 -0
  76. package/dist/components/ModelSelector/ScreenContainer.js +27 -0
  77. package/dist/components/ModelSelector/ScreenContainer.js.map +7 -0
  78. package/dist/components/ModelSelector/constants.js +37 -0
  79. package/dist/components/ModelSelector/constants.js.map +7 -0
  80. package/dist/components/ModelSelector/hooks/index.js +5 -0
  81. package/dist/components/ModelSelector/hooks/index.js.map +7 -0
  82. package/dist/components/ModelSelector/hooks/useEscapeNavigation.js +21 -0
  83. package/dist/components/ModelSelector/hooks/useEscapeNavigation.js.map +7 -0
  84. package/dist/components/ModelSelector/index.js +17 -0
  85. package/dist/components/ModelSelector/index.js.map +7 -0
  86. package/dist/components/ModelSelector/types.js +1 -0
  87. package/dist/components/ModelSelector/types.js.map +7 -0
  88. package/dist/components/PressEnterToContinue.js +1 -1
  89. package/dist/components/PressEnterToContinue.js.map +2 -2
  90. package/dist/components/ProjectOnboarding.js +1 -1
  91. package/dist/components/ProjectOnboarding.js.map +2 -2
  92. package/dist/components/PromptInput.js +88 -37
  93. package/dist/components/PromptInput.js.map +2 -2
  94. package/dist/components/QuitSummary.js +17 -10
  95. package/dist/components/QuitSummary.js.map +2 -2
  96. package/dist/components/SentryErrorBoundary.js.map +2 -2
  97. package/dist/components/StreamingBashOutput.js.map +2 -2
  98. package/dist/components/StructuredDiff.js.map +2 -2
  99. package/dist/components/SubagentProgress.js.map +2 -2
  100. package/dist/components/TaskCard.js.map +2 -2
  101. package/dist/components/TextInput.js.map +1 -1
  102. package/dist/components/TodoItem.js.map +1 -1
  103. package/dist/components/binary-feedback/BinaryFeedbackOption.js +1 -3
  104. package/dist/components/binary-feedback/BinaryFeedbackOption.js.map +2 -2
  105. package/dist/components/messages/AssistantLocalCommandOutputMessage.js.map +1 -1
  106. package/dist/components/messages/AssistantToolUseMessage.js +3 -1
  107. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  108. package/dist/components/messages/TaskProgressMessage.js.map +2 -2
  109. package/dist/components/messages/TaskToolMessage.js.map +2 -2
  110. package/dist/components/messages/UserToolResultMessage/utils.js.map +2 -2
  111. package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js.map +2 -2
  112. package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js.map +2 -2
  113. package/dist/components/permissions/hooks.js.map +2 -2
  114. package/dist/constants/modelCapabilities.js +1 -1
  115. package/dist/constants/modelCapabilities.js.map +2 -2
  116. package/dist/constants/prompts.js.map +1 -1
  117. package/dist/constants/timing.js +34 -0
  118. package/dist/constants/timing.js.map +7 -0
  119. package/dist/entrypoints/cli.js +128 -33
  120. package/dist/entrypoints/cli.js.map +3 -3
  121. package/dist/entrypoints/mcp.js +13 -18
  122. package/dist/entrypoints/mcp.js.map +2 -2
  123. package/dist/hooks/useCanUseTool.js.map +2 -2
  124. package/dist/hooks/useCancelRequest.js.map +1 -1
  125. package/dist/hooks/useHistorySearch.js.map +2 -2
  126. package/dist/hooks/useLogStartupTime.js.map +2 -2
  127. package/dist/hooks/usePermissionRequestLogging.js.map +2 -2
  128. package/dist/hooks/useTextInput.js.map +1 -1
  129. package/dist/hooks/useUnifiedCompletion.js +493 -394
  130. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  131. package/dist/index.js.map +2 -2
  132. package/dist/permissions.js +4 -7
  133. package/dist/permissions.js.map +2 -2
  134. package/dist/query.js +6 -1
  135. package/dist/query.js.map +2 -2
  136. package/dist/screens/REPL.js +72 -36
  137. package/dist/screens/REPL.js.map +2 -2
  138. package/dist/screens/ResumeConversation.js +2 -1
  139. package/dist/screens/ResumeConversation.js.map +2 -2
  140. package/dist/services/adapters/base.js.map +2 -2
  141. package/dist/services/adapters/chatCompletions.js.map +2 -2
  142. package/dist/services/adapters/responsesAPI.js +3 -1
  143. package/dist/services/adapters/responsesAPI.js.map +2 -2
  144. package/dist/services/claude.js +327 -328
  145. package/dist/services/claude.js.map +2 -2
  146. package/dist/services/customCommands.js +6 -1
  147. package/dist/services/customCommands.js.map +2 -2
  148. package/dist/services/fileFreshness.js.map +2 -2
  149. package/dist/services/gpt5ConnectionTest.js +20 -7
  150. package/dist/services/gpt5ConnectionTest.js.map +2 -2
  151. package/dist/services/hookExecutor.js +6 -12
  152. package/dist/services/hookExecutor.js.map +2 -2
  153. package/dist/services/mcpClient.js +29 -2
  154. package/dist/services/mcpClient.js.map +2 -2
  155. package/dist/services/mentionProcessor.js +23 -10
  156. package/dist/services/mentionProcessor.js.map +2 -2
  157. package/dist/services/modelAdapterFactory.js.map +2 -2
  158. package/dist/services/oauth.js.map +2 -2
  159. package/dist/services/openai.js +109 -72
  160. package/dist/services/openai.js.map +3 -3
  161. package/dist/services/responseStateManager.js.map +2 -2
  162. package/dist/services/systemReminder.js.map +2 -2
  163. package/dist/tools/ArchitectTool/ArchitectTool.js +10 -9
  164. package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
  165. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +14 -8
  166. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  167. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +8 -1
  168. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  169. package/dist/tools/BashOutputTool/BashOutputTool.js.map +2 -2
  170. package/dist/tools/BashTool/BashTool.js.map +2 -2
  171. package/dist/tools/FileReadTool/FileReadTool.js +23 -4
  172. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  173. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  174. package/dist/tools/GlobTool/GlobTool.js +11 -2
  175. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  176. package/dist/tools/GrepTool/GrepTool.js +7 -5
  177. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  178. package/dist/tools/MCPTool/MCPTool.js +11 -12
  179. package/dist/tools/MCPTool/MCPTool.js.map +2 -2
  180. package/dist/tools/MultiEditTool/MultiEditTool.js +4 -1
  181. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  182. package/dist/tools/NotebookReadTool/NotebookReadTool.js +11 -5
  183. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
  184. package/dist/tools/SkillTool/SkillTool.js +18 -6
  185. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  186. package/dist/tools/TaskTool/TaskTool.js +37 -51
  187. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  188. package/dist/tools/TaskTool/prompt.js.map +2 -2
  189. package/dist/tools/ThinkTool/ThinkTool.js +6 -1
  190. package/dist/tools/ThinkTool/ThinkTool.js.map +2 -2
  191. package/dist/tools/TodoWriteTool/TodoWriteTool.js +29 -5
  192. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
  193. package/dist/tools/URLFetcherTool/URLFetcherTool.js +5 -2
  194. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  195. package/dist/tools/URLFetcherTool/cache.js +6 -3
  196. package/dist/tools/URLFetcherTool/cache.js.map +2 -2
  197. package/dist/tools/URLFetcherTool/htmlToMarkdown.js +3 -1
  198. package/dist/tools/URLFetcherTool/htmlToMarkdown.js.map +2 -2
  199. package/dist/tools/WebSearchTool/WebSearchTool.js +6 -1
  200. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  201. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  202. package/dist/tools/WebSearchTool/searchProviders.js +15 -6
  203. package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
  204. package/dist/tools.js +4 -1
  205. package/dist/tools.js.map +2 -2
  206. package/dist/types/core.js +1 -0
  207. package/dist/types/core.js.map +7 -0
  208. package/dist/types/hooks.js +1 -4
  209. package/dist/types/hooks.js.map +2 -2
  210. package/dist/types/marketplace.js +8 -2
  211. package/dist/types/marketplace.js.map +2 -2
  212. package/dist/types/plugin.js +9 -6
  213. package/dist/types/plugin.js.map +2 -2
  214. package/dist/utils/BackgroundShellManager.js +76 -10
  215. package/dist/utils/BackgroundShellManager.js.map +2 -2
  216. package/dist/utils/PersistentShell.js +7 -2
  217. package/dist/utils/PersistentShell.js.map +2 -2
  218. package/dist/utils/advancedFuzzyMatcher.js +4 -1
  219. package/dist/utils/advancedFuzzyMatcher.js.map +2 -2
  220. package/dist/utils/agentLoader.js +69 -35
  221. package/dist/utils/agentLoader.js.map +2 -2
  222. package/dist/utils/agentStorage.js.map +2 -2
  223. package/dist/utils/async.js +163 -0
  224. package/dist/utils/async.js.map +7 -0
  225. package/dist/utils/autoUpdater.js +8 -2
  226. package/dist/utils/autoUpdater.js.map +2 -2
  227. package/dist/utils/commands.js +23 -11
  228. package/dist/utils/commands.js.map +2 -2
  229. package/dist/utils/commonUnixCommands.js +3 -1
  230. package/dist/utils/commonUnixCommands.js.map +2 -2
  231. package/dist/utils/compressionMode.js.map +2 -2
  232. package/dist/utils/config.js +30 -14
  233. package/dist/utils/config.js.map +2 -2
  234. package/dist/utils/debugLogger.js.map +2 -2
  235. package/dist/utils/env.js.map +2 -2
  236. package/dist/utils/envConfig.js +82 -0
  237. package/dist/utils/envConfig.js.map +7 -0
  238. package/dist/utils/errorHandling.js +89 -0
  239. package/dist/utils/errorHandling.js.map +7 -0
  240. package/dist/utils/expertChatStorage.js.map +2 -2
  241. package/dist/utils/fuzzyMatcher.js +13 -7
  242. package/dist/utils/fuzzyMatcher.js.map +2 -2
  243. package/dist/utils/hookManager.js +14 -4
  244. package/dist/utils/hookManager.js.map +2 -2
  245. package/dist/utils/log.js.map +2 -2
  246. package/dist/utils/marketplaceManager.js +44 -9
  247. package/dist/utils/marketplaceManager.js.map +2 -2
  248. package/dist/utils/messageContextManager.js.map +1 -1
  249. package/dist/utils/messages.js +6 -3
  250. package/dist/utils/messages.js.map +2 -2
  251. package/dist/utils/model.js +3 -1
  252. package/dist/utils/model.js.map +2 -2
  253. package/dist/utils/pluginInstaller.js +3 -15
  254. package/dist/utils/pluginInstaller.js.map +2 -2
  255. package/dist/utils/pluginLoader.js +41 -13
  256. package/dist/utils/pluginLoader.js.map +2 -2
  257. package/dist/utils/pluginRegistry.js.map +2 -2
  258. package/dist/utils/pluginValidator.js +71 -49
  259. package/dist/utils/pluginValidator.js.map +2 -2
  260. package/dist/utils/ptyCompat.js.map +2 -2
  261. package/dist/utils/roundConverter.js.map +2 -2
  262. package/dist/utils/secureFile.js +43 -14
  263. package/dist/utils/secureFile.js.map +2 -2
  264. package/dist/utils/sessionState.js.map +2 -2
  265. package/dist/utils/skillLoader.js.map +2 -2
  266. package/dist/utils/teamConfig.js +7 -4
  267. package/dist/utils/teamConfig.js.map +2 -2
  268. package/dist/utils/theme.js.map +2 -2
  269. package/dist/utils/thinking.js.map +2 -2
  270. package/dist/utils/unaryLogging.js.map +2 -2
  271. package/dist/version.js +2 -2
  272. package/dist/version.js.map +1 -1
  273. package/package.json +5 -5
@@ -3,7 +3,7 @@ const DEFAULT_CONFIG = {
3
3
  prefix: 0.35,
4
4
  // Strong weight for prefix matching
5
5
  substring: 0.2,
6
- // Good for partial matches
6
+ // Good for partial matches
7
7
  abbreviation: 0.3,
8
8
  // Key for "nde"→"node" cases
9
9
  editDistance: 0.1,
@@ -38,7 +38,10 @@ class FuzzyMatcher {
38
38
  config;
39
39
  constructor(config = {}) {
40
40
  this.config = { ...DEFAULT_CONFIG, ...config };
41
- const weightSum = Object.values(this.config.weights).reduce((a, b) => a + b, 0);
41
+ const weightSum = Object.values(this.config.weights).reduce(
42
+ (a, b) => a + b,
43
+ 0
44
+ );
42
45
  if (Math.abs(weightSum - 1) > 0.01) {
43
46
  Object.keys(this.config.weights).forEach((key) => {
44
47
  this.config.weights[key] /= weightSum;
@@ -68,10 +71,13 @@ class FuzzyMatcher {
68
71
  editDistance: this.editDistanceScore(text, pattern),
69
72
  popularity: this.popularityScore(text)
70
73
  };
71
- const rawScore = Object.entries(scores).reduce((total, [algorithm, score]) => {
72
- const weight = this.config.weights[algorithm];
73
- return total + score * weight;
74
- }, 0);
74
+ const rawScore = Object.entries(scores).reduce(
75
+ (total, [algorithm, score]) => {
76
+ const weight = this.config.weights[algorithm];
77
+ return total + score * weight;
78
+ },
79
+ 0
80
+ );
75
81
  const lengthPenalty = Math.max(0, text.length - 6) * 1.5;
76
82
  const finalScore = Math.max(0, rawScore - lengthPenalty);
77
83
  const maxAlgorithm = Object.entries(scores).reduce(
@@ -95,7 +101,7 @@ class FuzzyMatcher {
95
101
  return 100 * coverage;
96
102
  }
97
103
  /**
98
- * Algorithm 2: Substring Matching (like pinyin contains)
104
+ * Algorithm 2: Substring Matching (like pinyin contains)
99
105
  * Handles cases like "ode" → "node", "py3" → "python3"
100
106
  */
101
107
  substringScore(text, pattern) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/fuzzyMatcher.ts"],
4
- "sourcesContent": ["/**\n * Input Method Inspired Fuzzy Matching Algorithm\n * \n * Multi-algorithm weighted scoring system inspired by:\n * - Sogou/Baidu Pinyin input method algorithms\n * - Double-pinyin abbreviation matching\n * - Terminal completion best practices (fzf, zsh, fish)\n * \n * Designed specifically for command/terminal completion scenarios\n * where users type abbreviations like \"nde\" expecting \"node\"\n */\n\nexport interface MatchResult {\n score: number\n algorithm: string // Which algorithm contributed most to the score\n confidence: number // 0-1 confidence level\n}\n\nexport interface FuzzyMatcherConfig {\n // Algorithm weights (must sum to 1.0)\n weights: {\n prefix: number // Direct prefix matching (\"nod\" \u2192 \"node\")\n substring: number // Substring matching (\"ode\" \u2192 \"node\") \n abbreviation: number // Key chars matching (\"nde\" \u2192 \"node\")\n editDistance: number // Typo tolerance (\"noda\" \u2192 \"node\")\n popularity: number // Common command boost\n }\n \n // Scoring parameters\n minScore: number // Minimum score threshold\n maxEditDistance: number // Maximum edits allowed\n popularCommands: string[] // Commands to boost\n}\n\nconst DEFAULT_CONFIG: FuzzyMatcherConfig = {\n weights: {\n prefix: 0.35, // Strong weight for prefix matching\n substring: 0.20, // Good for partial matches \n abbreviation: 0.30, // Key for \"nde\"\u2192\"node\" cases\n editDistance: 0.10, // Typo tolerance\n popularity: 0.05 // Slight bias for common commands\n },\n minScore: 10, // Lower threshold for better matching\n maxEditDistance: 2,\n popularCommands: [\n 'node', 'npm', 'git', 'ls', 'cd', 'cat', 'grep', 'find', 'cp', 'mv',\n 'python', 'java', 'docker', 'curl', 'wget', 'vim', 'nano'\n ]\n}\n\nexport class FuzzyMatcher {\n private config: FuzzyMatcherConfig\n\n constructor(config: Partial<FuzzyMatcherConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n \n // Normalize weights to sum to 1.0\n const weightSum = Object.values(this.config.weights).reduce((a, b) => a + b, 0)\n if (Math.abs(weightSum - 1.0) > 0.01) {\n Object.keys(this.config.weights).forEach(key => {\n this.config.weights[key as keyof typeof this.config.weights] /= weightSum\n })\n }\n }\n\n /**\n * Calculate fuzzy match score for a candidate against a query\n */\n match(candidate: string, query: string): MatchResult {\n const text = candidate.toLowerCase()\n const pattern = query.toLowerCase()\n\n // Quick perfect match exits\n if (text === pattern) {\n return { score: 1000, algorithm: 'exact', confidence: 1.0 }\n }\n if (text.startsWith(pattern)) {\n return { \n score: 900 + (10 - pattern.length), \n algorithm: 'prefix-exact', \n confidence: 0.95 \n }\n }\n\n // Run all algorithms\n const scores = {\n prefix: this.prefixScore(text, pattern),\n substring: this.substringScore(text, pattern), \n abbreviation: this.abbreviationScore(text, pattern),\n editDistance: this.editDistanceScore(text, pattern),\n popularity: this.popularityScore(text)\n }\n\n // Weighted combination\n const rawScore = Object.entries(scores).reduce((total, [algorithm, score]) => {\n const weight = this.config.weights[algorithm as keyof typeof this.config.weights]\n return total + (score * weight)\n }, 0)\n\n // Length penalty (prefer shorter commands)\n const lengthPenalty = Math.max(0, text.length - 6) * 1.5\n const finalScore = Math.max(0, rawScore - lengthPenalty)\n\n // Determine primary algorithm and confidence\n const maxAlgorithm = Object.entries(scores).reduce((max, [alg, score]) => \n score > max.score ? { algorithm: alg, score } : max, \n { algorithm: 'none', score: 0 }\n )\n\n const confidence = Math.min(1.0, finalScore / 100)\n\n return {\n score: finalScore,\n algorithm: maxAlgorithm.algorithm,\n confidence\n }\n }\n\n /**\n * Algorithm 1: Prefix Matching (like pinyin prefix)\n * Handles cases like \"nod\" \u2192 \"node\"\n */\n private prefixScore(text: string, pattern: string): number {\n if (!text.startsWith(pattern)) return 0\n \n // Score based on prefix length vs total length\n const coverage = pattern.length / text.length\n return 100 * coverage\n }\n\n /**\n * Algorithm 2: Substring Matching (like pinyin contains) \n * Handles cases like \"ode\" \u2192 \"node\", \"py3\" \u2192 \"python3\"\n */\n private substringScore(text: string, pattern: string): number {\n // Direct substring match\n const index = text.indexOf(pattern)\n if (index !== -1) {\n // Earlier position and better coverage = higher score\n const positionFactor = Math.max(0, 10 - index) / 10\n const coverageFactor = pattern.length / text.length\n return 80 * positionFactor * coverageFactor\n }\n \n // Special handling for numeric suffixes (py3 \u2192 python3)\n // Check if pattern ends with a number and try prefix match + number\n const numMatch = pattern.match(/^(.+?)(\\d+)$/)\n if (numMatch) {\n const [, prefix, num] = numMatch\n // Check if text starts with prefix and ends with the same number\n if (text.startsWith(prefix) && text.endsWith(num)) {\n // Good match for patterns like \"py3\" \u2192 \"python3\"\n const coverageFactor = pattern.length / text.length\n return 70 * coverageFactor + 20 // Bonus for numeric suffix match\n }\n }\n \n return 0\n }\n\n /**\n * Algorithm 3: Abbreviation Matching (key innovation)\n * Handles cases like \"nde\" \u2192 \"node\", \"pyt3\" \u2192 \"python3\", \"gp5\" \u2192 \"gpt-5\"\n */\n private abbreviationScore(text: string, pattern: string): number {\n let score = 0\n let textPos = 0\n let perfectStart = false\n let consecutiveMatches = 0\n let wordBoundaryMatches = 0\n \n // Split text by hyphens to handle word boundaries better\n const textWords = text.split('-')\n const textClean = text.replace(/-/g, '').toLowerCase()\n \n for (let i = 0; i < pattern.length; i++) {\n const char = pattern[i]\n let charFound = false\n \n // Try to find in clean text (no hyphens)\n for (let j = textPos; j < textClean.length; j++) {\n if (textClean[j] === char) {\n charFound = true\n \n // Check if this character is at a word boundary in original text\n let originalPos = 0\n let cleanPos = 0\n for (let k = 0; k < text.length; k++) {\n if (text[k] === '-') continue\n if (cleanPos === j) {\n originalPos = k\n break\n }\n cleanPos++\n }\n \n // Consecutive character bonus\n if (j === textPos) {\n consecutiveMatches++\n } else {\n consecutiveMatches = 1\n }\n \n // Position-sensitive scoring\n if (i === 0 && j === 0) {\n score += 50 // Perfect first character\n perfectStart = true\n } else if (originalPos === 0 || text[originalPos - 1] === '-') {\n score += 35 // Word boundary match\n wordBoundaryMatches++\n } else if (j <= 2) {\n score += 20 // Early position\n } else if (j <= 6) {\n score += 10 // Mid position \n } else {\n score += 5 // Late position\n }\n \n // Consecutive character bonus\n if (consecutiveMatches > 1) {\n score += consecutiveMatches * 5\n }\n \n textPos = j + 1\n break\n }\n }\n \n if (!charFound) return 0 // Invalid abbreviation\n }\n \n // Critical bonuses\n if (perfectStart) score += 30\n if (wordBoundaryMatches >= 2) score += 25 // Multiple word boundaries\n if (textPos <= textClean.length * 0.8) score += 15 // Compact abbreviation\n \n // Special bonus for number matching at end\n const lastPatternChar = pattern[pattern.length - 1]\n const lastTextChar = text[text.length - 1]\n if (/\\d/.test(lastPatternChar) && lastPatternChar === lastTextChar) {\n score += 25\n }\n \n return score\n }\n\n /**\n * Algorithm 4: Edit Distance (typo tolerance)\n * Handles cases like \"noda\" \u2192 \"node\"\n */\n private editDistanceScore(text: string, pattern: string): number {\n if (pattern.length > text.length + this.config.maxEditDistance) return 0\n \n // Simplified Levenshtein distance \n const dp: number[][] = []\n const m = pattern.length\n const n = text.length\n \n // Initialize DP table\n for (let i = 0; i <= m; i++) {\n dp[i] = []\n for (let j = 0; j <= n; j++) {\n if (i === 0) dp[i][j] = j\n else if (j === 0) dp[i][j] = i\n else {\n const cost = pattern[i-1] === text[j-1] ? 0 : 1\n dp[i][j] = Math.min(\n dp[i-1][j] + 1, // deletion\n dp[i][j-1] + 1, // insertion\n dp[i-1][j-1] + cost // substitution\n )\n }\n }\n }\n \n const distance = dp[m][n]\n if (distance > this.config.maxEditDistance) return 0\n \n return Math.max(0, 30 - distance * 10)\n }\n\n /**\n * Algorithm 5: Command Popularity (like frequency in input method)\n * Boost common commands that users frequently type\n */\n private popularityScore(text: string): number {\n if (this.config.popularCommands.includes(text)) {\n return 40\n }\n \n // Short commands are often more commonly used\n if (text.length <= 5) return 10\n \n return 0\n }\n\n /**\n * Batch match multiple candidates and return sorted results\n */\n matchMany(candidates: string[], query: string): Array<{candidate: string, result: MatchResult}> {\n return candidates\n .map(candidate => ({ \n candidate, \n result: this.match(candidate, query) \n }))\n .filter(item => item.result.score >= this.config.minScore)\n .sort((a, b) => b.result.score - a.result.score)\n }\n}\n\n// Export convenience functions\nexport const defaultMatcher = new FuzzyMatcher()\n\nexport function matchCommand(command: string, query: string): MatchResult {\n return defaultMatcher.match(command, query)\n}\n\n// Import the advanced matcher\nimport { matchManyAdvanced } from './advancedFuzzyMatcher'\n\nexport function matchCommands(commands: string[], query: string): Array<{command: string, score: number}> {\n // Use the advanced matcher for better results\n return matchManyAdvanced(commands, query, 5) // Lower threshold for better matching\n .map(item => ({ \n command: item.candidate, \n score: item.score \n }))\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Input Method Inspired Fuzzy Matching Algorithm\n *\n * Multi-algorithm weighted scoring system inspired by:\n * - Sogou/Baidu Pinyin input method algorithms\n * - Double-pinyin abbreviation matching\n * - Terminal completion best practices (fzf, zsh, fish)\n *\n * Designed specifically for command/terminal completion scenarios\n * where users type abbreviations like \"nde\" expecting \"node\"\n */\n\nexport interface MatchResult {\n score: number\n algorithm: string // Which algorithm contributed most to the score\n confidence: number // 0-1 confidence level\n}\n\nexport interface FuzzyMatcherConfig {\n // Algorithm weights (must sum to 1.0)\n weights: {\n prefix: number // Direct prefix matching (\"nod\" \u2192 \"node\")\n substring: number // Substring matching (\"ode\" \u2192 \"node\")\n abbreviation: number // Key chars matching (\"nde\" \u2192 \"node\")\n editDistance: number // Typo tolerance (\"noda\" \u2192 \"node\")\n popularity: number // Common command boost\n }\n\n // Scoring parameters\n minScore: number // Minimum score threshold\n maxEditDistance: number // Maximum edits allowed\n popularCommands: string[] // Commands to boost\n}\n\nconst DEFAULT_CONFIG: FuzzyMatcherConfig = {\n weights: {\n prefix: 0.35, // Strong weight for prefix matching\n substring: 0.2, // Good for partial matches\n abbreviation: 0.3, // Key for \"nde\"\u2192\"node\" cases\n editDistance: 0.1, // Typo tolerance\n popularity: 0.05, // Slight bias for common commands\n },\n minScore: 10, // Lower threshold for better matching\n maxEditDistance: 2,\n popularCommands: [\n 'node',\n 'npm',\n 'git',\n 'ls',\n 'cd',\n 'cat',\n 'grep',\n 'find',\n 'cp',\n 'mv',\n 'python',\n 'java',\n 'docker',\n 'curl',\n 'wget',\n 'vim',\n 'nano',\n ],\n}\n\nexport class FuzzyMatcher {\n private config: FuzzyMatcherConfig\n\n constructor(config: Partial<FuzzyMatcherConfig> = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config }\n\n // Normalize weights to sum to 1.0\n const weightSum = Object.values(this.config.weights).reduce(\n (a, b) => a + b,\n 0,\n )\n if (Math.abs(weightSum - 1.0) > 0.01) {\n Object.keys(this.config.weights).forEach(key => {\n this.config.weights[key as keyof typeof this.config.weights] /=\n weightSum\n })\n }\n }\n\n /**\n * Calculate fuzzy match score for a candidate against a query\n */\n match(candidate: string, query: string): MatchResult {\n const text = candidate.toLowerCase()\n const pattern = query.toLowerCase()\n\n // Quick perfect match exits\n if (text === pattern) {\n return { score: 1000, algorithm: 'exact', confidence: 1.0 }\n }\n if (text.startsWith(pattern)) {\n return {\n score: 900 + (10 - pattern.length),\n algorithm: 'prefix-exact',\n confidence: 0.95,\n }\n }\n\n // Run all algorithms\n const scores = {\n prefix: this.prefixScore(text, pattern),\n substring: this.substringScore(text, pattern),\n abbreviation: this.abbreviationScore(text, pattern),\n editDistance: this.editDistanceScore(text, pattern),\n popularity: this.popularityScore(text),\n }\n\n // Weighted combination\n const rawScore = Object.entries(scores).reduce(\n (total, [algorithm, score]) => {\n const weight =\n this.config.weights[algorithm as keyof typeof this.config.weights]\n return total + score * weight\n },\n 0,\n )\n\n // Length penalty (prefer shorter commands)\n const lengthPenalty = Math.max(0, text.length - 6) * 1.5\n const finalScore = Math.max(0, rawScore - lengthPenalty)\n\n // Determine primary algorithm and confidence\n const maxAlgorithm = Object.entries(scores).reduce(\n (max, [alg, score]) =>\n score > max.score ? { algorithm: alg, score } : max,\n { algorithm: 'none', score: 0 },\n )\n\n const confidence = Math.min(1.0, finalScore / 100)\n\n return {\n score: finalScore,\n algorithm: maxAlgorithm.algorithm,\n confidence,\n }\n }\n\n /**\n * Algorithm 1: Prefix Matching (like pinyin prefix)\n * Handles cases like \"nod\" \u2192 \"node\"\n */\n private prefixScore(text: string, pattern: string): number {\n if (!text.startsWith(pattern)) return 0\n\n // Score based on prefix length vs total length\n const coverage = pattern.length / text.length\n return 100 * coverage\n }\n\n /**\n * Algorithm 2: Substring Matching (like pinyin contains)\n * Handles cases like \"ode\" \u2192 \"node\", \"py3\" \u2192 \"python3\"\n */\n private substringScore(text: string, pattern: string): number {\n // Direct substring match\n const index = text.indexOf(pattern)\n if (index !== -1) {\n // Earlier position and better coverage = higher score\n const positionFactor = Math.max(0, 10 - index) / 10\n const coverageFactor = pattern.length / text.length\n return 80 * positionFactor * coverageFactor\n }\n\n // Special handling for numeric suffixes (py3 \u2192 python3)\n // Check if pattern ends with a number and try prefix match + number\n const numMatch = pattern.match(/^(.+?)(\\d+)$/)\n if (numMatch) {\n const [, prefix, num] = numMatch\n // Check if text starts with prefix and ends with the same number\n if (text.startsWith(prefix) && text.endsWith(num)) {\n // Good match for patterns like \"py3\" \u2192 \"python3\"\n const coverageFactor = pattern.length / text.length\n return 70 * coverageFactor + 20 // Bonus for numeric suffix match\n }\n }\n\n return 0\n }\n\n /**\n * Algorithm 3: Abbreviation Matching (key innovation)\n * Handles cases like \"nde\" \u2192 \"node\", \"pyt3\" \u2192 \"python3\", \"gp5\" \u2192 \"gpt-5\"\n */\n private abbreviationScore(text: string, pattern: string): number {\n let score = 0\n let textPos = 0\n let perfectStart = false\n let consecutiveMatches = 0\n let wordBoundaryMatches = 0\n\n // Split text by hyphens to handle word boundaries better\n const textWords = text.split('-')\n const textClean = text.replace(/-/g, '').toLowerCase()\n\n for (let i = 0; i < pattern.length; i++) {\n const char = pattern[i]\n let charFound = false\n\n // Try to find in clean text (no hyphens)\n for (let j = textPos; j < textClean.length; j++) {\n if (textClean[j] === char) {\n charFound = true\n\n // Check if this character is at a word boundary in original text\n let originalPos = 0\n let cleanPos = 0\n for (let k = 0; k < text.length; k++) {\n if (text[k] === '-') continue\n if (cleanPos === j) {\n originalPos = k\n break\n }\n cleanPos++\n }\n\n // Consecutive character bonus\n if (j === textPos) {\n consecutiveMatches++\n } else {\n consecutiveMatches = 1\n }\n\n // Position-sensitive scoring\n if (i === 0 && j === 0) {\n score += 50 // Perfect first character\n perfectStart = true\n } else if (originalPos === 0 || text[originalPos - 1] === '-') {\n score += 35 // Word boundary match\n wordBoundaryMatches++\n } else if (j <= 2) {\n score += 20 // Early position\n } else if (j <= 6) {\n score += 10 // Mid position\n } else {\n score += 5 // Late position\n }\n\n // Consecutive character bonus\n if (consecutiveMatches > 1) {\n score += consecutiveMatches * 5\n }\n\n textPos = j + 1\n break\n }\n }\n\n if (!charFound) return 0 // Invalid abbreviation\n }\n\n // Critical bonuses\n if (perfectStart) score += 30\n if (wordBoundaryMatches >= 2) score += 25 // Multiple word boundaries\n if (textPos <= textClean.length * 0.8) score += 15 // Compact abbreviation\n\n // Special bonus for number matching at end\n const lastPatternChar = pattern[pattern.length - 1]\n const lastTextChar = text[text.length - 1]\n if (/\\d/.test(lastPatternChar) && lastPatternChar === lastTextChar) {\n score += 25\n }\n\n return score\n }\n\n /**\n * Algorithm 4: Edit Distance (typo tolerance)\n * Handles cases like \"noda\" \u2192 \"node\"\n */\n private editDistanceScore(text: string, pattern: string): number {\n if (pattern.length > text.length + this.config.maxEditDistance) return 0\n\n // Simplified Levenshtein distance\n const dp: number[][] = []\n const m = pattern.length\n const n = text.length\n\n // Initialize DP table\n for (let i = 0; i <= m; i++) {\n dp[i] = []\n for (let j = 0; j <= n; j++) {\n if (i === 0) dp[i][j] = j\n else if (j === 0) dp[i][j] = i\n else {\n const cost = pattern[i - 1] === text[j - 1] ? 0 : 1\n dp[i][j] = Math.min(\n dp[i - 1][j] + 1, // deletion\n dp[i][j - 1] + 1, // insertion\n dp[i - 1][j - 1] + cost, // substitution\n )\n }\n }\n }\n\n const distance = dp[m][n]\n if (distance > this.config.maxEditDistance) return 0\n\n return Math.max(0, 30 - distance * 10)\n }\n\n /**\n * Algorithm 5: Command Popularity (like frequency in input method)\n * Boost common commands that users frequently type\n */\n private popularityScore(text: string): number {\n if (this.config.popularCommands.includes(text)) {\n return 40\n }\n\n // Short commands are often more commonly used\n if (text.length <= 5) return 10\n\n return 0\n }\n\n /**\n * Batch match multiple candidates and return sorted results\n */\n matchMany(\n candidates: string[],\n query: string,\n ): Array<{ candidate: string; result: MatchResult }> {\n return candidates\n .map(candidate => ({\n candidate,\n result: this.match(candidate, query),\n }))\n .filter(item => item.result.score >= this.config.minScore)\n .sort((a, b) => b.result.score - a.result.score)\n }\n}\n\n// Export convenience functions\nexport const defaultMatcher = new FuzzyMatcher()\n\nexport function matchCommand(command: string, query: string): MatchResult {\n return defaultMatcher.match(command, query)\n}\n\n// Import the advanced matcher\nimport { matchManyAdvanced } from './advancedFuzzyMatcher'\n\nexport function matchCommands(\n commands: string[],\n query: string,\n): Array<{ command: string; score: number }> {\n // Use the advanced matcher for better results\n return matchManyAdvanced(commands, query, 5) // Lower threshold for better matching\n .map(item => ({\n command: item.candidate,\n score: item.score,\n }))\n}\n"],
5
+ "mappings": "AAkCA,MAAM,iBAAqC;AAAA,EACzC,SAAS;AAAA,IACP,QAAQ;AAAA;AAAA,IACR,WAAW;AAAA;AAAA,IACX,cAAc;AAAA;AAAA,IACd,cAAc;AAAA;AAAA,IACd,YAAY;AAAA;AAAA,EACd;AAAA,EACA,UAAU;AAAA;AAAA,EACV,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,MAAM,aAAa;AAAA,EAChB;AAAA,EAER,YAAY,SAAsC,CAAC,GAAG;AACpD,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAG7C,UAAM,YAAY,OAAO,OAAO,KAAK,OAAO,OAAO,EAAE;AAAA,MACnD,CAAC,GAAG,MAAM,IAAI;AAAA,MACd;AAAA,IACF;AACA,QAAI,KAAK,IAAI,YAAY,CAAG,IAAI,MAAM;AACpC,aAAO,KAAK,KAAK,OAAO,OAAO,EAAE,QAAQ,SAAO;AAC9C,aAAK,OAAO,QAAQ,GAAuC,KACzD;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAmB,OAA4B;AACnD,UAAM,OAAO,UAAU,YAAY;AACnC,UAAM,UAAU,MAAM,YAAY;AAGlC,QAAI,SAAS,SAAS;AACpB,aAAO,EAAE,OAAO,KAAM,WAAW,SAAS,YAAY,EAAI;AAAA,IAC5D;AACA,QAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,aAAO;AAAA,QACL,OAAO,OAAO,KAAK,QAAQ;AAAA,QAC3B,WAAW;AAAA,QACX,YAAY;AAAA,MACd;AAAA,IACF;AAGA,UAAM,SAAS;AAAA,MACb,QAAQ,KAAK,YAAY,MAAM,OAAO;AAAA,MACtC,WAAW,KAAK,eAAe,MAAM,OAAO;AAAA,MAC5C,cAAc,KAAK,kBAAkB,MAAM,OAAO;AAAA,MAClD,cAAc,KAAK,kBAAkB,MAAM,OAAO;AAAA,MAClD,YAAY,KAAK,gBAAgB,IAAI;AAAA,IACvC;AAGA,UAAM,WAAW,OAAO,QAAQ,MAAM,EAAE;AAAA,MACtC,CAAC,OAAO,CAAC,WAAW,KAAK,MAAM;AAC7B,cAAM,SACJ,KAAK,OAAO,QAAQ,SAA6C;AACnE,eAAO,QAAQ,QAAQ;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AAGA,UAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,SAAS,CAAC,IAAI;AACrD,UAAM,aAAa,KAAK,IAAI,GAAG,WAAW,aAAa;AAGvD,UAAM,eAAe,OAAO,QAAQ,MAAM,EAAE;AAAA,MAC1C,CAAC,KAAK,CAAC,KAAK,KAAK,MACf,QAAQ,IAAI,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI;AAAA,MAClD,EAAE,WAAW,QAAQ,OAAO,EAAE;AAAA,IAChC;AAEA,UAAM,aAAa,KAAK,IAAI,GAAK,aAAa,GAAG;AAEjD,WAAO;AAAA,MACL,OAAO;AAAA,MACP,WAAW,aAAa;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,MAAc,SAAyB;AACzD,QAAI,CAAC,KAAK,WAAW,OAAO,EAAG,QAAO;AAGtC,UAAM,WAAW,QAAQ,SAAS,KAAK;AACvC,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,MAAc,SAAyB;AAE5D,UAAM,QAAQ,KAAK,QAAQ,OAAO;AAClC,QAAI,UAAU,IAAI;AAEhB,YAAM,iBAAiB,KAAK,IAAI,GAAG,KAAK,KAAK,IAAI;AACjD,YAAM,iBAAiB,QAAQ,SAAS,KAAK;AAC7C,aAAO,KAAK,iBAAiB;AAAA,IAC/B;AAIA,UAAM,WAAW,QAAQ,MAAM,cAAc;AAC7C,QAAI,UAAU;AACZ,YAAM,CAAC,EAAE,QAAQ,GAAG,IAAI;AAExB,UAAI,KAAK,WAAW,MAAM,KAAK,KAAK,SAAS,GAAG,GAAG;AAEjD,cAAM,iBAAiB,QAAQ,SAAS,KAAK;AAC7C,eAAO,KAAK,iBAAiB;AAAA,MAC/B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,MAAc,SAAyB;AAC/D,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,QAAI,eAAe;AACnB,QAAI,qBAAqB;AACzB,QAAI,sBAAsB;AAG1B,UAAM,YAAY,KAAK,MAAM,GAAG;AAChC,UAAM,YAAY,KAAK,QAAQ,MAAM,EAAE,EAAE,YAAY;AAErD,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,YAAM,OAAO,QAAQ,CAAC;AACtB,UAAI,YAAY;AAGhB,eAAS,IAAI,SAAS,IAAI,UAAU,QAAQ,KAAK;AAC/C,YAAI,UAAU,CAAC,MAAM,MAAM;AACzB,sBAAY;AAGZ,cAAI,cAAc;AAClB,cAAI,WAAW;AACf,mBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,gBAAI,KAAK,CAAC,MAAM,IAAK;AACrB,gBAAI,aAAa,GAAG;AAClB,4BAAc;AACd;AAAA,YACF;AACA;AAAA,UACF;AAGA,cAAI,MAAM,SAAS;AACjB;AAAA,UACF,OAAO;AACL,iCAAqB;AAAA,UACvB;AAGA,cAAI,MAAM,KAAK,MAAM,GAAG;AACtB,qBAAS;AACT,2BAAe;AAAA,UACjB,WAAW,gBAAgB,KAAK,KAAK,cAAc,CAAC,MAAM,KAAK;AAC7D,qBAAS;AACT;AAAA,UACF,WAAW,KAAK,GAAG;AACjB,qBAAS;AAAA,UACX,WAAW,KAAK,GAAG;AACjB,qBAAS;AAAA,UACX,OAAO;AACL,qBAAS;AAAA,UACX;AAGA,cAAI,qBAAqB,GAAG;AAC1B,qBAAS,qBAAqB;AAAA,UAChC;AAEA,oBAAU,IAAI;AACd;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,UAAW,QAAO;AAAA,IACzB;AAGA,QAAI,aAAc,UAAS;AAC3B,QAAI,uBAAuB,EAAG,UAAS;AACvC,QAAI,WAAW,UAAU,SAAS,IAAK,UAAS;AAGhD,UAAM,kBAAkB,QAAQ,QAAQ,SAAS,CAAC;AAClD,UAAM,eAAe,KAAK,KAAK,SAAS,CAAC;AACzC,QAAI,KAAK,KAAK,eAAe,KAAK,oBAAoB,cAAc;AAClE,eAAS;AAAA,IACX;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,MAAc,SAAyB;AAC/D,QAAI,QAAQ,SAAS,KAAK,SAAS,KAAK,OAAO,gBAAiB,QAAO;AAGvE,UAAM,KAAiB,CAAC;AACxB,UAAM,IAAI,QAAQ;AAClB,UAAM,IAAI,KAAK;AAGf,aAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,SAAG,CAAC,IAAI,CAAC;AACT,eAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,YAAI,MAAM,EAAG,IAAG,CAAC,EAAE,CAAC,IAAI;AAAA,iBACf,MAAM,EAAG,IAAG,CAAC,EAAE,CAAC,IAAI;AAAA,aACxB;AACH,gBAAM,OAAO,QAAQ,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,IAAI;AAClD,aAAG,CAAC,EAAE,CAAC,IAAI,KAAK;AAAA,YACd,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI;AAAA;AAAA,YACf,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI;AAAA;AAAA,YACf,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI;AAAA;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,WAAW,GAAG,CAAC,EAAE,CAAC;AACxB,QAAI,WAAW,KAAK,OAAO,gBAAiB,QAAO;AAEnD,WAAO,KAAK,IAAI,GAAG,KAAK,WAAW,EAAE;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,MAAsB;AAC5C,QAAI,KAAK,OAAO,gBAAgB,SAAS,IAAI,GAAG;AAC9C,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,UAAU,EAAG,QAAO;AAE7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UACE,YACA,OACmD;AACnD,WAAO,WACJ,IAAI,gBAAc;AAAA,MACjB;AAAA,MACA,QAAQ,KAAK,MAAM,WAAW,KAAK;AAAA,IACrC,EAAE,EACD,OAAO,UAAQ,KAAK,OAAO,SAAS,KAAK,OAAO,QAAQ,EACxD,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,QAAQ,EAAE,OAAO,KAAK;AAAA,EACnD;AACF;AAGO,MAAM,iBAAiB,IAAI,aAAa;AAExC,SAAS,aAAa,SAAiB,OAA4B;AACxE,SAAO,eAAe,MAAM,SAAS,KAAK;AAC5C;AAGA,SAAS,yBAAyB;AAE3B,SAAS,cACd,UACA,OAC2C;AAE3C,SAAO,kBAAkB,UAAU,OAAO,CAAC,EACxC,IAAI,WAAS;AAAA,IACZ,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,EACd,EAAE;AACN;",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,9 @@ class HookManager {
29
29
  registerPlugins(plugins) {
30
30
  this.plugins = plugins;
31
31
  const totalHooks = plugins.reduce((sum, p) => sum + p.hooks.length, 0);
32
- logInfo(`HookManager: Registered ${plugins.length} plugin(s) with ${totalHooks} hook(s)`);
32
+ logInfo(
33
+ `HookManager: Registered ${plugins.length} plugin(s) with ${totalHooks} hook(s)`
34
+ );
33
35
  }
34
36
  /**
35
37
  * Enable or disable hook execution
@@ -60,7 +62,9 @@ class HookManager {
60
62
  if (matchingHooks.length === 0) {
61
63
  return { shouldContinue: true, shouldAskUser: false };
62
64
  }
63
- logDebug(`PreToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`);
65
+ logDebug(
66
+ `PreToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`
67
+ );
64
68
  const input = createPreToolUseInput(
65
69
  this.sessionId,
66
70
  this.transcriptPath,
@@ -108,7 +112,9 @@ class HookManager {
108
112
  if (matchingHooks.length === 0) {
109
113
  return;
110
114
  }
111
- logDebug(`PostToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`);
115
+ logDebug(
116
+ `PostToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`
117
+ );
112
118
  const input = createPostToolUseInput(
113
119
  this.sessionId,
114
120
  this.transcriptPath,
@@ -208,7 +214,11 @@ class HookManager {
208
214
  return;
209
215
  }
210
216
  logInfo(`SessionEnd: Executing ${matchingHooks.length} hook(s)`);
211
- const input = createSessionEndInput(this.sessionId, this.transcriptPath, reason);
217
+ const input = createSessionEndInput(
218
+ this.sessionId,
219
+ this.transcriptPath,
220
+ reason
221
+ );
212
222
  for (const hook of matchingHooks) {
213
223
  const plugin = this.plugins.find((p) => p.manifest.name === hook.pluginName);
214
224
  if (!plugin) continue;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/hookManager.ts"],
4
- "sourcesContent": ["/**\n * Hook Manager\n *\n * Central manager for plugin hooks lifecycle.\n * Coordinates hook execution across the application.\n */\n\nimport { HookEvent } from '../types/hooks'\nimport { LoadedPlugin } from '../types/plugin'\nimport {\n executeHooksForEvent,\n processHookDecisions,\n createPreToolUseInput,\n createPostToolUseInput,\n createUserPromptSubmitInput,\n createSessionStartInput,\n createSessionEndInput,\n type HookExecutionOptions,\n type HookExecutionResult,\n} from '../services/hookExecutor'\nimport { logError } from './log'\n\n// Simple logging helpers\nconst logInfo = (msg: string) => {\n // Only log in debug mode to reduce noise\n if (process.env.DEBUG) console.log(`[INFO] ${msg}`)\n}\nconst logDebug = (msg: string, ...args: any[]) => {\n if (process.env.DEBUG) console.log(`[DEBUG] ${msg}`, ...args)\n}\n\n/**\n * Hook manager instance\n */\nexport class HookManager {\n private plugins: LoadedPlugin[] = []\n private sessionId: string\n private transcriptPath: string\n private enabled: boolean = true\n\n constructor(sessionId: string, transcriptPath: string) {\n this.sessionId = sessionId\n this.transcriptPath = transcriptPath\n }\n\n /**\n * Register plugins with hooks\n */\n registerPlugins(plugins: LoadedPlugin[]) {\n this.plugins = plugins\n const totalHooks = plugins.reduce((sum, p) => sum + p.hooks.length, 0)\n logInfo(`HookManager: Registered ${plugins.length} plugin(s) with ${totalHooks} hook(s)`)\n }\n\n /**\n * Enable or disable hook execution\n */\n setEnabled(enabled: boolean) {\n this.enabled = enabled\n logDebug(`HookManager: ${enabled ? 'Enabled' : 'Disabled'}`)\n }\n\n /**\n * Execute PreToolUse hooks\n */\n async executePreToolUse(\n toolName: string,\n toolInput: Record<string, unknown>,\n ): Promise<{\n shouldContinue: boolean\n shouldAskUser: boolean\n reason?: string\n }> {\n if (!this.enabled) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n // Collect all hooks across all plugins\n const allHooks = this.plugins.flatMap((p) => p.hooks)\n\n // Filter hooks that match this tool\n const matchingHooks = allHooks.filter((hook) => {\n if (hook.event !== HookEvent.PreToolUse) return false\n if (!hook.matcher) return true // No matcher means match all\n if (hook.matcher === '*' || hook.matcher === '') return true\n\n // Check if tool name matches the pattern\n try {\n const regex = new RegExp(hook.matcher)\n return regex.test(toolName)\n } catch {\n // If regex is invalid, try exact match\n return hook.matcher === toolName\n }\n })\n\n if (matchingHooks.length === 0) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n logDebug(`PreToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`)\n\n // Execute hooks\n const input = createPreToolUseInput(\n this.sessionId,\n this.transcriptPath,\n toolName,\n toolInput,\n )\n\n const results: HookExecutionResult[] = []\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find((p) => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n const result = await executeHooksForEvent(\n HookEvent.PreToolUse,\n [hook],\n input,\n options,\n )\n\n results.push(...result)\n }\n\n return processHookDecisions(results)\n }\n\n /**\n * Execute PostToolUse hooks\n */\n async executePostToolUse(\n toolName: string,\n toolInput: Record<string, unknown>,\n toolOutput: Record<string, unknown>,\n ): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n const allHooks = this.plugins.flatMap((p) => p.hooks)\n\n const matchingHooks = allHooks.filter((hook) => {\n if (hook.event !== HookEvent.PostToolUse) return false\n if (!hook.matcher) return true\n if (hook.matcher === '*' || hook.matcher === '') return true\n\n try {\n const regex = new RegExp(hook.matcher)\n return regex.test(toolName)\n } catch {\n return hook.matcher === toolName\n }\n })\n\n if (matchingHooks.length === 0) {\n return\n }\n\n logDebug(`PostToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`)\n\n const input = createPostToolUseInput(\n this.sessionId,\n this.transcriptPath,\n toolName,\n toolInput,\n toolOutput,\n )\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find((p) => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n // PostToolUse hooks don't affect workflow, just execute them\n await executeHooksForEvent(HookEvent.PostToolUse, [hook], input, options)\n }\n }\n\n /**\n * Execute UserPromptSubmit hooks\n */\n async executeUserPromptSubmit(\n userPrompt: string,\n ): Promise<{\n shouldContinue: boolean\n shouldAskUser: boolean\n reason?: string\n }> {\n if (!this.enabled) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n const allHooks = this.plugins.flatMap((p) => p.hooks)\n const matchingHooks = allHooks.filter(\n (hook) => hook.event === HookEvent.UserPromptSubmit,\n )\n\n if (matchingHooks.length === 0) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n logDebug(`UserPromptSubmit: ${matchingHooks.length} hook(s)`)\n\n const input = createUserPromptSubmitInput(\n this.sessionId,\n this.transcriptPath,\n userPrompt,\n )\n\n const results: HookExecutionResult[] = []\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find((p) => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n const result = await executeHooksForEvent(\n HookEvent.UserPromptSubmit,\n [hook],\n input,\n options,\n )\n\n results.push(...result)\n }\n\n return processHookDecisions(results)\n }\n\n /**\n * Execute SessionStart hooks\n */\n async executeSessionStart(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n const allHooks = this.plugins.flatMap((p) => p.hooks)\n const matchingHooks = allHooks.filter(\n (hook) => hook.event === HookEvent.SessionStart,\n )\n\n if (matchingHooks.length === 0) {\n return\n }\n\n logInfo(`SessionStart: Executing ${matchingHooks.length} hook(s)`)\n\n const input = createSessionStartInput(this.sessionId, this.transcriptPath)\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find((p) => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n await executeHooksForEvent(HookEvent.SessionStart, [hook], input, options)\n }\n }\n\n /**\n * Execute SessionEnd hooks\n */\n async executeSessionEnd(reason: 'clear' | 'logout' | 'prompt_input_exit' | 'other' = 'other'): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n const allHooks = this.plugins.flatMap((p) => p.hooks)\n const matchingHooks = allHooks.filter(\n (hook) => hook.event === HookEvent.SessionEnd,\n )\n\n if (matchingHooks.length === 0) {\n return\n }\n\n logInfo(`SessionEnd: Executing ${matchingHooks.length} hook(s)`)\n\n const input = createSessionEndInput(this.sessionId, this.transcriptPath, reason)\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find((p) => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n await executeHooksForEvent(HookEvent.SessionEnd, [hook], input, options)\n }\n }\n}\n\n/**\n * Global hook manager instance\n */\nlet globalHookManager: HookManager | null = null\n\n/**\n * Initialize global hook manager\n */\nexport function initializeHookManager(\n sessionId: string,\n transcriptPath: string,\n plugins: LoadedPlugin[],\n): HookManager {\n globalHookManager = new HookManager(sessionId, transcriptPath)\n globalHookManager.registerPlugins(plugins)\n return globalHookManager\n}\n\n/**\n * Get global hook manager\n */\nexport function getHookManager(): HookManager | null {\n return globalHookManager\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Hook Manager\n *\n * Central manager for plugin hooks lifecycle.\n * Coordinates hook execution across the application.\n */\n\nimport { HookEvent } from '../types/hooks'\nimport { LoadedPlugin } from '../types/plugin'\nimport {\n executeHooksForEvent,\n processHookDecisions,\n createPreToolUseInput,\n createPostToolUseInput,\n createUserPromptSubmitInput,\n createSessionStartInput,\n createSessionEndInput,\n type HookExecutionOptions,\n type HookExecutionResult,\n} from '../services/hookExecutor'\nimport { logError } from './log'\n\n// Simple logging helpers\nconst logInfo = (msg: string) => {\n // Only log in debug mode to reduce noise\n if (process.env.DEBUG) console.log(`[INFO] ${msg}`)\n}\nconst logDebug = (msg: string, ...args: any[]) => {\n if (process.env.DEBUG) console.log(`[DEBUG] ${msg}`, ...args)\n}\n\n/**\n * Hook manager instance\n */\nexport class HookManager {\n private plugins: LoadedPlugin[] = []\n private sessionId: string\n private transcriptPath: string\n private enabled: boolean = true\n\n constructor(sessionId: string, transcriptPath: string) {\n this.sessionId = sessionId\n this.transcriptPath = transcriptPath\n }\n\n /**\n * Register plugins with hooks\n */\n registerPlugins(plugins: LoadedPlugin[]) {\n this.plugins = plugins\n const totalHooks = plugins.reduce((sum, p) => sum + p.hooks.length, 0)\n logInfo(\n `HookManager: Registered ${plugins.length} plugin(s) with ${totalHooks} hook(s)`,\n )\n }\n\n /**\n * Enable or disable hook execution\n */\n setEnabled(enabled: boolean) {\n this.enabled = enabled\n logDebug(`HookManager: ${enabled ? 'Enabled' : 'Disabled'}`)\n }\n\n /**\n * Execute PreToolUse hooks\n */\n async executePreToolUse(\n toolName: string,\n toolInput: Record<string, unknown>,\n ): Promise<{\n shouldContinue: boolean\n shouldAskUser: boolean\n reason?: string\n }> {\n if (!this.enabled) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n // Collect all hooks across all plugins\n const allHooks = this.plugins.flatMap(p => p.hooks)\n\n // Filter hooks that match this tool\n const matchingHooks = allHooks.filter(hook => {\n if (hook.event !== HookEvent.PreToolUse) return false\n if (!hook.matcher) return true // No matcher means match all\n if (hook.matcher === '*' || hook.matcher === '') return true\n\n // Check if tool name matches the pattern\n try {\n const regex = new RegExp(hook.matcher)\n return regex.test(toolName)\n } catch {\n // If regex is invalid, try exact match\n return hook.matcher === toolName\n }\n })\n\n if (matchingHooks.length === 0) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n logDebug(\n `PreToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`,\n )\n\n // Execute hooks\n const input = createPreToolUseInput(\n this.sessionId,\n this.transcriptPath,\n toolName,\n toolInput,\n )\n\n const results: HookExecutionResult[] = []\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find(p => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n const result = await executeHooksForEvent(\n HookEvent.PreToolUse,\n [hook],\n input,\n options,\n )\n\n results.push(...result)\n }\n\n return processHookDecisions(results)\n }\n\n /**\n * Execute PostToolUse hooks\n */\n async executePostToolUse(\n toolName: string,\n toolInput: Record<string, unknown>,\n toolOutput: Record<string, unknown>,\n ): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n const allHooks = this.plugins.flatMap(p => p.hooks)\n\n const matchingHooks = allHooks.filter(hook => {\n if (hook.event !== HookEvent.PostToolUse) return false\n if (!hook.matcher) return true\n if (hook.matcher === '*' || hook.matcher === '') return true\n\n try {\n const regex = new RegExp(hook.matcher)\n return regex.test(toolName)\n } catch {\n return hook.matcher === toolName\n }\n })\n\n if (matchingHooks.length === 0) {\n return\n }\n\n logDebug(\n `PostToolUse: ${matchingHooks.length} hook(s) matched for tool: ${toolName}`,\n )\n\n const input = createPostToolUseInput(\n this.sessionId,\n this.transcriptPath,\n toolName,\n toolInput,\n toolOutput,\n )\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find(p => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n // PostToolUse hooks don't affect workflow, just execute them\n await executeHooksForEvent(HookEvent.PostToolUse, [hook], input, options)\n }\n }\n\n /**\n * Execute UserPromptSubmit hooks\n */\n async executeUserPromptSubmit(userPrompt: string): Promise<{\n shouldContinue: boolean\n shouldAskUser: boolean\n reason?: string\n }> {\n if (!this.enabled) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n const allHooks = this.plugins.flatMap(p => p.hooks)\n const matchingHooks = allHooks.filter(\n hook => hook.event === HookEvent.UserPromptSubmit,\n )\n\n if (matchingHooks.length === 0) {\n return { shouldContinue: true, shouldAskUser: false }\n }\n\n logDebug(`UserPromptSubmit: ${matchingHooks.length} hook(s)`)\n\n const input = createUserPromptSubmitInput(\n this.sessionId,\n this.transcriptPath,\n userPrompt,\n )\n\n const results: HookExecutionResult[] = []\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find(p => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n const result = await executeHooksForEvent(\n HookEvent.UserPromptSubmit,\n [hook],\n input,\n options,\n )\n\n results.push(...result)\n }\n\n return processHookDecisions(results)\n }\n\n /**\n * Execute SessionStart hooks\n */\n async executeSessionStart(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n const allHooks = this.plugins.flatMap(p => p.hooks)\n const matchingHooks = allHooks.filter(\n hook => hook.event === HookEvent.SessionStart,\n )\n\n if (matchingHooks.length === 0) {\n return\n }\n\n logInfo(`SessionStart: Executing ${matchingHooks.length} hook(s)`)\n\n const input = createSessionStartInput(this.sessionId, this.transcriptPath)\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find(p => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n await executeHooksForEvent(HookEvent.SessionStart, [hook], input, options)\n }\n }\n\n /**\n * Execute SessionEnd hooks\n */\n async executeSessionEnd(\n reason: 'clear' | 'logout' | 'prompt_input_exit' | 'other' = 'other',\n ): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n const allHooks = this.plugins.flatMap(p => p.hooks)\n const matchingHooks = allHooks.filter(\n hook => hook.event === HookEvent.SessionEnd,\n )\n\n if (matchingHooks.length === 0) {\n return\n }\n\n logInfo(`SessionEnd: Executing ${matchingHooks.length} hook(s)`)\n\n const input = createSessionEndInput(\n this.sessionId,\n this.transcriptPath,\n reason,\n )\n\n for (const hook of matchingHooks) {\n const plugin = this.plugins.find(p => p.manifest.name === hook.pluginName)\n if (!plugin) continue\n\n const options: HookExecutionOptions = {\n sessionId: this.sessionId,\n transcriptPath: this.transcriptPath,\n pluginRoot: plugin.location,\n }\n\n await executeHooksForEvent(HookEvent.SessionEnd, [hook], input, options)\n }\n }\n}\n\n/**\n * Global hook manager instance\n */\nlet globalHookManager: HookManager | null = null\n\n/**\n * Initialize global hook manager\n */\nexport function initializeHookManager(\n sessionId: string,\n transcriptPath: string,\n plugins: LoadedPlugin[],\n): HookManager {\n globalHookManager = new HookManager(sessionId, transcriptPath)\n globalHookManager.registerPlugins(plugins)\n return globalHookManager\n}\n\n/**\n * Get global hook manager\n */\nexport function getHookManager(): HookManager | null {\n return globalHookManager\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/log.ts"],
4
- "sourcesContent": ["import {\n existsSync,\n mkdirSync,\n writeFileSync,\n readFileSync,\n promises as fsPromises,\n} from 'fs'\nimport { dirname, join } from 'path'\nimport { captureException } from '@services/sentry'\nimport { randomUUID } from 'crypto'\nimport envPaths from 'env-paths'\nimport type { LogOption, SerializedMessage } from '@minto-types/logs'\nimport { MACRO } from '@constants/macros'\nimport { PRODUCT_COMMAND } from '@constants/product'\n\nconst IN_MEMORY_ERROR_LOG: Array<{ error: string; timestamp: string }> = []\nconst MAX_IN_MEMORY_ERRORS = 100 // Limit to prevent memory issues\n\nconst PERMISSION_ERROR_CODES = new Set(['EACCES', 'EPERM', 'EROFS'])\n\nfunction isPermissionError(error: unknown): error is NodeJS.ErrnoException {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n PERMISSION_ERROR_CODES.has((error as NodeJS.ErrnoException).code ?? '')\n )\n}\n\nfunction safeMkdir(dir: string): boolean {\n if (existsSync(dir)) return true\n try {\n mkdirSync(dir, { recursive: true })\n return true\n } catch (error) {\n if (isPermissionError(error)) {\n return false\n }\n throw error\n }\n}\n\nfunction safeWriteFile(path: string, data: string, encoding: BufferEncoding = 'utf8'): boolean {\n try {\n writeFileSync(path, data, encoding)\n return true\n } catch (error) {\n if (isPermissionError(error)) {\n return false\n }\n throw error\n }\n}\n\nexport const SESSION_ID = randomUUID()\n\nconst paths = envPaths(PRODUCT_COMMAND)\n\nfunction getProjectDir(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9]/g, '-')\n}\n\nexport const CACHE_PATHS = {\n errors: () => join(paths.cache, getProjectDir(process.cwd()), 'errors'),\n messages: () => join(paths.cache, getProjectDir(process.cwd()), 'messages'),\n mcpLogs: (serverName: string) =>\n join(paths.cache, getProjectDir(process.cwd()), `mcp-logs-${serverName}`),\n}\n\nexport function dateToFilename(date: Date): string {\n return date.toISOString().replace(/[:.]/g, '-')\n}\n\nconst DATE = dateToFilename(new Date())\n\nfunction getErrorsPath(): string {\n return join(CACHE_PATHS.errors(), DATE + '.txt')\n}\n\nexport function getMessagesPath(\n messageLogName: string,\n forkNumber: number,\n sidechainNumber: number,\n): string {\n return join(\n CACHE_PATHS.messages(),\n `${messageLogName}${forkNumber > 0 ? `-${forkNumber}` : ''}${\n sidechainNumber > 0 ? `-sidechain-${sidechainNumber}` : ''\n }.json`,\n )\n}\n\nexport function logError(error: unknown): void {\n try {\n if (process.env.NODE_ENV === 'test') {\n console.error(error)\n }\n\n const errorStr =\n error instanceof Error ? error.stack || error.message : String(error)\n\n const errorInfo = {\n error: errorStr,\n timestamp: new Date().toISOString(),\n }\n\n if (IN_MEMORY_ERROR_LOG.length >= MAX_IN_MEMORY_ERRORS) {\n IN_MEMORY_ERROR_LOG.shift() // Remove oldest error\n }\n IN_MEMORY_ERROR_LOG.push(errorInfo)\n\n appendToLog(getErrorsPath(), {\n error: errorStr,\n })\n } catch {\n // pass\n }\n // Also send to Sentry with session ID, but don't await\n captureException(error)\n}\n\nexport function getErrorsLog(): object[] {\n return readLog(getErrorsPath())\n}\n\nexport function getInMemoryErrors(): object[] {\n return [...IN_MEMORY_ERROR_LOG]\n}\n\nfunction readLog(path: string): object[] {\n if (!existsSync(path)) {\n return []\n }\n try {\n return JSON.parse(readFileSync(path, 'utf8'))\n } catch {\n return []\n }\n}\n\nfunction appendToLog(path: string, message: object): void {\n if (process.env.USER_TYPE === 'external') {\n return\n }\n\n const dir = dirname(path)\n if (!safeMkdir(dir)) {\n return\n }\n\n // Create messages file with empty array if it doesn't exist\n if (!existsSync(path) && !safeWriteFile(path, '[]')) {\n return\n }\n\n const messages = readLog(path)\n const messageWithTimestamp = {\n ...message,\n cwd: process.cwd(),\n userType: process.env.USER_TYPE,\n sessionId: SESSION_ID,\n timestamp: new Date().toISOString(),\n version: MACRO.VERSION,\n }\n messages.push(messageWithTimestamp)\n\n safeWriteFile(path, JSON.stringify(messages, null, 2))\n}\n\nexport function overwriteLog(path: string, messages: object[]): void {\n if (process.env.USER_TYPE === 'external') {\n return\n }\n\n if (!messages.length) {\n return\n }\n\n const dir = dirname(path)\n if (!safeMkdir(dir)) {\n return\n }\n\n const messagesWithMetadata = messages.map(message => ({\n ...message,\n cwd: process.cwd(),\n userType: process.env.USER_TYPE,\n sessionId: SESSION_ID,\n timestamp: new Date().toISOString(),\n version: MACRO.VERSION,\n }))\n\n safeWriteFile(path, JSON.stringify(messagesWithMetadata, null, 2))\n}\n\nexport async function loadLogList(\n path = CACHE_PATHS.messages(),\n): Promise<LogOption[]> {\n if (!existsSync(path)) {\n logError(`No logs found at ${path}`)\n return []\n }\n\n const files = await fsPromises.readdir(path)\n const logData = await Promise.all(\n files.map(async (file, i) => {\n const fullPath = join(path, file)\n const content = await fsPromises.readFile(fullPath, 'utf8')\n const messages = JSON.parse(content) as SerializedMessage[]\n const firstMessage = messages[0]\n const lastMessage = messages[messages.length - 1]\n const firstPrompt =\n firstMessage?.type === 'user' &&\n typeof firstMessage?.message?.content === 'string'\n ? firstMessage?.message?.content\n : 'No prompt'\n\n const { date, forkNumber, sidechainNumber } = parseLogFilename(file)\n return {\n date,\n forkNumber,\n fullPath,\n messages,\n value: i, // hack: overwritten after sorting, right below this\n created: parseISOString(firstMessage?.timestamp || date),\n modified: lastMessage?.timestamp\n ? parseISOString(lastMessage.timestamp)\n : parseISOString(date),\n firstPrompt:\n firstPrompt.split('\\n')[0]?.slice(0, 50) +\n (firstPrompt.length > 50 ? '\u2026' : '') || 'No prompt',\n messageCount: messages.length,\n sidechainNumber,\n }\n }),\n )\n\n return sortLogs(logData.filter(_ => _.messages.length)).map((_, i) => ({\n ..._,\n value: i,\n }))\n}\n\nexport function parseLogFilename(filename: string): {\n date: string\n forkNumber: number | undefined\n sidechainNumber: number | undefined\n} {\n const base = filename.split('.')[0]!\n // Default timestamp format has 6 segments: 2025-01-27T01-31-35-104Z\n const segments = base.split('-')\n const hasSidechain = base.includes('-sidechain-')\n\n let date = base\n let forkNumber: number | undefined = undefined\n let sidechainNumber: number | undefined = undefined\n\n if (hasSidechain) {\n const sidechainIndex = segments.indexOf('sidechain')\n sidechainNumber = Number(segments[sidechainIndex + 1])\n // Fork number is before sidechain if exists\n if (sidechainIndex > 6) {\n forkNumber = Number(segments[sidechainIndex - 1])\n date = segments.slice(0, 6).join('-')\n } else {\n date = segments.slice(0, 6).join('-')\n }\n } else if (segments.length > 6) {\n // Has fork number\n const lastSegment = Number(segments[segments.length - 1])\n forkNumber = lastSegment >= 0 ? lastSegment : undefined\n date = segments.slice(0, 6).join('-')\n } else {\n // Basic timestamp only\n date = base\n }\n\n return { date, forkNumber, sidechainNumber }\n}\n\nexport function getNextAvailableLogForkNumber(\n date: string,\n forkNumber: number,\n // Main chain has sidechainNumber 0\n sidechainNumber: number,\n): number {\n while (existsSync(getMessagesPath(date, forkNumber, sidechainNumber))) {\n forkNumber++\n }\n return forkNumber\n}\n\nexport function getNextAvailableLogSidechainNumber(\n date: string,\n forkNumber: number,\n): number {\n let sidechainNumber = 1\n while (existsSync(getMessagesPath(date, forkNumber, sidechainNumber))) {\n sidechainNumber++\n }\n return sidechainNumber\n}\n\nexport function getForkNumberFromFilename(\n filename: string,\n): number | undefined {\n const base = filename.split('.')[0]!\n const segments = base.split('-')\n const hasSidechain = base.includes('-sidechain-')\n\n if (hasSidechain) {\n const sidechainIndex = segments.indexOf('sidechain')\n if (sidechainIndex > 6) {\n return Number(segments[sidechainIndex - 1])\n }\n return undefined\n }\n\n if (segments.length > 6) {\n const lastNumber = Number(segments[segments.length - 1])\n return lastNumber >= 0 ? lastNumber : undefined\n }\n return undefined\n}\n\nexport function sortLogs(logs: LogOption[]): LogOption[] {\n return logs.sort((a, b) => {\n // Sort by modified date (newest first)\n const modifiedDiff = b.modified.getTime() - a.modified.getTime()\n if (modifiedDiff !== 0) {\n return modifiedDiff\n }\n\n // If modified dates are equal, sort by created date\n const createdDiff = b.created.getTime() - a.created.getTime()\n if (createdDiff !== 0) {\n return createdDiff\n }\n\n // If both dates are equal, sort by fork number\n return (b.forkNumber ?? 0) - (a.forkNumber ?? 0)\n })\n}\n\nexport function formatDate(date: Date): string {\n const now = new Date()\n const yesterday = new Date(now)\n yesterday.setDate(yesterday.getDate() - 1)\n\n const isToday = date.toDateString() === now.toDateString()\n const isYesterday = date.toDateString() === yesterday.toDateString()\n\n const timeStr = date\n .toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n })\n .toLowerCase()\n\n if (isToday) {\n return `Today at ${timeStr}`\n } else if (isYesterday) {\n return `Yesterday at ${timeStr}`\n } else {\n return (\n date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n }) + ` at ${timeStr}`\n )\n }\n}\n\nexport function parseISOString(s: string): Date {\n const b = s.split(/\\D+/)\n return new Date(\n Date.UTC(\n parseInt(b[0]!, 10),\n parseInt(b[1]!, 10) - 1,\n parseInt(b[2]!, 10),\n parseInt(b[3]!, 10),\n parseInt(b[4]!, 10),\n parseInt(b[5]!, 10),\n parseInt(b[6]!, 10),\n ),\n )\n}\n\nexport function logMCPError(serverName: string, error: unknown): void {\n try {\n const logDir = CACHE_PATHS.mcpLogs(serverName)\n const errorStr =\n error instanceof Error ? error.stack || error.message : String(error)\n const timestamp = new Date().toISOString()\n\n const logFile = join(logDir, DATE + '.txt')\n\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true })\n }\n\n if (!existsSync(logFile)) {\n writeFileSync(logFile, '[]', 'utf8')\n }\n\n const errorInfo = {\n error: errorStr,\n timestamp,\n sessionId: SESSION_ID,\n cwd: process.cwd(),\n }\n\n const messages = readLog(logFile)\n messages.push(errorInfo)\n writeFileSync(logFile, JSON.stringify(messages, null, 2), 'utf8')\n } catch {\n // Silently fail\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n existsSync,\n mkdirSync,\n writeFileSync,\n readFileSync,\n promises as fsPromises,\n} from 'fs'\nimport { dirname, join } from 'path'\nimport { captureException } from '@services/sentry'\nimport { randomUUID } from 'crypto'\nimport envPaths from 'env-paths'\nimport type { LogOption, SerializedMessage } from '@minto-types/logs'\nimport { MACRO } from '@constants/macros'\nimport { PRODUCT_COMMAND } from '@constants/product'\n\nconst IN_MEMORY_ERROR_LOG: Array<{ error: string; timestamp: string }> = []\nconst MAX_IN_MEMORY_ERRORS = 100 // Limit to prevent memory issues\n\nconst PERMISSION_ERROR_CODES = new Set(['EACCES', 'EPERM', 'EROFS'])\n\nfunction isPermissionError(error: unknown): error is NodeJS.ErrnoException {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n PERMISSION_ERROR_CODES.has((error as NodeJS.ErrnoException).code ?? '')\n )\n}\n\nfunction safeMkdir(dir: string): boolean {\n if (existsSync(dir)) return true\n try {\n mkdirSync(dir, { recursive: true })\n return true\n } catch (error) {\n if (isPermissionError(error)) {\n return false\n }\n throw error\n }\n}\n\nfunction safeWriteFile(\n path: string,\n data: string,\n encoding: BufferEncoding = 'utf8',\n): boolean {\n try {\n writeFileSync(path, data, encoding)\n return true\n } catch (error) {\n if (isPermissionError(error)) {\n return false\n }\n throw error\n }\n}\n\nexport const SESSION_ID = randomUUID()\n\nconst paths = envPaths(PRODUCT_COMMAND)\n\nfunction getProjectDir(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9]/g, '-')\n}\n\nexport const CACHE_PATHS = {\n errors: () => join(paths.cache, getProjectDir(process.cwd()), 'errors'),\n messages: () => join(paths.cache, getProjectDir(process.cwd()), 'messages'),\n mcpLogs: (serverName: string) =>\n join(paths.cache, getProjectDir(process.cwd()), `mcp-logs-${serverName}`),\n}\n\nexport function dateToFilename(date: Date): string {\n return date.toISOString().replace(/[:.]/g, '-')\n}\n\nconst DATE = dateToFilename(new Date())\n\nfunction getErrorsPath(): string {\n return join(CACHE_PATHS.errors(), DATE + '.txt')\n}\n\nexport function getMessagesPath(\n messageLogName: string,\n forkNumber: number,\n sidechainNumber: number,\n): string {\n return join(\n CACHE_PATHS.messages(),\n `${messageLogName}${forkNumber > 0 ? `-${forkNumber}` : ''}${\n sidechainNumber > 0 ? `-sidechain-${sidechainNumber}` : ''\n }.json`,\n )\n}\n\nexport function logError(error: unknown): void {\n try {\n if (process.env.NODE_ENV === 'test') {\n console.error(error)\n }\n\n const errorStr =\n error instanceof Error ? error.stack || error.message : String(error)\n\n const errorInfo = {\n error: errorStr,\n timestamp: new Date().toISOString(),\n }\n\n if (IN_MEMORY_ERROR_LOG.length >= MAX_IN_MEMORY_ERRORS) {\n IN_MEMORY_ERROR_LOG.shift() // Remove oldest error\n }\n IN_MEMORY_ERROR_LOG.push(errorInfo)\n\n appendToLog(getErrorsPath(), {\n error: errorStr,\n })\n } catch {\n // pass\n }\n // Also send to Sentry with session ID, but don't await\n captureException(error)\n}\n\nexport function getErrorsLog(): object[] {\n return readLog(getErrorsPath())\n}\n\nexport function getInMemoryErrors(): object[] {\n return [...IN_MEMORY_ERROR_LOG]\n}\n\nfunction readLog(path: string): object[] {\n if (!existsSync(path)) {\n return []\n }\n try {\n return JSON.parse(readFileSync(path, 'utf8'))\n } catch {\n return []\n }\n}\n\nfunction appendToLog(path: string, message: object): void {\n if (process.env.USER_TYPE === 'external') {\n return\n }\n\n const dir = dirname(path)\n if (!safeMkdir(dir)) {\n return\n }\n\n // Create messages file with empty array if it doesn't exist\n if (!existsSync(path) && !safeWriteFile(path, '[]')) {\n return\n }\n\n const messages = readLog(path)\n const messageWithTimestamp = {\n ...message,\n cwd: process.cwd(),\n userType: process.env.USER_TYPE,\n sessionId: SESSION_ID,\n timestamp: new Date().toISOString(),\n version: MACRO.VERSION,\n }\n messages.push(messageWithTimestamp)\n\n safeWriteFile(path, JSON.stringify(messages, null, 2))\n}\n\nexport function overwriteLog(path: string, messages: object[]): void {\n if (process.env.USER_TYPE === 'external') {\n return\n }\n\n if (!messages.length) {\n return\n }\n\n const dir = dirname(path)\n if (!safeMkdir(dir)) {\n return\n }\n\n const messagesWithMetadata = messages.map(message => ({\n ...message,\n cwd: process.cwd(),\n userType: process.env.USER_TYPE,\n sessionId: SESSION_ID,\n timestamp: new Date().toISOString(),\n version: MACRO.VERSION,\n }))\n\n safeWriteFile(path, JSON.stringify(messagesWithMetadata, null, 2))\n}\n\nexport async function loadLogList(\n path = CACHE_PATHS.messages(),\n): Promise<LogOption[]> {\n if (!existsSync(path)) {\n logError(`No logs found at ${path}`)\n return []\n }\n\n const files = await fsPromises.readdir(path)\n const logData = await Promise.all(\n files.map(async (file, i) => {\n const fullPath = join(path, file)\n const content = await fsPromises.readFile(fullPath, 'utf8')\n const messages = JSON.parse(content) as SerializedMessage[]\n const firstMessage = messages[0]\n const lastMessage = messages[messages.length - 1]\n const firstPrompt =\n firstMessage?.type === 'user' &&\n typeof firstMessage?.message?.content === 'string'\n ? firstMessage?.message?.content\n : 'No prompt'\n\n const { date, forkNumber, sidechainNumber } = parseLogFilename(file)\n return {\n date,\n forkNumber,\n fullPath,\n messages,\n value: i, // hack: overwritten after sorting, right below this\n created: parseISOString(firstMessage?.timestamp || date),\n modified: lastMessage?.timestamp\n ? parseISOString(lastMessage.timestamp)\n : parseISOString(date),\n firstPrompt:\n firstPrompt.split('\\n')[0]?.slice(0, 50) +\n (firstPrompt.length > 50 ? '\u2026' : '') || 'No prompt',\n messageCount: messages.length,\n sidechainNumber,\n }\n }),\n )\n\n return sortLogs(logData.filter(_ => _.messages.length)).map((_, i) => ({\n ..._,\n value: i,\n }))\n}\n\nexport function parseLogFilename(filename: string): {\n date: string\n forkNumber: number | undefined\n sidechainNumber: number | undefined\n} {\n const base = filename.split('.')[0]!\n // Default timestamp format has 6 segments: 2025-01-27T01-31-35-104Z\n const segments = base.split('-')\n const hasSidechain = base.includes('-sidechain-')\n\n let date = base\n let forkNumber: number | undefined = undefined\n let sidechainNumber: number | undefined = undefined\n\n if (hasSidechain) {\n const sidechainIndex = segments.indexOf('sidechain')\n sidechainNumber = Number(segments[sidechainIndex + 1])\n // Fork number is before sidechain if exists\n if (sidechainIndex > 6) {\n forkNumber = Number(segments[sidechainIndex - 1])\n date = segments.slice(0, 6).join('-')\n } else {\n date = segments.slice(0, 6).join('-')\n }\n } else if (segments.length > 6) {\n // Has fork number\n const lastSegment = Number(segments[segments.length - 1])\n forkNumber = lastSegment >= 0 ? lastSegment : undefined\n date = segments.slice(0, 6).join('-')\n } else {\n // Basic timestamp only\n date = base\n }\n\n return { date, forkNumber, sidechainNumber }\n}\n\nexport function getNextAvailableLogForkNumber(\n date: string,\n forkNumber: number,\n // Main chain has sidechainNumber 0\n sidechainNumber: number,\n): number {\n while (existsSync(getMessagesPath(date, forkNumber, sidechainNumber))) {\n forkNumber++\n }\n return forkNumber\n}\n\nexport function getNextAvailableLogSidechainNumber(\n date: string,\n forkNumber: number,\n): number {\n let sidechainNumber = 1\n while (existsSync(getMessagesPath(date, forkNumber, sidechainNumber))) {\n sidechainNumber++\n }\n return sidechainNumber\n}\n\nexport function getForkNumberFromFilename(\n filename: string,\n): number | undefined {\n const base = filename.split('.')[0]!\n const segments = base.split('-')\n const hasSidechain = base.includes('-sidechain-')\n\n if (hasSidechain) {\n const sidechainIndex = segments.indexOf('sidechain')\n if (sidechainIndex > 6) {\n return Number(segments[sidechainIndex - 1])\n }\n return undefined\n }\n\n if (segments.length > 6) {\n const lastNumber = Number(segments[segments.length - 1])\n return lastNumber >= 0 ? lastNumber : undefined\n }\n return undefined\n}\n\nexport function sortLogs(logs: LogOption[]): LogOption[] {\n return logs.sort((a, b) => {\n // Sort by modified date (newest first)\n const modifiedDiff = b.modified.getTime() - a.modified.getTime()\n if (modifiedDiff !== 0) {\n return modifiedDiff\n }\n\n // If modified dates are equal, sort by created date\n const createdDiff = b.created.getTime() - a.created.getTime()\n if (createdDiff !== 0) {\n return createdDiff\n }\n\n // If both dates are equal, sort by fork number\n return (b.forkNumber ?? 0) - (a.forkNumber ?? 0)\n })\n}\n\nexport function formatDate(date: Date): string {\n const now = new Date()\n const yesterday = new Date(now)\n yesterday.setDate(yesterday.getDate() - 1)\n\n const isToday = date.toDateString() === now.toDateString()\n const isYesterday = date.toDateString() === yesterday.toDateString()\n\n const timeStr = date\n .toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n })\n .toLowerCase()\n\n if (isToday) {\n return `Today at ${timeStr}`\n } else if (isYesterday) {\n return `Yesterday at ${timeStr}`\n } else {\n return (\n date.toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n }) + ` at ${timeStr}`\n )\n }\n}\n\nexport function parseISOString(s: string): Date {\n const b = s.split(/\\D+/)\n return new Date(\n Date.UTC(\n parseInt(b[0]!, 10),\n parseInt(b[1]!, 10) - 1,\n parseInt(b[2]!, 10),\n parseInt(b[3]!, 10),\n parseInt(b[4]!, 10),\n parseInt(b[5]!, 10),\n parseInt(b[6]!, 10),\n ),\n )\n}\n\nexport function logMCPError(serverName: string, error: unknown): void {\n try {\n const logDir = CACHE_PATHS.mcpLogs(serverName)\n const errorStr =\n error instanceof Error ? error.stack || error.message : String(error)\n const timestamp = new Date().toISOString()\n\n const logFile = join(logDir, DATE + '.txt')\n\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true })\n }\n\n if (!existsSync(logFile)) {\n writeFileSync(logFile, '[]', 'utf8')\n }\n\n const errorInfo = {\n error: errorStr,\n timestamp,\n sessionId: SESSION_ID,\n cwd: process.cwd(),\n }\n\n const messages = readLog(logFile)\n messages.push(errorInfo)\n writeFileSync(logFile, JSON.stringify(messages, null, 2), 'utf8')\n } catch {\n // Silently fail\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,13 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, cpSync, symlinkSync, lstatSync } from "fs";
1
+ import {
2
+ existsSync,
3
+ readFileSync,
4
+ writeFileSync,
5
+ mkdirSync,
6
+ rmSync,
7
+ cpSync,
8
+ symlinkSync,
9
+ lstatSync
10
+ } from "fs";
2
11
  import { join, resolve, isAbsolute } from "path";
3
12
  import { homedir } from "os";
4
13
  import { execFileNoThrow } from "./execFileNoThrow.js";
@@ -184,10 +193,16 @@ async function updateMarketplace(name) {
184
193
  let manifest;
185
194
  switch (marketplace.source.type) {
186
195
  case "github":
187
- manifest = await fetchGitHubMarketplace(marketplace.source.repo, marketplace.source.ref);
196
+ manifest = await fetchGitHubMarketplace(
197
+ marketplace.source.repo,
198
+ marketplace.source.ref
199
+ );
188
200
  break;
189
201
  case "url":
190
- manifest = await fetchUrlMarketplace(marketplace.source.url, marketplace.source.ref);
202
+ manifest = await fetchUrlMarketplace(
203
+ marketplace.source.url,
204
+ marketplace.source.ref
205
+ );
191
206
  break;
192
207
  case "local":
193
208
  manifest = loadLocalMarketplace(marketplace.source.path);
@@ -239,7 +254,10 @@ function loadMarketplaceSettings() {
239
254
  const settings = JSON.parse(content);
240
255
  return settings;
241
256
  } catch (error) {
242
- console.error(`Error loading marketplace settings from ${label} (${path}):`, error);
257
+ console.error(
258
+ `Error loading marketplace settings from ${label} (${path}):`,
259
+ error
260
+ );
243
261
  }
244
262
  }
245
263
  }
@@ -249,12 +267,18 @@ async function autoRegisterMarketplaces() {
249
267
  const settings = loadMarketplaceSettings();
250
268
  if (!settings.extraKnownMarketplaces) return;
251
269
  const registry = loadRegistry();
252
- for (const [name, config] of Object.entries(settings.extraKnownMarketplaces)) {
270
+ for (const [name, config] of Object.entries(
271
+ settings.extraKnownMarketplaces
272
+ )) {
253
273
  if (registry.some((m) => m.name === name)) continue;
254
274
  try {
255
275
  let source;
256
276
  if (config.source.source === "github" && config.source.repo) {
257
- source = { type: "github", repo: config.source.repo, ref: config.source.ref };
277
+ source = {
278
+ type: "github",
279
+ repo: config.source.repo,
280
+ ref: config.source.ref
281
+ };
258
282
  } else if (config.source.source === "url" && config.source.url) {
259
283
  source = { type: "url", url: config.source.url, ref: config.source.ref };
260
284
  } else if (config.source.source === "local" && config.source.path) {
@@ -295,7 +319,10 @@ async function getMarketplaceRepoPath(marketplace) {
295
319
  return { path: tempDir, cleanup: true };
296
320
  }
297
321
  case "url": {
298
- const tempDir = await cloneGitRepo(marketplace.source.url, marketplace.source.ref);
322
+ const tempDir = await cloneGitRepo(
323
+ marketplace.source.url,
324
+ marketplace.source.ref
325
+ );
299
326
  return { path: tempDir, cleanup: true };
300
327
  }
301
328
  case "local": {
@@ -388,7 +415,11 @@ async function installPluginFromMarketplace(pluginName, marketplaceName, targetD
388
415
  marketplaceRepoPath = repoInfo.path;
389
416
  cleanupMarketplaceRepo = repoInfo.cleanup;
390
417
  const pluginRoot = marketplace.manifest.metadata?.pluginRoot || "";
391
- const pluginSourcePath = join(marketplaceRepoPath, pluginRoot, plugin.source);
418
+ const pluginSourcePath = join(
419
+ marketplaceRepoPath,
420
+ pluginRoot,
421
+ plugin.source
422
+ );
392
423
  if (!existsSync(pluginSourcePath)) {
393
424
  throw new MarketplaceError(
394
425
  `Plugin source path does not exist: ${pluginSourcePath} (relative path: ${plugin.source})`,
@@ -448,7 +479,11 @@ async function installPluginFromMarketplace(pluginName, marketplaceName, targetD
448
479
  keywords: plugin.keywords || [],
449
480
  category: plugin.category
450
481
  };
451
- writeFileSync(pluginManifestPath, JSON.stringify(pluginManifest, null, 2), "utf-8");
482
+ writeFileSync(
483
+ pluginManifestPath,
484
+ JSON.stringify(pluginManifest, null, 2),
485
+ "utf-8"
486
+ );
452
487
  }
453
488
  return installDir;
454
489
  } finally {