@within-7/minto 0.2.0 → 0.3.3
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 +22 -24
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/context.js +2 -1
- package/dist/commands/context.js.map +2 -2
- package/dist/commands/export.js +2 -1
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/mcp-interactive.js +7 -6
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +3 -2
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/permissions.js +4 -3
- package/dist/commands/permissions.js.map +2 -2
- package/dist/commands/plugin/AddMarketplaceForm.js +3 -2
- package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
- package/dist/commands/plugin/ConfirmDialog.js +2 -1
- package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
- package/dist/commands/plugin/ErrorView.js +2 -1
- package/dist/commands/plugin/ErrorView.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js +5 -4
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsManager.js +5 -4
- package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
- package/dist/commands/plugin/MainMenu.js +2 -1
- package/dist/commands/plugin/MainMenu.js.map +2 -2
- package/dist/commands/plugin/MarketplaceManager.js +5 -4
- package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
- package/dist/commands/plugin/MarketplaceSelector.js +4 -3
- package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
- package/dist/commands/plugin/PlaceholderScreen.js +3 -2
- package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
- package/dist/commands/plugin/PluginBrowser.js +6 -5
- package/dist/commands/plugin/PluginBrowser.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsInstall.js +5 -4
- package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsManage.js +4 -3
- package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
- package/dist/commands/plugin.js +16 -15
- package/dist/commands/plugin.js.map +2 -2
- package/dist/commands/sandbox.js +4 -3
- package/dist/commands/sandbox.js.map +2 -2
- package/dist/commands/setup.js +2 -1
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/status.js +2 -1
- package/dist/commands/status.js.map +2 -2
- package/dist/commands/undo.js +245 -0
- package/dist/commands/undo.js.map +7 -0
- package/dist/commands.js +2 -0
- package/dist/commands.js.map +2 -2
- package/dist/components/AgentThinkingBlock.js +1 -1
- package/dist/components/AgentThinkingBlock.js.map +2 -2
- package/dist/components/AsciiLogo.js +7 -8
- package/dist/components/AsciiLogo.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/QuestionView.js +2 -1
- package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
- package/dist/components/CollapsibleHint.js +2 -1
- package/dist/components/CollapsibleHint.js.map +2 -2
- package/dist/components/Config.js +3 -2
- package/dist/components/Config.js.map +2 -2
- package/dist/components/ConsoleOAuthFlow.js +2 -1
- package/dist/components/ConsoleOAuthFlow.js.map +2 -2
- package/dist/components/Cost.js +2 -1
- package/dist/components/Cost.js.map +2 -2
- package/dist/components/HeaderBar.js +13 -8
- package/dist/components/HeaderBar.js.map +2 -2
- package/dist/components/HistorySearchOverlay.js +4 -3
- package/dist/components/HistorySearchOverlay.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +8 -11
- package/dist/components/HotkeyHelpPanel.js.map +2 -2
- package/dist/components/InvalidConfigDialog.js +2 -1
- package/dist/components/InvalidConfigDialog.js.map +2 -2
- package/dist/components/Logo.js +23 -67
- package/dist/components/Logo.js.map +2 -2
- package/dist/components/MCPServerApprovalDialog.js +2 -1
- package/dist/components/MCPServerApprovalDialog.js.map +2 -2
- package/dist/components/MCPServerDialogCopy.js +2 -1
- package/dist/components/MCPServerDialogCopy.js.map +2 -2
- package/dist/components/MCPServerMultiselectDialog.js +2 -1
- package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
- package/dist/components/MessageSelector.js +4 -3
- package/dist/components/MessageSelector.js.map +2 -2
- package/dist/components/ModeIndicator.js +2 -1
- package/dist/components/ModeIndicator.js.map +2 -2
- package/dist/components/ModelConfig.js +4 -3
- package/dist/components/ModelConfig.js.map +2 -2
- package/dist/components/ModelListManager.js +4 -3
- package/dist/components/ModelListManager.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +26 -13
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/Onboarding.js +3 -2
- package/dist/components/Onboarding.js.map +2 -2
- package/dist/components/OperationSummary.js +130 -0
- package/dist/components/OperationSummary.js.map +7 -0
- package/dist/components/PromptInput.js +88 -75
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/SensitiveFileWarning.js +31 -0
- package/dist/components/SensitiveFileWarning.js.map +7 -0
- package/dist/components/Spinner.js +71 -22
- package/dist/components/Spinner.js.map +2 -2
- package/dist/components/StructuredDiff.js +6 -8
- package/dist/components/StructuredDiff.js.map +2 -2
- package/dist/components/SubagentBlock.js +4 -2
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/SubagentProgress.js +17 -6
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TaskCard.js +14 -11
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TextInput.js +9 -1
- package/dist/components/TextInput.js.map +2 -2
- package/dist/components/TodoPanel.js +44 -26
- package/dist/components/TodoPanel.js.map +2 -2
- package/dist/components/ToolUseLoader.js +2 -2
- package/dist/components/ToolUseLoader.js.map +2 -2
- package/dist/components/TreeConnector.js +4 -3
- package/dist/components/TreeConnector.js.map +2 -2
- package/dist/components/TrustDialog.js +2 -1
- package/dist/components/TrustDialog.js.map +2 -2
- package/dist/components/binary-feedback/BinaryFeedbackView.js +2 -1
- package/dist/components/binary-feedback/BinaryFeedbackView.js.map +2 -2
- package/dist/components/messages/AssistantTextMessage.js +17 -9
- package/dist/components/messages/AssistantTextMessage.js.map +2 -2
- package/dist/components/messages/AssistantToolUseMessage.js +8 -4
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/GroupRenderer.js +2 -1
- package/dist/components/messages/GroupRenderer.js.map +2 -2
- package/dist/components/messages/NestedTasksPreview.js +13 -1
- package/dist/components/messages/NestedTasksPreview.js.map +2 -2
- package/dist/components/messages/ParallelTasksGroupView.js +4 -3
- package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
- package/dist/components/messages/TaskInModuleView.js +35 -15
- package/dist/components/messages/TaskInModuleView.js.map +2 -2
- package/dist/components/messages/TaskOutputContent.js +9 -6
- package/dist/components/messages/TaskOutputContent.js.map +2 -2
- package/dist/components/messages/UserPromptMessage.js +2 -2
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/constants/colors.js +90 -72
- package/dist/constants/colors.js.map +2 -2
- package/dist/constants/prompts.js +22 -1
- package/dist/constants/prompts.js.map +2 -2
- package/dist/constants/toolInputExamples.js +84 -0
- package/dist/constants/toolInputExamples.js.map +7 -0
- package/dist/core/backupManager.js +321 -0
- package/dist/core/backupManager.js.map +7 -0
- package/dist/core/costTracker.js +9 -18
- package/dist/core/costTracker.js.map +2 -2
- package/dist/core/gitAutoCommit.js +287 -0
- package/dist/core/gitAutoCommit.js.map +7 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +2 -2
- package/dist/core/operationTracker.js +212 -0
- package/dist/core/operationTracker.js.map +7 -0
- package/dist/core/permissions/rules/allowedToolsRule.js +1 -1
- package/dist/core/permissions/rules/allowedToolsRule.js.map +2 -2
- package/dist/core/permissions/rules/autoEscalationRule.js +5 -0
- package/dist/core/permissions/rules/autoEscalationRule.js.map +2 -2
- package/dist/core/permissions/rules/projectBoundaryRule.js +5 -0
- package/dist/core/permissions/rules/projectBoundaryRule.js.map +2 -2
- package/dist/core/permissions/rules/sensitivePathsRule.js +5 -0
- package/dist/core/permissions/rules/sensitivePathsRule.js.map +2 -2
- package/dist/core/tokenStats.js +9 -0
- package/dist/core/tokenStats.js.map +7 -0
- package/dist/core/tokenStatsManager.js +331 -0
- package/dist/core/tokenStatsManager.js.map +7 -0
- package/dist/entrypoints/cli.js +122 -88
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/hooks/useAgentTokenStats.js +72 -0
- package/dist/hooks/useAgentTokenStats.js.map +7 -0
- package/dist/hooks/useAgentTranscripts.js +30 -6
- package/dist/hooks/useAgentTranscripts.js.map +2 -2
- package/dist/hooks/useLogMessages.js +12 -1
- package/dist/hooks/useLogMessages.js.map +2 -2
- package/dist/i18n/locales/en.js +6 -5
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +6 -5
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/permissions.js +147 -1
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +78 -4
- package/dist/query.js.map +3 -3
- package/dist/screens/REPL.js +23 -3
- package/dist/screens/REPL.js.map +2 -2
- package/dist/screens/ResumeConversation.js +2 -0
- package/dist/screens/ResumeConversation.js.map +2 -2
- package/dist/services/claude.js +54 -3
- package/dist/services/claude.js.map +2 -2
- package/dist/services/intelligentCompactor.js +1 -1
- package/dist/services/intelligentCompactor.js.map +2 -2
- package/dist/services/mcpClient.js +81 -25
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/sandbox/filesystemBoundary.js +58 -17
- package/dist/services/sandbox/filesystemBoundary.js.map +2 -2
- package/dist/services/taskStore.js +205 -0
- package/dist/services/taskStore.js.map +7 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +3 -2
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +42 -4
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +43 -7
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +184 -34
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +24 -9
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileEditTool/prompt.js +10 -4
- package/dist/tools/FileEditTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/utils.js +10 -4
- package/dist/tools/FileEditTool/utils.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js +1 -1
- package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
- package/dist/tools/FileReadTool/prompt.js +16 -1
- package/dist/tools/FileReadTool/prompt.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +1 -1
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +1 -1
- package/dist/tools/FileWriteTool/prompt.js +12 -3
- package/dist/tools/FileWriteTool/prompt.js.map +2 -2
- package/dist/tools/GlobTool/prompt.js +12 -1
- package/dist/tools/GlobTool/prompt.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +333 -65
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/GrepTool/prompt.js +15 -8
- package/dist/tools/GrepTool/prompt.js.map +2 -2
- package/dist/tools/MultiEditTool/prompt.js +5 -3
- package/dist/tools/MultiEditTool/prompt.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +59 -46
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/prompt.js +1 -1
- package/dist/tools/NotebookEditTool/prompt.js.map +1 -1
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +3 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +3 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/prompt.js +1 -1
- package/dist/tools/PlanModeTool/prompt.js.map +1 -1
- package/dist/tools/SkillTool/SkillTool.js +4 -3
- package/dist/tools/SkillTool/SkillTool.js.map +2 -2
- package/dist/tools/SkillTool/prompt.js +1 -1
- package/dist/tools/SkillTool/prompt.js.map +1 -1
- package/dist/tools/TaskCreateTool/TaskCreateTool.js +102 -0
- package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +7 -0
- package/dist/tools/TaskCreateTool/prompt.js +47 -0
- package/dist/tools/TaskCreateTool/prompt.js.map +7 -0
- package/dist/tools/TaskGetTool/TaskGetTool.js +115 -0
- package/dist/tools/TaskGetTool/TaskGetTool.js.map +7 -0
- package/dist/tools/TaskGetTool/prompt.js +28 -0
- package/dist/tools/TaskGetTool/prompt.js.map +7 -0
- package/dist/tools/TaskListTool/TaskListTool.js +102 -0
- package/dist/tools/TaskListTool/TaskListTool.js.map +7 -0
- package/dist/tools/TaskListTool/prompt.js +27 -0
- package/dist/tools/TaskListTool/prompt.js.map +7 -0
- package/dist/tools/TaskOutputTool/TaskOutputTool.js +3 -2
- package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +2 -2
- package/dist/tools/TaskStopTool/TaskStopTool.js +150 -0
- package/dist/tools/TaskStopTool/TaskStopTool.js.map +7 -0
- package/dist/tools/TaskStopTool/prompt.js +15 -0
- package/dist/tools/TaskStopTool/prompt.js.map +7 -0
- package/dist/tools/TaskTool/TaskTool.js +49 -1
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +134 -0
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +7 -0
- package/dist/tools/TaskUpdateTool/prompt.js +81 -0
- package/dist/tools/TaskUpdateTool/prompt.js.map +7 -0
- package/dist/tools/URLFetcherTool/prompt.js +1 -1
- package/dist/tools/URLFetcherTool/prompt.js.map +1 -1
- package/dist/tools.js +12 -0
- package/dist/tools.js.map +2 -2
- package/dist/utils/CircuitBreaker.js +242 -0
- package/dist/utils/CircuitBreaker.js.map +7 -0
- package/dist/utils/ask.js +2 -0
- package/dist/utils/ask.js.map +2 -2
- package/dist/utils/config.js +47 -5
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/credentials/CredentialStore.js +1 -0
- package/dist/utils/credentials/CredentialStore.js.map +7 -0
- package/dist/utils/credentials/EncryptedFileStore.js +157 -0
- package/dist/utils/credentials/EncryptedFileStore.js.map +7 -0
- package/dist/utils/credentials/index.js +37 -0
- package/dist/utils/credentials/index.js.map +7 -0
- package/dist/utils/credentials/migration.js +82 -0
- package/dist/utils/credentials/migration.js.map +7 -0
- package/dist/utils/markdown.js +13 -1
- package/dist/utils/markdown.js.map +2 -2
- package/dist/utils/model.js +15 -2
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/permissions/filesystem.js +5 -1
- package/dist/utils/permissions/filesystem.js.map +2 -2
- package/dist/utils/ripgrep.js +53 -1
- package/dist/utils/ripgrep.js.map +2 -2
- package/dist/utils/safePath.js +132 -0
- package/dist/utils/safePath.js.map +7 -0
- package/dist/utils/sensitiveFiles.js +125 -0
- package/dist/utils/sensitiveFiles.js.map +7 -0
- package/dist/utils/taskDisplayUtils.js +9 -9
- package/dist/utils/taskDisplayUtils.js.map +2 -2
- package/dist/utils/terminal.js +12 -0
- package/dist/utils/terminal.js.map +2 -2
- package/dist/utils/theme.js +6 -6
- package/dist/utils/theme.js.map +1 -1
- package/dist/utils/toolRiskClassification.js +207 -0
- package/dist/utils/toolRiskClassification.js.map +7 -0
- package/dist/utils/tooling/safeRender.js +17 -17
- package/dist/utils/tooling/safeRender.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +22 -28
- package/dist/hooks/useCancelRequest.js +0 -31
- package/dist/hooks/useCancelRequest.js.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/markdown.ts"],
|
|
4
|
-
"sourcesContent": ["import { marked, Token } from 'marked'\nimport { stripSystemMessages } from './messages'\nimport chalk from 'chalk'\nimport { EOL } from 'os'\nimport { highlight, supportsLanguage } from 'cli-highlight'\nimport { logError } from './log'\n\nexport function applyMarkdown(content: string): string {\n return marked\n .lexer(
|
|
5
|
-
"mappings": "AAAA,SAAS,cAAqB;AAC9B,SAAS,2BAA2B;AACpC,OAAO,WAAW;AAClB,SAAS,WAAW;AACpB,SAAS,WAAW,wBAAwB;AAC5C,SAAS,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import { marked, Token } from 'marked'\nimport { stripSystemMessages } from './messages'\nimport chalk from 'chalk'\nimport { EOL } from 'os'\nimport { highlight, supportsLanguage } from 'cli-highlight'\nimport { logError } from './log'\n\n/**\n * Strip outer markdown code block wrapper if present.\n * AI models sometimes wrap their response in ```markdown ... ``` which\n * causes the content to be parsed as a code block instead of actual markdown.\n */\nfunction stripMarkdownCodeBlockWrapper(content: string): string {\n const trimmed = content.trim()\n // Match ```markdown or ```md at the start and ``` at the end\n const codeBlockRegex = /^```(?:markdown|md)?\\s*\\n([\\s\\S]*?)\\n```$/\n const match = trimmed.match(codeBlockRegex)\n if (match) {\n return match[1] ?? trimmed\n }\n return content\n}\n\nexport function applyMarkdown(content: string): string {\n // Pre-process: remove outer markdown code block wrapper if present\n const preprocessed = stripMarkdownCodeBlockWrapper(\n stripSystemMessages(content),\n )\n return marked\n .lexer(preprocessed)\n .map(_ => format(_))\n .join('')\n .trim()\n}\n\nfunction format(\n token: Token,\n listDepth = 0,\n orderedListNumber: number | null = null,\n parent: Token | null = null,\n): string {\n switch (token.type) {\n case 'blockquote':\n return chalk.dim.italic((token.tokens ?? []).map(_ => format(_)).join(''))\n case 'code':\n if (token.lang && supportsLanguage(token.lang)) {\n return highlight(token.text, { language: token.lang }) + EOL\n } else {\n logError(\n `Language not supported while highlighting code, falling back to markdown: ${token.lang}`,\n )\n return highlight(token.text, { language: 'markdown' }) + EOL\n }\n case 'codespan':\n // inline code\n return chalk.blue(token.text)\n case 'em':\n return chalk.italic((token.tokens ?? []).map(_ => format(_)).join(''))\n case 'strong':\n return chalk.bold((token.tokens ?? []).map(_ => format(_)).join(''))\n case 'heading':\n switch (token.depth) {\n case 1: // h1\n return (\n chalk.bold.italic.underline(\n (token.tokens ?? []).map(_ => format(_)).join(''),\n ) +\n EOL +\n EOL\n )\n case 2: // h2\n return (\n chalk.bold((token.tokens ?? []).map(_ => format(_)).join('')) +\n EOL +\n EOL\n )\n default: // h3+\n return (\n chalk.bold.dim((token.tokens ?? []).map(_ => format(_)).join('')) +\n EOL +\n EOL\n )\n }\n case 'hr':\n return '---'\n case 'image':\n return `[Image: ${token.title}: ${token.href}]`\n case 'link':\n return chalk.blue(token.href)\n case 'list': {\n return token.items\n .map((_: Token, index: number) =>\n format(\n _,\n listDepth,\n token.ordered ? token.start + index : null,\n token,\n ),\n )\n .join('')\n }\n case 'list_item':\n return (token.tokens ?? [])\n .map(\n _ =>\n `${' '.repeat(listDepth)}${format(_, listDepth + 1, orderedListNumber, token)}`,\n )\n .join('')\n case 'paragraph':\n return (token.tokens ?? []).map(_ => format(_)).join('') + EOL\n case 'space':\n return EOL\n case 'text':\n if (parent?.type === 'list_item') {\n return `${orderedListNumber === null ? '-' : getListNumber(listDepth, orderedListNumber) + '.'} ${token.tokens ? token.tokens.map(_ => format(_, listDepth, orderedListNumber, token)).join('') : token.text}${EOL}`\n } else {\n return token.text\n }\n }\n // TODO: tables\n return ''\n}\n\nconst DEPTH_1_LIST_NUMBERS = [\n 'a',\n 'b',\n 'c',\n 'd',\n 'e',\n 'f',\n 'g',\n 'h',\n 'i',\n 'j',\n 'k',\n 'l',\n 'm',\n 'n',\n 'o',\n 'p',\n 'q',\n 'r',\n 's',\n 't',\n 'u',\n 'v',\n 'w',\n 'x',\n 'y',\n 'z',\n 'aa',\n 'ab',\n 'ac',\n 'ad',\n 'ae',\n 'af',\n 'ag',\n 'ah',\n 'ai',\n 'aj',\n 'ak',\n 'al',\n 'am',\n 'an',\n 'ao',\n 'ap',\n 'aq',\n 'ar',\n 'as',\n 'at',\n 'au',\n 'av',\n 'aw',\n 'ax',\n 'ay',\n 'az',\n]\nconst DEPTH_2_LIST_NUMBERS = [\n 'i',\n 'ii',\n 'iii',\n 'iv',\n 'v',\n 'vi',\n 'vii',\n 'viii',\n 'ix',\n 'x',\n 'xi',\n 'xii',\n 'xiii',\n 'xiv',\n 'xv',\n 'xvi',\n 'xvii',\n 'xviii',\n 'xix',\n 'xx',\n 'xxi',\n 'xxii',\n 'xxiii',\n 'xxiv',\n 'xxv',\n 'xxvi',\n 'xxvii',\n 'xxviii',\n 'xxix',\n 'xxx',\n 'xxxi',\n 'xxxii',\n 'xxxiii',\n 'xxxiv',\n 'xxxv',\n 'xxxvi',\n 'xxxvii',\n 'xxxviii',\n 'xxxix',\n 'xl',\n]\n\nfunction getListNumber(listDepth: number, orderedListNumber: number): string {\n switch (listDepth) {\n case 0:\n case 1:\n return orderedListNumber.toString()\n case 2:\n return DEPTH_1_LIST_NUMBERS[orderedListNumber - 1]! // TODO: don't hard code the list\n case 3:\n return DEPTH_2_LIST_NUMBERS[orderedListNumber - 1]! // TODO: don't hard code the list\n default:\n return orderedListNumber.toString()\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/utils/model.js
CHANGED
|
@@ -20,10 +20,18 @@ const getSlowAndCapableModel = memoize(async () => {
|
|
|
20
20
|
if (model) {
|
|
21
21
|
return model;
|
|
22
22
|
}
|
|
23
|
+
const hasConfiguredModels = modelManager.hasConfiguredModels();
|
|
24
|
+
if (hasConfiguredModels) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"No main model configured. Please use /model to set your default model."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
23
29
|
const modelConfig = await getModelConfig();
|
|
24
30
|
if (USE_BEDROCK) return modelConfig.bedrock;
|
|
25
31
|
if (USE_VERTEX) return modelConfig.vertex;
|
|
26
|
-
|
|
32
|
+
throw new Error(
|
|
33
|
+
"No models configured. Please run /model to add and configure your AI models."
|
|
34
|
+
);
|
|
27
35
|
});
|
|
28
36
|
function getModelContextLength(pointerType = "main") {
|
|
29
37
|
const config = getGlobalConfig();
|
|
@@ -50,7 +58,12 @@ function getModelContextLength(pointerType = "main") {
|
|
|
50
58
|
return 2e5;
|
|
51
59
|
}
|
|
52
60
|
async function isDefaultSlowAndCapableModel() {
|
|
53
|
-
|
|
61
|
+
try {
|
|
62
|
+
const configuredModel = await getSlowAndCapableModel();
|
|
63
|
+
return !process.env.ANTHROPIC_MODEL || process.env.ANTHROPIC_MODEL === configuredModel;
|
|
64
|
+
} catch {
|
|
65
|
+
return !process.env.ANTHROPIC_MODEL;
|
|
66
|
+
}
|
|
54
67
|
}
|
|
55
68
|
function getVertexRegionForModel(model) {
|
|
56
69
|
if (model?.startsWith("claude-3-5-haiku")) {
|
package/dist/utils/model.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/model.ts"],
|
|
4
|
-
"sourcesContent": ["import { memoize } from 'lodash-es'\n\nimport { logError } from './log'\nimport {\n getGlobalConfig,\n ModelProfile,\n ModelPointerType,\n saveGlobalConfig,\n} from './config'\n\nexport const USE_BEDROCK = !!process.env.CLAUDE_CODE_USE_BEDROCK\nexport const USE_VERTEX = !!process.env.CLAUDE_CODE_USE_VERTEX\n\nexport interface ModelConfig {\n bedrock: string\n vertex: string\n firstParty: string\n}\n\nconst DEFAULT_MODEL_CONFIG: ModelConfig = {\n bedrock: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',\n vertex: 'claude-3-7-sonnet@20250219',\n firstParty: 'claude-sonnet-4-20250514',\n}\n\n/**\n * Helper to get the model config from defaults.\n */\nasync function getModelConfig(): Promise<ModelConfig> {\n return DEFAULT_MODEL_CONFIG\n}\n\nexport const getSlowAndCapableModel = memoize(async (): Promise<string> => {\n const config = await getGlobalConfig()\n\n // Use ModelManager for proper model resolution\n const modelManager = new ModelManager(config)\n const model = modelManager.getMainAgentModel()\n\n if (model) {\n return model\n }\n\n // Final fallback to default model\n const modelConfig = await getModelConfig()\n if (USE_BEDROCK) return modelConfig.bedrock\n if (USE_VERTEX) return modelConfig.vertex\n return modelConfig.firstParty\n})\n\n/**\n * Get context length for a model pointer type\n */\nexport function getModelContextLength(\n pointerType: ModelPointerType = 'main',\n): number {\n const config = getGlobalConfig()\n const modelManager = new ModelManager(config)\n\n // Get the model name based on pointer type\n let modelName: string | null = null\n switch (pointerType) {\n case 'main':\n modelName = modelManager.getMainAgentModel()\n break\n case 'task':\n modelName = modelManager.getTaskToolModel()\n break\n default:\n modelName = modelManager.getMainAgentModel()\n }\n\n // Find the profile for this model\n if (modelName) {\n const profile = config.modelProfiles?.find(\n (p: ModelProfile) => p.modelName === modelName && p.isActive,\n )\n if (profile && profile.contextLength) {\n return profile.contextLength\n }\n }\n\n // Default fallback (Claude Sonnet context length)\n return 200000\n}\n\nexport async function isDefaultSlowAndCapableModel(): Promise<boolean> {\n return (\n !process.env.ANTHROPIC_MODEL ||\n process.env.ANTHROPIC_MODEL === (await getSlowAndCapableModel())\n )\n}\n\n/**\n * Get the region for a specific Vertex model\n * Checks for hardcoded model-specific environment variables first,\n * then falls back to CLOUD_ML_REGION env var or default region\n */\nexport function getVertexRegionForModel(\n model: string | undefined,\n): string | undefined {\n if (model?.startsWith('claude-3-5-haiku')) {\n return process.env.VERTEX_REGION_CLAUDE_3_5_HAIKU\n } else if (model?.startsWith('claude-3-5-sonnet')) {\n return process.env.VERTEX_REGION_CLAUDE_3_5_SONNET\n } else if (model?.startsWith('claude-3-7-sonnet')) {\n return process.env.VERTEX_REGION_CLAUDE_3_7_SONNET\n }\n}\n\n/**\n * Comprehensive ModelManager class for centralized model selection and management.\n * Provides a clean interface for model selection across the application.\n */\nexport class ModelManager {\n private config: any // Using any to handle legacy properties\n private modelProfiles: ModelProfile[]\n\n constructor(config: any) {\n this.config = config\n this.modelProfiles = config.modelProfiles || []\n }\n\n /**\n * Get the current terminal model (for interactive CLI sessions)\n */\n getCurrentModel(): string | null {\n // Use main pointer from new ModelProfile system\n const mainModelName = this.config.modelPointers?.main\n if (mainModelName) {\n const profile = this.findModelProfile(mainModelName)\n if (profile && profile.isActive) {\n return profile.modelName\n }\n }\n\n // Fallback to main agent model\n return this.getMainAgentModel()\n }\n\n /**\n * Get the main agent default model (for non-terminal mode and MCP calls)\n */\n getMainAgentModel(): string | null {\n // Use main pointer from new ModelProfile system\n const mainModelName = this.config.modelPointers?.main\n if (mainModelName) {\n const profile = this.findModelProfile(mainModelName)\n if (profile && profile.isActive) {\n return profile.modelName\n }\n }\n\n // Fallback to first active profile\n const activeProfile = this.modelProfiles.find(p => p.isActive)\n if (activeProfile) {\n return activeProfile.modelName\n }\n\n return null\n }\n\n /**\n * Get the task tool default model (for Task tool sub-agents)\n */\n getTaskToolModel(): string | null {\n // Use task pointer from new ModelProfile system\n const taskModelName = this.config.modelPointers?.task\n if (taskModelName) {\n const profile = this.findModelProfile(taskModelName)\n if (profile && profile.isActive) {\n return profile.modelName\n }\n }\n\n // Fallback to main agent model\n return this.getMainAgentModel()\n }\n\n /**\n * Switch to the next available model with enhanced context overflow handling\n * If target model can't handle current context, shows warning and reverts after delay\n *\n * @param currentContextTokens - Current conversation token count for validation\n * @returns Object with detailed model name and context status information\n */\n switchToNextModelWithContextCheck(currentContextTokens: number = 0): {\n success: boolean\n modelName: string | null\n previousModelName: string | null\n contextOverflow: boolean\n usagePercentage: number\n // Enhanced feedback fields\n currentContextTokens: number\n targetContextLimit: number\n skippedModels: Array<{ name: string; reason: string }>\n totalAvailableModels: number\n } {\n // Use ALL configured models, not just active ones\n const allProfiles = this.getAllConfiguredModels()\n if (allProfiles.length === 0) {\n return {\n success: false,\n modelName: null,\n previousModelName: null,\n contextOverflow: false,\n usagePercentage: 0,\n currentContextTokens,\n targetContextLimit: 0,\n skippedModels: [],\n totalAvailableModels: 0,\n }\n }\n\n // Sort by createdAt for consistent cycling order (don't use lastUsed)\n // Using lastUsed causes the order to change each time, preventing proper cycling\n allProfiles.sort((a, b) => {\n return a.createdAt - b.createdAt // Oldest first for consistent order\n })\n\n const currentMainModelName = this.config.modelPointers?.main\n const currentModel = currentMainModelName\n ? this.findModelProfile(currentMainModelName)\n : null\n const previousModelName = currentModel?.name || null\n\n if (!currentMainModelName) {\n // No current main model, select first available (activate if needed)\n const firstModel = allProfiles[0]\n if (!firstModel.isActive) {\n firstModel.isActive = true\n }\n this.setPointer('main', firstModel.modelName)\n this.updateLastUsed(firstModel.modelName)\n\n const analysis = this.analyzeContextCompatibility(\n firstModel,\n currentContextTokens,\n )\n return {\n success: true,\n modelName: firstModel.name,\n previousModelName: null,\n contextOverflow: !analysis.compatible,\n usagePercentage: analysis.usagePercentage,\n currentContextTokens,\n targetContextLimit: firstModel.contextLength,\n skippedModels: [],\n totalAvailableModels: allProfiles.length,\n }\n }\n\n // Find current model index in ALL models\n const currentIndex = allProfiles.findIndex(\n p => p.modelName === currentMainModelName,\n )\n if (currentIndex === -1) {\n // Current model not found, select first available (activate if needed)\n const firstModel = allProfiles[0]\n if (!firstModel.isActive) {\n firstModel.isActive = true\n }\n this.setPointer('main', firstModel.modelName)\n this.updateLastUsed(firstModel.modelName)\n\n const analysis = this.analyzeContextCompatibility(\n firstModel,\n currentContextTokens,\n )\n return {\n success: true,\n modelName: firstModel.name,\n previousModelName,\n contextOverflow: !analysis.compatible,\n usagePercentage: analysis.usagePercentage,\n currentContextTokens,\n targetContextLimit: firstModel.contextLength,\n skippedModels: [],\n totalAvailableModels: allProfiles.length,\n }\n }\n\n // Check if only one model is available\n if (allProfiles.length === 1) {\n const currentModel = allProfiles[0]\n return {\n success: false,\n modelName: null,\n previousModelName,\n contextOverflow: false,\n usagePercentage: 0,\n currentContextTokens,\n targetContextLimit: currentModel?.contextLength || 0,\n skippedModels: [],\n totalAvailableModels: 1,\n }\n }\n\n // Get next model in cycle (from ALL models)\n const nextIndex = (currentIndex + 1) % allProfiles.length\n const nextModel = allProfiles[nextIndex]\n\n // Activate the model if it's not already active\n const wasInactive = !nextModel.isActive\n if (!nextModel.isActive) {\n nextModel.isActive = true\n }\n\n // Analyze context compatibility for next model\n const analysis = this.analyzeContextCompatibility(\n nextModel,\n currentContextTokens,\n )\n\n // Always switch to next model, but return context status\n this.setPointer('main', nextModel.modelName)\n this.updateLastUsed(nextModel.modelName)\n\n // Save configuration if we activated a new model\n if (wasInactive) {\n this.saveConfig()\n }\n\n return {\n success: true,\n modelName: nextModel.name,\n previousModelName,\n contextOverflow: !analysis.compatible,\n usagePercentage: analysis.usagePercentage,\n currentContextTokens,\n targetContextLimit: nextModel.contextLength,\n skippedModels: [], // In simple round-robin, no models are skipped\n totalAvailableModels: allProfiles.length,\n }\n }\n\n /**\n * Simple model switching for UI components (compatible interface)\n * @param currentContextTokens - Current conversation token count for validation\n * @returns Compatible interface for PromptInput component\n */\n switchToNextModel(currentContextTokens: number = 0): {\n success: boolean\n modelName: string | null\n blocked?: boolean\n message?: string\n } {\n // Use the enhanced context check method for consistency\n const result = this.switchToNextModelWithContextCheck(currentContextTokens)\n\n if (!result.success) {\n const allModels = this.getAllConfiguredModels()\n if (allModels.length === 0) {\n return {\n success: false,\n modelName: null,\n blocked: false,\n message: '\u274C No models configured. Use /model to add models.',\n }\n } else if (allModels.length === 1) {\n return {\n success: false,\n modelName: null,\n blocked: false,\n message: `\u26A0\uFE0F Only one model configured (${allModels[0].modelName}). Use /model to add more models for switching.`,\n }\n }\n }\n\n // Convert the detailed result to the simple interface\n const currentModel = this.findModelProfile(this.config.modelPointers?.main)\n const allModels = this.getAllConfiguredModels()\n const currentIndex = allModels.findIndex(\n m => m.modelName === currentModel?.modelName,\n )\n const totalModels = allModels.length\n\n return {\n success: result.success,\n modelName: result.modelName,\n blocked: result.contextOverflow,\n message: result.success\n ? result.contextOverflow\n ? `\u26A0\uFE0F Context usage: ${result.usagePercentage.toFixed(1)}% - ${result.modelName}`\n : `\u2705 Switched to ${result.modelName} (${currentIndex + 1}/${totalModels})${currentModel?.provider ? ` [${currentModel.provider}]` : ''}`\n : `\u274C Failed to switch models`,\n }\n }\n\n /**\n * Revert to previous model (used when context overflow requires rollback)\n */\n revertToPreviousModel(previousModelName: string): boolean {\n const previousModel = this.modelProfiles.find(\n p => p.name === previousModelName && p.isActive,\n )\n if (!previousModel) {\n return false\n }\n\n this.setPointer('main', previousModel.modelName)\n this.updateLastUsed(previousModel.modelName)\n return true\n }\n\n /**\n * Enhanced context validation with different severity levels\n */\n analyzeContextCompatibility(\n model: ModelProfile,\n contextTokens: number,\n ): {\n compatible: boolean\n severity: 'safe' | 'warning' | 'critical'\n usagePercentage: number\n recommendation: string\n } {\n const usableContext = Math.floor(model.contextLength * 0.8) // Reserve 20% for output\n const usagePercentage = (contextTokens / usableContext) * 100\n\n if (usagePercentage <= 70) {\n return {\n compatible: true,\n severity: 'safe',\n usagePercentage,\n recommendation: 'Full context preserved',\n }\n } else if (usagePercentage <= 90) {\n return {\n compatible: true,\n severity: 'warning',\n usagePercentage,\n recommendation: 'Context usage high, consider compression',\n }\n } else {\n return {\n compatible: false,\n severity: 'critical',\n usagePercentage,\n recommendation: 'Auto-compression or message truncation required',\n }\n }\n }\n\n /**\n * Switch to next model with enhanced context analysis\n */\n switchToNextModelWithAnalysis(currentContextTokens: number = 0): {\n modelName: string | null\n contextAnalysis: ReturnType<typeof this.analyzeContextCompatibility> | null\n requiresCompression: boolean\n estimatedTokensAfterSwitch: number\n } {\n const result = this.switchToNextModel(currentContextTokens)\n\n if (!result.success || !result.modelName) {\n return {\n modelName: null,\n contextAnalysis: null,\n requiresCompression: false,\n estimatedTokensAfterSwitch: 0,\n }\n }\n\n const newModel = this.getModel('main')\n if (!newModel) {\n return {\n modelName: result.modelName,\n contextAnalysis: null,\n requiresCompression: false,\n estimatedTokensAfterSwitch: currentContextTokens,\n }\n }\n\n const analysis = this.analyzeContextCompatibility(\n newModel,\n currentContextTokens,\n )\n\n return {\n modelName: result.modelName,\n contextAnalysis: analysis,\n requiresCompression: analysis.severity === 'critical',\n estimatedTokensAfterSwitch: currentContextTokens,\n }\n }\n\n /**\n * Check if a model can handle the given context size (legacy method)\n */\n canModelHandleContext(model: ModelProfile, contextTokens: number): boolean {\n const analysis = this.analyzeContextCompatibility(model, contextTokens)\n return analysis.compatible\n }\n\n /**\n * Find the first model that can handle the given context size\n */\n findModelWithSufficientContext(\n models: ModelProfile[],\n contextTokens: number,\n ): ModelProfile | null {\n return (\n models.find(model => this.canModelHandleContext(model, contextTokens)) ||\n null\n )\n }\n\n /**\n * Unified model getter for different contexts\n */\n getModelForContext(\n contextType: 'terminal' | 'main-agent' | 'task-tool',\n ): string | null {\n switch (contextType) {\n case 'terminal':\n return this.getCurrentModel()\n case 'main-agent':\n return this.getMainAgentModel()\n case 'task-tool':\n return this.getTaskToolModel()\n default:\n return this.getMainAgentModel()\n }\n }\n\n /**\n * Get all active model profiles\n */\n getActiveModelProfiles(): ModelProfile[] {\n return this.modelProfiles.filter(p => p.isActive)\n }\n\n /**\n * Check if any models are configured\n */\n hasConfiguredModels(): boolean {\n return this.getActiveModelProfiles().length > 0\n }\n\n // New model pointer system methods\n\n /**\n * Get model by pointer type (main, task, reasoning, quick)\n */\n getModel(pointer: ModelPointerType): ModelProfile | null {\n const pointerId = this.config.modelPointers?.[pointer]\n if (!pointerId) {\n return this.getDefaultModel()\n }\n\n const profile = this.findModelProfile(pointerId)\n return profile && profile.isActive ? profile : this.getDefaultModel()\n }\n\n /**\n * Get model name by pointer type\n */\n getModelName(pointer: ModelPointerType): string | null {\n const profile = this.getModel(pointer)\n return profile ? profile.modelName : null\n }\n\n /**\n * Get reasoning model (with fallback)\n */\n getReasoningModel(): string | null {\n return this.getModelName('reasoning') || this.getModelName('main')\n }\n\n /**\n * Get quick model (with fallback)\n */\n getQuickModel(): string | null {\n return (\n this.getModelName('quick') ||\n this.getModelName('task') ||\n this.getModelName('main')\n )\n }\n\n /**\n * Get compact model for context compression/summarization (with fallback)\n * Fallback chain: compact -> quick -> task -> main\n */\n getCompactModel(): string | null {\n return (\n this.getModelName('compact') ||\n this.getModelName('quick') ||\n this.getModelName('task') ||\n this.getModelName('main')\n )\n }\n\n /**\n * Add a new model profile with duplicate validation\n */\n async addModel(\n config: Omit<ModelProfile, 'createdAt' | 'isActive'>,\n ): Promise<string> {\n // Check for duplicate modelName (actual model identifier)\n const existingByModelName = this.modelProfiles.find(\n p => p.modelName === config.modelName,\n )\n if (existingByModelName) {\n throw new Error(\n `Model with modelName '${config.modelName}' already exists: ${existingByModelName.name}`,\n )\n }\n\n // Check for duplicate friendly name\n const existingByName = this.modelProfiles.find(p => p.name === config.name)\n if (existingByName) {\n throw new Error(`Model with name '${config.name}' already exists`)\n }\n\n const newModel: ModelProfile = {\n ...config,\n createdAt: Date.now(),\n isActive: true,\n }\n\n this.modelProfiles.push(newModel)\n\n // If this is the first model, set all pointers to it\n if (this.modelProfiles.length === 1) {\n this.config.modelPointers = {\n main: config.modelName,\n task: config.modelName,\n reasoning: config.modelName,\n quick: config.modelName,\n compact: config.modelName,\n }\n this.config.defaultModelName = config.modelName\n }\n\n this.saveConfig()\n return config.modelName\n }\n\n /**\n * Set model pointer assignment\n */\n setPointer(pointer: ModelPointerType, modelName: string): void {\n if (!this.findModelProfile(modelName)) {\n throw new Error(`Model '${modelName}' not found`)\n }\n\n if (!this.config.modelPointers) {\n this.config.modelPointers = {\n main: '',\n task: '',\n reasoning: '',\n quick: '',\n compact: '',\n }\n }\n\n this.config.modelPointers[pointer] = modelName\n this.saveConfig()\n }\n\n /**\n * Get all active models for pointer assignment\n */\n getAvailableModels(): ModelProfile[] {\n return this.modelProfiles.filter(p => p.isActive)\n }\n\n /**\n * Get all configured models (both active and inactive) for switching\n */\n getAllConfiguredModels(): ModelProfile[] {\n return this.modelProfiles\n }\n\n /**\n * Get all available model names (modelName field) - active only\n */\n getAllAvailableModelNames(): string[] {\n return this.getAvailableModels().map(p => p.modelName)\n }\n\n /**\n * Get all configured model names (both active and inactive)\n */\n getAllConfiguredModelNames(): string[] {\n return this.getAllConfiguredModels().map(p => p.modelName)\n }\n\n /**\n * Debug method to get detailed model switching information\n */\n getModelSwitchingDebugInfo(): {\n totalModels: number\n activeModels: number\n inactiveModels: number\n currentMainModel: string | null\n availableModels: Array<{\n name: string\n modelName: string\n provider: string\n isActive: boolean\n lastUsed?: number\n }>\n modelPointers: Record<string, string | undefined>\n } {\n const availableModels = this.getAvailableModels()\n const currentMainModelName = this.config.modelPointers?.main\n\n return {\n totalModels: this.modelProfiles.length,\n activeModels: availableModels.length,\n inactiveModels: this.modelProfiles.length - availableModels.length,\n currentMainModel: currentMainModelName || null,\n availableModels: this.modelProfiles.map(p => ({\n name: p.name,\n modelName: p.modelName,\n provider: p.provider,\n isActive: p.isActive,\n lastUsed: p.lastUsed,\n })),\n modelPointers: this.config.modelPointers || {},\n }\n }\n\n /**\n * Remove a model profile\n */\n removeModel(modelName: string): void {\n this.modelProfiles = this.modelProfiles.filter(\n p => p.modelName !== modelName,\n )\n\n // Clean up pointers that reference deleted model\n if (this.config.modelPointers) {\n Object.keys(this.config.modelPointers).forEach(pointer => {\n if (\n this.config.modelPointers[pointer as ModelPointerType] === modelName\n ) {\n this.config.modelPointers[pointer as ModelPointerType] =\n this.config.defaultModelName || ''\n }\n })\n }\n\n this.saveConfig()\n }\n\n /**\n * Get default model profile\n */\n private getDefaultModel(): ModelProfile | null {\n if (this.config.defaultModelId) {\n const profile = this.findModelProfile(this.config.defaultModelId)\n if (profile && profile.isActive) {\n return profile\n }\n }\n return this.modelProfiles.find(p => p.isActive) || null\n }\n\n /**\n * Save configuration changes\n * Note: This updates the global config file. The singleton instance\n * is automatically refreshed to avoid stale data issues.\n */\n private saveConfig(): void {\n const updatedConfig = {\n ...this.config,\n modelProfiles: this.modelProfiles,\n }\n saveGlobalConfig(updatedConfig)\n\n // Refresh the global singleton to avoid stale data race conditions\n // This ensures any subsequent getModelManager() calls get fresh data\n refreshGlobalModelManagerInstance(this)\n }\n\n /**\n * Get a fallback model when no specific model is configured\n */\n async getFallbackModel(): Promise<string> {\n const modelConfig = await getModelConfig()\n if (USE_BEDROCK) return modelConfig.bedrock\n if (USE_VERTEX) return modelConfig.vertex\n return modelConfig.firstParty\n }\n\n /**\n * \u7EDF\u4E00\u7684\u6A21\u578B\u89E3\u6790\u65B9\u6CD5\uFF1A\u652F\u6301\u6307\u9488\u3001model ID \u548C\u771F\u5B9E\u6A21\u578B\u540D\u79F0\n * @param modelParam - \u53EF\u4EE5\u662F\u6A21\u578B\u6307\u9488 ('main', 'task', etc.)\u3001\u5185\u90E8model ID \u6216\u771F\u5B9E\u6A21\u578B\u540D\u79F0 ('gpt-4o', 'claude-3-5-sonnet')\n * @returns ModelProfile \u6216 null\n */\n resolveModel(modelParam: string | ModelPointerType): ModelProfile | null {\n // \u9996\u5148\u68C0\u67E5\u662F\u5426\u662F\u6A21\u578B\u6307\u9488\n if (\n ['main', 'task', 'reasoning', 'quick', 'compact'].includes(modelParam)\n ) {\n const pointerId =\n this.config.modelPointers?.[modelParam as ModelPointerType]\n if (pointerId) {\n // pointerId \u53EF\u80FD\u662F\u5185\u90E8ID\u6216\u771F\u5B9E\u6A21\u578B\u540D\u79F0\uFF0C\u5C1D\u8BD5\u4E24\u79CD\u67E5\u627E\u65B9\u5F0F\n let profile = this.findModelProfile(pointerId) // \u6309\u5185\u90E8ID\u67E5\u627E\n if (!profile) {\n profile = this.findModelProfileByModelName(pointerId) // \u6309\u771F\u5B9E\u6A21\u578B\u540D\u67E5\u627E\n }\n if (profile && profile.isActive) {\n return profile\n }\n }\n // \u6307\u9488\u65E0\u6548\u65F6\uFF0C\u5C1D\u8BD5 fallback \u5230\u9ED8\u8BA4\u6A21\u578B\n return this.getDefaultModel()\n }\n\n // \u4E0D\u662F\u6307\u9488\uFF0C\u5C1D\u8BD5\u591A\u79CD\u67E5\u627E\u65B9\u5F0F\n // 1. \u5C1D\u8BD5\u6309\u5185\u90E8 model ID \u67E5\u627E\n let profile = this.findModelProfile(modelParam)\n if (profile && profile.isActive) {\n return profile\n }\n\n // 2. \u5C1D\u8BD5\u6309\u771F\u5B9E\u6A21\u578B\u540D\u79F0\u67E5\u627E\n profile = this.findModelProfileByModelName(modelParam)\n if (profile && profile.isActive) {\n return profile\n }\n\n // 3. \u5C1D\u8BD5\u6309\u53CB\u597D\u540D\u79F0\u67E5\u627E\n profile = this.findModelProfileByName(modelParam)\n if (profile && profile.isActive) {\n return profile\n }\n\n // \u6240\u6709\u67E5\u627E\u65B9\u5F0F\u90FD\u5931\u8D25\uFF0C\u5C1D\u8BD5 fallback \u5230\u9ED8\u8BA4\u6A21\u578B\n return this.getDefaultModel()\n }\n\n /**\n * \u89E3\u6790\u6A21\u578B\u53C2\u6570\u5E76\u8FD4\u56DE\u5B8C\u6574\u4FE1\u606F\n */\n resolveModelWithInfo(modelParam: string | ModelPointerType): {\n success: boolean\n profile: ModelProfile | null\n error?: string\n } {\n const isPointer = [\n 'main',\n 'task',\n 'reasoning',\n 'quick',\n 'compact',\n ].includes(modelParam)\n\n if (isPointer) {\n const pointerId =\n this.config.modelPointers?.[modelParam as ModelPointerType]\n if (!pointerId) {\n return {\n success: false,\n profile: null,\n error: `Model pointer '${modelParam}' is not configured. Use /model to set up models.`,\n }\n }\n\n // pointerId \u53EF\u80FD\u662F\u5185\u90E8ID\u6216\u771F\u5B9E\u6A21\u578B\u540D\u79F0\n let profile = this.findModelProfile(pointerId)\n if (!profile) {\n profile = this.findModelProfileByModelName(pointerId)\n }\n\n if (!profile) {\n return {\n success: false,\n profile: null,\n error: `Model pointer '${modelParam}' points to invalid model '${pointerId}'. Use /model to reconfigure.`,\n }\n }\n\n if (!profile.isActive) {\n return {\n success: false,\n profile: null,\n error: `Model '${profile.name}' (pointed by '${modelParam}') is inactive. Use /model to activate it.`,\n }\n }\n\n return {\n success: true,\n profile,\n }\n } else {\n // \u76F4\u63A5\u7684 model ID \u6216\u6A21\u578B\u540D\u79F0\uFF0C\u5C1D\u8BD5\u591A\u79CD\u67E5\u627E\u65B9\u5F0F\n let profile = this.findModelProfile(modelParam)\n if (!profile) {\n profile = this.findModelProfileByModelName(modelParam)\n }\n if (!profile) {\n profile = this.findModelProfileByName(modelParam)\n }\n\n if (!profile) {\n return {\n success: false,\n profile: null,\n error: `Model '${modelParam}' not found. Use /model to add models.`,\n }\n }\n\n if (!profile.isActive) {\n return {\n success: false,\n profile: null,\n error: `Model '${profile.name}' is inactive. Use /model to activate it.`,\n }\n }\n\n return {\n success: true,\n profile,\n }\n }\n }\n\n // Private helper methods\n private findModelProfile(modelName: string): ModelProfile | null {\n return this.modelProfiles.find(p => p.modelName === modelName) || null\n }\n\n private findModelProfileByModelName(modelName: string): ModelProfile | null {\n return this.modelProfiles.find(p => p.modelName === modelName) || null\n }\n\n private findModelProfileByName(name: string): ModelProfile | null {\n return this.modelProfiles.find(p => p.name === name) || null\n }\n\n private updateLastUsed(modelName: string): void {\n const profile = this.findModelProfile(modelName)\n if (profile) {\n profile.lastUsed = Date.now()\n }\n }\n\n /**\n * Find model profile by provider-qualified name (e.g., \"openai:gpt-4o\", \"anthropic:claude-3-5-sonnet\")\n * @param qualifiedName - Format: \"provider:modelName\" or just \"modelName\"\n * @returns ModelProfile or null\n */\n findModelByProviderQualified(qualifiedName: string): ModelProfile | null {\n // Check if it's a provider-qualified name\n if (qualifiedName.includes(':')) {\n const [provider, modelName] = qualifiedName.split(':', 2)\n // Find model matching both provider and modelName\n return (\n this.modelProfiles.find(\n p =>\n p.provider.toLowerCase() === provider.toLowerCase() &&\n (p.modelName === modelName ||\n p.modelName.toLowerCase() === modelName.toLowerCase() ||\n p.name.toLowerCase() === modelName.toLowerCase()),\n ) || null\n )\n }\n\n // Not provider-qualified, fall back to regular lookup\n return (\n this.findModelProfile(qualifiedName) ||\n this.findModelProfileByName(qualifiedName)\n )\n }\n\n /**\n * Enhanced model resolution supporting provider:model format\n * @param modelParam - Can be pointer, provider:model, modelName, or friendly name\n * @returns ModelProfile or null\n */\n resolveProviderQualifiedModel(modelParam: string): {\n profile: ModelProfile | null\n provider?: string\n modelId?: string\n } {\n // Check for provider:model format first\n if (\n modelParam.includes(':') &&\n !['main', 'task', 'reasoning', 'quick', 'compact'].includes(\n modelParam.split(':')[0],\n )\n ) {\n const [provider, modelId] = modelParam.split(':', 2)\n const profile = this.findModelByProviderQualified(modelParam)\n return { profile, provider, modelId }\n }\n\n // Fall back to regular resolve\n const profile = this.resolveModel(modelParam)\n return { profile }\n }\n\n /**\n * Get all models from a specific provider\n */\n getModelsByProvider(provider: string): ModelProfile[] {\n return this.modelProfiles.filter(\n p => p.provider.toLowerCase() === provider.toLowerCase(),\n )\n }\n\n /**\n * Get list of unique providers\n */\n getUniqueProviders(): string[] {\n const providers = new Set(this.modelProfiles.map(p => p.provider))\n return Array.from(providers)\n }\n}\n\n// Global ModelManager instance to avoid config read/write race conditions\nlet globalModelManager: ModelManager | null = null\n\n/**\n * Internal function to refresh the global singleton with an updated instance\n * This is called by ModelManager.saveConfig() to avoid stale data\n */\nfunction refreshGlobalModelManagerInstance(instance: ModelManager): void {\n globalModelManager = instance\n}\n\n/**\n * Get the global ModelManager instance (singleton pattern to fix race conditions)\n */\nexport const getModelManager = (): ModelManager => {\n try {\n if (!globalModelManager) {\n const config = getGlobalConfig()\n if (!config) {\n console.warn(\n 'No global config available, creating ModelManager with empty config',\n )\n globalModelManager = new ModelManager({\n modelProfiles: [],\n modelPointers: {\n main: '',\n task: '',\n reasoning: '',\n quick: '',\n compact: '',\n },\n })\n } else {\n globalModelManager = new ModelManager(config)\n }\n }\n return globalModelManager\n } catch (error) {\n console.error('Error creating ModelManager:', error)\n // Return a fallback ModelManager with empty configuration\n return new ModelManager({\n modelProfiles: [],\n modelPointers: {\n main: '',\n task: '',\n reasoning: '',\n quick: '',\n compact: '',\n },\n })\n }\n}\n\n/**\n * Force reload of the global ModelManager instance\n * Used when configuration changes to ensure fresh data\n */\nexport const reloadModelManager = (): void => {\n globalModelManager = null\n // Force creation of new instance with fresh config\n getModelManager()\n}\n\n/**\n * Get the quick model for fast operations\n */\nexport const getQuickModel = (): string => {\n const manager = getModelManager()\n const quickModel = manager.getModel('quick')\n return quickModel?.modelName || 'quick' // Return pointer if model not resolved\n}\n\n/**\n * Get the compact model for context compression/summarization\n */\nexport const getCompactModel = (): string => {\n const manager = getModelManager()\n const compactModel = manager.getCompactModel()\n return compactModel || 'compact' // Return pointer if model not resolved\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { memoize } from 'lodash-es'\n\nimport { logError } from './log'\nimport {\n getGlobalConfig,\n ModelProfile,\n ModelPointerType,\n saveGlobalConfig,\n} from './config'\n\nexport const USE_BEDROCK = !!process.env.CLAUDE_CODE_USE_BEDROCK\nexport const USE_VERTEX = !!process.env.CLAUDE_CODE_USE_VERTEX\n\nexport interface ModelConfig {\n bedrock: string\n vertex: string\n firstParty: string\n}\n\nconst DEFAULT_MODEL_CONFIG: ModelConfig = {\n bedrock: 'us.anthropic.claude-3-7-sonnet-20250219-v1:0',\n vertex: 'claude-3-7-sonnet@20250219',\n firstParty: 'claude-sonnet-4-20250514',\n}\n\n/**\n * Helper to get the model config from defaults.\n */\nasync function getModelConfig(): Promise<ModelConfig> {\n return DEFAULT_MODEL_CONFIG\n}\n\nexport const getSlowAndCapableModel = memoize(async (): Promise<string> => {\n const config = await getGlobalConfig()\n\n // Use ModelManager for proper model resolution\n const modelManager = new ModelManager(config)\n const model = modelManager.getMainAgentModel()\n\n if (model) {\n return model\n }\n\n // Check if user has configured any models - if so, don't fallback to hardcoded defaults\n // This prevents the system from trying to use Claude models when user only has other providers\n const hasConfiguredModels = modelManager.hasConfiguredModels()\n if (hasConfiguredModels) {\n // User has models but none is set as main - this shouldn't happen normally\n // Return empty string to trigger proper error handling upstream\n throw new Error(\n 'No main model configured. Please use /model to set your default model.',\n )\n }\n\n // Only use hardcoded defaults for Bedrock/Vertex enterprise deployments\n // These are Anthropic-specific cloud deployments where Claude models are guaranteed\n const modelConfig = await getModelConfig()\n if (USE_BEDROCK) return modelConfig.bedrock\n if (USE_VERTEX) return modelConfig.vertex\n\n // For first-party (direct API) usage without any configured models,\n // throw an error to guide user to configure models\n throw new Error(\n 'No models configured. Please run /model to add and configure your AI models.',\n )\n})\n\n/**\n * Get context length for a model pointer type\n */\nexport function getModelContextLength(\n pointerType: ModelPointerType = 'main',\n): number {\n const config = getGlobalConfig()\n const modelManager = new ModelManager(config)\n\n // Get the model name based on pointer type\n let modelName: string | null = null\n switch (pointerType) {\n case 'main':\n modelName = modelManager.getMainAgentModel()\n break\n case 'task':\n modelName = modelManager.getTaskToolModel()\n break\n default:\n modelName = modelManager.getMainAgentModel()\n }\n\n // Find the profile for this model\n if (modelName) {\n const profile = config.modelProfiles?.find(\n (p: ModelProfile) => p.modelName === modelName && p.isActive,\n )\n if (profile && profile.contextLength) {\n return profile.contextLength\n }\n }\n\n // Default fallback (Claude Sonnet context length)\n return 200000\n}\n\nexport async function isDefaultSlowAndCapableModel(): Promise<boolean> {\n try {\n const configuredModel = await getSlowAndCapableModel()\n return (\n !process.env.ANTHROPIC_MODEL ||\n process.env.ANTHROPIC_MODEL === configuredModel\n )\n } catch {\n // If no model is configured, we're using \"default\" (which means none)\n return !process.env.ANTHROPIC_MODEL\n }\n}\n\n/**\n * Get the region for a specific Vertex model\n * Checks for hardcoded model-specific environment variables first,\n * then falls back to CLOUD_ML_REGION env var or default region\n */\nexport function getVertexRegionForModel(\n model: string | undefined,\n): string | undefined {\n if (model?.startsWith('claude-3-5-haiku')) {\n return process.env.VERTEX_REGION_CLAUDE_3_5_HAIKU\n } else if (model?.startsWith('claude-3-5-sonnet')) {\n return process.env.VERTEX_REGION_CLAUDE_3_5_SONNET\n } else if (model?.startsWith('claude-3-7-sonnet')) {\n return process.env.VERTEX_REGION_CLAUDE_3_7_SONNET\n }\n}\n\n/**\n * Comprehensive ModelManager class for centralized model selection and management.\n * Provides a clean interface for model selection across the application.\n */\nexport class ModelManager {\n private config: any // Using any to handle legacy properties\n private modelProfiles: ModelProfile[]\n\n constructor(config: any) {\n this.config = config\n this.modelProfiles = config.modelProfiles || []\n }\n\n /**\n * Get the current terminal model (for interactive CLI sessions)\n */\n getCurrentModel(): string | null {\n // Use main pointer from new ModelProfile system\n const mainModelName = this.config.modelPointers?.main\n if (mainModelName) {\n const profile = this.findModelProfile(mainModelName)\n if (profile && profile.isActive) {\n return profile.modelName\n }\n }\n\n // Fallback to main agent model\n return this.getMainAgentModel()\n }\n\n /**\n * Get the main agent default model (for non-terminal mode and MCP calls)\n */\n getMainAgentModel(): string | null {\n // Use main pointer from new ModelProfile system\n const mainModelName = this.config.modelPointers?.main\n if (mainModelName) {\n const profile = this.findModelProfile(mainModelName)\n if (profile && profile.isActive) {\n return profile.modelName\n }\n }\n\n // Fallback to first active profile\n const activeProfile = this.modelProfiles.find(p => p.isActive)\n if (activeProfile) {\n return activeProfile.modelName\n }\n\n return null\n }\n\n /**\n * Get the task tool default model (for Task tool sub-agents)\n */\n getTaskToolModel(): string | null {\n // Use task pointer from new ModelProfile system\n const taskModelName = this.config.modelPointers?.task\n if (taskModelName) {\n const profile = this.findModelProfile(taskModelName)\n if (profile && profile.isActive) {\n return profile.modelName\n }\n }\n\n // Fallback to main agent model\n return this.getMainAgentModel()\n }\n\n /**\n * Switch to the next available model with enhanced context overflow handling\n * If target model can't handle current context, shows warning and reverts after delay\n *\n * @param currentContextTokens - Current conversation token count for validation\n * @returns Object with detailed model name and context status information\n */\n switchToNextModelWithContextCheck(currentContextTokens: number = 0): {\n success: boolean\n modelName: string | null\n previousModelName: string | null\n contextOverflow: boolean\n usagePercentage: number\n // Enhanced feedback fields\n currentContextTokens: number\n targetContextLimit: number\n skippedModels: Array<{ name: string; reason: string }>\n totalAvailableModels: number\n } {\n // Use ALL configured models, not just active ones\n const allProfiles = this.getAllConfiguredModels()\n if (allProfiles.length === 0) {\n return {\n success: false,\n modelName: null,\n previousModelName: null,\n contextOverflow: false,\n usagePercentage: 0,\n currentContextTokens,\n targetContextLimit: 0,\n skippedModels: [],\n totalAvailableModels: 0,\n }\n }\n\n // Sort by createdAt for consistent cycling order (don't use lastUsed)\n // Using lastUsed causes the order to change each time, preventing proper cycling\n allProfiles.sort((a, b) => {\n return a.createdAt - b.createdAt // Oldest first for consistent order\n })\n\n const currentMainModelName = this.config.modelPointers?.main\n const currentModel = currentMainModelName\n ? this.findModelProfile(currentMainModelName)\n : null\n const previousModelName = currentModel?.name || null\n\n if (!currentMainModelName) {\n // No current main model, select first available (activate if needed)\n const firstModel = allProfiles[0]\n if (!firstModel.isActive) {\n firstModel.isActive = true\n }\n this.setPointer('main', firstModel.modelName)\n this.updateLastUsed(firstModel.modelName)\n\n const analysis = this.analyzeContextCompatibility(\n firstModel,\n currentContextTokens,\n )\n return {\n success: true,\n modelName: firstModel.name,\n previousModelName: null,\n contextOverflow: !analysis.compatible,\n usagePercentage: analysis.usagePercentage,\n currentContextTokens,\n targetContextLimit: firstModel.contextLength,\n skippedModels: [],\n totalAvailableModels: allProfiles.length,\n }\n }\n\n // Find current model index in ALL models\n const currentIndex = allProfiles.findIndex(\n p => p.modelName === currentMainModelName,\n )\n if (currentIndex === -1) {\n // Current model not found, select first available (activate if needed)\n const firstModel = allProfiles[0]\n if (!firstModel.isActive) {\n firstModel.isActive = true\n }\n this.setPointer('main', firstModel.modelName)\n this.updateLastUsed(firstModel.modelName)\n\n const analysis = this.analyzeContextCompatibility(\n firstModel,\n currentContextTokens,\n )\n return {\n success: true,\n modelName: firstModel.name,\n previousModelName,\n contextOverflow: !analysis.compatible,\n usagePercentage: analysis.usagePercentage,\n currentContextTokens,\n targetContextLimit: firstModel.contextLength,\n skippedModels: [],\n totalAvailableModels: allProfiles.length,\n }\n }\n\n // Check if only one model is available\n if (allProfiles.length === 1) {\n const currentModel = allProfiles[0]\n return {\n success: false,\n modelName: null,\n previousModelName,\n contextOverflow: false,\n usagePercentage: 0,\n currentContextTokens,\n targetContextLimit: currentModel?.contextLength || 0,\n skippedModels: [],\n totalAvailableModels: 1,\n }\n }\n\n // Get next model in cycle (from ALL models)\n const nextIndex = (currentIndex + 1) % allProfiles.length\n const nextModel = allProfiles[nextIndex]\n\n // Activate the model if it's not already active\n const wasInactive = !nextModel.isActive\n if (!nextModel.isActive) {\n nextModel.isActive = true\n }\n\n // Analyze context compatibility for next model\n const analysis = this.analyzeContextCompatibility(\n nextModel,\n currentContextTokens,\n )\n\n // Always switch to next model, but return context status\n this.setPointer('main', nextModel.modelName)\n this.updateLastUsed(nextModel.modelName)\n\n // Save configuration if we activated a new model\n if (wasInactive) {\n this.saveConfig()\n }\n\n return {\n success: true,\n modelName: nextModel.name,\n previousModelName,\n contextOverflow: !analysis.compatible,\n usagePercentage: analysis.usagePercentage,\n currentContextTokens,\n targetContextLimit: nextModel.contextLength,\n skippedModels: [], // In simple round-robin, no models are skipped\n totalAvailableModels: allProfiles.length,\n }\n }\n\n /**\n * Simple model switching for UI components (compatible interface)\n * @param currentContextTokens - Current conversation token count for validation\n * @returns Compatible interface for PromptInput component\n */\n switchToNextModel(currentContextTokens: number = 0): {\n success: boolean\n modelName: string | null\n blocked?: boolean\n message?: string\n } {\n // Use the enhanced context check method for consistency\n const result = this.switchToNextModelWithContextCheck(currentContextTokens)\n\n if (!result.success) {\n const allModels = this.getAllConfiguredModels()\n if (allModels.length === 0) {\n return {\n success: false,\n modelName: null,\n blocked: false,\n message: '\u274C No models configured. Use /model to add models.',\n }\n } else if (allModels.length === 1) {\n return {\n success: false,\n modelName: null,\n blocked: false,\n message: `\u26A0\uFE0F Only one model configured (${allModels[0].modelName}). Use /model to add more models for switching.`,\n }\n }\n }\n\n // Convert the detailed result to the simple interface\n const currentModel = this.findModelProfile(this.config.modelPointers?.main)\n const allModels = this.getAllConfiguredModels()\n const currentIndex = allModels.findIndex(\n m => m.modelName === currentModel?.modelName,\n )\n const totalModels = allModels.length\n\n return {\n success: result.success,\n modelName: result.modelName,\n blocked: result.contextOverflow,\n message: result.success\n ? result.contextOverflow\n ? `\u26A0\uFE0F Context usage: ${result.usagePercentage.toFixed(1)}% - ${result.modelName}`\n : `\u2705 Switched to ${result.modelName} (${currentIndex + 1}/${totalModels})${currentModel?.provider ? ` [${currentModel.provider}]` : ''}`\n : `\u274C Failed to switch models`,\n }\n }\n\n /**\n * Revert to previous model (used when context overflow requires rollback)\n */\n revertToPreviousModel(previousModelName: string): boolean {\n const previousModel = this.modelProfiles.find(\n p => p.name === previousModelName && p.isActive,\n )\n if (!previousModel) {\n return false\n }\n\n this.setPointer('main', previousModel.modelName)\n this.updateLastUsed(previousModel.modelName)\n return true\n }\n\n /**\n * Enhanced context validation with different severity levels\n */\n analyzeContextCompatibility(\n model: ModelProfile,\n contextTokens: number,\n ): {\n compatible: boolean\n severity: 'safe' | 'warning' | 'critical'\n usagePercentage: number\n recommendation: string\n } {\n const usableContext = Math.floor(model.contextLength * 0.8) // Reserve 20% for output\n const usagePercentage = (contextTokens / usableContext) * 100\n\n if (usagePercentage <= 70) {\n return {\n compatible: true,\n severity: 'safe',\n usagePercentage,\n recommendation: 'Full context preserved',\n }\n } else if (usagePercentage <= 90) {\n return {\n compatible: true,\n severity: 'warning',\n usagePercentage,\n recommendation: 'Context usage high, consider compression',\n }\n } else {\n return {\n compatible: false,\n severity: 'critical',\n usagePercentage,\n recommendation: 'Auto-compression or message truncation required',\n }\n }\n }\n\n /**\n * Switch to next model with enhanced context analysis\n */\n switchToNextModelWithAnalysis(currentContextTokens: number = 0): {\n modelName: string | null\n contextAnalysis: ReturnType<typeof this.analyzeContextCompatibility> | null\n requiresCompression: boolean\n estimatedTokensAfterSwitch: number\n } {\n const result = this.switchToNextModel(currentContextTokens)\n\n if (!result.success || !result.modelName) {\n return {\n modelName: null,\n contextAnalysis: null,\n requiresCompression: false,\n estimatedTokensAfterSwitch: 0,\n }\n }\n\n const newModel = this.getModel('main')\n if (!newModel) {\n return {\n modelName: result.modelName,\n contextAnalysis: null,\n requiresCompression: false,\n estimatedTokensAfterSwitch: currentContextTokens,\n }\n }\n\n const analysis = this.analyzeContextCompatibility(\n newModel,\n currentContextTokens,\n )\n\n return {\n modelName: result.modelName,\n contextAnalysis: analysis,\n requiresCompression: analysis.severity === 'critical',\n estimatedTokensAfterSwitch: currentContextTokens,\n }\n }\n\n /**\n * Check if a model can handle the given context size (legacy method)\n */\n canModelHandleContext(model: ModelProfile, contextTokens: number): boolean {\n const analysis = this.analyzeContextCompatibility(model, contextTokens)\n return analysis.compatible\n }\n\n /**\n * Find the first model that can handle the given context size\n */\n findModelWithSufficientContext(\n models: ModelProfile[],\n contextTokens: number,\n ): ModelProfile | null {\n return (\n models.find(model => this.canModelHandleContext(model, contextTokens)) ||\n null\n )\n }\n\n /**\n * Unified model getter for different contexts\n */\n getModelForContext(\n contextType: 'terminal' | 'main-agent' | 'task-tool',\n ): string | null {\n switch (contextType) {\n case 'terminal':\n return this.getCurrentModel()\n case 'main-agent':\n return this.getMainAgentModel()\n case 'task-tool':\n return this.getTaskToolModel()\n default:\n return this.getMainAgentModel()\n }\n }\n\n /**\n * Get all active model profiles\n */\n getActiveModelProfiles(): ModelProfile[] {\n return this.modelProfiles.filter(p => p.isActive)\n }\n\n /**\n * Check if any models are configured\n */\n hasConfiguredModels(): boolean {\n return this.getActiveModelProfiles().length > 0\n }\n\n // New model pointer system methods\n\n /**\n * Get model by pointer type (main, task, reasoning, quick)\n */\n getModel(pointer: ModelPointerType): ModelProfile | null {\n const pointerId = this.config.modelPointers?.[pointer]\n if (!pointerId) {\n return this.getDefaultModel()\n }\n\n const profile = this.findModelProfile(pointerId)\n return profile && profile.isActive ? profile : this.getDefaultModel()\n }\n\n /**\n * Get model name by pointer type\n */\n getModelName(pointer: ModelPointerType): string | null {\n const profile = this.getModel(pointer)\n return profile ? profile.modelName : null\n }\n\n /**\n * Get reasoning model (with fallback)\n */\n getReasoningModel(): string | null {\n return this.getModelName('reasoning') || this.getModelName('main')\n }\n\n /**\n * Get quick model (with fallback)\n */\n getQuickModel(): string | null {\n return (\n this.getModelName('quick') ||\n this.getModelName('task') ||\n this.getModelName('main')\n )\n }\n\n /**\n * Get compact model for context compression/summarization (with fallback)\n * Fallback chain: compact -> quick -> task -> main\n */\n getCompactModel(): string | null {\n return (\n this.getModelName('compact') ||\n this.getModelName('quick') ||\n this.getModelName('task') ||\n this.getModelName('main')\n )\n }\n\n /**\n * Add a new model profile with duplicate validation\n */\n async addModel(\n config: Omit<ModelProfile, 'createdAt' | 'isActive'>,\n ): Promise<string> {\n // Check for duplicate modelName (actual model identifier)\n const existingByModelName = this.modelProfiles.find(\n p => p.modelName === config.modelName,\n )\n if (existingByModelName) {\n throw new Error(\n `Model with modelName '${config.modelName}' already exists: ${existingByModelName.name}`,\n )\n }\n\n // Check for duplicate friendly name\n const existingByName = this.modelProfiles.find(p => p.name === config.name)\n if (existingByName) {\n throw new Error(`Model with name '${config.name}' already exists`)\n }\n\n const newModel: ModelProfile = {\n ...config,\n createdAt: Date.now(),\n isActive: true,\n }\n\n this.modelProfiles.push(newModel)\n\n // If this is the first model, set all pointers to it\n if (this.modelProfiles.length === 1) {\n this.config.modelPointers = {\n main: config.modelName,\n task: config.modelName,\n reasoning: config.modelName,\n quick: config.modelName,\n compact: config.modelName,\n }\n this.config.defaultModelName = config.modelName\n }\n\n this.saveConfig()\n return config.modelName\n }\n\n /**\n * Set model pointer assignment\n */\n setPointer(pointer: ModelPointerType, modelName: string): void {\n if (!this.findModelProfile(modelName)) {\n throw new Error(`Model '${modelName}' not found`)\n }\n\n if (!this.config.modelPointers) {\n this.config.modelPointers = {\n main: '',\n task: '',\n reasoning: '',\n quick: '',\n compact: '',\n }\n }\n\n this.config.modelPointers[pointer] = modelName\n this.saveConfig()\n }\n\n /**\n * Get all active models for pointer assignment\n */\n getAvailableModels(): ModelProfile[] {\n return this.modelProfiles.filter(p => p.isActive)\n }\n\n /**\n * Get all configured models (both active and inactive) for switching\n */\n getAllConfiguredModels(): ModelProfile[] {\n return this.modelProfiles\n }\n\n /**\n * Get all available model names (modelName field) - active only\n */\n getAllAvailableModelNames(): string[] {\n return this.getAvailableModels().map(p => p.modelName)\n }\n\n /**\n * Get all configured model names (both active and inactive)\n */\n getAllConfiguredModelNames(): string[] {\n return this.getAllConfiguredModels().map(p => p.modelName)\n }\n\n /**\n * Debug method to get detailed model switching information\n */\n getModelSwitchingDebugInfo(): {\n totalModels: number\n activeModels: number\n inactiveModels: number\n currentMainModel: string | null\n availableModels: Array<{\n name: string\n modelName: string\n provider: string\n isActive: boolean\n lastUsed?: number\n }>\n modelPointers: Record<string, string | undefined>\n } {\n const availableModels = this.getAvailableModels()\n const currentMainModelName = this.config.modelPointers?.main\n\n return {\n totalModels: this.modelProfiles.length,\n activeModels: availableModels.length,\n inactiveModels: this.modelProfiles.length - availableModels.length,\n currentMainModel: currentMainModelName || null,\n availableModels: this.modelProfiles.map(p => ({\n name: p.name,\n modelName: p.modelName,\n provider: p.provider,\n isActive: p.isActive,\n lastUsed: p.lastUsed,\n })),\n modelPointers: this.config.modelPointers || {},\n }\n }\n\n /**\n * Remove a model profile\n */\n removeModel(modelName: string): void {\n this.modelProfiles = this.modelProfiles.filter(\n p => p.modelName !== modelName,\n )\n\n // Clean up pointers that reference deleted model\n if (this.config.modelPointers) {\n Object.keys(this.config.modelPointers).forEach(pointer => {\n if (\n this.config.modelPointers[pointer as ModelPointerType] === modelName\n ) {\n this.config.modelPointers[pointer as ModelPointerType] =\n this.config.defaultModelName || ''\n }\n })\n }\n\n this.saveConfig()\n }\n\n /**\n * Get default model profile\n */\n private getDefaultModel(): ModelProfile | null {\n if (this.config.defaultModelId) {\n const profile = this.findModelProfile(this.config.defaultModelId)\n if (profile && profile.isActive) {\n return profile\n }\n }\n return this.modelProfiles.find(p => p.isActive) || null\n }\n\n /**\n * Save configuration changes\n * Note: This updates the global config file. The singleton instance\n * is automatically refreshed to avoid stale data issues.\n */\n private saveConfig(): void {\n const updatedConfig = {\n ...this.config,\n modelProfiles: this.modelProfiles,\n }\n saveGlobalConfig(updatedConfig)\n\n // Refresh the global singleton to avoid stale data race conditions\n // This ensures any subsequent getModelManager() calls get fresh data\n refreshGlobalModelManagerInstance(this)\n }\n\n /**\n * Get a fallback model when no specific model is configured\n */\n async getFallbackModel(): Promise<string> {\n const modelConfig = await getModelConfig()\n if (USE_BEDROCK) return modelConfig.bedrock\n if (USE_VERTEX) return modelConfig.vertex\n return modelConfig.firstParty\n }\n\n /**\n * \u7EDF\u4E00\u7684\u6A21\u578B\u89E3\u6790\u65B9\u6CD5\uFF1A\u652F\u6301\u6307\u9488\u3001model ID \u548C\u771F\u5B9E\u6A21\u578B\u540D\u79F0\n * @param modelParam - \u53EF\u4EE5\u662F\u6A21\u578B\u6307\u9488 ('main', 'task', etc.)\u3001\u5185\u90E8model ID \u6216\u771F\u5B9E\u6A21\u578B\u540D\u79F0 ('gpt-4o', 'claude-3-5-sonnet')\n * @returns ModelProfile \u6216 null\n */\n resolveModel(modelParam: string | ModelPointerType): ModelProfile | null {\n // \u9996\u5148\u68C0\u67E5\u662F\u5426\u662F\u6A21\u578B\u6307\u9488\n if (\n ['main', 'task', 'reasoning', 'quick', 'compact'].includes(modelParam)\n ) {\n const pointerId =\n this.config.modelPointers?.[modelParam as ModelPointerType]\n if (pointerId) {\n // pointerId \u53EF\u80FD\u662F\u5185\u90E8ID\u6216\u771F\u5B9E\u6A21\u578B\u540D\u79F0\uFF0C\u5C1D\u8BD5\u4E24\u79CD\u67E5\u627E\u65B9\u5F0F\n let profile = this.findModelProfile(pointerId) // \u6309\u5185\u90E8ID\u67E5\u627E\n if (!profile) {\n profile = this.findModelProfileByModelName(pointerId) // \u6309\u771F\u5B9E\u6A21\u578B\u540D\u67E5\u627E\n }\n if (profile && profile.isActive) {\n return profile\n }\n }\n // \u6307\u9488\u65E0\u6548\u65F6\uFF0C\u5C1D\u8BD5 fallback \u5230\u9ED8\u8BA4\u6A21\u578B\n return this.getDefaultModel()\n }\n\n // \u4E0D\u662F\u6307\u9488\uFF0C\u5C1D\u8BD5\u591A\u79CD\u67E5\u627E\u65B9\u5F0F\n // 1. \u5C1D\u8BD5\u6309\u5185\u90E8 model ID \u67E5\u627E\n let profile = this.findModelProfile(modelParam)\n if (profile && profile.isActive) {\n return profile\n }\n\n // 2. \u5C1D\u8BD5\u6309\u771F\u5B9E\u6A21\u578B\u540D\u79F0\u67E5\u627E\n profile = this.findModelProfileByModelName(modelParam)\n if (profile && profile.isActive) {\n return profile\n }\n\n // 3. \u5C1D\u8BD5\u6309\u53CB\u597D\u540D\u79F0\u67E5\u627E\n profile = this.findModelProfileByName(modelParam)\n if (profile && profile.isActive) {\n return profile\n }\n\n // \u6240\u6709\u67E5\u627E\u65B9\u5F0F\u90FD\u5931\u8D25\uFF0C\u5C1D\u8BD5 fallback \u5230\u9ED8\u8BA4\u6A21\u578B\n return this.getDefaultModel()\n }\n\n /**\n * \u89E3\u6790\u6A21\u578B\u53C2\u6570\u5E76\u8FD4\u56DE\u5B8C\u6574\u4FE1\u606F\n */\n resolveModelWithInfo(modelParam: string | ModelPointerType): {\n success: boolean\n profile: ModelProfile | null\n error?: string\n } {\n const isPointer = [\n 'main',\n 'task',\n 'reasoning',\n 'quick',\n 'compact',\n ].includes(modelParam)\n\n if (isPointer) {\n const pointerId =\n this.config.modelPointers?.[modelParam as ModelPointerType]\n if (!pointerId) {\n return {\n success: false,\n profile: null,\n error: `Model pointer '${modelParam}' is not configured. Use /model to set up models.`,\n }\n }\n\n // pointerId \u53EF\u80FD\u662F\u5185\u90E8ID\u6216\u771F\u5B9E\u6A21\u578B\u540D\u79F0\n let profile = this.findModelProfile(pointerId)\n if (!profile) {\n profile = this.findModelProfileByModelName(pointerId)\n }\n\n if (!profile) {\n return {\n success: false,\n profile: null,\n error: `Model pointer '${modelParam}' points to invalid model '${pointerId}'. Use /model to reconfigure.`,\n }\n }\n\n if (!profile.isActive) {\n return {\n success: false,\n profile: null,\n error: `Model '${profile.name}' (pointed by '${modelParam}') is inactive. Use /model to activate it.`,\n }\n }\n\n return {\n success: true,\n profile,\n }\n } else {\n // \u76F4\u63A5\u7684 model ID \u6216\u6A21\u578B\u540D\u79F0\uFF0C\u5C1D\u8BD5\u591A\u79CD\u67E5\u627E\u65B9\u5F0F\n let profile = this.findModelProfile(modelParam)\n if (!profile) {\n profile = this.findModelProfileByModelName(modelParam)\n }\n if (!profile) {\n profile = this.findModelProfileByName(modelParam)\n }\n\n if (!profile) {\n return {\n success: false,\n profile: null,\n error: `Model '${modelParam}' not found. Use /model to add models.`,\n }\n }\n\n if (!profile.isActive) {\n return {\n success: false,\n profile: null,\n error: `Model '${profile.name}' is inactive. Use /model to activate it.`,\n }\n }\n\n return {\n success: true,\n profile,\n }\n }\n }\n\n // Private helper methods\n private findModelProfile(modelName: string): ModelProfile | null {\n return this.modelProfiles.find(p => p.modelName === modelName) || null\n }\n\n private findModelProfileByModelName(modelName: string): ModelProfile | null {\n return this.modelProfiles.find(p => p.modelName === modelName) || null\n }\n\n private findModelProfileByName(name: string): ModelProfile | null {\n return this.modelProfiles.find(p => p.name === name) || null\n }\n\n private updateLastUsed(modelName: string): void {\n const profile = this.findModelProfile(modelName)\n if (profile) {\n profile.lastUsed = Date.now()\n }\n }\n\n /**\n * Find model profile by provider-qualified name (e.g., \"openai:gpt-4o\", \"anthropic:claude-3-5-sonnet\")\n * @param qualifiedName - Format: \"provider:modelName\" or just \"modelName\"\n * @returns ModelProfile or null\n */\n findModelByProviderQualified(qualifiedName: string): ModelProfile | null {\n // Check if it's a provider-qualified name\n if (qualifiedName.includes(':')) {\n const [provider, modelName] = qualifiedName.split(':', 2)\n // Find model matching both provider and modelName\n return (\n this.modelProfiles.find(\n p =>\n p.provider.toLowerCase() === provider.toLowerCase() &&\n (p.modelName === modelName ||\n p.modelName.toLowerCase() === modelName.toLowerCase() ||\n p.name.toLowerCase() === modelName.toLowerCase()),\n ) || null\n )\n }\n\n // Not provider-qualified, fall back to regular lookup\n return (\n this.findModelProfile(qualifiedName) ||\n this.findModelProfileByName(qualifiedName)\n )\n }\n\n /**\n * Enhanced model resolution supporting provider:model format\n * @param modelParam - Can be pointer, provider:model, modelName, or friendly name\n * @returns ModelProfile or null\n */\n resolveProviderQualifiedModel(modelParam: string): {\n profile: ModelProfile | null\n provider?: string\n modelId?: string\n } {\n // Check for provider:model format first\n if (\n modelParam.includes(':') &&\n !['main', 'task', 'reasoning', 'quick', 'compact'].includes(\n modelParam.split(':')[0],\n )\n ) {\n const [provider, modelId] = modelParam.split(':', 2)\n const profile = this.findModelByProviderQualified(modelParam)\n return { profile, provider, modelId }\n }\n\n // Fall back to regular resolve\n const profile = this.resolveModel(modelParam)\n return { profile }\n }\n\n /**\n * Get all models from a specific provider\n */\n getModelsByProvider(provider: string): ModelProfile[] {\n return this.modelProfiles.filter(\n p => p.provider.toLowerCase() === provider.toLowerCase(),\n )\n }\n\n /**\n * Get list of unique providers\n */\n getUniqueProviders(): string[] {\n const providers = new Set(this.modelProfiles.map(p => p.provider))\n return Array.from(providers)\n }\n}\n\n// Global ModelManager instance to avoid config read/write race conditions\nlet globalModelManager: ModelManager | null = null\n\n/**\n * Internal function to refresh the global singleton with an updated instance\n * This is called by ModelManager.saveConfig() to avoid stale data\n */\nfunction refreshGlobalModelManagerInstance(instance: ModelManager): void {\n globalModelManager = instance\n}\n\n/**\n * Get the global ModelManager instance (singleton pattern to fix race conditions)\n */\nexport const getModelManager = (): ModelManager => {\n try {\n if (!globalModelManager) {\n const config = getGlobalConfig()\n if (!config) {\n console.warn(\n 'No global config available, creating ModelManager with empty config',\n )\n globalModelManager = new ModelManager({\n modelProfiles: [],\n modelPointers: {\n main: '',\n task: '',\n reasoning: '',\n quick: '',\n compact: '',\n },\n })\n } else {\n globalModelManager = new ModelManager(config)\n }\n }\n return globalModelManager\n } catch (error) {\n console.error('Error creating ModelManager:', error)\n // Return a fallback ModelManager with empty configuration\n return new ModelManager({\n modelProfiles: [],\n modelPointers: {\n main: '',\n task: '',\n reasoning: '',\n quick: '',\n compact: '',\n },\n })\n }\n}\n\n/**\n * Force reload of the global ModelManager instance\n * Used when configuration changes to ensure fresh data\n */\nexport const reloadModelManager = (): void => {\n globalModelManager = null\n // Force creation of new instance with fresh config\n getModelManager()\n}\n\n/**\n * Get the quick model for fast operations\n */\nexport const getQuickModel = (): string => {\n const manager = getModelManager()\n const quickModel = manager.getModel('quick')\n return quickModel?.modelName || 'quick' // Return pointer if model not resolved\n}\n\n/**\n * Get the compact model for context compression/summarization\n */\nexport const getCompactModel = (): string => {\n const manager = getModelManager()\n const compactModel = manager.getCompactModel()\n return compactModel || 'compact' // Return pointer if model not resolved\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe;AAGxB;AAAA,EACE;AAAA,EAGA;AAAA,OACK;AAEA,MAAM,cAAc,CAAC,CAAC,QAAQ,IAAI;AAClC,MAAM,aAAa,CAAC,CAAC,QAAQ,IAAI;AAQxC,MAAM,uBAAoC;AAAA,EACxC,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AACd;AAKA,eAAe,iBAAuC;AACpD,SAAO;AACT;AAEO,MAAM,yBAAyB,QAAQ,YAA6B;AACzE,QAAM,SAAS,MAAM,gBAAgB;AAGrC,QAAM,eAAe,IAAI,aAAa,MAAM;AAC5C,QAAM,QAAQ,aAAa,kBAAkB;AAE7C,MAAI,OAAO;AACT,WAAO;AAAA,EACT;AAIA,QAAM,sBAAsB,aAAa,oBAAoB;AAC7D,MAAI,qBAAqB;AAGvB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAIA,QAAM,cAAc,MAAM,eAAe;AACzC,MAAI,YAAa,QAAO,YAAY;AACpC,MAAI,WAAY,QAAO,YAAY;AAInC,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF,CAAC;AAKM,SAAS,sBACd,cAAgC,QACxB;AACR,QAAM,SAAS,gBAAgB;AAC/B,QAAM,eAAe,IAAI,aAAa,MAAM;AAG5C,MAAI,YAA2B;AAC/B,UAAQ,aAAa;AAAA,IACnB,KAAK;AACH,kBAAY,aAAa,kBAAkB;AAC3C;AAAA,IACF,KAAK;AACH,kBAAY,aAAa,iBAAiB;AAC1C;AAAA,IACF;AACE,kBAAY,aAAa,kBAAkB;AAAA,EAC/C;AAGA,MAAI,WAAW;AACb,UAAM,UAAU,OAAO,eAAe;AAAA,MACpC,CAAC,MAAoB,EAAE,cAAc,aAAa,EAAE;AAAA,IACtD;AACA,QAAI,WAAW,QAAQ,eAAe;AACpC,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAGA,SAAO;AACT;AAEA,eAAsB,+BAAiD;AACrE,MAAI;AACF,UAAM,kBAAkB,MAAM,uBAAuB;AACrD,WACE,CAAC,QAAQ,IAAI,mBACb,QAAQ,IAAI,oBAAoB;AAAA,EAEpC,QAAQ;AAEN,WAAO,CAAC,QAAQ,IAAI;AAAA,EACtB;AACF;AAOO,SAAS,wBACd,OACoB;AACpB,MAAI,OAAO,WAAW,kBAAkB,GAAG;AACzC,WAAO,QAAQ,IAAI;AAAA,EACrB,WAAW,OAAO,WAAW,mBAAmB,GAAG;AACjD,WAAO,QAAQ,IAAI;AAAA,EACrB,WAAW,OAAO,WAAW,mBAAmB,GAAG;AACjD,WAAO,QAAQ,IAAI;AAAA,EACrB;AACF;AAMO,MAAM,aAAa;AAAA,EAChB;AAAA;AAAA,EACA;AAAA,EAER,YAAY,QAAa;AACvB,SAAK,SAAS;AACd,SAAK,gBAAgB,OAAO,iBAAiB,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAiC;AAE/B,UAAM,gBAAgB,KAAK,OAAO,eAAe;AACjD,QAAI,eAAe;AACjB,YAAM,UAAU,KAAK,iBAAiB,aAAa;AACnD,UAAI,WAAW,QAAQ,UAAU;AAC/B,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAGA,WAAO,KAAK,kBAAkB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAmC;AAEjC,UAAM,gBAAgB,KAAK,OAAO,eAAe;AACjD,QAAI,eAAe;AACjB,YAAM,UAAU,KAAK,iBAAiB,aAAa;AACnD,UAAI,WAAW,QAAQ,UAAU;AAC/B,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAGA,UAAM,gBAAgB,KAAK,cAAc,KAAK,OAAK,EAAE,QAAQ;AAC7D,QAAI,eAAe;AACjB,aAAO,cAAc;AAAA,IACvB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAkC;AAEhC,UAAM,gBAAgB,KAAK,OAAO,eAAe;AACjD,QAAI,eAAe;AACjB,YAAM,UAAU,KAAK,iBAAiB,aAAa;AACnD,UAAI,WAAW,QAAQ,UAAU;AAC/B,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAGA,WAAO,KAAK,kBAAkB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,kCAAkC,uBAA+B,GAW/D;AAEA,UAAM,cAAc,KAAK,uBAAuB;AAChD,QAAI,YAAY,WAAW,GAAG;AAC5B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,QACX,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,QACjB,iBAAiB;AAAA,QACjB;AAAA,QACA,oBAAoB;AAAA,QACpB,eAAe,CAAC;AAAA,QAChB,sBAAsB;AAAA,MACxB;AAAA,IACF;AAIA,gBAAY,KAAK,CAAC,GAAG,MAAM;AACzB,aAAO,EAAE,YAAY,EAAE;AAAA,IACzB,CAAC;AAED,UAAM,uBAAuB,KAAK,OAAO,eAAe;AACxD,UAAM,eAAe,uBACjB,KAAK,iBAAiB,oBAAoB,IAC1C;AACJ,UAAM,oBAAoB,cAAc,QAAQ;AAEhD,QAAI,CAAC,sBAAsB;AAEzB,YAAM,aAAa,YAAY,CAAC;AAChC,UAAI,CAAC,WAAW,UAAU;AACxB,mBAAW,WAAW;AAAA,MACxB;AACA,WAAK,WAAW,QAAQ,WAAW,SAAS;AAC5C,WAAK,eAAe,WAAW,SAAS;AAExC,YAAMA,YAAW,KAAK;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW,WAAW;AAAA,QACtB,mBAAmB;AAAA,QACnB,iBAAiB,CAACA,UAAS;AAAA,QAC3B,iBAAiBA,UAAS;AAAA,QAC1B;AAAA,QACA,oBAAoB,WAAW;AAAA,QAC/B,eAAe,CAAC;AAAA,QAChB,sBAAsB,YAAY;AAAA,MACpC;AAAA,IACF;AAGA,UAAM,eAAe,YAAY;AAAA,MAC/B,OAAK,EAAE,cAAc;AAAA,IACvB;AACA,QAAI,iBAAiB,IAAI;AAEvB,YAAM,aAAa,YAAY,CAAC;AAChC,UAAI,CAAC,WAAW,UAAU;AACxB,mBAAW,WAAW;AAAA,MACxB;AACA,WAAK,WAAW,QAAQ,WAAW,SAAS;AAC5C,WAAK,eAAe,WAAW,SAAS;AAExC,YAAMA,YAAW,KAAK;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AACA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW,WAAW;AAAA,QACtB;AAAA,QACA,iBAAiB,CAACA,UAAS;AAAA,QAC3B,iBAAiBA,UAAS;AAAA,QAC1B;AAAA,QACA,oBAAoB,WAAW;AAAA,QAC/B,eAAe,CAAC;AAAA,QAChB,sBAAsB,YAAY;AAAA,MACpC;AAAA,IACF;AAGA,QAAI,YAAY,WAAW,GAAG;AAC5B,YAAMC,gBAAe,YAAY,CAAC;AAClC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,QACX;AAAA,QACA,iBAAiB;AAAA,QACjB,iBAAiB;AAAA,QACjB;AAAA,QACA,oBAAoBA,eAAc,iBAAiB;AAAA,QACnD,eAAe,CAAC;AAAA,QAChB,sBAAsB;AAAA,MACxB;AAAA,IACF;AAGA,UAAM,aAAa,eAAe,KAAK,YAAY;AACnD,UAAM,YAAY,YAAY,SAAS;AAGvC,UAAM,cAAc,CAAC,UAAU;AAC/B,QAAI,CAAC,UAAU,UAAU;AACvB,gBAAU,WAAW;AAAA,IACvB;AAGA,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AAGA,SAAK,WAAW,QAAQ,UAAU,SAAS;AAC3C,SAAK,eAAe,UAAU,SAAS;AAGvC,QAAI,aAAa;AACf,WAAK,WAAW;AAAA,IAClB;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,WAAW,UAAU;AAAA,MACrB;AAAA,MACA,iBAAiB,CAAC,SAAS;AAAA,MAC3B,iBAAiB,SAAS;AAAA,MAC1B;AAAA,MACA,oBAAoB,UAAU;AAAA,MAC9B,eAAe,CAAC;AAAA;AAAA,MAChB,sBAAsB,YAAY;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAAkB,uBAA+B,GAK/C;AAEA,UAAM,SAAS,KAAK,kCAAkC,oBAAoB;AAE1E,QAAI,CAAC,OAAO,SAAS;AACnB,YAAMC,aAAY,KAAK,uBAAuB;AAC9C,UAAIA,WAAU,WAAW,GAAG;AAC1B,eAAO;AAAA,UACL,SAAS;AAAA,UACT,WAAW;AAAA,UACX,SAAS;AAAA,UACT,SAAS;AAAA,QACX;AAAA,MACF,WAAWA,WAAU,WAAW,GAAG;AACjC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,WAAW;AAAA,UACX,SAAS;AAAA,UACT,SAAS,2CAAiCA,WAAU,CAAC,EAAE,SAAS;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAGA,UAAM,eAAe,KAAK,iBAAiB,KAAK,OAAO,eAAe,IAAI;AAC1E,UAAM,YAAY,KAAK,uBAAuB;AAC9C,UAAM,eAAe,UAAU;AAAA,MAC7B,OAAK,EAAE,cAAc,cAAc;AAAA,IACrC;AACA,UAAM,cAAc,UAAU;AAE9B,WAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,WAAW,OAAO;AAAA,MAClB,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO,UACZ,OAAO,kBACL,+BAAqB,OAAO,gBAAgB,QAAQ,CAAC,CAAC,OAAO,OAAO,SAAS,KAC7E,sBAAiB,OAAO,SAAS,KAAK,eAAe,CAAC,IAAI,WAAW,IAAI,cAAc,WAAW,KAAK,aAAa,QAAQ,MAAM,EAAE,KACtI;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,mBAAoC;AACxD,UAAM,gBAAgB,KAAK,cAAc;AAAA,MACvC,OAAK,EAAE,SAAS,qBAAqB,EAAE;AAAA,IACzC;AACA,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,IACT;AAEA,SAAK,WAAW,QAAQ,cAAc,SAAS;AAC/C,SAAK,eAAe,cAAc,SAAS;AAC3C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,4BACE,OACA,eAMA;AACA,UAAM,gBAAgB,KAAK,MAAM,MAAM,gBAAgB,GAAG;AAC1D,UAAM,kBAAmB,gBAAgB,gBAAiB;AAE1D,QAAI,mBAAmB,IAAI;AACzB,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,QACA,gBAAgB;AAAA,MAClB;AAAA,IACF,WAAW,mBAAmB,IAAI;AAChC,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,QACA,gBAAgB;AAAA,MAClB;AAAA,IACF,OAAO;AACL,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,QACA,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,8BAA8B,uBAA+B,GAK3D;AACA,UAAM,SAAS,KAAK,kBAAkB,oBAAoB;AAE1D,QAAI,CAAC,OAAO,WAAW,CAAC,OAAO,WAAW;AACxC,aAAO;AAAA,QACL,WAAW;AAAA,QACX,iBAAiB;AAAA,QACjB,qBAAqB;AAAA,QACrB,4BAA4B;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,SAAS,MAAM;AACrC,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL,WAAW,OAAO;AAAA,QAClB,iBAAiB;AAAA,QACjB,qBAAqB;AAAA,QACrB,4BAA4B;AAAA,MAC9B;AAAA,IACF;AAEA,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,WAAW,OAAO;AAAA,MAClB,iBAAiB;AAAA,MACjB,qBAAqB,SAAS,aAAa;AAAA,MAC3C,4BAA4B;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,OAAqB,eAAgC;AACzE,UAAM,WAAW,KAAK,4BAA4B,OAAO,aAAa;AACtE,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,+BACE,QACA,eACqB;AACrB,WACE,OAAO,KAAK,WAAS,KAAK,sBAAsB,OAAO,aAAa,CAAC,KACrE;AAAA,EAEJ;AAAA;AAAA;AAAA;AAAA,EAKA,mBACE,aACe;AACf,YAAQ,aAAa;AAAA,MACnB,KAAK;AACH,eAAO,KAAK,gBAAgB;AAAA,MAC9B,KAAK;AACH,eAAO,KAAK,kBAAkB;AAAA,MAChC,KAAK;AACH,eAAO,KAAK,iBAAiB;AAAA,MAC/B;AACE,eAAO,KAAK,kBAAkB;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAyC;AACvC,WAAO,KAAK,cAAc,OAAO,OAAK,EAAE,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA+B;AAC7B,WAAO,KAAK,uBAAuB,EAAE,SAAS;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,SAAgD;AACvD,UAAM,YAAY,KAAK,OAAO,gBAAgB,OAAO;AACrD,QAAI,CAAC,WAAW;AACd,aAAO,KAAK,gBAAgB;AAAA,IAC9B;AAEA,UAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,WAAO,WAAW,QAAQ,WAAW,UAAU,KAAK,gBAAgB;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAA0C;AACrD,UAAM,UAAU,KAAK,SAAS,OAAO;AACrC,WAAO,UAAU,QAAQ,YAAY;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAmC;AACjC,WAAO,KAAK,aAAa,WAAW,KAAK,KAAK,aAAa,MAAM;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,gBAA+B;AAC7B,WACE,KAAK,aAAa,OAAO,KACzB,KAAK,aAAa,MAAM,KACxB,KAAK,aAAa,MAAM;AAAA,EAE5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAiC;AAC/B,WACE,KAAK,aAAa,SAAS,KAC3B,KAAK,aAAa,OAAO,KACzB,KAAK,aAAa,MAAM,KACxB,KAAK,aAAa,MAAM;AAAA,EAE5B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,QACiB;AAEjB,UAAM,sBAAsB,KAAK,cAAc;AAAA,MAC7C,OAAK,EAAE,cAAc,OAAO;AAAA,IAC9B;AACA,QAAI,qBAAqB;AACvB,YAAM,IAAI;AAAA,QACR,yBAAyB,OAAO,SAAS,qBAAqB,oBAAoB,IAAI;AAAA,MACxF;AAAA,IACF;AAGA,UAAM,iBAAiB,KAAK,cAAc,KAAK,OAAK,EAAE,SAAS,OAAO,IAAI;AAC1E,QAAI,gBAAgB;AAClB,YAAM,IAAI,MAAM,oBAAoB,OAAO,IAAI,kBAAkB;AAAA,IACnE;AAEA,UAAM,WAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,WAAW,KAAK,IAAI;AAAA,MACpB,UAAU;AAAA,IACZ;AAEA,SAAK,cAAc,KAAK,QAAQ;AAGhC,QAAI,KAAK,cAAc,WAAW,GAAG;AACnC,WAAK,OAAO,gBAAgB;AAAA,QAC1B,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,WAAW,OAAO;AAAA,QAClB,OAAO,OAAO;AAAA,QACd,SAAS,OAAO;AAAA,MAClB;AACA,WAAK,OAAO,mBAAmB,OAAO;AAAA,IACxC;AAEA,SAAK,WAAW;AAChB,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,SAA2B,WAAyB;AAC7D,QAAI,CAAC,KAAK,iBAAiB,SAAS,GAAG;AACrC,YAAM,IAAI,MAAM,UAAU,SAAS,aAAa;AAAA,IAClD;AAEA,QAAI,CAAC,KAAK,OAAO,eAAe;AAC9B,WAAK,OAAO,gBAAgB;AAAA,QAC1B,MAAM;AAAA,QACN,MAAM;AAAA,QACN,WAAW;AAAA,QACX,OAAO;AAAA,QACP,SAAS;AAAA,MACX;AAAA,IACF;AAEA,SAAK,OAAO,cAAc,OAAO,IAAI;AACrC,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqC;AACnC,WAAO,KAAK,cAAc,OAAO,OAAK,EAAE,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAyC;AACvC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,4BAAsC;AACpC,WAAO,KAAK,mBAAmB,EAAE,IAAI,OAAK,EAAE,SAAS;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,6BAAuC;AACrC,WAAO,KAAK,uBAAuB,EAAE,IAAI,OAAK,EAAE,SAAS;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKA,6BAaE;AACA,UAAM,kBAAkB,KAAK,mBAAmB;AAChD,UAAM,uBAAuB,KAAK,OAAO,eAAe;AAExD,WAAO;AAAA,MACL,aAAa,KAAK,cAAc;AAAA,MAChC,cAAc,gBAAgB;AAAA,MAC9B,gBAAgB,KAAK,cAAc,SAAS,gBAAgB;AAAA,MAC5D,kBAAkB,wBAAwB;AAAA,MAC1C,iBAAiB,KAAK,cAAc,IAAI,QAAM;AAAA,QAC5C,MAAM,EAAE;AAAA,QACR,WAAW,EAAE;AAAA,QACb,UAAU,EAAE;AAAA,QACZ,UAAU,EAAE;AAAA,QACZ,UAAU,EAAE;AAAA,MACd,EAAE;AAAA,MACF,eAAe,KAAK,OAAO,iBAAiB,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,WAAyB;AACnC,SAAK,gBAAgB,KAAK,cAAc;AAAA,MACtC,OAAK,EAAE,cAAc;AAAA,IACvB;AAGA,QAAI,KAAK,OAAO,eAAe;AAC7B,aAAO,KAAK,KAAK,OAAO,aAAa,EAAE,QAAQ,aAAW;AACxD,YACE,KAAK,OAAO,cAAc,OAA2B,MAAM,WAC3D;AACA,eAAK,OAAO,cAAc,OAA2B,IACnD,KAAK,OAAO,oBAAoB;AAAA,QACpC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAuC;AAC7C,QAAI,KAAK,OAAO,gBAAgB;AAC9B,YAAM,UAAU,KAAK,iBAAiB,KAAK,OAAO,cAAc;AAChE,UAAI,WAAW,QAAQ,UAAU;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO,KAAK,cAAc,KAAK,OAAK,EAAE,QAAQ,KAAK;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,aAAmB;AACzB,UAAM,gBAAgB;AAAA,MACpB,GAAG,KAAK;AAAA,MACR,eAAe,KAAK;AAAA,IACtB;AACA,qBAAiB,aAAa;AAI9B,sCAAkC,IAAI;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAoC;AACxC,UAAM,cAAc,MAAM,eAAe;AACzC,QAAI,YAAa,QAAO,YAAY;AACpC,QAAI,WAAY,QAAO,YAAY;AACnC,WAAO,YAAY;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,YAA4D;AAEvE,QACE,CAAC,QAAQ,QAAQ,aAAa,SAAS,SAAS,EAAE,SAAS,UAAU,GACrE;AACA,YAAM,YACJ,KAAK,OAAO,gBAAgB,UAA8B;AAC5D,UAAI,WAAW;AAEb,YAAIC,WAAU,KAAK,iBAAiB,SAAS;AAC7C,YAAI,CAACA,UAAS;AACZ,UAAAA,WAAU,KAAK,4BAA4B,SAAS;AAAA,QACtD;AACA,YAAIA,YAAWA,SAAQ,UAAU;AAC/B,iBAAOA;AAAA,QACT;AAAA,MACF;AAEA,aAAO,KAAK,gBAAgB;AAAA,IAC9B;AAIA,QAAI,UAAU,KAAK,iBAAiB,UAAU;AAC9C,QAAI,WAAW,QAAQ,UAAU;AAC/B,aAAO;AAAA,IACT;AAGA,cAAU,KAAK,4BAA4B,UAAU;AACrD,QAAI,WAAW,QAAQ,UAAU;AAC/B,aAAO;AAAA,IACT;AAGA,cAAU,KAAK,uBAAuB,UAAU;AAChD,QAAI,WAAW,QAAQ,UAAU;AAC/B,aAAO;AAAA,IACT;AAGA,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,YAInB;AACA,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,SAAS,UAAU;AAErB,QAAI,WAAW;AACb,YAAM,YACJ,KAAK,OAAO,gBAAgB,UAA8B;AAC5D,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,OAAO,kBAAkB,UAAU;AAAA,QACrC;AAAA,MACF;AAGA,UAAI,UAAU,KAAK,iBAAiB,SAAS;AAC7C,UAAI,CAAC,SAAS;AACZ,kBAAU,KAAK,4BAA4B,SAAS;AAAA,MACtD;AAEA,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,OAAO,kBAAkB,UAAU,8BAA8B,SAAS;AAAA,QAC5E;AAAA,MACF;AAEA,UAAI,CAAC,QAAQ,UAAU;AACrB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,OAAO,UAAU,QAAQ,IAAI,kBAAkB,UAAU;AAAA,QAC3D;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,MACF;AAAA,IACF,OAAO;AAEL,UAAI,UAAU,KAAK,iBAAiB,UAAU;AAC9C,UAAI,CAAC,SAAS;AACZ,kBAAU,KAAK,4BAA4B,UAAU;AAAA,MACvD;AACA,UAAI,CAAC,SAAS;AACZ,kBAAU,KAAK,uBAAuB,UAAU;AAAA,MAClD;AAEA,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,OAAO,UAAU,UAAU;AAAA,QAC7B;AAAA,MACF;AAEA,UAAI,CAAC,QAAQ,UAAU;AACrB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,OAAO,UAAU,QAAQ,IAAI;AAAA,QAC/B;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,iBAAiB,WAAwC;AAC/D,WAAO,KAAK,cAAc,KAAK,OAAK,EAAE,cAAc,SAAS,KAAK;AAAA,EACpE;AAAA,EAEQ,4BAA4B,WAAwC;AAC1E,WAAO,KAAK,cAAc,KAAK,OAAK,EAAE,cAAc,SAAS,KAAK;AAAA,EACpE;AAAA,EAEQ,uBAAuB,MAAmC;AAChE,WAAO,KAAK,cAAc,KAAK,OAAK,EAAE,SAAS,IAAI,KAAK;AAAA,EAC1D;AAAA,EAEQ,eAAe,WAAyB;AAC9C,UAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,QAAI,SAAS;AACX,cAAQ,WAAW,KAAK,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,6BAA6B,eAA4C;AAEvE,QAAI,cAAc,SAAS,GAAG,GAAG;AAC/B,YAAM,CAAC,UAAU,SAAS,IAAI,cAAc,MAAM,KAAK,CAAC;AAExD,aACE,KAAK,cAAc;AAAA,QACjB,OACE,EAAE,SAAS,YAAY,MAAM,SAAS,YAAY,MACjD,EAAE,cAAc,aACf,EAAE,UAAU,YAAY,MAAM,UAAU,YAAY,KACpD,EAAE,KAAK,YAAY,MAAM,UAAU,YAAY;AAAA,MACrD,KAAK;AAAA,IAET;AAGA,WACE,KAAK,iBAAiB,aAAa,KACnC,KAAK,uBAAuB,aAAa;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,8BAA8B,YAI5B;AAEA,QACE,WAAW,SAAS,GAAG,KACvB,CAAC,CAAC,QAAQ,QAAQ,aAAa,SAAS,SAAS,EAAE;AAAA,MACjD,WAAW,MAAM,GAAG,EAAE,CAAC;AAAA,IACzB,GACA;AACA,YAAM,CAAC,UAAU,OAAO,IAAI,WAAW,MAAM,KAAK,CAAC;AACnD,YAAMA,WAAU,KAAK,6BAA6B,UAAU;AAC5D,aAAO,EAAE,SAAAA,UAAS,UAAU,QAAQ;AAAA,IACtC;AAGA,UAAM,UAAU,KAAK,aAAa,UAAU;AAC5C,WAAO,EAAE,QAAQ;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,UAAkC;AACpD,WAAO,KAAK,cAAc;AAAA,MACxB,OAAK,EAAE,SAAS,YAAY,MAAM,SAAS,YAAY;AAAA,IACzD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA+B;AAC7B,UAAM,YAAY,IAAI,IAAI,KAAK,cAAc,IAAI,OAAK,EAAE,QAAQ,CAAC;AACjE,WAAO,MAAM,KAAK,SAAS;AAAA,EAC7B;AACF;AAGA,IAAI,qBAA0C;AAM9C,SAAS,kCAAkC,UAA8B;AACvE,uBAAqB;AACvB;AAKO,MAAM,kBAAkB,MAAoB;AACjD,MAAI;AACF,QAAI,CAAC,oBAAoB;AACvB,YAAM,SAAS,gBAAgB;AAC/B,UAAI,CAAC,QAAQ;AACX,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,6BAAqB,IAAI,aAAa;AAAA,UACpC,eAAe,CAAC;AAAA,UAChB,eAAe;AAAA,YACb,MAAM;AAAA,YACN,MAAM;AAAA,YACN,WAAW;AAAA,YACX,OAAO;AAAA,YACP,SAAS;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AACL,6BAAqB,IAAI,aAAa,MAAM;AAAA,MAC9C;AAAA,IACF;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,MAAM,gCAAgC,KAAK;AAEnD,WAAO,IAAI,aAAa;AAAA,MACtB,eAAe,CAAC;AAAA,MAChB,eAAe;AAAA,QACb,MAAM;AAAA,QACN,MAAM;AAAA,QACN,WAAW;AAAA,QACX,OAAO;AAAA,QACP,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAMO,MAAM,qBAAqB,MAAY;AAC5C,uBAAqB;AAErB,kBAAgB;AAClB;AAKO,MAAM,gBAAgB,MAAc;AACzC,QAAM,UAAU,gBAAgB;AAChC,QAAM,aAAa,QAAQ,SAAS,OAAO;AAC3C,SAAO,YAAY,aAAa;AAClC;AAKO,MAAM,kBAAkB,MAAc;AAC3C,QAAM,UAAU,gBAAgB;AAChC,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,SAAO,gBAAgB;AACzB;",
|
|
6
6
|
"names": ["analysis", "currentModel", "allModels", "profile"]
|
|
7
7
|
}
|
|
@@ -4,13 +4,17 @@ import {
|
|
|
4
4
|
getCurrentProjectConfig,
|
|
5
5
|
saveCurrentProjectConfig
|
|
6
6
|
} from "../config.js";
|
|
7
|
+
import { safeResolvePath } from "../safePath.js";
|
|
7
8
|
const readFileAllowedDirectories = /* @__PURE__ */ new Set();
|
|
8
9
|
const writeFileAllowedDirectories = /* @__PURE__ */ new Set();
|
|
9
10
|
let persistentReadPermissions = [];
|
|
10
11
|
let persistentWritePermissions = [];
|
|
11
12
|
let persistentPermissionsLoaded = false;
|
|
12
13
|
function toAbsolutePath(path) {
|
|
13
|
-
const
|
|
14
|
+
const cwd = getCwd();
|
|
15
|
+
const originalCwd = getOriginalCwd();
|
|
16
|
+
const validationResult = safeResolvePath(path, cwd, originalCwd);
|
|
17
|
+
const abs = validationResult.resolvedPath;
|
|
14
18
|
return normalizeForCompare(abs);
|
|
15
19
|
}
|
|
16
20
|
function normalizeForCompare(p) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/utils/permissions/filesystem.ts"],
|
|
4
|
-
"sourcesContent": ["import { isAbsolute, resolve, relative, dirname } from 'path'\nimport { getCwd, getOriginalCwd } from '@utils/state'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n} from '@utils/config'\n\n/**\n * Permission persistence mode\n */\nexport type PermissionPersistenceMode = 'session' | 'project' | 'global'\n\n/**\n * File permission entry for persistent storage\n */\nexport interface FilePermissionEntry {\n /** Path that was granted permission */\n path: string\n /** Type of permission */\n type: 'read' | 'write'\n /** When the permission was granted */\n grantedAt: number\n /** Expiration timestamp (optional) */\n expiresAt?: number\n /** Reason for granting (for audit purposes) */\n reason?: string\n}\n\n// In-memory storage for file permissions that resets each session\n// Sets of allowed directories for read and write operations\nconst readFileAllowedDirectories: Set<string> = new Set()\nconst writeFileAllowedDirectories: Set<string> = new Set()\n\n// Persistent permission entries (loaded from config)\nlet persistentReadPermissions: FilePermissionEntry[] = []\nlet persistentWritePermissions: FilePermissionEntry[] = []\nlet persistentPermissionsLoaded = false\n\n/**\n * Ensures a path is absolute by resolving it relative to cwd if necessary\n * @param path The path to normalize\n * @returns Absolute path\n */\nexport function toAbsolutePath(path: string): string {\n const abs = isAbsolute(path) ? resolve(path) : resolve(getCwd(), path)\n return normalizeForCompare(abs)\n}\n\nfunction normalizeForCompare(p: string): string {\n // Normalize separators and resolve .. and . segments\n const norm = resolve(p)\n // On Windows, comparisons should be case-insensitive\n return process.platform === 'win32' ? norm.toLowerCase() : norm\n}\n\nfunction isSubpath(base: string, target: string): boolean {\n const rel = relative(base, target)\n // If different drive letters on Windows, relative returns the target path\n if (!rel || rel === '') return true\n // Not a subpath if it goes up to parent\n if (rel.startsWith('..')) return false\n // Not a subpath if absolute\n if (isAbsolute(rel)) return false\n return true\n}\n\n/**\n * Ensures a path is in the original cwd path\n * @param directory The directory path to normalize\n * @returns Absolute path\n */\nexport function pathInOriginalCwd(path: string): boolean {\n const absolutePath = toAbsolutePath(path)\n const base = toAbsolutePath(getOriginalCwd())\n return isSubpath(base, absolutePath)\n}\n\n/**\n * Load persistent permissions from project config\n */\nfunction loadPersistentPermissions(): void {\n if (persistentPermissionsLoaded) return\n\n try {\n const config = getCurrentProjectConfig()\n const filePermissions = (config as any).filePermissions as\n | { read?: FilePermissionEntry[]; write?: FilePermissionEntry[] }\n | undefined\n\n if (filePermissions) {\n const now = Date.now()\n\n // Load read permissions (filter out expired)\n persistentReadPermissions = (filePermissions.read || []).filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n\n // Load write permissions (filter out expired)\n persistentWritePermissions = (filePermissions.write || []).filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n }\n\n persistentPermissionsLoaded = true\n } catch {\n // Silently fail - use session-only permissions\n persistentPermissionsLoaded = true\n }\n}\n\n/**\n * Save persistent permissions to project config\n */\nfunction savePersistentPermissions(): void {\n try {\n const config = getCurrentProjectConfig()\n\n // Only save if there are permissions to save\n if (\n persistentReadPermissions.length > 0 ||\n persistentWritePermissions.length > 0\n ) {\n ;(config as any).filePermissions = {\n read: persistentReadPermissions,\n write: persistentWritePermissions,\n }\n saveCurrentProjectConfig(config)\n }\n } catch {\n // Silently fail - permissions will work for session only\n }\n}\n\n/**\n * Check if read permission exists for the specified directory\n * @param directory The directory to check permission for\n * @returns true if read permission exists, false otherwise\n */\nexport function hasReadPermission(directory: string): boolean {\n loadPersistentPermissions()\n\n const absolutePath = toAbsolutePath(directory)\n\n // Check session permissions\n for (const allowedPath of readFileAllowedDirectories) {\n if (isSubpath(allowedPath, absolutePath)) return true\n }\n\n // Check persistent permissions\n const now = Date.now()\n for (const entry of persistentReadPermissions) {\n if (entry.expiresAt && entry.expiresAt < now) continue\n const normalizedEntry = toAbsolutePath(entry.path)\n if (isSubpath(normalizedEntry, absolutePath)) return true\n }\n\n return false\n}\n\n/**\n * Check if write permission exists for the specified directory\n * @param directory The directory to check permission for\n * @returns true if write permission exists, false otherwise\n */\nexport function hasWritePermission(directory: string): boolean {\n loadPersistentPermissions()\n\n const absolutePath = toAbsolutePath(directory)\n\n // Check session permissions\n for (const allowedPath of writeFileAllowedDirectories) {\n if (isSubpath(allowedPath, absolutePath)) return true\n }\n\n // Check persistent permissions\n const now = Date.now()\n for (const entry of persistentWritePermissions) {\n if (entry.expiresAt && entry.expiresAt < now) continue\n const normalizedEntry = toAbsolutePath(entry.path)\n if (isSubpath(normalizedEntry, absolutePath)) return true\n }\n\n return false\n}\n\n/**\n * Save read permission for a directory\n * @param directory The directory to grant read permission for\n * @param persist Whether to persist the permission (default: session only)\n * @param expiresIn Optional expiration time in milliseconds\n * @param reason Optional reason for granting permission\n */\nexport function saveReadPermission(\n directory: string,\n persist: boolean = false,\n expiresIn?: number,\n reason?: string,\n): void {\n const absolutePath = toAbsolutePath(directory)\n\n // Remove any existing subpaths contained by this new path\n for (const allowedPath of Array.from(readFileAllowedDirectories)) {\n if (isSubpath(absolutePath, allowedPath)) {\n readFileAllowedDirectories.delete(allowedPath)\n }\n }\n readFileAllowedDirectories.add(absolutePath)\n\n // Handle persistence\n if (persist) {\n loadPersistentPermissions()\n\n const entry: FilePermissionEntry = {\n path: absolutePath,\n type: 'read',\n grantedAt: Date.now(),\n expiresAt: expiresIn ? Date.now() + expiresIn : undefined,\n reason,\n }\n\n // Remove existing entry for same path\n persistentReadPermissions = persistentReadPermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n persistentReadPermissions.push(entry)\n savePersistentPermissions()\n }\n}\n\nexport const saveReadPermissionForTest = saveReadPermission\n\n/**\n * Grants read permission for the original project directory.\n * This is useful for initializing read access to the project root.\n */\nexport function grantReadPermissionForOriginalDir(): void {\n const originalProjectDir = getOriginalCwd()\n saveReadPermission(originalProjectDir, false)\n}\n\n/**\n * Save write permission for a directory\n * @param directory The directory to grant write permission for\n * @param persist Whether to persist the permission (default: session only)\n * @param expiresIn Optional expiration time in milliseconds\n * @param reason Optional reason for granting permission\n */\nexport function saveWritePermission(\n directory: string,\n persist: boolean = false,\n expiresIn?: number,\n reason?: string,\n): void {\n const absolutePath = toAbsolutePath(directory)\n\n for (const allowedPath of Array.from(writeFileAllowedDirectories)) {\n if (isSubpath(absolutePath, allowedPath)) {\n writeFileAllowedDirectories.delete(allowedPath)\n }\n }\n writeFileAllowedDirectories.add(absolutePath)\n\n // Handle persistence\n if (persist) {\n loadPersistentPermissions()\n\n const entry: FilePermissionEntry = {\n path: absolutePath,\n type: 'write',\n grantedAt: Date.now(),\n expiresAt: expiresIn ? Date.now() + expiresIn : undefined,\n reason,\n }\n\n // Remove existing entry for same path\n persistentWritePermissions = persistentWritePermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n persistentWritePermissions.push(entry)\n savePersistentPermissions()\n }\n}\n\n/**\n * Grants write permission for the original project directory.\n * This is useful for initializing write access to the project root.\n */\nexport function grantWritePermissionForOriginalDir(): void {\n const originalProjectDir = getOriginalCwd()\n saveWritePermission(originalProjectDir, false)\n}\n\n/**\n * Grant permission for a specific file path\n * @param filePath The file path to grant permission for\n * @param type Permission type (read or write)\n * @param persist Whether to persist the permission\n * @param expiresIn Optional expiration time in milliseconds\n * @param reason Optional reason for granting permission\n */\nexport function grantFilePermission(\n filePath: string,\n type: 'read' | 'write',\n persist: boolean = false,\n expiresIn?: number,\n reason?: string,\n): void {\n // Grant permission to the file's directory\n const dir = dirname(toAbsolutePath(filePath))\n\n if (type === 'read') {\n saveReadPermission(dir, persist, expiresIn, reason)\n } else {\n saveWritePermission(dir, persist, expiresIn, reason)\n }\n}\n\n/**\n * Revoke a specific persistent permission\n * @param path The path to revoke permission for\n * @param type Permission type (read or write)\n */\nexport function revokePersistentPermission(\n path: string,\n type: 'read' | 'write',\n): boolean {\n loadPersistentPermissions()\n\n const absolutePath = toAbsolutePath(path)\n let found = false\n\n if (type === 'read') {\n const before = persistentReadPermissions.length\n persistentReadPermissions = persistentReadPermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n found = persistentReadPermissions.length < before\n } else {\n const before = persistentWritePermissions.length\n persistentWritePermissions = persistentWritePermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n found = persistentWritePermissions.length < before\n }\n\n if (found) {\n savePersistentPermissions()\n }\n\n return found\n}\n\n/**\n * Get all persistent permissions\n */\nexport function getPersistentPermissions(): {\n read: FilePermissionEntry[]\n write: FilePermissionEntry[]\n} {\n loadPersistentPermissions()\n return {\n read: [...persistentReadPermissions],\n write: [...persistentWritePermissions],\n }\n}\n\n/**\n * Clear all expired persistent permissions\n */\nexport function clearExpiredPermissions(): number {\n loadPersistentPermissions()\n\n const now = Date.now()\n const beforeRead = persistentReadPermissions.length\n const beforeWrite = persistentWritePermissions.length\n\n persistentReadPermissions = persistentReadPermissions.filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n persistentWritePermissions = persistentWritePermissions.filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n\n const cleared =\n beforeRead -\n persistentReadPermissions.length +\n (beforeWrite - persistentWritePermissions.length)\n\n if (cleared > 0) {\n savePersistentPermissions()\n }\n\n return cleared\n}\n\n// For testing purposes\nexport function clearFilePermissions(): void {\n readFileAllowedDirectories.clear()\n writeFileAllowedDirectories.clear()\n persistentReadPermissions = []\n persistentWritePermissions = []\n persistentPermissionsLoaded = false\n}\n\n/**\n * Reload persistent permissions (useful after config changes)\n */\nexport function reloadPersistentPermissions(): void {\n persistentPermissionsLoaded = false\n loadPersistentPermissions()\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,SAAS,UAAU,eAAe;AACvD,SAAS,QAAQ,sBAAsB;AACvC;AAAA,EACE;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import { isAbsolute, resolve, relative, dirname } from 'path'\nimport { getCwd, getOriginalCwd } from '@utils/state'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n} from '@utils/config'\nimport { safeResolvePath } from '../safePath'\n\n/**\n * Permission persistence mode\n */\nexport type PermissionPersistenceMode = 'session' | 'project' | 'global'\n\n/**\n * File permission entry for persistent storage\n */\nexport interface FilePermissionEntry {\n /** Path that was granted permission */\n path: string\n /** Type of permission */\n type: 'read' | 'write'\n /** When the permission was granted */\n grantedAt: number\n /** Expiration timestamp (optional) */\n expiresAt?: number\n /** Reason for granting (for audit purposes) */\n reason?: string\n}\n\n// In-memory storage for file permissions that resets each session\n// Sets of allowed directories for read and write operations\nconst readFileAllowedDirectories: Set<string> = new Set()\nconst writeFileAllowedDirectories: Set<string> = new Set()\n\n// Persistent permission entries (loaded from config)\nlet persistentReadPermissions: FilePermissionEntry[] = []\nlet persistentWritePermissions: FilePermissionEntry[] = []\nlet persistentPermissionsLoaded = false\n\n/**\n * Ensures a path is absolute by resolving it relative to cwd if necessary.\n * Uses safe resolution to handle symlinks and prevent traversal attacks.\n * @param path The path to normalize\n * @returns Absolute path\n */\nexport function toAbsolutePath(path: string): string {\n const cwd = getCwd()\n const originalCwd = getOriginalCwd()\n\n // Use safe resolution to follow symlinks and detect boundary issues\n // Allow paths to go up to the original working directory boundary\n const validationResult = safeResolvePath(path, cwd, originalCwd)\n\n // Use the safely resolved path\n const abs = validationResult.resolvedPath\n return normalizeForCompare(abs)\n}\n\nfunction normalizeForCompare(p: string): string {\n // Normalize separators and resolve .. and . segments\n const norm = resolve(p)\n // On Windows, comparisons should be case-insensitive\n return process.platform === 'win32' ? norm.toLowerCase() : norm\n}\n\nfunction isSubpath(base: string, target: string): boolean {\n const rel = relative(base, target)\n // If different drive letters on Windows, relative returns the target path\n if (!rel || rel === '') return true\n // Not a subpath if it goes up to parent\n if (rel.startsWith('..')) return false\n // Not a subpath if absolute\n if (isAbsolute(rel)) return false\n return true\n}\n\n/**\n * Ensures a path is in the original cwd path\n * @param directory The directory path to normalize\n * @returns Absolute path\n */\nexport function pathInOriginalCwd(path: string): boolean {\n const absolutePath = toAbsolutePath(path)\n const base = toAbsolutePath(getOriginalCwd())\n return isSubpath(base, absolutePath)\n}\n\n/**\n * Load persistent permissions from project config\n */\nfunction loadPersistentPermissions(): void {\n if (persistentPermissionsLoaded) return\n\n try {\n const config = getCurrentProjectConfig()\n const filePermissions = (config as any).filePermissions as\n | { read?: FilePermissionEntry[]; write?: FilePermissionEntry[] }\n | undefined\n\n if (filePermissions) {\n const now = Date.now()\n\n // Load read permissions (filter out expired)\n persistentReadPermissions = (filePermissions.read || []).filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n\n // Load write permissions (filter out expired)\n persistentWritePermissions = (filePermissions.write || []).filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n }\n\n persistentPermissionsLoaded = true\n } catch {\n // Silently fail - use session-only permissions\n persistentPermissionsLoaded = true\n }\n}\n\n/**\n * Save persistent permissions to project config\n */\nfunction savePersistentPermissions(): void {\n try {\n const config = getCurrentProjectConfig()\n\n // Only save if there are permissions to save\n if (\n persistentReadPermissions.length > 0 ||\n persistentWritePermissions.length > 0\n ) {\n ;(config as any).filePermissions = {\n read: persistentReadPermissions,\n write: persistentWritePermissions,\n }\n saveCurrentProjectConfig(config)\n }\n } catch {\n // Silently fail - permissions will work for session only\n }\n}\n\n/**\n * Check if read permission exists for the specified directory\n * @param directory The directory to check permission for\n * @returns true if read permission exists, false otherwise\n */\nexport function hasReadPermission(directory: string): boolean {\n loadPersistentPermissions()\n\n const absolutePath = toAbsolutePath(directory)\n\n // Check session permissions\n for (const allowedPath of readFileAllowedDirectories) {\n if (isSubpath(allowedPath, absolutePath)) return true\n }\n\n // Check persistent permissions\n const now = Date.now()\n for (const entry of persistentReadPermissions) {\n if (entry.expiresAt && entry.expiresAt < now) continue\n const normalizedEntry = toAbsolutePath(entry.path)\n if (isSubpath(normalizedEntry, absolutePath)) return true\n }\n\n return false\n}\n\n/**\n * Check if write permission exists for the specified directory\n * @param directory The directory to check permission for\n * @returns true if write permission exists, false otherwise\n */\nexport function hasWritePermission(directory: string): boolean {\n loadPersistentPermissions()\n\n const absolutePath = toAbsolutePath(directory)\n\n // Check session permissions\n for (const allowedPath of writeFileAllowedDirectories) {\n if (isSubpath(allowedPath, absolutePath)) return true\n }\n\n // Check persistent permissions\n const now = Date.now()\n for (const entry of persistentWritePermissions) {\n if (entry.expiresAt && entry.expiresAt < now) continue\n const normalizedEntry = toAbsolutePath(entry.path)\n if (isSubpath(normalizedEntry, absolutePath)) return true\n }\n\n return false\n}\n\n/**\n * Save read permission for a directory\n * @param directory The directory to grant read permission for\n * @param persist Whether to persist the permission (default: session only)\n * @param expiresIn Optional expiration time in milliseconds\n * @param reason Optional reason for granting permission\n */\nexport function saveReadPermission(\n directory: string,\n persist: boolean = false,\n expiresIn?: number,\n reason?: string,\n): void {\n const absolutePath = toAbsolutePath(directory)\n\n // Remove any existing subpaths contained by this new path\n for (const allowedPath of Array.from(readFileAllowedDirectories)) {\n if (isSubpath(absolutePath, allowedPath)) {\n readFileAllowedDirectories.delete(allowedPath)\n }\n }\n readFileAllowedDirectories.add(absolutePath)\n\n // Handle persistence\n if (persist) {\n loadPersistentPermissions()\n\n const entry: FilePermissionEntry = {\n path: absolutePath,\n type: 'read',\n grantedAt: Date.now(),\n expiresAt: expiresIn ? Date.now() + expiresIn : undefined,\n reason,\n }\n\n // Remove existing entry for same path\n persistentReadPermissions = persistentReadPermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n persistentReadPermissions.push(entry)\n savePersistentPermissions()\n }\n}\n\nexport const saveReadPermissionForTest = saveReadPermission\n\n/**\n * Grants read permission for the original project directory.\n * This is useful for initializing read access to the project root.\n */\nexport function grantReadPermissionForOriginalDir(): void {\n const originalProjectDir = getOriginalCwd()\n saveReadPermission(originalProjectDir, false)\n}\n\n/**\n * Save write permission for a directory\n * @param directory The directory to grant write permission for\n * @param persist Whether to persist the permission (default: session only)\n * @param expiresIn Optional expiration time in milliseconds\n * @param reason Optional reason for granting permission\n */\nexport function saveWritePermission(\n directory: string,\n persist: boolean = false,\n expiresIn?: number,\n reason?: string,\n): void {\n const absolutePath = toAbsolutePath(directory)\n\n for (const allowedPath of Array.from(writeFileAllowedDirectories)) {\n if (isSubpath(absolutePath, allowedPath)) {\n writeFileAllowedDirectories.delete(allowedPath)\n }\n }\n writeFileAllowedDirectories.add(absolutePath)\n\n // Handle persistence\n if (persist) {\n loadPersistentPermissions()\n\n const entry: FilePermissionEntry = {\n path: absolutePath,\n type: 'write',\n grantedAt: Date.now(),\n expiresAt: expiresIn ? Date.now() + expiresIn : undefined,\n reason,\n }\n\n // Remove existing entry for same path\n persistentWritePermissions = persistentWritePermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n persistentWritePermissions.push(entry)\n savePersistentPermissions()\n }\n}\n\n/**\n * Grants write permission for the original project directory.\n * This is useful for initializing write access to the project root.\n */\nexport function grantWritePermissionForOriginalDir(): void {\n const originalProjectDir = getOriginalCwd()\n saveWritePermission(originalProjectDir, false)\n}\n\n/**\n * Grant permission for a specific file path\n * @param filePath The file path to grant permission for\n * @param type Permission type (read or write)\n * @param persist Whether to persist the permission\n * @param expiresIn Optional expiration time in milliseconds\n * @param reason Optional reason for granting permission\n */\nexport function grantFilePermission(\n filePath: string,\n type: 'read' | 'write',\n persist: boolean = false,\n expiresIn?: number,\n reason?: string,\n): void {\n // Grant permission to the file's directory\n const dir = dirname(toAbsolutePath(filePath))\n\n if (type === 'read') {\n saveReadPermission(dir, persist, expiresIn, reason)\n } else {\n saveWritePermission(dir, persist, expiresIn, reason)\n }\n}\n\n/**\n * Revoke a specific persistent permission\n * @param path The path to revoke permission for\n * @param type Permission type (read or write)\n */\nexport function revokePersistentPermission(\n path: string,\n type: 'read' | 'write',\n): boolean {\n loadPersistentPermissions()\n\n const absolutePath = toAbsolutePath(path)\n let found = false\n\n if (type === 'read') {\n const before = persistentReadPermissions.length\n persistentReadPermissions = persistentReadPermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n found = persistentReadPermissions.length < before\n } else {\n const before = persistentWritePermissions.length\n persistentWritePermissions = persistentWritePermissions.filter(\n p => toAbsolutePath(p.path) !== absolutePath,\n )\n found = persistentWritePermissions.length < before\n }\n\n if (found) {\n savePersistentPermissions()\n }\n\n return found\n}\n\n/**\n * Get all persistent permissions\n */\nexport function getPersistentPermissions(): {\n read: FilePermissionEntry[]\n write: FilePermissionEntry[]\n} {\n loadPersistentPermissions()\n return {\n read: [...persistentReadPermissions],\n write: [...persistentWritePermissions],\n }\n}\n\n/**\n * Clear all expired persistent permissions\n */\nexport function clearExpiredPermissions(): number {\n loadPersistentPermissions()\n\n const now = Date.now()\n const beforeRead = persistentReadPermissions.length\n const beforeWrite = persistentWritePermissions.length\n\n persistentReadPermissions = persistentReadPermissions.filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n persistentWritePermissions = persistentWritePermissions.filter(\n p => !p.expiresAt || p.expiresAt > now,\n )\n\n const cleared =\n beforeRead -\n persistentReadPermissions.length +\n (beforeWrite - persistentWritePermissions.length)\n\n if (cleared > 0) {\n savePersistentPermissions()\n }\n\n return cleared\n}\n\n// For testing purposes\nexport function clearFilePermissions(): void {\n readFileAllowedDirectories.clear()\n writeFileAllowedDirectories.clear()\n persistentReadPermissions = []\n persistentWritePermissions = []\n persistentPermissionsLoaded = false\n}\n\n/**\n * Reload persistent permissions (useful after config changes)\n */\nexport function reloadPersistentPermissions(): void {\n persistentPermissionsLoaded = false\n loadPersistentPermissions()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/utils/ripgrep.js
CHANGED
|
@@ -115,6 +115,57 @@ async function* ripGrepStreaming(args, target, abortSignal) {
|
|
|
115
115
|
durationMs: Date.now() - startTime
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
|
+
async function* ripGrepStreamingWithContent(args, target, abortSignal) {
|
|
119
|
+
await codesignRipgrepIfNecessary();
|
|
120
|
+
const rg = ripgrepPath();
|
|
121
|
+
d("ripgrep streaming with content called: %s %o", rg, target, args);
|
|
122
|
+
const startTime = Date.now();
|
|
123
|
+
let totalLines = 0;
|
|
124
|
+
let buffer = "";
|
|
125
|
+
const child = spawn(rg, [...args, target], {
|
|
126
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
127
|
+
signal: abortSignal
|
|
128
|
+
});
|
|
129
|
+
for await (const chunk of child.stdout) {
|
|
130
|
+
buffer += chunk.toString();
|
|
131
|
+
const lines = buffer.split("\n");
|
|
132
|
+
buffer = lines.pop() || "";
|
|
133
|
+
for (const line of lines) {
|
|
134
|
+
if (line) {
|
|
135
|
+
totalLines++;
|
|
136
|
+
yield { type: "line", line };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (buffer.trim()) {
|
|
141
|
+
totalLines++;
|
|
142
|
+
yield { type: "line", line: buffer.trim() };
|
|
143
|
+
}
|
|
144
|
+
await new Promise((resolve2, reject) => {
|
|
145
|
+
child.on("close", (code) => {
|
|
146
|
+
if (code === 0 || code === 1) {
|
|
147
|
+
resolve2();
|
|
148
|
+
} else if (code !== null) {
|
|
149
|
+
d("ripgrep streaming with content error, exit code: %d", code);
|
|
150
|
+
reject(new Error(`ripgrep exited with code ${code}`));
|
|
151
|
+
} else {
|
|
152
|
+
resolve2();
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
child.on("error", (err) => {
|
|
156
|
+
if (err.name === "AbortError") {
|
|
157
|
+
resolve2();
|
|
158
|
+
} else {
|
|
159
|
+
reject(err);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
yield {
|
|
164
|
+
type: "complete",
|
|
165
|
+
totalLines,
|
|
166
|
+
durationMs: Date.now() - startTime
|
|
167
|
+
};
|
|
168
|
+
}
|
|
118
169
|
async function listAllContentFiles(path2, abortSignal, limit) {
|
|
119
170
|
try {
|
|
120
171
|
d("listAllContentFiles called: %s", path2);
|
|
@@ -179,6 +230,7 @@ async function codesignRipgrepIfNecessary() {
|
|
|
179
230
|
export {
|
|
180
231
|
listAllContentFiles,
|
|
181
232
|
ripGrep,
|
|
182
|
-
ripGrepStreaming
|
|
233
|
+
ripGrepStreaming,
|
|
234
|
+
ripGrepStreamingWithContent
|
|
183
235
|
};
|
|
184
236
|
//# sourceMappingURL=ripgrep.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/ripgrep.ts"],
|
|
4
|
-
"sourcesContent": ["import { findActualExecutable } from 'spawn-rx'\nimport { memoize } from 'lodash-es'\nimport { fileURLToPath, resolve } from 'node:url'\nimport * as path from 'path'\nimport { logError } from './log'\nimport { execFileNoThrow } from './execFileNoThrow'\nimport { execFile, spawn } from 'child_process'\nimport debug from 'debug'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = resolve(\n __filename,\n process.env.NODE_ENV === 'test' ? '../..' : '.',\n)\n\nconst d = debug('claude:ripgrep')\n\nconst useBuiltinRipgrep = !!process.env.USE_BUILTIN_RIPGREP\nif (useBuiltinRipgrep) {\n d('Using builtin ripgrep because USE_BUILTIN_RIPGREP is set')\n}\n\nconst ripgrepPath = memoize(() => {\n const { cmd } = findActualExecutable('rg', [])\n d(`ripgrep initially resolved as: ${cmd}`)\n\n if (cmd !== 'rg' && !useBuiltinRipgrep) {\n // NB: If we're able to find ripgrep in $PATH, cmd will be an absolute\n // path rather than just returning 'rg'\n return cmd\n } else {\n // Use the one we ship in-box\n const rgRoot = path.resolve(__dirname, 'vendor', 'ripgrep')\n if (process.platform === 'win32') {\n // NB: Ripgrep doesn't ship an aarch64 binary for Windows, boooooo\n return path.resolve(rgRoot, 'x64-win32', 'rg.exe')\n }\n\n const ret = path.resolve(\n rgRoot,\n `${process.arch}-${process.platform}`,\n 'rg',\n )\n\n d('internal ripgrep resolved as: %s', ret)\n return ret\n }\n})\n\nexport async function ripGrep(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): Promise<string[]> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep called: %s %o', rg, target, args)\n\n // NB: When running interactively, ripgrep does not require a path as its last\n // argument, but when run non-interactively, it will hang unless a path or file\n // pattern is provided\n return new Promise(resolve => {\n execFile(\n ripgrepPath(),\n [...args, target],\n {\n maxBuffer: 1_000_000,\n signal: abortSignal,\n timeout: 10_000,\n },\n (error, stdout) => {\n if (error) {\n // Exit code 1 from ripgrep means \"no matches found\" - this is normal\n if (error.code !== 1) {\n d('ripgrep error: %o', error)\n logError(error)\n }\n resolve([])\n } else {\n d('ripgrep succeeded with %s', stdout)\n resolve(stdout.trim().split('\\n').filter(Boolean))\n }\n },\n )\n })\n}\n\n/**\n * Streaming ripgrep result type\n */\nexport type RipGrepStreamChunk = {\n type: 'match'\n file: string\n}\n\nexport type RipGrepStreamResult = {\n type: 'complete'\n totalFiles: number\n durationMs: number\n}\n\nexport type RipGrepStreamYield = RipGrepStreamChunk | RipGrepStreamResult\n\n/**\n * Streaming version of ripGrep that yields matches as they are found.\n * This provides real-time feedback during searches of large codebases.\n */\nexport async function* ripGrepStreaming(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): AsyncGenerator<RipGrepStreamYield, void, unknown> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep streaming called: %s %o', rg, target, args)\n\n const startTime = Date.now()\n let totalFiles = 0\n let buffer = ''\n\n const child = spawn(rg, [...args, target], {\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: abortSignal,\n })\n\n // Process stdout line by line\n for await (const chunk of child.stdout) {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const file = line.trim()\n if (file) {\n totalFiles++\n yield { type: 'match', file }\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n totalFiles++\n yield { type: 'match', file: buffer.trim() }\n }\n\n // Wait for process to complete\n await new Promise<void>((resolve, reject) => {\n child.on('close', code => {\n if (code === 0 || code === 1) {\n // Exit code 1 means \"no matches found\" - this is normal\n resolve()\n } else if (code !== null) {\n d('ripgrep streaming error, exit code: %d', code)\n reject(new Error(`ripgrep exited with code ${code}`))\n } else {\n resolve()\n }\n })\n child.on('error', err => {\n // AbortError is expected when cancelled\n if (err.name === 'AbortError') {\n resolve()\n } else {\n reject(err)\n }\n })\n })\n\n yield {\n type: 'complete',\n totalFiles,\n durationMs: Date.now() - startTime,\n }\n}\n\n// NB: We do something tricky here. We know that ripgrep processes common\n// ignore files for us, so we just ripgrep for any character, which matches\n// all non-empty files\nexport async function listAllContentFiles(\n path: string,\n abortSignal: AbortSignal,\n limit: number,\n): Promise<string[]> {\n try {\n d('listAllContentFiles called: %s', path)\n return (await ripGrep(['-l', '.', path], path, abortSignal)).slice(0, limit)\n } catch (e) {\n d('listAllContentFiles failed: %o', e)\n\n logError(e)\n return []\n }\n}\n\nlet alreadyDoneSignCheck = false\nasync function codesignRipgrepIfNecessary() {\n if (process.platform !== 'darwin' || alreadyDoneSignCheck) {\n return\n }\n\n alreadyDoneSignCheck = true\n\n // First, check to see if ripgrep is already signed\n d('checking if ripgrep is already signed')\n const lines = (\n await execFileNoThrow(\n 'codesign',\n ['-vv', '-d', ripgrepPath()],\n undefined,\n undefined,\n false,\n )\n ).stdout.split('\\n')\n\n const needsSigned = lines.find(line => line.includes('linker-signed'))\n if (!needsSigned) {\n d('seems to be already signed')\n return\n }\n\n try {\n d('signing ripgrep')\n const signResult = await execFileNoThrow('codesign', [\n '--sign',\n '-',\n '--force',\n '--preserve-metadata=entitlements,requirements,flags,runtime',\n ripgrepPath(),\n ])\n\n if (signResult.code !== 0) {\n d('failed to sign ripgrep: %o', signResult)\n logError(\n `Failed to sign ripgrep: ${signResult.stdout} ${signResult.stderr}`,\n )\n }\n\n d('removing quarantine')\n const quarantineResult = await execFileNoThrow('xattr', [\n '-d',\n 'com.apple.quarantine',\n ripgrepPath(),\n ])\n\n if (quarantineResult.code !== 0) {\n d('failed to remove quarantine: %o', quarantineResult)\n logError(\n `Failed to remove quarantine: ${quarantineResult.stdout} ${quarantineResult.stderr}`,\n )\n }\n } catch (e) {\n d('failed during sign: %o', e)\n logError(e)\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,4BAA4B;AACrC,SAAS,eAAe;AACxB,SAAS,eAAe,eAAe;AACvC,YAAY,UAAU;AACtB,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAChC,SAAS,UAAU,aAAa;AAChC,OAAO,WAAW;AAElB,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,YAAY;AAAA,EAChB;AAAA,EACA,QAAQ,IAAI,aAAa,SAAS,UAAU;AAC9C;AAEA,MAAM,IAAI,MAAM,gBAAgB;AAEhC,MAAM,oBAAoB,CAAC,CAAC,QAAQ,IAAI;AACxC,IAAI,mBAAmB;AACrB,IAAE,0DAA0D;AAC9D;AAEA,MAAM,cAAc,QAAQ,MAAM;AAChC,QAAM,EAAE,IAAI,IAAI,qBAAqB,MAAM,CAAC,CAAC;AAC7C,IAAE,kCAAkC,GAAG,EAAE;AAEzC,MAAI,QAAQ,QAAQ,CAAC,mBAAmB;AAGtC,WAAO;AAAA,EACT,OAAO;AAEL,UAAM,SAAS,KAAK,QAAQ,WAAW,UAAU,SAAS;AAC1D,QAAI,QAAQ,aAAa,SAAS;AAEhC,aAAO,KAAK,QAAQ,QAAQ,aAAa,QAAQ;AAAA,IACnD;AAEA,UAAM,MAAM,KAAK;AAAA,MACf;AAAA,MACA,GAAG,QAAQ,IAAI,IAAI,QAAQ,QAAQ;AAAA,MACnC;AAAA,IACF;AAEA,MAAE,oCAAoC,GAAG;AACzC,WAAO;AAAA,EACT;AACF,CAAC;AAED,eAAsB,QACpB,MACA,QACA,aACmB;AACnB,QAAM,2BAA2B;AACjC,QAAM,KAAK,YAAY;AACvB,IAAE,yBAAyB,IAAI,QAAQ,IAAI;AAK3C,SAAO,IAAI,QAAQ,CAAAA,aAAW;AAC5B;AAAA,MACE,YAAY;AAAA,MACZ,CAAC,GAAG,MAAM,MAAM;AAAA,MAChB;AAAA,QACE,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,CAAC,OAAO,WAAW;AACjB,YAAI,OAAO;AAET,cAAI,MAAM,SAAS,GAAG;AACpB,cAAE,qBAAqB,KAAK;AAC5B,qBAAS,KAAK;AAAA,UAChB;AACA,UAAAA,SAAQ,CAAC,CAAC;AAAA,QACZ,OAAO;AACL,YAAE,6BAA6B,MAAM;AACrC,UAAAA,SAAQ,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO,CAAC;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;
|
|
4
|
+
"sourcesContent": ["import { findActualExecutable } from 'spawn-rx'\nimport { memoize } from 'lodash-es'\nimport { fileURLToPath, resolve } from 'node:url'\nimport * as path from 'path'\nimport { logError } from './log'\nimport { execFileNoThrow } from './execFileNoThrow'\nimport { execFile, spawn } from 'child_process'\nimport debug from 'debug'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = resolve(\n __filename,\n process.env.NODE_ENV === 'test' ? '../..' : '.',\n)\n\nconst d = debug('claude:ripgrep')\n\nconst useBuiltinRipgrep = !!process.env.USE_BUILTIN_RIPGREP\nif (useBuiltinRipgrep) {\n d('Using builtin ripgrep because USE_BUILTIN_RIPGREP is set')\n}\n\nconst ripgrepPath = memoize(() => {\n const { cmd } = findActualExecutable('rg', [])\n d(`ripgrep initially resolved as: ${cmd}`)\n\n if (cmd !== 'rg' && !useBuiltinRipgrep) {\n // NB: If we're able to find ripgrep in $PATH, cmd will be an absolute\n // path rather than just returning 'rg'\n return cmd\n } else {\n // Use the one we ship in-box\n const rgRoot = path.resolve(__dirname, 'vendor', 'ripgrep')\n if (process.platform === 'win32') {\n // NB: Ripgrep doesn't ship an aarch64 binary for Windows, boooooo\n return path.resolve(rgRoot, 'x64-win32', 'rg.exe')\n }\n\n const ret = path.resolve(\n rgRoot,\n `${process.arch}-${process.platform}`,\n 'rg',\n )\n\n d('internal ripgrep resolved as: %s', ret)\n return ret\n }\n})\n\nexport async function ripGrep(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): Promise<string[]> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep called: %s %o', rg, target, args)\n\n // NB: When running interactively, ripgrep does not require a path as its last\n // argument, but when run non-interactively, it will hang unless a path or file\n // pattern is provided\n return new Promise(resolve => {\n execFile(\n ripgrepPath(),\n [...args, target],\n {\n maxBuffer: 1_000_000,\n signal: abortSignal,\n timeout: 10_000,\n },\n (error, stdout) => {\n if (error) {\n // Exit code 1 from ripgrep means \"no matches found\" - this is normal\n if (error.code !== 1) {\n d('ripgrep error: %o', error)\n logError(error)\n }\n resolve([])\n } else {\n d('ripgrep succeeded with %s', stdout)\n resolve(stdout.trim().split('\\n').filter(Boolean))\n }\n },\n )\n })\n}\n\n/**\n * Streaming ripgrep result type for file matching\n */\nexport type RipGrepStreamChunk = {\n type: 'match'\n file: string\n}\n\nexport type RipGrepStreamResult = {\n type: 'complete'\n totalFiles: number\n durationMs: number\n}\n\nexport type RipGrepStreamYield = RipGrepStreamChunk | RipGrepStreamResult\n\n/**\n * Streaming ripgrep result type for content output\n */\nexport type RipGrepContentChunk = {\n type: 'line'\n line: string\n}\n\nexport type RipGrepContentResult = {\n type: 'complete'\n totalLines: number\n durationMs: number\n}\n\nexport type RipGrepContentYield = RipGrepContentChunk | RipGrepContentResult\n\n/**\n * Streaming version of ripGrep that yields matches as they are found.\n * This provides real-time feedback during searches of large codebases.\n */\nexport async function* ripGrepStreaming(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): AsyncGenerator<RipGrepStreamYield, void, unknown> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep streaming called: %s %o', rg, target, args)\n\n const startTime = Date.now()\n let totalFiles = 0\n let buffer = ''\n\n const child = spawn(rg, [...args, target], {\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: abortSignal,\n })\n\n // Process stdout line by line\n for await (const chunk of child.stdout) {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const file = line.trim()\n if (file) {\n totalFiles++\n yield { type: 'match', file }\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n totalFiles++\n yield { type: 'match', file: buffer.trim() }\n }\n\n // Wait for process to complete\n await new Promise<void>((resolve, reject) => {\n child.on('close', code => {\n if (code === 0 || code === 1) {\n // Exit code 1 means \"no matches found\" - this is normal\n resolve()\n } else if (code !== null) {\n d('ripgrep streaming error, exit code: %d', code)\n reject(new Error(`ripgrep exited with code ${code}`))\n } else {\n resolve()\n }\n })\n child.on('error', err => {\n // AbortError is expected when cancelled\n if (err.name === 'AbortError') {\n resolve()\n } else {\n reject(err)\n }\n })\n })\n\n yield {\n type: 'complete',\n totalFiles,\n durationMs: Date.now() - startTime,\n }\n}\n\n/**\n * Streaming version of ripGrep that yields raw content lines.\n * Used for content mode and count mode where we need the full output.\n */\nexport async function* ripGrepStreamingWithContent(\n args: string[],\n target: string,\n abortSignal: AbortSignal,\n): AsyncGenerator<RipGrepContentYield, void, unknown> {\n await codesignRipgrepIfNecessary()\n const rg = ripgrepPath()\n d('ripgrep streaming with content called: %s %o', rg, target, args)\n\n const startTime = Date.now()\n let totalLines = 0\n let buffer = ''\n\n const child = spawn(rg, [...args, target], {\n stdio: ['ignore', 'pipe', 'pipe'],\n signal: abortSignal,\n })\n\n // Process stdout line by line\n for await (const chunk of child.stdout) {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n // Keep the last incomplete line in buffer\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n if (line) {\n totalLines++\n yield { type: 'line', line }\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n totalLines++\n yield { type: 'line', line: buffer.trim() }\n }\n\n // Wait for process to complete\n await new Promise<void>((resolve, reject) => {\n child.on('close', code => {\n if (code === 0 || code === 1) {\n // Exit code 1 means \"no matches found\" - this is normal\n resolve()\n } else if (code !== null) {\n d('ripgrep streaming with content error, exit code: %d', code)\n reject(new Error(`ripgrep exited with code ${code}`))\n } else {\n resolve()\n }\n })\n child.on('error', err => {\n // AbortError is expected when cancelled\n if (err.name === 'AbortError') {\n resolve()\n } else {\n reject(err)\n }\n })\n })\n\n yield {\n type: 'complete',\n totalLines,\n durationMs: Date.now() - startTime,\n }\n}\n\n// NB: We do something tricky here. We know that ripgrep processes common\n// ignore files for us, so we just ripgrep for any character, which matches\n// all non-empty files\nexport async function listAllContentFiles(\n path: string,\n abortSignal: AbortSignal,\n limit: number,\n): Promise<string[]> {\n try {\n d('listAllContentFiles called: %s', path)\n return (await ripGrep(['-l', '.', path], path, abortSignal)).slice(0, limit)\n } catch (e) {\n d('listAllContentFiles failed: %o', e)\n\n logError(e)\n return []\n }\n}\n\nlet alreadyDoneSignCheck = false\nasync function codesignRipgrepIfNecessary() {\n if (process.platform !== 'darwin' || alreadyDoneSignCheck) {\n return\n }\n\n alreadyDoneSignCheck = true\n\n // First, check to see if ripgrep is already signed\n d('checking if ripgrep is already signed')\n const lines = (\n await execFileNoThrow(\n 'codesign',\n ['-vv', '-d', ripgrepPath()],\n undefined,\n undefined,\n false,\n )\n ).stdout.split('\\n')\n\n const needsSigned = lines.find(line => line.includes('linker-signed'))\n if (!needsSigned) {\n d('seems to be already signed')\n return\n }\n\n try {\n d('signing ripgrep')\n const signResult = await execFileNoThrow('codesign', [\n '--sign',\n '-',\n '--force',\n '--preserve-metadata=entitlements,requirements,flags,runtime',\n ripgrepPath(),\n ])\n\n if (signResult.code !== 0) {\n d('failed to sign ripgrep: %o', signResult)\n logError(\n `Failed to sign ripgrep: ${signResult.stdout} ${signResult.stderr}`,\n )\n }\n\n d('removing quarantine')\n const quarantineResult = await execFileNoThrow('xattr', [\n '-d',\n 'com.apple.quarantine',\n ripgrepPath(),\n ])\n\n if (quarantineResult.code !== 0) {\n d('failed to remove quarantine: %o', quarantineResult)\n logError(\n `Failed to remove quarantine: ${quarantineResult.stdout} ${quarantineResult.stderr}`,\n )\n }\n } catch (e) {\n d('failed during sign: %o', e)\n logError(e)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["resolve", "path"]
|
|
7
7
|
}
|