@within-7/minto 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agents/AgentsCommand.js +2342 -0
- package/dist/commands/agents/AgentsCommand.js.map +7 -0
- package/dist/commands/agents/constants.js +58 -0
- package/dist/commands/agents/constants.js.map +7 -0
- package/dist/commands/agents/index.js +37 -0
- package/dist/commands/agents/index.js.map +7 -0
- package/dist/commands/agents/types.js +10 -0
- package/dist/commands/agents/types.js.map +7 -0
- package/dist/commands/agents/utils/fileOperations.js +185 -0
- package/dist/commands/agents/utils/fileOperations.js.map +7 -0
- package/dist/commands/agents/utils/index.js +21 -0
- package/dist/commands/agents/utils/index.js.map +7 -0
- package/dist/commands/bug.js +2 -2
- package/dist/commands/bug.js.map +2 -2
- package/dist/commands/compact.js +5 -5
- package/dist/commands/compact.js.map +2 -2
- package/dist/commands/ctx_viz.js +55 -22
- package/dist/commands/ctx_viz.js.map +2 -2
- package/dist/commands/mcp-interactive.js +11 -11
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +94 -32
- package/dist/commands/model.js.map +3 -3
- package/dist/commands/plugin/AddMarketplaceForm.js +49 -21
- package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
- package/dist/commands/plugin/ConfirmDialog.js +38 -26
- package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js +24 -8
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsManager.js +3 -1
- package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
- package/dist/commands/plugin/MainMenu.js +16 -7
- package/dist/commands/plugin/MainMenu.js.map +2 -2
- package/dist/commands/plugin/MarketplaceManager.js +84 -39
- package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
- package/dist/commands/plugin/MarketplaceSelector.js +7 -3
- package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
- package/dist/commands/plugin/PlaceholderScreen.js +16 -2
- package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
- package/dist/commands/plugin/PluginBrowser.js +4 -2
- package/dist/commands/plugin/PluginBrowser.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsInstall.js +12 -6
- package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsManage.js +14 -5
- package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
- package/dist/commands/plugin/example-usage.js.map +2 -2
- package/dist/commands/plugin/utils.js.map +2 -2
- package/dist/commands/plugin.js +226 -46
- package/dist/commands/plugin.js.map +2 -2
- package/dist/commands/refreshCommands.js +6 -3
- package/dist/commands/refreshCommands.js.map +2 -2
- package/dist/commands/resume.js +2 -1
- package/dist/commands/resume.js.map +2 -2
- package/dist/commands/setup.js +19 -5
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/terminalSetup.js +2 -2
- package/dist/commands/terminalSetup.js.map +1 -1
- package/dist/commands.js +14 -30
- package/dist/commands.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/QuestionView.js +10 -1
- package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
- package/dist/components/BackgroundTasksPanel.js +5 -1
- package/dist/components/BackgroundTasksPanel.js.map +2 -2
- package/dist/components/Config.js +17 -4
- package/dist/components/Config.js.map +2 -2
- package/dist/components/ConsoleOAuthFlow.js.map +2 -2
- package/dist/components/CustomSelect/select-option.js +4 -1
- package/dist/components/CustomSelect/select-option.js.map +2 -2
- package/dist/components/Help.js +6 -8
- package/dist/components/Help.js.map +2 -2
- package/dist/components/Logo.js +1 -1
- package/dist/components/Logo.js.map +2 -2
- package/dist/components/ModelListManager.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +2030 -0
- package/dist/components/ModelSelector/ModelSelector.js.map +7 -0
- package/dist/components/ModelSelector/ScreenContainer.js +27 -0
- package/dist/components/ModelSelector/ScreenContainer.js.map +7 -0
- package/dist/components/ModelSelector/constants.js +37 -0
- package/dist/components/ModelSelector/constants.js.map +7 -0
- package/dist/components/ModelSelector/hooks/index.js +5 -0
- package/dist/components/ModelSelector/hooks/index.js.map +7 -0
- package/dist/components/ModelSelector/hooks/useEscapeNavigation.js +21 -0
- package/dist/components/ModelSelector/hooks/useEscapeNavigation.js.map +7 -0
- package/dist/components/ModelSelector/index.js +17 -0
- package/dist/components/ModelSelector/index.js.map +7 -0
- package/dist/components/ModelSelector/types.js +1 -0
- package/dist/components/ModelSelector/types.js.map +7 -0
- package/dist/components/PressEnterToContinue.js +1 -1
- package/dist/components/PressEnterToContinue.js.map +2 -2
- package/dist/components/ProjectOnboarding.js +1 -1
- package/dist/components/ProjectOnboarding.js.map +2 -2
- package/dist/components/PromptInput.js +88 -37
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/QuitSummary.js +17 -10
- package/dist/components/QuitSummary.js.map +2 -2
- package/dist/components/SentryErrorBoundary.js.map +2 -2
- package/dist/components/StreamingBashOutput.js.map +2 -2
- package/dist/components/StructuredDiff.js.map +2 -2
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TextInput.js.map +1 -1
- package/dist/components/TodoItem.js.map +1 -1
- package/dist/components/binary-feedback/BinaryFeedbackOption.js +1 -3
- package/dist/components/binary-feedback/BinaryFeedbackOption.js.map +2 -2
- package/dist/components/messages/AssistantLocalCommandOutputMessage.js.map +1 -1
- package/dist/components/messages/AssistantToolUseMessage.js +3 -1
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/TaskProgressMessage.js.map +2 -2
- package/dist/components/messages/TaskToolMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/utils.js.map +2 -2
- package/dist/components/permissions/FileEditPermissionRequest/FileEditToolDiff.js.map +2 -2
- package/dist/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js.map +2 -2
- package/dist/components/permissions/hooks.js.map +2 -2
- package/dist/constants/modelCapabilities.js +1 -1
- package/dist/constants/modelCapabilities.js.map +2 -2
- package/dist/constants/prompts.js.map +1 -1
- package/dist/constants/timing.js +34 -0
- package/dist/constants/timing.js.map +7 -0
- package/dist/entrypoints/cli.js +128 -33
- package/dist/entrypoints/cli.js.map +3 -3
- package/dist/entrypoints/mcp.js +13 -18
- package/dist/entrypoints/mcp.js.map +2 -2
- package/dist/hooks/useCanUseTool.js.map +2 -2
- package/dist/hooks/useCancelRequest.js.map +1 -1
- package/dist/hooks/useHistorySearch.js.map +2 -2
- package/dist/hooks/useLogStartupTime.js.map +2 -2
- package/dist/hooks/usePermissionRequestLogging.js.map +2 -2
- package/dist/hooks/useTextInput.js.map +1 -1
- package/dist/hooks/useUnifiedCompletion.js +493 -394
- package/dist/hooks/useUnifiedCompletion.js.map +2 -2
- package/dist/index.js.map +2 -2
- package/dist/permissions.js +4 -7
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +6 -1
- package/dist/query.js.map +2 -2
- package/dist/screens/REPL.js +72 -36
- package/dist/screens/REPL.js.map +2 -2
- package/dist/screens/ResumeConversation.js +2 -1
- package/dist/screens/ResumeConversation.js.map +2 -2
- package/dist/services/adapters/base.js.map +2 -2
- package/dist/services/adapters/chatCompletions.js.map +2 -2
- package/dist/services/adapters/responsesAPI.js +3 -1
- package/dist/services/adapters/responsesAPI.js.map +2 -2
- package/dist/services/claude.js +327 -328
- package/dist/services/claude.js.map +2 -2
- package/dist/services/customCommands.js +6 -1
- package/dist/services/customCommands.js.map +2 -2
- package/dist/services/fileFreshness.js.map +2 -2
- package/dist/services/gpt5ConnectionTest.js +20 -7
- package/dist/services/gpt5ConnectionTest.js.map +2 -2
- package/dist/services/hookExecutor.js +6 -12
- package/dist/services/hookExecutor.js.map +2 -2
- package/dist/services/mcpClient.js +29 -2
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/mentionProcessor.js +23 -10
- package/dist/services/mentionProcessor.js.map +2 -2
- package/dist/services/modelAdapterFactory.js.map +2 -2
- package/dist/services/oauth.js.map +2 -2
- package/dist/services/openai.js +109 -72
- package/dist/services/openai.js.map +3 -3
- package/dist/services/responseStateManager.js.map +2 -2
- package/dist/services/systemReminder.js.map +2 -2
- package/dist/tools/ArchitectTool/ArchitectTool.js.map +1 -1
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +14 -8
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/BashOutputTool/BashOutputTool.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +1 -4
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js +4 -1
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
- package/dist/tools/NotebookReadTool/NotebookReadTool.js +3 -1
- package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
- package/dist/tools/SkillTool/SkillTool.js +12 -6
- package/dist/tools/SkillTool/SkillTool.js.map +2 -2
- package/dist/tools/TaskTool/TaskTool.js +14 -5
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskTool/prompt.js.map +2 -2
- package/dist/tools/ThinkTool/ThinkTool.js +6 -1
- package/dist/tools/ThinkTool/ThinkTool.js.map +2 -2
- package/dist/tools/TodoWriteTool/TodoWriteTool.js +23 -3
- package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/URLFetcherTool.js +2 -2
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/cache.js +6 -3
- package/dist/tools/URLFetcherTool/cache.js.map +2 -2
- package/dist/tools/URLFetcherTool/htmlToMarkdown.js +3 -1
- package/dist/tools/URLFetcherTool/htmlToMarkdown.js.map +2 -2
- package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
- package/dist/tools/WebSearchTool/prompt.js.map +2 -2
- package/dist/tools/WebSearchTool/searchProviders.js +15 -6
- package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
- package/dist/tools.js +4 -1
- package/dist/tools.js.map +2 -2
- package/dist/types/core.js +1 -0
- package/dist/types/core.js.map +7 -0
- package/dist/types/hooks.js +1 -4
- package/dist/types/hooks.js.map +2 -2
- package/dist/types/marketplace.js +8 -2
- package/dist/types/marketplace.js.map +2 -2
- package/dist/types/plugin.js +9 -6
- package/dist/types/plugin.js.map +2 -2
- package/dist/utils/BackgroundShellManager.js +76 -10
- package/dist/utils/BackgroundShellManager.js.map +2 -2
- package/dist/utils/PersistentShell.js +7 -2
- package/dist/utils/PersistentShell.js.map +2 -2
- package/dist/utils/advancedFuzzyMatcher.js +4 -1
- package/dist/utils/advancedFuzzyMatcher.js.map +2 -2
- package/dist/utils/agentLoader.js +69 -35
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/agentStorage.js.map +2 -2
- package/dist/utils/async.js +163 -0
- package/dist/utils/async.js.map +7 -0
- package/dist/utils/autoUpdater.js +8 -2
- package/dist/utils/autoUpdater.js.map +2 -2
- package/dist/utils/commands.js +23 -11
- package/dist/utils/commands.js.map +2 -2
- package/dist/utils/commonUnixCommands.js +3 -1
- package/dist/utils/commonUnixCommands.js.map +2 -2
- package/dist/utils/compressionMode.js.map +2 -2
- package/dist/utils/config.js +30 -14
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/debugLogger.js.map +2 -2
- package/dist/utils/env.js.map +2 -2
- package/dist/utils/envConfig.js +82 -0
- package/dist/utils/envConfig.js.map +7 -0
- package/dist/utils/errorHandling.js +89 -0
- package/dist/utils/errorHandling.js.map +7 -0
- package/dist/utils/expertChatStorage.js.map +2 -2
- package/dist/utils/fuzzyMatcher.js +13 -7
- package/dist/utils/fuzzyMatcher.js.map +2 -2
- package/dist/utils/hookManager.js +14 -4
- package/dist/utils/hookManager.js.map +2 -2
- package/dist/utils/log.js.map +2 -2
- package/dist/utils/marketplaceManager.js +44 -9
- package/dist/utils/marketplaceManager.js.map +2 -2
- package/dist/utils/messageContextManager.js.map +1 -1
- package/dist/utils/messages.js +6 -3
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/model.js +3 -1
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/pluginInstaller.js +3 -15
- package/dist/utils/pluginInstaller.js.map +2 -2
- package/dist/utils/pluginLoader.js +41 -13
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/pluginRegistry.js.map +2 -2
- package/dist/utils/pluginValidator.js +71 -49
- package/dist/utils/pluginValidator.js.map +2 -2
- package/dist/utils/ptyCompat.js.map +2 -2
- package/dist/utils/roundConverter.js.map +2 -2
- package/dist/utils/secureFile.js +43 -14
- package/dist/utils/secureFile.js.map +2 -2
- package/dist/utils/sessionState.js.map +2 -2
- package/dist/utils/skillLoader.js.map +2 -2
- package/dist/utils/teamConfig.js +7 -4
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/theme.js.map +2 -2
- package/dist/utils/thinking.js.map +2 -2
- package/dist/utils/unaryLogging.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/advancedFuzzyMatcher.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Advanced Fuzzy Matching Algorithm\n
|
|
5
|
-
"mappings": "AAsBO,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA,EAIhC,MAAM,WAAmB,OAA4B;AAEnD,UAAM,OAAO,UAAU,YAAY;AACnC,UAAM,UAAU,MAAM,YAAY;AAGlC,QAAI,SAAS,SAAS;AACpB,aAAO,EAAE,OAAO,KAAO,SAAS,MAAM,WAAW,QAAQ;AAAA,IAC3D;AAGA,UAAM,aAAa;AAAA,MACjB,KAAK,iBAAiB,MAAM,OAAO;AAAA,MACnC,KAAK,iBAAiB,MAAM,OAAO;AAAA,MACnC,KAAK,kBAAkB,MAAM,OAAO;AAAA,MACpC,KAAK,kBAAkB,MAAM,OAAO;AAAA,MACpC,KAAK,mBAAmB,MAAM,OAAO;AAAA,MACrC,KAAK,iBAAiB,MAAM,OAAO;AAAA,MACnC,KAAK,kBAAkB,MAAM,OAAO;AAAA,IACtC;AAGA,QAAI,YAAY;AAChB,QAAI,gBAAgB;AAEpB,eAAW,UAAU,YAAY;AAC/B,UAAI,OAAO,QAAQ,WAAW;AAC5B,oBAAY,OAAO;AACnB,wBAAgB,OAAO;AAAA,MACzB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS,YAAY;AAAA,MACrB,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,
|
|
4
|
+
"sourcesContent": ["/**\n * Advanced Fuzzy Matching Algorithm\n *\n * Inspired by:\n * - Chinese Pinyin input methods (Sogou, Baidu)\n * - IDE intelligent completion (VSCode, IntelliJ)\n * - Terminal fuzzy finders (fzf, peco)\n *\n * Key features:\n * - Hyphen-aware matching (dao \u2192 dao-qi-harmony)\n * - Numeric suffix matching (py3 \u2192 python3)\n * - Abbreviation matching (dq \u2192 dao-qi)\n * - Subsequence matching\n * - Word boundary bonus\n */\n\nexport interface MatchResult {\n score: number\n matched: boolean\n algorithm: string\n}\n\nexport class AdvancedFuzzyMatcher {\n /**\n * Main matching function - combines multiple algorithms\n */\n match(candidate: string, query: string): MatchResult {\n // Normalize inputs\n const text = candidate.toLowerCase()\n const pattern = query.toLowerCase()\n\n // Quick exact match - give HUGE score for exact matches\n if (text === pattern) {\n return { score: 10000, matched: true, algorithm: 'exact' }\n }\n\n // Try all algorithms and combine scores\n const algorithms = [\n this.exactPrefixMatch(text, pattern),\n this.hyphenAwareMatch(text, pattern),\n this.wordBoundaryMatch(text, pattern),\n this.abbreviationMatch(text, pattern),\n this.numericSuffixMatch(text, pattern),\n this.subsequenceMatch(text, pattern),\n this.fuzzySegmentMatch(text, pattern),\n ]\n\n // Get best score\n let bestScore = 0\n let bestAlgorithm = 'none'\n\n for (const result of algorithms) {\n if (result.score > bestScore) {\n bestScore = result.score\n bestAlgorithm = result.algorithm\n }\n }\n\n return {\n score: bestScore,\n matched: bestScore > 10,\n algorithm: bestAlgorithm,\n }\n }\n\n /**\n * Exact prefix matching\n */\n private exactPrefixMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n if (text.startsWith(pattern)) {\n const coverage = pattern.length / text.length\n // Higher base score for prefix matches to prioritize them\n return { score: 1000 + coverage * 500, algorithm: 'prefix' }\n }\n return { score: 0, algorithm: 'prefix' }\n }\n\n /**\n * Hyphen-aware matching (dao \u2192 dao-qi-harmony-designer)\n * Treats hyphens as optional word boundaries\n */\n private hyphenAwareMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n // Split by hyphens and try to match\n const words = text.split('-')\n\n // Check if pattern matches the beginning of hyphenated words\n if (words[0].startsWith(pattern)) {\n const coverage = pattern.length / words[0].length\n return { score: 300 + coverage * 100, algorithm: 'hyphen-prefix' }\n }\n\n // Check if pattern matches concatenated words (ignoring hyphens)\n const concatenated = words.join('')\n if (concatenated.startsWith(pattern)) {\n const coverage = pattern.length / concatenated.length\n return { score: 250 + coverage * 100, algorithm: 'hyphen-concat' }\n }\n\n // Check if pattern matches any word start\n for (let i = 0; i < words.length; i++) {\n if (words[i].startsWith(pattern)) {\n return { score: 200 - i * 10, algorithm: 'hyphen-word' }\n }\n }\n\n return { score: 0, algorithm: 'hyphen' }\n }\n\n /**\n * Word boundary matching (dq \u2192 dao-qi)\n * Matches characters at word boundaries\n */\n private wordBoundaryMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n const words = text.split(/[-_\\s]+/)\n let patternIdx = 0\n let score = 0\n let matched = false\n\n for (const word of words) {\n if (patternIdx >= pattern.length) break\n\n if (word[0] === pattern[patternIdx]) {\n score += 50 // Bonus for word boundary match\n patternIdx++\n matched = true\n\n // Try to match more characters in this word\n for (let i = 1; i < word.length && patternIdx < pattern.length; i++) {\n if (word[i] === pattern[patternIdx]) {\n score += 20\n patternIdx++\n }\n }\n }\n }\n\n if (matched && patternIdx === pattern.length) {\n return { score, algorithm: 'word-boundary' }\n }\n\n return { score: 0, algorithm: 'word-boundary' }\n }\n\n /**\n * Abbreviation matching (nde \u2192 node, daoqi \u2192 dao-qi)\n */\n private abbreviationMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n let textIdx = 0\n let patternIdx = 0\n let score = 0\n let lastMatchIdx = -1\n\n while (patternIdx < pattern.length && textIdx < text.length) {\n if (text[textIdx] === pattern[patternIdx]) {\n // Calculate position score\n const gap = lastMatchIdx === -1 ? 0 : textIdx - lastMatchIdx - 1\n\n if (textIdx === 0) {\n score += 50 // First character match\n } else if (lastMatchIdx >= 0 && gap === 0) {\n score += 30 // Consecutive match\n } else if (text[textIdx - 1] === '-' || text[textIdx - 1] === '_') {\n score += 40 // Word boundary match\n } else {\n score += Math.max(5, 20 - gap * 2) // Distance penalty\n }\n\n lastMatchIdx = textIdx\n patternIdx++\n }\n textIdx++\n }\n\n if (patternIdx === pattern.length) {\n // Bonus for compact matches\n const spread = lastMatchIdx / pattern.length\n if (spread <= 3) score += 50\n else if (spread <= 5) score += 30\n\n return { score, algorithm: 'abbreviation' }\n }\n\n return { score: 0, algorithm: 'abbreviation' }\n }\n\n /**\n * Numeric suffix matching (py3 \u2192 python3, np18 \u2192 node18)\n */\n private numericSuffixMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n // Check if pattern has numeric suffix\n const patternMatch = pattern.match(/^(.+?)(\\d+)$/)\n if (!patternMatch) return { score: 0, algorithm: 'numeric' }\n\n const [, prefix, suffix] = patternMatch\n\n // Check if text ends with same number\n if (!text.endsWith(suffix)) return { score: 0, algorithm: 'numeric' }\n\n // Check if prefix matches start of text\n const textWithoutSuffix = text.slice(0, -suffix.length)\n if (textWithoutSuffix.startsWith(prefix)) {\n const coverage = prefix.length / textWithoutSuffix.length\n return { score: 200 + coverage * 100, algorithm: 'numeric-suffix' }\n }\n\n // Check abbreviation match for prefix\n const abbrevResult = this.abbreviationMatch(textWithoutSuffix, prefix)\n if (abbrevResult.score > 0) {\n return { score: abbrevResult.score + 50, algorithm: 'numeric-abbrev' }\n }\n\n return { score: 0, algorithm: 'numeric' }\n }\n\n /**\n * Subsequence matching - characters appear in order\n */\n private subsequenceMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n let textIdx = 0\n let patternIdx = 0\n let score = 0\n\n while (patternIdx < pattern.length && textIdx < text.length) {\n if (text[textIdx] === pattern[patternIdx]) {\n score += 10\n patternIdx++\n }\n textIdx++\n }\n\n if (patternIdx === pattern.length) {\n // Penalty for spread\n const spread = textIdx / pattern.length\n score = Math.max(10, score - spread * 5)\n return { score, algorithm: 'subsequence' }\n }\n\n return { score: 0, algorithm: 'subsequence' }\n }\n\n /**\n * Fuzzy segment matching (dao \u2192 dao-qi-harmony)\n * Matches segments flexibly\n */\n private fuzzySegmentMatch(\n text: string,\n pattern: string,\n ): { score: number; algorithm: string } {\n // Remove hyphens and underscores for matching\n const cleanText = text.replace(/[-_]/g, '')\n const cleanPattern = pattern.replace(/[-_]/g, '')\n\n // Check if clean pattern is a prefix of clean text\n if (cleanText.startsWith(cleanPattern)) {\n const coverage = cleanPattern.length / cleanText.length\n return { score: 150 + coverage * 100, algorithm: 'fuzzy-segment' }\n }\n\n // Check if pattern appears anywhere in clean text\n const index = cleanText.indexOf(cleanPattern)\n if (index !== -1) {\n const positionPenalty = index * 5\n return {\n score: Math.max(50, 100 - positionPenalty),\n algorithm: 'fuzzy-contains',\n }\n }\n\n return { score: 0, algorithm: 'fuzzy-segment' }\n }\n}\n\n// Export singleton instance and helper functions\nexport const advancedMatcher = new AdvancedFuzzyMatcher()\n\nexport function matchAdvanced(candidate: string, query: string): MatchResult {\n return advancedMatcher.match(candidate, query)\n}\n\nexport function matchManyAdvanced(\n candidates: string[],\n query: string,\n minScore: number = 10,\n): Array<{ candidate: string; score: number; algorithm: string }> {\n return candidates\n .map(candidate => {\n const result = advancedMatcher.match(candidate, query)\n return {\n candidate,\n score: result.score,\n algorithm: result.algorithm,\n }\n })\n .filter(item => item.score >= minScore)\n .sort((a, b) => b.score - a.score)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
readFileSync,
|
|
4
|
+
readdirSync,
|
|
5
|
+
statSync,
|
|
6
|
+
watch
|
|
7
|
+
} from "fs";
|
|
2
8
|
import { join } from "path";
|
|
3
9
|
import { homedir } from "os";
|
|
4
10
|
import matter from "gray-matter";
|
|
@@ -29,7 +35,9 @@ function parseTools(tools) {
|
|
|
29
35
|
if (!tools) return "*";
|
|
30
36
|
if (tools === "*") return "*";
|
|
31
37
|
if (Array.isArray(tools)) {
|
|
32
|
-
const filteredTools = tools.filter(
|
|
38
|
+
const filteredTools = tools.filter(
|
|
39
|
+
(t) => typeof t === "string"
|
|
40
|
+
);
|
|
33
41
|
return filteredTools.length > 0 ? filteredTools : "*";
|
|
34
42
|
}
|
|
35
43
|
if (typeof tools === "string") {
|
|
@@ -53,11 +61,15 @@ async function scanAgentDirectory(dirPath, location) {
|
|
|
53
61
|
const content = readFileSync(filePath, "utf-8");
|
|
54
62
|
const { data: frontmatter, content: body } = matter(content);
|
|
55
63
|
if (!frontmatter.name || !frontmatter.description) {
|
|
56
|
-
console.warn(
|
|
64
|
+
console.warn(
|
|
65
|
+
`Skipping ${filePath}: missing required fields (name, description)`
|
|
66
|
+
);
|
|
57
67
|
continue;
|
|
58
68
|
}
|
|
59
69
|
if (frontmatter.model && !frontmatter.model_name && !warnedAgents.has(frontmatter.name) && process.env.MINTO_DEBUG_AGENTS) {
|
|
60
|
-
console.warn(
|
|
70
|
+
console.warn(
|
|
71
|
+
`\u26A0\uFE0F Agent ${frontmatter.name}: 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`
|
|
72
|
+
);
|
|
61
73
|
warnedAgents.add(frontmatter.name);
|
|
62
74
|
}
|
|
63
75
|
const agent = {
|
|
@@ -91,11 +103,15 @@ async function loadPluginAgents() {
|
|
|
91
103
|
const content = readFileSync(pluginAgent.filePath, "utf-8");
|
|
92
104
|
const { data: frontmatter, content: body } = matter(content);
|
|
93
105
|
if (!frontmatter.name || !frontmatter.description) {
|
|
94
|
-
console.warn(
|
|
106
|
+
console.warn(
|
|
107
|
+
`Skipping plugin agent ${pluginAgent.filePath}: missing required fields (name, description)`
|
|
108
|
+
);
|
|
95
109
|
continue;
|
|
96
110
|
}
|
|
97
111
|
if (frontmatter.model && !frontmatter.model_name && !warnedAgents.has(frontmatter.name) && process.env.MINTO_DEBUG_AGENTS) {
|
|
98
|
-
console.warn(
|
|
112
|
+
console.warn(
|
|
113
|
+
`\u26A0\uFE0F Plugin agent ${frontmatter.name} (from ${plugin.manifest.name}): 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`
|
|
114
|
+
);
|
|
99
115
|
warnedAgents.add(frontmatter.name);
|
|
100
116
|
}
|
|
101
117
|
const agent = {
|
|
@@ -107,11 +123,16 @@ async function loadPluginAgents() {
|
|
|
107
123
|
pluginName: plugin.manifest.name,
|
|
108
124
|
...frontmatter.color && { color: frontmatter.color },
|
|
109
125
|
// Only use model_name field, ignore deprecated 'model' field
|
|
110
|
-
...frontmatter.model_name && {
|
|
126
|
+
...frontmatter.model_name && {
|
|
127
|
+
model_name: frontmatter.model_name
|
|
128
|
+
}
|
|
111
129
|
};
|
|
112
130
|
agents.push(agent);
|
|
113
131
|
} catch (error) {
|
|
114
|
-
console.warn(
|
|
132
|
+
console.warn(
|
|
133
|
+
`Failed to load plugin agent ${pluginAgent.name} from ${plugin.manifest.name}:`,
|
|
134
|
+
error
|
|
135
|
+
);
|
|
115
136
|
}
|
|
116
137
|
}
|
|
117
138
|
}
|
|
@@ -126,7 +147,13 @@ async function loadAllAgents() {
|
|
|
126
147
|
const userMintoDir = join(homedir(), ".minto", "agents");
|
|
127
148
|
const projectClaudeDir = join(getCwd(), ".claude", "agents");
|
|
128
149
|
const projectMintoDir = join(getCwd(), ".minto", "agents");
|
|
129
|
-
const [
|
|
150
|
+
const [
|
|
151
|
+
pluginAgents,
|
|
152
|
+
userClaudeAgents,
|
|
153
|
+
userMintoAgents,
|
|
154
|
+
projectClaudeAgents,
|
|
155
|
+
projectMintoAgents
|
|
156
|
+
] = await Promise.all([
|
|
130
157
|
loadPluginAgents(),
|
|
131
158
|
scanAgentDirectory(userClaudeDir, "user"),
|
|
132
159
|
scanAgentDirectory(userMintoDir, "user"),
|
|
@@ -154,7 +181,14 @@ async function loadAllAgents() {
|
|
|
154
181
|
agentMap.set(agent.agentType, agent);
|
|
155
182
|
}
|
|
156
183
|
const activeAgents = Array.from(agentMap.values());
|
|
157
|
-
const allAgents = [
|
|
184
|
+
const allAgents = [
|
|
185
|
+
...builtinAgents,
|
|
186
|
+
...pluginAgents,
|
|
187
|
+
...userClaudeAgents,
|
|
188
|
+
...userMintoAgents,
|
|
189
|
+
...projectClaudeAgents,
|
|
190
|
+
...projectMintoAgents
|
|
191
|
+
];
|
|
158
192
|
return { activeAgents, allAgents };
|
|
159
193
|
} catch (error) {
|
|
160
194
|
console.error("Failed to load agents, falling back to built-in:", error);
|
|
@@ -164,18 +198,14 @@ async function loadAllAgents() {
|
|
|
164
198
|
};
|
|
165
199
|
}
|
|
166
200
|
}
|
|
167
|
-
const getActiveAgents = memoize(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const { allAgents } = await loadAllAgents();
|
|
176
|
-
return allAgents;
|
|
177
|
-
}
|
|
178
|
-
);
|
|
201
|
+
const getActiveAgents = memoize(async () => {
|
|
202
|
+
const { activeAgents } = await loadAllAgents();
|
|
203
|
+
return activeAgents;
|
|
204
|
+
});
|
|
205
|
+
const getAllAgents = memoize(async () => {
|
|
206
|
+
const { allAgents } = await loadAllAgents();
|
|
207
|
+
return allAgents;
|
|
208
|
+
});
|
|
179
209
|
function clearAgentCache() {
|
|
180
210
|
getActiveAgents.cache?.clear?.();
|
|
181
211
|
getAllAgents.cache?.clear?.();
|
|
@@ -188,12 +218,10 @@ const getAgentByType = memoize(
|
|
|
188
218
|
return agents.find((agent) => agent.agentType === agentType);
|
|
189
219
|
}
|
|
190
220
|
);
|
|
191
|
-
const getAvailableAgentTypes = memoize(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
);
|
|
221
|
+
const getAvailableAgentTypes = memoize(async () => {
|
|
222
|
+
const agents = await getActiveAgents();
|
|
223
|
+
return agents.map((agent) => agent.agentType);
|
|
224
|
+
});
|
|
197
225
|
let watchers = [];
|
|
198
226
|
async function startAgentWatcher(onChange) {
|
|
199
227
|
await stopAgentWatcher();
|
|
@@ -203,14 +231,20 @@ async function startAgentWatcher(onChange) {
|
|
|
203
231
|
const projectMintoDir = join(getCwd(), ".minto", "agents");
|
|
204
232
|
const watchDirectory = (dirPath, label) => {
|
|
205
233
|
if (existsSync(dirPath)) {
|
|
206
|
-
const watcher = watch(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
234
|
+
const watcher = watch(
|
|
235
|
+
dirPath,
|
|
236
|
+
{ recursive: false },
|
|
237
|
+
async (eventType, filename) => {
|
|
238
|
+
if (filename && filename.endsWith(".md")) {
|
|
239
|
+
console.log(
|
|
240
|
+
`\u{1F504} Agent configuration changed in ${label}: ${filename}`
|
|
241
|
+
);
|
|
242
|
+
clearAgentCache();
|
|
243
|
+
getAllAgents.cache?.clear?.();
|
|
244
|
+
onChange?.();
|
|
245
|
+
}
|
|
212
246
|
}
|
|
213
|
-
|
|
247
|
+
);
|
|
214
248
|
watchers.push(watcher);
|
|
215
249
|
}
|
|
216
250
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/agentLoader.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Agent configuration loader\n * Loads agent configurations from markdown files with YAML frontmatter.\n * Maintains compatibility with Claude Code `.claude` agent directories while\n * prioritizing Minto-specific overrides.\n */\n\nimport { existsSync, readFileSync, readdirSync, statSync, watch, FSWatcher } from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\nimport matter from 'gray-matter'\nimport { getCwd } from './state'\nimport { memoize } from 'lodash-es'\nimport { loadAllPlugins } from './pluginLoader'\n\n// Track warned agents to avoid spam\nconst warnedAgents = new Set<string>()\n\nexport interface AgentConfig {\n agentType: string // Agent identifier (matches subagent_type)\n whenToUse: string // Description of when to use this agent\n tools: string[] | '*' // Tool permissions\n systemPrompt: string // System prompt content\n location: 'built-in' | 'user' | 'project' | 'plugin'\n color?: string // Optional UI color\n model_name?: string // Optional model override\n pluginName?: string // Source plugin name (if loaded from plugin)\n}\n\n// Built-in general-purpose agent as fallback\nconst BUILTIN_GENERAL_PURPOSE: AgentConfig = {\n agentType: 'general-purpose',\n whenToUse: 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks',\n tools: '*',\n systemPrompt: `You are a general-purpose agent. Given the user's task, use the tools available to complete it efficiently and thoroughly.\n\nWhen to use your capabilities:\n- Searching for code, configurations, and patterns across large codebases\n- Analyzing multiple files to understand system architecture \n- Investigating complex questions that require exploring many files\n- Performing multi-step research tasks\n\nGuidelines:\n- For file searches: Use Grep or Glob when you need to search broadly. Use FileRead when you know the specific file path.\n- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.\n- Be thorough: Check multiple locations, consider different naming conventions, look for related files.\n- Complete tasks directly using your capabilities.`,\n location: 'built-in'\n}\n\n/**\n * Parse tools field from frontmatter\n */\nfunction parseTools(tools: any): string[] | '*' {\n if (!tools) return '*'\n if (tools === '*') return '*'\n if (Array.isArray(tools)) {\n // Ensure all items are strings and filter out non-strings\n const filteredTools = tools.filter((t): t is string => typeof t === 'string')\n return filteredTools.length > 0 ? filteredTools : '*'\n }\n if (typeof tools === 'string') {\n return [tools]\n }\n return '*'\n}\n\n/**\n * Scan a directory for agent configuration files\n */\nasync function scanAgentDirectory(dirPath: string, location: 'user' | 'project'): Promise<AgentConfig[]> {\n if (!existsSync(dirPath)) {\n return []\n }\n\n const agents: AgentConfig[] = []\n\n try {\n const files = readdirSync(dirPath)\n\n for (const file of files) {\n if (!file.endsWith('.md')) continue\n\n const filePath = join(dirPath, file)\n const stat = statSync(filePath)\n\n if (!stat.isFile()) continue\n\n try {\n const content = readFileSync(filePath, 'utf-8')\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields\n if (!frontmatter.name || !frontmatter.description) {\n console.warn(`Skipping ${filePath}: missing required fields (name, description)`)\n continue\n }\n\n // Silently ignore deprecated 'model' field - no warnings by default\n // Only warn if MINTO_DEBUG_AGENTS environment variable is set\n if (frontmatter.model && !frontmatter.model_name && !warnedAgents.has(frontmatter.name) && process.env.MINTO_DEBUG_AGENTS) {\n console.warn(`\u26A0\uFE0F Agent ${frontmatter.name}: 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`)\n warnedAgents.add(frontmatter.name)\n }\n\n // Build agent config\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location,\n ...(frontmatter.color && { color: frontmatter.color }),\n // Only use model_name field, ignore deprecated 'model' field\n ...(frontmatter.model_name && { model_name: frontmatter.model_name })\n }\n\n agents.push(agent)\n } catch (error) {\n console.warn(`Failed to parse agent file ${filePath}:`, error)\n }\n }\n } catch (error) {\n console.warn(`Failed to scan directory ${dirPath}:`, error)\n }\n\n return agents\n}\n\n/**\n * Load agents from installed plugins\n */\nasync function loadPluginAgents(): Promise<AgentConfig[]> {\n const agents: AgentConfig[] = []\n\n try {\n const plugins = loadAllPlugins()\n\n for (const plugin of plugins) {\n // Skip disabled plugins\n if (!plugin.enabled) continue\n\n for (const pluginAgent of plugin.agents) {\n try {\n // Read the agent file to parse frontmatter and content\n const content = readFileSync(pluginAgent.filePath, 'utf-8')\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields\n if (!frontmatter.name || !frontmatter.description) {\n console.warn(`Skipping plugin agent ${pluginAgent.filePath}: missing required fields (name, description)`)\n continue\n }\n\n // Warn about deprecated 'model' field if debug mode is enabled\n if (frontmatter.model && !frontmatter.model_name && !warnedAgents.has(frontmatter.name) && process.env.MINTO_DEBUG_AGENTS) {\n console.warn(`\u26A0\uFE0F Plugin agent ${frontmatter.name} (from ${plugin.manifest.name}): 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`)\n warnedAgents.add(frontmatter.name)\n }\n\n // Build agent config\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location: 'plugin',\n pluginName: plugin.manifest.name,\n ...(frontmatter.color && { color: frontmatter.color }),\n // Only use model_name field, ignore deprecated 'model' field\n ...(frontmatter.model_name && { model_name: frontmatter.model_name })\n }\n\n agents.push(agent)\n } catch (error) {\n console.warn(`Failed to load plugin agent ${pluginAgent.name} from ${plugin.manifest.name}:`, error)\n }\n }\n }\n } catch (error) {\n console.warn('Failed to load plugin agents:', error)\n }\n\n return agents\n}\n\n/**\n * Load all agent configurations\n *\n * Directory Priority (later overrides earlier):\n * 1. Built-in agents\n * 2. Plugin agents\n * 3. ~/.claude/agents (Claude Code user directory - compatible)\n * 4. ~/.minto/agents (Minto user directory - primary)\n * 5. ./.claude/agents (Claude Code project directory - compatible)\n * 6. ./.minto/agents (Minto project directory - highest priority)\n */\nasync function loadAllAgents(): Promise<{\n activeAgents: AgentConfig[]\n allAgents: AgentConfig[]\n}> {\n try {\n // Define directories in priority order\n const userClaudeDir = join(homedir(), '.claude', 'agents')\n const userMintoDir = join(homedir(), '.minto', 'agents')\n const projectClaudeDir = join(getCwd(), '.claude', 'agents')\n const projectMintoDir = join(getCwd(), '.minto', 'agents')\n\n // Load from all sources in parallel\n const [pluginAgents, userClaudeAgents, userMintoAgents, projectClaudeAgents, projectMintoAgents] = await Promise.all([\n loadPluginAgents(),\n scanAgentDirectory(userClaudeDir, 'user'),\n scanAgentDirectory(userMintoDir, 'user'),\n scanAgentDirectory(projectClaudeDir, 'project'),\n scanAgentDirectory(projectMintoDir, 'project')\n ])\n\n // Built-in agents (currently just general-purpose)\n const builtinAgents = [BUILTIN_GENERAL_PURPOSE]\n\n // Apply priority override: built-in < plugin < .claude (user) < .minto (user) < .claude (project) < .minto (project)\n // Later entries override earlier ones with the same agentType\n const agentMap = new Map<string, AgentConfig>()\n\n // Add in priority order (later entries override earlier ones)\n for (const agent of builtinAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of pluginAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of userClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of userMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n\n const activeAgents = Array.from(agentMap.values())\n const allAgents = [...builtinAgents, ...pluginAgents, ...userClaudeAgents, ...userMintoAgents, ...projectClaudeAgents, ...projectMintoAgents]\n\n return { activeAgents, allAgents }\n } catch (error) {\n console.error('Failed to load agents, falling back to built-in:', error)\n return {\n activeAgents: [BUILTIN_GENERAL_PURPOSE],\n allAgents: [BUILTIN_GENERAL_PURPOSE]\n }\n }\n}\n\n// Memoized version for performance\nexport const getActiveAgents = memoize(\n async (): Promise<AgentConfig[]> => {\n const { activeAgents } = await loadAllAgents()\n return activeAgents\n }\n)\n\n// Get all agents (both active and overridden)\nexport const getAllAgents = memoize(\n async (): Promise<AgentConfig[]> => {\n const { allAgents } = await loadAllAgents()\n return allAgents\n }\n)\n\n// Clear cache when needed\nexport function clearAgentCache() {\n getActiveAgents.cache?.clear?.()\n getAllAgents.cache?.clear?.()\n getAgentByType.cache?.clear?.()\n getAvailableAgentTypes.cache?.clear?.()\n}\n\n// Get a specific agent by type\nexport const getAgentByType = memoize(\n async (agentType: string): Promise<AgentConfig | undefined> => {\n const agents = await getActiveAgents()\n return agents.find(agent => agent.agentType === agentType)\n }\n)\n\n// Get all available agent types for validation\nexport const getAvailableAgentTypes = memoize(\n async (): Promise<string[]> => {\n const agents = await getActiveAgents()\n return agents.map(agent => agent.agentType)\n }\n)\n\n// File watcher for hot reload\nlet watchers: FSWatcher[] = []\n\n/**\n * Start watching agent configuration directories for changes\n */\nexport async function startAgentWatcher(onChange?: () => void): Promise<void> {\n await stopAgentWatcher() // Clean up any existing watchers\n \n // Watch both Claude (.claude) and Minto (.minto) directories\n const userClaudeDir = join(homedir(), '.claude', 'agents')\n const userMintoDir = join(homedir(), '.minto', 'agents')\n const projectClaudeDir = join(getCwd(), '.claude', 'agents')\n const projectMintoDir = join(getCwd(), '.minto', 'agents')\n\n const watchDirectory = (dirPath: string, label: string) => {\n if (existsSync(dirPath)) {\n const watcher = watch(dirPath, { recursive: false }, async (eventType, filename) => {\n if (filename && filename.endsWith('.md')) {\n console.log(`\uD83D\uDD04 Agent configuration changed in ${label}: ${filename}`)\n clearAgentCache()\n // Also clear any other related caches\n getAllAgents.cache?.clear?.()\n onChange?.()\n }\n })\n watchers.push(watcher)\n }\n }\n\n // Watch all directories\n watchDirectory(userClaudeDir, 'user/.claude')\n watchDirectory(userMintoDir, 'user/.minto')\n watchDirectory(projectClaudeDir, 'project/.claude')\n watchDirectory(projectMintoDir, 'project/.minto')\n}\n\n/**\n * Stop watching agent configuration directories\n */\nexport async function stopAgentWatcher(): Promise<void> {\n // FSWatcher.close() is synchronous and does not accept a callback on Node 18/20\n try {\n for (const watcher of watchers) {\n try {\n watcher.close()\n } catch (err) {\n console.error('Failed to close file watcher:', err)\n }\n }\n } finally {\n watchers = []\n }\n}\n"],
|
|
5
|
-
"mappings": "AAOA,
|
|
4
|
+
"sourcesContent": ["/**\n * Agent configuration loader\n * Loads agent configurations from markdown files with YAML frontmatter.\n * Maintains compatibility with Claude Code `.claude` agent directories while\n * prioritizing Minto-specific overrides.\n */\n\nimport {\n existsSync,\n readFileSync,\n readdirSync,\n statSync,\n watch,\n FSWatcher,\n} from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\nimport matter from 'gray-matter'\nimport { getCwd } from './state'\nimport { memoize } from 'lodash-es'\nimport { loadAllPlugins } from './pluginLoader'\n\n// Track warned agents to avoid spam\nconst warnedAgents = new Set<string>()\n\nexport interface AgentConfig {\n agentType: string // Agent identifier (matches subagent_type)\n whenToUse: string // Description of when to use this agent\n tools: string[] | '*' // Tool permissions\n systemPrompt: string // System prompt content\n location: 'built-in' | 'user' | 'project' | 'plugin'\n color?: string // Optional UI color\n model_name?: string // Optional model override\n pluginName?: string // Source plugin name (if loaded from plugin)\n}\n\n// Built-in general-purpose agent as fallback\nconst BUILTIN_GENERAL_PURPOSE: AgentConfig = {\n agentType: 'general-purpose',\n whenToUse:\n 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks',\n tools: '*',\n systemPrompt: `You are a general-purpose agent. Given the user's task, use the tools available to complete it efficiently and thoroughly.\n\nWhen to use your capabilities:\n- Searching for code, configurations, and patterns across large codebases\n- Analyzing multiple files to understand system architecture \n- Investigating complex questions that require exploring many files\n- Performing multi-step research tasks\n\nGuidelines:\n- For file searches: Use Grep or Glob when you need to search broadly. Use FileRead when you know the specific file path.\n- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.\n- Be thorough: Check multiple locations, consider different naming conventions, look for related files.\n- Complete tasks directly using your capabilities.`,\n location: 'built-in',\n}\n\n/**\n * Parse tools field from frontmatter\n */\nfunction parseTools(tools: any): string[] | '*' {\n if (!tools) return '*'\n if (tools === '*') return '*'\n if (Array.isArray(tools)) {\n // Ensure all items are strings and filter out non-strings\n const filteredTools = tools.filter(\n (t): t is string => typeof t === 'string',\n )\n return filteredTools.length > 0 ? filteredTools : '*'\n }\n if (typeof tools === 'string') {\n return [tools]\n }\n return '*'\n}\n\n/**\n * Scan a directory for agent configuration files\n */\nasync function scanAgentDirectory(\n dirPath: string,\n location: 'user' | 'project',\n): Promise<AgentConfig[]> {\n if (!existsSync(dirPath)) {\n return []\n }\n\n const agents: AgentConfig[] = []\n\n try {\n const files = readdirSync(dirPath)\n\n for (const file of files) {\n if (!file.endsWith('.md')) continue\n\n const filePath = join(dirPath, file)\n const stat = statSync(filePath)\n\n if (!stat.isFile()) continue\n\n try {\n const content = readFileSync(filePath, 'utf-8')\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields\n if (!frontmatter.name || !frontmatter.description) {\n console.warn(\n `Skipping ${filePath}: missing required fields (name, description)`,\n )\n continue\n }\n\n // Silently ignore deprecated 'model' field - no warnings by default\n // Only warn if MINTO_DEBUG_AGENTS environment variable is set\n if (\n frontmatter.model &&\n !frontmatter.model_name &&\n !warnedAgents.has(frontmatter.name) &&\n process.env.MINTO_DEBUG_AGENTS\n ) {\n console.warn(\n `\u26A0\uFE0F Agent ${frontmatter.name}: 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`,\n )\n warnedAgents.add(frontmatter.name)\n }\n\n // Build agent config\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location,\n ...(frontmatter.color && { color: frontmatter.color }),\n // Only use model_name field, ignore deprecated 'model' field\n ...(frontmatter.model_name && { model_name: frontmatter.model_name }),\n }\n\n agents.push(agent)\n } catch (error) {\n console.warn(`Failed to parse agent file ${filePath}:`, error)\n }\n }\n } catch (error) {\n console.warn(`Failed to scan directory ${dirPath}:`, error)\n }\n\n return agents\n}\n\n/**\n * Load agents from installed plugins\n */\nasync function loadPluginAgents(): Promise<AgentConfig[]> {\n const agents: AgentConfig[] = []\n\n try {\n const plugins = loadAllPlugins()\n\n for (const plugin of plugins) {\n // Skip disabled plugins\n if (!plugin.enabled) continue\n\n for (const pluginAgent of plugin.agents) {\n try {\n // Read the agent file to parse frontmatter and content\n const content = readFileSync(pluginAgent.filePath, 'utf-8')\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields\n if (!frontmatter.name || !frontmatter.description) {\n console.warn(\n `Skipping plugin agent ${pluginAgent.filePath}: missing required fields (name, description)`,\n )\n continue\n }\n\n // Warn about deprecated 'model' field if debug mode is enabled\n if (\n frontmatter.model &&\n !frontmatter.model_name &&\n !warnedAgents.has(frontmatter.name) &&\n process.env.MINTO_DEBUG_AGENTS\n ) {\n console.warn(\n `\u26A0\uFE0F Plugin agent ${frontmatter.name} (from ${plugin.manifest.name}): 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`,\n )\n warnedAgents.add(frontmatter.name)\n }\n\n // Build agent config\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location: 'plugin',\n pluginName: plugin.manifest.name,\n ...(frontmatter.color && { color: frontmatter.color }),\n // Only use model_name field, ignore deprecated 'model' field\n ...(frontmatter.model_name && {\n model_name: frontmatter.model_name,\n }),\n }\n\n agents.push(agent)\n } catch (error) {\n console.warn(\n `Failed to load plugin agent ${pluginAgent.name} from ${plugin.manifest.name}:`,\n error,\n )\n }\n }\n }\n } catch (error) {\n console.warn('Failed to load plugin agents:', error)\n }\n\n return agents\n}\n\n/**\n * Load all agent configurations\n *\n * Directory Priority (later overrides earlier):\n * 1. Built-in agents\n * 2. Plugin agents\n * 3. ~/.claude/agents (Claude Code user directory - compatible)\n * 4. ~/.minto/agents (Minto user directory - primary)\n * 5. ./.claude/agents (Claude Code project directory - compatible)\n * 6. ./.minto/agents (Minto project directory - highest priority)\n */\nasync function loadAllAgents(): Promise<{\n activeAgents: AgentConfig[]\n allAgents: AgentConfig[]\n}> {\n try {\n // Define directories in priority order\n const userClaudeDir = join(homedir(), '.claude', 'agents')\n const userMintoDir = join(homedir(), '.minto', 'agents')\n const projectClaudeDir = join(getCwd(), '.claude', 'agents')\n const projectMintoDir = join(getCwd(), '.minto', 'agents')\n\n // Load from all sources in parallel\n const [\n pluginAgents,\n userClaudeAgents,\n userMintoAgents,\n projectClaudeAgents,\n projectMintoAgents,\n ] = await Promise.all([\n loadPluginAgents(),\n scanAgentDirectory(userClaudeDir, 'user'),\n scanAgentDirectory(userMintoDir, 'user'),\n scanAgentDirectory(projectClaudeDir, 'project'),\n scanAgentDirectory(projectMintoDir, 'project'),\n ])\n\n // Built-in agents (currently just general-purpose)\n const builtinAgents = [BUILTIN_GENERAL_PURPOSE]\n\n // Apply priority override: built-in < plugin < .claude (user) < .minto (user) < .claude (project) < .minto (project)\n // Later entries override earlier ones with the same agentType\n const agentMap = new Map<string, AgentConfig>()\n\n // Add in priority order (later entries override earlier ones)\n for (const agent of builtinAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of pluginAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of userClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of userMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n\n const activeAgents = Array.from(agentMap.values())\n const allAgents = [\n ...builtinAgents,\n ...pluginAgents,\n ...userClaudeAgents,\n ...userMintoAgents,\n ...projectClaudeAgents,\n ...projectMintoAgents,\n ]\n\n return { activeAgents, allAgents }\n } catch (error) {\n console.error('Failed to load agents, falling back to built-in:', error)\n return {\n activeAgents: [BUILTIN_GENERAL_PURPOSE],\n allAgents: [BUILTIN_GENERAL_PURPOSE],\n }\n }\n}\n\n// Memoized version for performance\nexport const getActiveAgents = memoize(async (): Promise<AgentConfig[]> => {\n const { activeAgents } = await loadAllAgents()\n return activeAgents\n})\n\n// Get all agents (both active and overridden)\nexport const getAllAgents = memoize(async (): Promise<AgentConfig[]> => {\n const { allAgents } = await loadAllAgents()\n return allAgents\n})\n\n// Clear cache when needed\nexport function clearAgentCache() {\n getActiveAgents.cache?.clear?.()\n getAllAgents.cache?.clear?.()\n getAgentByType.cache?.clear?.()\n getAvailableAgentTypes.cache?.clear?.()\n}\n\n// Get a specific agent by type\nexport const getAgentByType = memoize(\n async (agentType: string): Promise<AgentConfig | undefined> => {\n const agents = await getActiveAgents()\n return agents.find(agent => agent.agentType === agentType)\n },\n)\n\n// Get all available agent types for validation\nexport const getAvailableAgentTypes = memoize(async (): Promise<string[]> => {\n const agents = await getActiveAgents()\n return agents.map(agent => agent.agentType)\n})\n\n// File watcher for hot reload\nlet watchers: FSWatcher[] = []\n\n/**\n * Start watching agent configuration directories for changes\n */\nexport async function startAgentWatcher(onChange?: () => void): Promise<void> {\n await stopAgentWatcher() // Clean up any existing watchers\n\n // Watch both Claude (.claude) and Minto (.minto) directories\n const userClaudeDir = join(homedir(), '.claude', 'agents')\n const userMintoDir = join(homedir(), '.minto', 'agents')\n const projectClaudeDir = join(getCwd(), '.claude', 'agents')\n const projectMintoDir = join(getCwd(), '.minto', 'agents')\n\n const watchDirectory = (dirPath: string, label: string) => {\n if (existsSync(dirPath)) {\n const watcher = watch(\n dirPath,\n { recursive: false },\n async (eventType, filename) => {\n if (filename && filename.endsWith('.md')) {\n console.log(\n `\uD83D\uDD04 Agent configuration changed in ${label}: ${filename}`,\n )\n clearAgentCache()\n // Also clear any other related caches\n getAllAgents.cache?.clear?.()\n onChange?.()\n }\n },\n )\n watchers.push(watcher)\n }\n }\n\n // Watch all directories\n watchDirectory(userClaudeDir, 'user/.claude')\n watchDirectory(userMintoDir, 'user/.minto')\n watchDirectory(projectClaudeDir, 'project/.claude')\n watchDirectory(projectMintoDir, 'project/.minto')\n}\n\n/**\n * Stop watching agent configuration directories\n */\nexport async function stopAgentWatcher(): Promise<void> {\n // FSWatcher.close() is synchronous and does not accept a callback on Node 18/20\n try {\n for (const watcher of watchers) {\n try {\n watcher.close()\n } catch (err) {\n console.error('Failed to close file watcher:', err)\n }\n }\n } finally {\n watchers = []\n }\n}\n"],
|
|
5
|
+
"mappings": "AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,YAAqB;AAC9B,SAAS,eAAe;AACxB,OAAO,YAAY;AACnB,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAG/B,MAAM,eAAe,oBAAI,IAAY;AAcrC,MAAM,0BAAuC;AAAA,EAC3C,WAAW;AAAA,EACX,WACE;AAAA,EACF,OAAO;AAAA,EACP,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAad,UAAU;AACZ;AAKA,SAAS,WAAW,OAA4B;AAC9C,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,UAAU,IAAK,QAAO;AAC1B,MAAI,MAAM,QAAQ,KAAK,GAAG;AAExB,UAAM,gBAAgB,MAAM;AAAA,MAC1B,CAAC,MAAmB,OAAO,MAAM;AAAA,IACnC;AACA,WAAO,cAAc,SAAS,IAAI,gBAAgB;AAAA,EACpD;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,CAAC,KAAK;AAAA,EACf;AACA,SAAO;AACT;AAKA,eAAe,mBACb,SACA,UACwB;AACxB,MAAI,CAAC,WAAW,OAAO,GAAG;AACxB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAwB,CAAC;AAE/B,MAAI;AACF,UAAM,QAAQ,YAAY,OAAO;AAEjC,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,KAAK,SAAS,KAAK,EAAG;AAE3B,YAAM,WAAW,KAAK,SAAS,IAAI;AACnC,YAAM,OAAO,SAAS,QAAQ;AAE9B,UAAI,CAAC,KAAK,OAAO,EAAG;AAEpB,UAAI;AACF,cAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,cAAM,EAAE,MAAM,aAAa,SAAS,KAAK,IAAI,OAAO,OAAO;AAG3D,YAAI,CAAC,YAAY,QAAQ,CAAC,YAAY,aAAa;AACjD,kBAAQ;AAAA,YACN,YAAY,QAAQ;AAAA,UACtB;AACA;AAAA,QACF;AAIA,YACE,YAAY,SACZ,CAAC,YAAY,cACb,CAAC,aAAa,IAAI,YAAY,IAAI,KAClC,QAAQ,IAAI,oBACZ;AACA,kBAAQ;AAAA,YACN,sBAAY,YAAY,IAAI;AAAA,UAC9B;AACA,uBAAa,IAAI,YAAY,IAAI;AAAA,QACnC;AAGA,cAAM,QAAqB;AAAA,UACzB,WAAW,YAAY;AAAA,UACvB,WAAW,YAAY,YAAY,QAAQ,QAAQ,IAAI;AAAA,UACvD,OAAO,WAAW,YAAY,KAAK;AAAA,UACnC,cAAc,KAAK,KAAK;AAAA,UACxB;AAAA,UACA,GAAI,YAAY,SAAS,EAAE,OAAO,YAAY,MAAM;AAAA;AAAA,UAEpD,GAAI,YAAY,cAAc,EAAE,YAAY,YAAY,WAAW;AAAA,QACrE;AAEA,eAAO,KAAK,KAAK;AAAA,MACnB,SAAS,OAAO;AACd,gBAAQ,KAAK,8BAA8B,QAAQ,KAAK,KAAK;AAAA,MAC/D;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,KAAK,4BAA4B,OAAO,KAAK,KAAK;AAAA,EAC5D;AAEA,SAAO;AACT;AAKA,eAAe,mBAA2C;AACxD,QAAM,SAAwB,CAAC;AAE/B,MAAI;AACF,UAAM,UAAU,eAAe;AAE/B,eAAW,UAAU,SAAS;AAE5B,UAAI,CAAC,OAAO,QAAS;AAErB,iBAAW,eAAe,OAAO,QAAQ;AACvC,YAAI;AAEF,gBAAM,UAAU,aAAa,YAAY,UAAU,OAAO;AAC1D,gBAAM,EAAE,MAAM,aAAa,SAAS,KAAK,IAAI,OAAO,OAAO;AAG3D,cAAI,CAAC,YAAY,QAAQ,CAAC,YAAY,aAAa;AACjD,oBAAQ;AAAA,cACN,yBAAyB,YAAY,QAAQ;AAAA,YAC/C;AACA;AAAA,UACF;AAGA,cACE,YAAY,SACZ,CAAC,YAAY,cACb,CAAC,aAAa,IAAI,YAAY,IAAI,KAClC,QAAQ,IAAI,oBACZ;AACA,oBAAQ;AAAA,cACN,6BAAmB,YAAY,IAAI,UAAU,OAAO,SAAS,IAAI;AAAA,YACnE;AACA,yBAAa,IAAI,YAAY,IAAI;AAAA,UACnC;AAGA,gBAAM,QAAqB;AAAA,YACzB,WAAW,YAAY;AAAA,YACvB,WAAW,YAAY,YAAY,QAAQ,QAAQ,IAAI;AAAA,YACvD,OAAO,WAAW,YAAY,KAAK;AAAA,YACnC,cAAc,KAAK,KAAK;AAAA,YACxB,UAAU;AAAA,YACV,YAAY,OAAO,SAAS;AAAA,YAC5B,GAAI,YAAY,SAAS,EAAE,OAAO,YAAY,MAAM;AAAA;AAAA,YAEpD,GAAI,YAAY,cAAc;AAAA,cAC5B,YAAY,YAAY;AAAA,YAC1B;AAAA,UACF;AAEA,iBAAO,KAAK,KAAK;AAAA,QACnB,SAAS,OAAO;AACd,kBAAQ;AAAA,YACN,+BAA+B,YAAY,IAAI,SAAS,OAAO,SAAS,IAAI;AAAA,YAC5E;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,KAAK,iCAAiC,KAAK;AAAA,EACrD;AAEA,SAAO;AACT;AAaA,eAAe,gBAGZ;AACD,MAAI;AAEF,UAAM,gBAAgB,KAAK,QAAQ,GAAG,WAAW,QAAQ;AACzD,UAAM,eAAe,KAAK,QAAQ,GAAG,UAAU,QAAQ;AACvD,UAAM,mBAAmB,KAAK,OAAO,GAAG,WAAW,QAAQ;AAC3D,UAAM,kBAAkB,KAAK,OAAO,GAAG,UAAU,QAAQ;AAGzD,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,MAAM,QAAQ,IAAI;AAAA,MACpB,iBAAiB;AAAA,MACjB,mBAAmB,eAAe,MAAM;AAAA,MACxC,mBAAmB,cAAc,MAAM;AAAA,MACvC,mBAAmB,kBAAkB,SAAS;AAAA,MAC9C,mBAAmB,iBAAiB,SAAS;AAAA,IAC/C,CAAC;AAGD,UAAM,gBAAgB,CAAC,uBAAuB;AAI9C,UAAM,WAAW,oBAAI,IAAyB;AAG9C,eAAW,SAAS,eAAe;AACjC,eAAS,IAAI,MAAM,WAAW,KAAK;AAAA,IACrC;AACA,eAAW,SAAS,cAAc;AAChC,eAAS,IAAI,MAAM,WAAW,KAAK;AAAA,IACrC;AACA,eAAW,SAAS,kBAAkB;AACpC,eAAS,IAAI,MAAM,WAAW,KAAK;AAAA,IACrC;AACA,eAAW,SAAS,iBAAiB;AACnC,eAAS,IAAI,MAAM,WAAW,KAAK;AAAA,IACrC;AACA,eAAW,SAAS,qBAAqB;AACvC,eAAS,IAAI,MAAM,WAAW,KAAK;AAAA,IACrC;AACA,eAAW,SAAS,oBAAoB;AACtC,eAAS,IAAI,MAAM,WAAW,KAAK;AAAA,IACrC;AAEA,UAAM,eAAe,MAAM,KAAK,SAAS,OAAO,CAAC;AACjD,UAAM,YAAY;AAAA,MAChB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAEA,WAAO,EAAE,cAAc,UAAU;AAAA,EACnC,SAAS,OAAO;AACd,YAAQ,MAAM,oDAAoD,KAAK;AACvE,WAAO;AAAA,MACL,cAAc,CAAC,uBAAuB;AAAA,MACtC,WAAW,CAAC,uBAAuB;AAAA,IACrC;AAAA,EACF;AACF;AAGO,MAAM,kBAAkB,QAAQ,YAAoC;AACzE,QAAM,EAAE,aAAa,IAAI,MAAM,cAAc;AAC7C,SAAO;AACT,CAAC;AAGM,MAAM,eAAe,QAAQ,YAAoC;AACtE,QAAM,EAAE,UAAU,IAAI,MAAM,cAAc;AAC1C,SAAO;AACT,CAAC;AAGM,SAAS,kBAAkB;AAChC,kBAAgB,OAAO,QAAQ;AAC/B,eAAa,OAAO,QAAQ;AAC5B,iBAAe,OAAO,QAAQ;AAC9B,yBAAuB,OAAO,QAAQ;AACxC;AAGO,MAAM,iBAAiB;AAAA,EAC5B,OAAO,cAAwD;AAC7D,UAAM,SAAS,MAAM,gBAAgB;AACrC,WAAO,OAAO,KAAK,WAAS,MAAM,cAAc,SAAS;AAAA,EAC3D;AACF;AAGO,MAAM,yBAAyB,QAAQ,YAA+B;AAC3E,QAAM,SAAS,MAAM,gBAAgB;AACrC,SAAO,OAAO,IAAI,WAAS,MAAM,SAAS;AAC5C,CAAC;AAGD,IAAI,WAAwB,CAAC;AAK7B,eAAsB,kBAAkB,UAAsC;AAC5E,QAAM,iBAAiB;AAGvB,QAAM,gBAAgB,KAAK,QAAQ,GAAG,WAAW,QAAQ;AACzD,QAAM,eAAe,KAAK,QAAQ,GAAG,UAAU,QAAQ;AACvD,QAAM,mBAAmB,KAAK,OAAO,GAAG,WAAW,QAAQ;AAC3D,QAAM,kBAAkB,KAAK,OAAO,GAAG,UAAU,QAAQ;AAEzD,QAAM,iBAAiB,CAAC,SAAiB,UAAkB;AACzD,QAAI,WAAW,OAAO,GAAG;AACvB,YAAM,UAAU;AAAA,QACd;AAAA,QACA,EAAE,WAAW,MAAM;AAAA,QACnB,OAAO,WAAW,aAAa;AAC7B,cAAI,YAAY,SAAS,SAAS,KAAK,GAAG;AACxC,oBAAQ;AAAA,cACN,4CAAqC,KAAK,KAAK,QAAQ;AAAA,YACzD;AACA,4BAAgB;AAEhB,yBAAa,OAAO,QAAQ;AAC5B,uBAAW;AAAA,UACb;AAAA,QACF;AAAA,MACF;AACA,eAAS,KAAK,OAAO;AAAA,IACvB;AAAA,EACF;AAGA,iBAAe,eAAe,cAAc;AAC5C,iBAAe,cAAc,aAAa;AAC1C,iBAAe,kBAAkB,iBAAiB;AAClD,iBAAe,iBAAiB,gBAAgB;AAClD;AAKA,eAAsB,mBAAkC;AAEtD,MAAI;AACF,eAAW,WAAW,UAAU;AAC9B,UAAI;AACF,gBAAQ,MAAM;AAAA,MAChB,SAAS,KAAK;AACZ,gBAAQ,MAAM,iCAAiC,GAAG;AAAA,MACpD;AAAA,IACF;AAAA,EACF,UAAE;AACA,eAAW,CAAC;AAAA,EACd;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/agentStorage.ts"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport { randomUUID } from 'crypto'\n\n/**\n * Agent Storage Utilities\n * Provides file-based state isolation for different agents\n * Based on Minto's Agent ID architecture\n */\n\n/**\n * Get the minto config directory\n * Priority: MINTO_CONFIG_DIR > CLAUDE_CONFIG_DIR > ~/.minto\n */\nfunction getConfigDirectory(): string {\n return process.env.MINTO_CONFIG_DIR
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAY3B,SAAS,qBAA6B;AACpC,
|
|
4
|
+
"sourcesContent": ["import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport { randomUUID } from 'crypto'\n\n/**\n * Agent Storage Utilities\n * Provides file-based state isolation for different agents\n * Based on Minto's Agent ID architecture\n */\n\n/**\n * Get the minto config directory\n * Priority: MINTO_CONFIG_DIR > CLAUDE_CONFIG_DIR > ~/.minto\n */\nfunction getConfigDirectory(): string {\n return (\n process.env.MINTO_CONFIG_DIR ??\n process.env.CLAUDE_CONFIG_DIR ??\n join(homedir(), '.minto')\n )\n}\n\n/**\n * Get the current session ID\n */\nfunction getSessionId(): string {\n // This should be set when the session starts\n return process.env.MINTO_SESSION_ID ?? 'default-session'\n}\n\n/**\n * Generate agent-specific file path\n * Pattern: ${sessionId}-agent-${agentId}.json\n * Stored in ~/.minto/ directory\n */\nexport function getAgentFilePath(agentId: string): string {\n const sessionId = getSessionId()\n const filename = `${sessionId}-agent-${agentId}.json`\n const configDir = getConfigDirectory()\n\n // Ensure minto config directory exists\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true })\n }\n\n return join(configDir, filename)\n}\n\n/**\n * Read agent-specific data from storage\n */\nexport function readAgentData<T = any>(agentId: string): T | null {\n const filePath = getAgentFilePath(agentId)\n\n if (!existsSync(filePath)) {\n return null\n }\n\n try {\n const content = readFileSync(filePath, 'utf-8')\n return JSON.parse(content) as T\n } catch (error) {\n console.error(`Failed to read agent data for ${agentId}:`, error)\n return null\n }\n}\n\n/**\n * Write agent-specific data to storage\n */\nexport function writeAgentData<T = any>(agentId: string, data: T): void {\n const filePath = getAgentFilePath(agentId)\n\n try {\n writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8')\n } catch (error) {\n console.error(`Failed to write agent data for ${agentId}:`, error)\n throw error\n }\n}\n\n/**\n * Get default agent ID if none is provided\n */\nexport function getDefaultAgentId(): string {\n return 'default'\n}\n\n/**\n * Resolve agent ID from context\n */\nexport function resolveAgentId(agentId?: string): string {\n return agentId || getDefaultAgentId()\n}\n\n/**\n * Generate a new unique Agent ID\n */\nexport function generateAgentId(): string {\n return randomUUID()\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAY3B,SAAS,qBAA6B;AACpC,SACE,QAAQ,IAAI,oBACZ,QAAQ,IAAI,qBACZ,KAAK,QAAQ,GAAG,QAAQ;AAE5B;AAKA,SAAS,eAAuB;AAE9B,SAAO,QAAQ,IAAI,oBAAoB;AACzC;AAOO,SAAS,iBAAiB,SAAyB;AACxD,QAAM,YAAY,aAAa;AAC/B,QAAM,WAAW,GAAG,SAAS,UAAU,OAAO;AAC9C,QAAM,YAAY,mBAAmB;AAGrC,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,cAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AAEA,SAAO,KAAK,WAAW,QAAQ;AACjC;AAKO,SAAS,cAAuB,SAA2B;AAChE,QAAM,WAAW,iBAAiB,OAAO;AAEzC,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,iCAAiC,OAAO,KAAK,KAAK;AAChE,WAAO;AAAA,EACT;AACF;AAKO,SAAS,eAAwB,SAAiB,MAAe;AACtE,QAAM,WAAW,iBAAiB,OAAO;AAEzC,MAAI;AACF,kBAAc,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,OAAO;AAAA,EAChE,SAAS,OAAO;AACd,YAAQ,MAAM,kCAAkC,OAAO,KAAK,KAAK;AACjE,UAAM;AAAA,EACR;AACF;AAKO,SAAS,oBAA4B;AAC1C,SAAO;AACT;AAKO,SAAS,eAAe,SAA0B;AACvD,SAAO,WAAW,kBAAkB;AACtC;AAKO,SAAS,kBAA0B;AACxC,SAAO,WAAW;AACpB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const DEFAULT_RETRY_CONFIG = {
|
|
2
|
+
baseDelayMs: 1e3,
|
|
3
|
+
maxDelayMs: 32e3,
|
|
4
|
+
maxServerDelayMs: 6e4,
|
|
5
|
+
jitterFactor: 0.1
|
|
6
|
+
};
|
|
7
|
+
function abortableDelay(delayMs, signal) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (signal?.aborted) {
|
|
10
|
+
reject(new Error("Request was aborted"));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const timeoutId = setTimeout(() => {
|
|
14
|
+
resolve();
|
|
15
|
+
}, delayMs);
|
|
16
|
+
if (signal) {
|
|
17
|
+
const abortHandler = () => {
|
|
18
|
+
clearTimeout(timeoutId);
|
|
19
|
+
reject(new Error("Request was aborted"));
|
|
20
|
+
};
|
|
21
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function getRetryDelay(attempt, retryAfterHeader, config = DEFAULT_RETRY_CONFIG) {
|
|
26
|
+
if (retryAfterHeader) {
|
|
27
|
+
const retryAfterMs = parseInt(retryAfterHeader, 10) * 1e3;
|
|
28
|
+
if (!isNaN(retryAfterMs) && retryAfterMs > 0) {
|
|
29
|
+
return Math.min(retryAfterMs, config.maxServerDelayMs);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const delay = config.baseDelayMs * Math.pow(2, attempt - 1);
|
|
33
|
+
const jitter = Math.random() * config.jitterFactor * delay;
|
|
34
|
+
return Math.min(delay + jitter, config.maxDelayMs);
|
|
35
|
+
}
|
|
36
|
+
function withTimeout(promise, timeoutMs, message = "Operation timed out") {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const timeoutId = setTimeout(() => {
|
|
39
|
+
reject(new Error(message));
|
|
40
|
+
}, timeoutMs);
|
|
41
|
+
promise.then((result) => {
|
|
42
|
+
clearTimeout(timeoutId);
|
|
43
|
+
resolve(result);
|
|
44
|
+
}).catch((error) => {
|
|
45
|
+
clearTimeout(timeoutId);
|
|
46
|
+
reject(error);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function createTimeoutController(timeoutMs) {
|
|
51
|
+
const controller = new AbortController();
|
|
52
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
53
|
+
return {
|
|
54
|
+
controller,
|
|
55
|
+
cleanup: () => clearTimeout(timeoutId)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function retryWithBackoff(fn, options = {}) {
|
|
59
|
+
const {
|
|
60
|
+
maxRetries = 3,
|
|
61
|
+
signal,
|
|
62
|
+
config = DEFAULT_RETRY_CONFIG,
|
|
63
|
+
onRetry
|
|
64
|
+
} = options;
|
|
65
|
+
const fullConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
|
|
66
|
+
let lastError;
|
|
67
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
68
|
+
if (signal?.aborted) {
|
|
69
|
+
throw new Error("Request was aborted");
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return await fn();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
75
|
+
if (attempt < maxRetries) {
|
|
76
|
+
onRetry?.(attempt, lastError);
|
|
77
|
+
const delay = getRetryDelay(attempt, void 0, fullConfig);
|
|
78
|
+
await abortableDelay(delay, signal);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw lastError ?? new Error("Retry failed with unknown error");
|
|
83
|
+
}
|
|
84
|
+
function memoizeWithLimit(fn, options = {}) {
|
|
85
|
+
const { max = 100, ttl = 6e4, resolver } = options;
|
|
86
|
+
const cache = /* @__PURE__ */ new Map();
|
|
87
|
+
const evictOldest = () => {
|
|
88
|
+
if (cache.size >= max) {
|
|
89
|
+
const oldest = cache.keys().next().value;
|
|
90
|
+
if (oldest) cache.delete(oldest);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const isExpired = (entry) => {
|
|
94
|
+
return Date.now() - entry.timestamp > ttl;
|
|
95
|
+
};
|
|
96
|
+
return ((...args) => {
|
|
97
|
+
const key = resolver ? resolver(...args) : JSON.stringify(args);
|
|
98
|
+
const existing = cache.get(key);
|
|
99
|
+
if (existing && !isExpired(existing)) {
|
|
100
|
+
cache.delete(key);
|
|
101
|
+
cache.set(key, existing);
|
|
102
|
+
return existing.value;
|
|
103
|
+
}
|
|
104
|
+
if (existing) {
|
|
105
|
+
cache.delete(key);
|
|
106
|
+
}
|
|
107
|
+
const value = fn(...args);
|
|
108
|
+
evictOldest();
|
|
109
|
+
cache.set(key, { value, timestamp: Date.now() });
|
|
110
|
+
return value;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function memoizeAsyncWithLimit(fn, options = {}) {
|
|
114
|
+
const { max = 100, ttl = 6e4, resolver } = options;
|
|
115
|
+
const cache = /* @__PURE__ */ new Map();
|
|
116
|
+
const pending = /* @__PURE__ */ new Map();
|
|
117
|
+
const evictOldest = () => {
|
|
118
|
+
if (cache.size >= max) {
|
|
119
|
+
const oldest = cache.keys().next().value;
|
|
120
|
+
if (oldest) cache.delete(oldest);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const isExpired = (entry) => {
|
|
124
|
+
return Date.now() - entry.timestamp > ttl;
|
|
125
|
+
};
|
|
126
|
+
return (async (...args) => {
|
|
127
|
+
const key = resolver ? resolver(...args) : JSON.stringify(args);
|
|
128
|
+
const existing = cache.get(key);
|
|
129
|
+
if (existing && !isExpired(existing)) {
|
|
130
|
+
cache.delete(key);
|
|
131
|
+
cache.set(key, existing);
|
|
132
|
+
return existing.value;
|
|
133
|
+
}
|
|
134
|
+
const pendingPromise = pending.get(key);
|
|
135
|
+
if (pendingPromise) {
|
|
136
|
+
return pendingPromise;
|
|
137
|
+
}
|
|
138
|
+
if (existing) {
|
|
139
|
+
cache.delete(key);
|
|
140
|
+
}
|
|
141
|
+
const promise = fn(...args);
|
|
142
|
+
pending.set(key, promise);
|
|
143
|
+
try {
|
|
144
|
+
const value = await promise;
|
|
145
|
+
evictOldest();
|
|
146
|
+
cache.set(key, { value, timestamp: Date.now() });
|
|
147
|
+
return value;
|
|
148
|
+
} finally {
|
|
149
|
+
pending.delete(key);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
DEFAULT_RETRY_CONFIG,
|
|
155
|
+
abortableDelay,
|
|
156
|
+
createTimeoutController,
|
|
157
|
+
getRetryDelay,
|
|
158
|
+
memoizeAsyncWithLimit,
|
|
159
|
+
memoizeWithLimit,
|
|
160
|
+
retryWithBackoff,
|
|
161
|
+
withTimeout
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=async.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/async.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared async utilities for consistent async patterns across the codebase.\n * Extracted from claude.ts and openai.ts to eliminate code duplication.\n */\n\nexport interface RetryConfig {\n baseDelayMs: number\n maxDelayMs: number\n maxServerDelayMs: number\n jitterFactor: number\n}\n\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n baseDelayMs: 1000,\n maxDelayMs: 32000,\n maxServerDelayMs: 60000,\n jitterFactor: 0.1,\n}\n\nexport interface RetryOptions {\n maxRetries?: number\n signal?: AbortSignal\n config?: Partial<RetryConfig>\n onRetry?: (attempt: number, error: Error) => void\n}\n\n/**\n * Creates a promise that resolves after the specified delay.\n * Can be aborted via an AbortSignal.\n */\nexport function abortableDelay(\n delayMs: number,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error('Request was aborted'))\n return\n }\n\n const timeoutId = setTimeout(() => {\n resolve()\n }, delayMs)\n\n if (signal) {\n const abortHandler = () => {\n clearTimeout(timeoutId)\n reject(new Error('Request was aborted'))\n }\n signal.addEventListener('abort', abortHandler, { once: true })\n }\n })\n}\n\n/**\n * Calculate retry delay with exponential backoff and optional jitter.\n * Respects server-provided Retry-After headers when available.\n */\nexport function getRetryDelay(\n attempt: number,\n retryAfterHeader?: string | null,\n config: RetryConfig = DEFAULT_RETRY_CONFIG,\n): number {\n if (retryAfterHeader) {\n const retryAfterMs = parseInt(retryAfterHeader, 10) * 1000\n if (!isNaN(retryAfterMs) && retryAfterMs > 0) {\n return Math.min(retryAfterMs, config.maxServerDelayMs)\n }\n }\n\n const delay = config.baseDelayMs * Math.pow(2, attempt - 1)\n const jitter = Math.random() * config.jitterFactor * delay\n\n return Math.min(delay + jitter, config.maxDelayMs)\n}\n\n/**\n * Wraps a promise with a timeout.\n * Rejects with a timeout error if the promise doesn't resolve in time.\n */\nexport function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message = 'Operation timed out',\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error(message))\n }, timeoutMs)\n\n promise\n .then(result => {\n clearTimeout(timeoutId)\n resolve(result)\n })\n .catch(error => {\n clearTimeout(timeoutId)\n reject(error)\n })\n })\n}\n\n/**\n * Creates an AbortController that automatically aborts after the specified timeout.\n * Returns both the controller and a cleanup function.\n */\nexport function createTimeoutController(timeoutMs: number): {\n controller: AbortController\n cleanup: () => void\n} {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs)\n\n return {\n controller,\n cleanup: () => clearTimeout(timeoutId),\n }\n}\n\n/**\n * Retries an async function with exponential backoff.\n * Supports abort signals and custom retry conditions.\n */\nexport async function retryWithBackoff<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {},\n): Promise<T> {\n const {\n maxRetries = 3,\n signal,\n config = DEFAULT_RETRY_CONFIG,\n onRetry,\n } = options\n\n const fullConfig = { ...DEFAULT_RETRY_CONFIG, ...config }\n let lastError: Error | undefined\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n if (signal?.aborted) {\n throw new Error('Request was aborted')\n }\n\n try {\n return await fn()\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error))\n\n if (attempt < maxRetries) {\n onRetry?.(attempt, lastError)\n const delay = getRetryDelay(attempt, undefined, fullConfig)\n await abortableDelay(delay, signal)\n }\n }\n }\n\n throw lastError ?? new Error('Retry failed with unknown error')\n}\n\n/**\n * Options for memoizeWithLimit\n */\nexport interface MemoizeOptions<T extends (...args: unknown[]) => unknown> {\n /** Maximum number of cached entries (default: 100) */\n max?: number\n /** Time-to-live in milliseconds (default: 60000) */\n ttl?: number\n /** Custom resolver function to generate cache key from arguments */\n resolver?: (...args: Parameters<T>) => string\n}\n\n/**\n * Creates a memoized version of a function with LRU cache and TTL.\n * Unlike lodash memoize which has unlimited cache, this has bounded memory usage.\n *\n * @param fn - The function to memoize\n * @param options - Cache configuration options\n * @returns Memoized function\n */\nexport function memoizeWithLimit<T extends (...args: unknown[]) => unknown>(\n fn: T,\n options: MemoizeOptions<T> = {},\n): T {\n const { max = 100, ttl = 60000, resolver } = options\n\n interface CacheEntry {\n value: ReturnType<T>\n timestamp: number\n }\n\n const cache = new Map<string, CacheEntry>()\n\n // LRU eviction helper\n const evictOldest = () => {\n if (cache.size >= max) {\n const oldest = cache.keys().next().value\n if (oldest) cache.delete(oldest)\n }\n }\n\n // Check if entry is expired\n const isExpired = (entry: CacheEntry): boolean => {\n return Date.now() - entry.timestamp > ttl\n }\n\n return ((...args: Parameters<T>): ReturnType<T> => {\n const key = resolver ? resolver(...args) : JSON.stringify(args)\n\n // Check cache\n const existing = cache.get(key)\n if (existing && !isExpired(existing)) {\n // Move to end for LRU\n cache.delete(key)\n cache.set(key, existing)\n return existing.value\n }\n\n // Remove expired entry if exists\n if (existing) {\n cache.delete(key)\n }\n\n // Compute new value\n const value = fn(...args) as ReturnType<T>\n\n // Evict oldest if at capacity\n evictOldest()\n\n // Store in cache\n cache.set(key, { value, timestamp: Date.now() })\n\n return value\n }) as T\n}\n\n/**\n * Async version of memoizeWithLimit for async functions\n */\nexport function memoizeAsyncWithLimit<\n T extends (...args: unknown[]) => Promise<unknown>,\n>(fn: T, options: MemoizeOptions<T> = {}): T {\n const { max = 100, ttl = 60000, resolver } = options\n\n interface CacheEntry {\n value: Awaited<ReturnType<T>>\n timestamp: number\n }\n\n const cache = new Map<string, CacheEntry>()\n const pending = new Map<string, Promise<Awaited<ReturnType<T>>>>()\n\n const evictOldest = () => {\n if (cache.size >= max) {\n const oldest = cache.keys().next().value\n if (oldest) cache.delete(oldest)\n }\n }\n\n const isExpired = (entry: CacheEntry): boolean => {\n return Date.now() - entry.timestamp > ttl\n }\n\n return (async (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>> => {\n const key = resolver ? resolver(...args) : JSON.stringify(args)\n\n // Check cache\n const existing = cache.get(key)\n if (existing && !isExpired(existing)) {\n cache.delete(key)\n cache.set(key, existing)\n return existing.value\n }\n\n // Check pending\n const pendingPromise = pending.get(key)\n if (pendingPromise) {\n return pendingPromise\n }\n\n // Remove expired\n if (existing) {\n cache.delete(key)\n }\n\n // Compute new value\n const promise = fn(...args) as Promise<Awaited<ReturnType<T>>>\n pending.set(key, promise)\n\n try {\n const value = await promise\n evictOldest()\n cache.set(key, { value, timestamp: Date.now() })\n return value\n } finally {\n pending.delete(key)\n }\n }) as T\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -3,7 +3,11 @@ import { logError } from "./log.js";
|
|
|
3
3
|
import { lt, gt } from "semver";
|
|
4
4
|
import { MACRO } from "../constants/macros.js";
|
|
5
5
|
import { PRODUCT_NAME } from "../constants/product.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getGlobalConfig,
|
|
8
|
+
saveGlobalConfig,
|
|
9
|
+
isAutoUpdaterDisabled
|
|
10
|
+
} from "./config.js";
|
|
7
11
|
import { env } from "./env.js";
|
|
8
12
|
async function assertMinVersion() {
|
|
9
13
|
try {
|
|
@@ -88,7 +92,9 @@ async function checkAndNotifyUpdate() {
|
|
|
88
92
|
lastSuggestedVersion: latest
|
|
89
93
|
});
|
|
90
94
|
const suggestions = await getUpdateCommandSuggestions();
|
|
91
|
-
console.log(
|
|
95
|
+
console.log(
|
|
96
|
+
`New version available: ${latest} (current: ${MACRO.VERSION})`
|
|
97
|
+
);
|
|
92
98
|
console.log("Run the following command to update:");
|
|
93
99
|
for (const command of suggestions) console.log(` ${command}`);
|
|
94
100
|
} else {
|