@within-7/minto 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/dist/commands/agents/AgentsCommand.js +22 -24
  2. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  3. package/dist/commands/context.js +2 -1
  4. package/dist/commands/context.js.map +2 -2
  5. package/dist/commands/export.js +2 -1
  6. package/dist/commands/export.js.map +2 -2
  7. package/dist/commands/mcp-interactive.js +7 -6
  8. package/dist/commands/mcp-interactive.js.map +2 -2
  9. package/dist/commands/model.js +3 -2
  10. package/dist/commands/model.js.map +2 -2
  11. package/dist/commands/permissions.js +4 -3
  12. package/dist/commands/permissions.js.map +2 -2
  13. package/dist/commands/plugin/AddMarketplaceForm.js +3 -2
  14. package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
  15. package/dist/commands/plugin/ConfirmDialog.js +2 -1
  16. package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
  17. package/dist/commands/plugin/ErrorView.js +2 -1
  18. package/dist/commands/plugin/ErrorView.js.map +2 -2
  19. package/dist/commands/plugin/InstalledPluginsByMarketplace.js +5 -4
  20. package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
  21. package/dist/commands/plugin/InstalledPluginsManager.js +5 -4
  22. package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
  23. package/dist/commands/plugin/MainMenu.js +2 -1
  24. package/dist/commands/plugin/MainMenu.js.map +2 -2
  25. package/dist/commands/plugin/MarketplaceManager.js +5 -4
  26. package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
  27. package/dist/commands/plugin/MarketplaceSelector.js +4 -3
  28. package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
  29. package/dist/commands/plugin/PlaceholderScreen.js +3 -2
  30. package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
  31. package/dist/commands/plugin/PluginBrowser.js +6 -5
  32. package/dist/commands/plugin/PluginBrowser.js.map +2 -2
  33. package/dist/commands/plugin/PluginDetailsInstall.js +5 -4
  34. package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
  35. package/dist/commands/plugin/PluginDetailsManage.js +4 -3
  36. package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
  37. package/dist/commands/plugin.js +16 -15
  38. package/dist/commands/plugin.js.map +2 -2
  39. package/dist/commands/sandbox.js +4 -3
  40. package/dist/commands/sandbox.js.map +2 -2
  41. package/dist/commands/setup.js +2 -1
  42. package/dist/commands/setup.js.map +2 -2
  43. package/dist/commands/status.js +2 -1
  44. package/dist/commands/status.js.map +2 -2
  45. package/dist/commands/undo.js +245 -0
  46. package/dist/commands/undo.js.map +7 -0
  47. package/dist/commands.js +2 -0
  48. package/dist/commands.js.map +2 -2
  49. package/dist/components/AgentThinkingBlock.js +1 -1
  50. package/dist/components/AgentThinkingBlock.js.map +2 -2
  51. package/dist/components/AsciiLogo.js +7 -8
  52. package/dist/components/AsciiLogo.js.map +2 -2
  53. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
  54. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  55. package/dist/components/AskUserQuestionDialog/QuestionView.js +2 -1
  56. package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
  57. package/dist/components/CollapsibleHint.js +2 -1
  58. package/dist/components/CollapsibleHint.js.map +2 -2
  59. package/dist/components/Config.js +3 -2
  60. package/dist/components/Config.js.map +2 -2
  61. package/dist/components/ConsoleOAuthFlow.js +2 -1
  62. package/dist/components/ConsoleOAuthFlow.js.map +2 -2
  63. package/dist/components/Cost.js +2 -1
  64. package/dist/components/Cost.js.map +2 -2
  65. package/dist/components/HeaderBar.js +13 -8
  66. package/dist/components/HeaderBar.js.map +2 -2
  67. package/dist/components/HistorySearchOverlay.js +4 -3
  68. package/dist/components/HistorySearchOverlay.js.map +2 -2
  69. package/dist/components/HotkeyHelpPanel.js +8 -11
  70. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  71. package/dist/components/InvalidConfigDialog.js +2 -1
  72. package/dist/components/InvalidConfigDialog.js.map +2 -2
  73. package/dist/components/Logo.js +23 -67
  74. package/dist/components/Logo.js.map +2 -2
  75. package/dist/components/MCPServerApprovalDialog.js +2 -1
  76. package/dist/components/MCPServerApprovalDialog.js.map +2 -2
  77. package/dist/components/MCPServerDialogCopy.js +2 -1
  78. package/dist/components/MCPServerDialogCopy.js.map +2 -2
  79. package/dist/components/MCPServerMultiselectDialog.js +2 -1
  80. package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
  81. package/dist/components/MessageSelector.js +4 -3
  82. package/dist/components/MessageSelector.js.map +2 -2
  83. package/dist/components/ModeIndicator.js +2 -1
  84. package/dist/components/ModeIndicator.js.map +2 -2
  85. package/dist/components/ModelConfig.js +4 -3
  86. package/dist/components/ModelConfig.js.map +2 -2
  87. package/dist/components/ModelListManager.js +4 -3
  88. package/dist/components/ModelListManager.js.map +2 -2
  89. package/dist/components/ModelSelector/ModelSelector.js +26 -13
  90. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  91. package/dist/components/Onboarding.js +3 -2
  92. package/dist/components/Onboarding.js.map +2 -2
  93. package/dist/components/OperationSummary.js +130 -0
  94. package/dist/components/OperationSummary.js.map +7 -0
  95. package/dist/components/PromptInput.js +88 -75
  96. package/dist/components/PromptInput.js.map +2 -2
  97. package/dist/components/SensitiveFileWarning.js +31 -0
  98. package/dist/components/SensitiveFileWarning.js.map +7 -0
  99. package/dist/components/Spinner.js +71 -22
  100. package/dist/components/Spinner.js.map +2 -2
  101. package/dist/components/StructuredDiff.js +6 -8
  102. package/dist/components/StructuredDiff.js.map +2 -2
  103. package/dist/components/SubagentBlock.js +4 -2
  104. package/dist/components/SubagentBlock.js.map +2 -2
  105. package/dist/components/SubagentProgress.js +7 -4
  106. package/dist/components/SubagentProgress.js.map +2 -2
  107. package/dist/components/TaskCard.js +14 -11
  108. package/dist/components/TaskCard.js.map +2 -2
  109. package/dist/components/TextInput.js +9 -1
  110. package/dist/components/TextInput.js.map +2 -2
  111. package/dist/components/TodoPanel.js +44 -26
  112. package/dist/components/TodoPanel.js.map +2 -2
  113. package/dist/components/ToolUseLoader.js +2 -2
  114. package/dist/components/ToolUseLoader.js.map +2 -2
  115. package/dist/components/TreeConnector.js +4 -3
  116. package/dist/components/TreeConnector.js.map +2 -2
  117. package/dist/components/TrustDialog.js +2 -1
  118. package/dist/components/TrustDialog.js.map +2 -2
  119. package/dist/components/binary-feedback/BinaryFeedbackView.js +2 -1
  120. package/dist/components/binary-feedback/BinaryFeedbackView.js.map +2 -2
  121. package/dist/components/messages/AssistantTextMessage.js +17 -9
  122. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  123. package/dist/components/messages/AssistantToolUseMessage.js +8 -4
  124. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  125. package/dist/components/messages/GroupRenderer.js +2 -1
  126. package/dist/components/messages/GroupRenderer.js.map +2 -2
  127. package/dist/components/messages/NestedTasksPreview.js +13 -1
  128. package/dist/components/messages/NestedTasksPreview.js.map +2 -2
  129. package/dist/components/messages/ParallelTasksGroupView.js +4 -3
  130. package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
  131. package/dist/components/messages/TaskInModuleView.js +35 -15
  132. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  133. package/dist/components/messages/TaskOutputContent.js +9 -6
  134. package/dist/components/messages/TaskOutputContent.js.map +2 -2
  135. package/dist/components/messages/UserPromptMessage.js +2 -2
  136. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  137. package/dist/constants/colors.js +90 -72
  138. package/dist/constants/colors.js.map +2 -2
  139. package/dist/constants/toolInputExamples.js +84 -0
  140. package/dist/constants/toolInputExamples.js.map +7 -0
  141. package/dist/core/backupManager.js +321 -0
  142. package/dist/core/backupManager.js.map +7 -0
  143. package/dist/core/costTracker.js +9 -18
  144. package/dist/core/costTracker.js.map +2 -2
  145. package/dist/core/gitAutoCommit.js +287 -0
  146. package/dist/core/gitAutoCommit.js.map +7 -0
  147. package/dist/core/index.js +3 -0
  148. package/dist/core/index.js.map +2 -2
  149. package/dist/core/operationTracker.js +212 -0
  150. package/dist/core/operationTracker.js.map +7 -0
  151. package/dist/core/permissions/rules/allowedToolsRule.js +1 -1
  152. package/dist/core/permissions/rules/allowedToolsRule.js.map +2 -2
  153. package/dist/core/permissions/rules/autoEscalationRule.js +5 -0
  154. package/dist/core/permissions/rules/autoEscalationRule.js.map +2 -2
  155. package/dist/core/permissions/rules/projectBoundaryRule.js +5 -0
  156. package/dist/core/permissions/rules/projectBoundaryRule.js.map +2 -2
  157. package/dist/core/permissions/rules/sensitivePathsRule.js +5 -0
  158. package/dist/core/permissions/rules/sensitivePathsRule.js.map +2 -2
  159. package/dist/core/tokenStats.js +9 -0
  160. package/dist/core/tokenStats.js.map +7 -0
  161. package/dist/core/tokenStatsManager.js +331 -0
  162. package/dist/core/tokenStatsManager.js.map +7 -0
  163. package/dist/entrypoints/cli.js +115 -87
  164. package/dist/entrypoints/cli.js.map +2 -2
  165. package/dist/hooks/useAgentTokenStats.js +72 -0
  166. package/dist/hooks/useAgentTokenStats.js.map +7 -0
  167. package/dist/hooks/useAgentTranscripts.js +30 -6
  168. package/dist/hooks/useAgentTranscripts.js.map +2 -2
  169. package/dist/hooks/useLogMessages.js +12 -1
  170. package/dist/hooks/useLogMessages.js.map +2 -2
  171. package/dist/i18n/locales/en.js +6 -5
  172. package/dist/i18n/locales/en.js.map +2 -2
  173. package/dist/i18n/locales/zh-CN.js +6 -5
  174. package/dist/i18n/locales/zh-CN.js.map +2 -2
  175. package/dist/i18n/types.js.map +1 -1
  176. package/dist/permissions.js +28 -1
  177. package/dist/permissions.js.map +2 -2
  178. package/dist/query.js +78 -4
  179. package/dist/query.js.map +3 -3
  180. package/dist/screens/REPL.js +23 -3
  181. package/dist/screens/REPL.js.map +2 -2
  182. package/dist/services/claude.js +54 -3
  183. package/dist/services/claude.js.map +2 -2
  184. package/dist/services/intelligentCompactor.js +1 -1
  185. package/dist/services/intelligentCompactor.js.map +2 -2
  186. package/dist/services/mcpClient.js +81 -25
  187. package/dist/services/mcpClient.js.map +2 -2
  188. package/dist/services/sandbox/filesystemBoundary.js +58 -17
  189. package/dist/services/sandbox/filesystemBoundary.js.map +2 -2
  190. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +3 -2
  191. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  192. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +2 -1
  193. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  194. package/dist/tools/BashTool/BashTool.js +22 -3
  195. package/dist/tools/BashTool/BashTool.js.map +2 -2
  196. package/dist/tools/BashTool/prompt.js +178 -34
  197. package/dist/tools/BashTool/prompt.js.map +2 -2
  198. package/dist/tools/FileEditTool/prompt.js +6 -3
  199. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  200. package/dist/tools/FileWriteTool/prompt.js +4 -2
  201. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  202. package/dist/tools/MultiEditTool/prompt.js +5 -3
  203. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  204. package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -1
  205. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  206. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +3 -2
  207. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  208. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +3 -2
  209. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  210. package/dist/tools/PlanModeTool/prompt.js +1 -1
  211. package/dist/tools/PlanModeTool/prompt.js.map +1 -1
  212. package/dist/tools/SkillTool/SkillTool.js +4 -3
  213. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  214. package/dist/tools/SkillTool/prompt.js +1 -1
  215. package/dist/tools/SkillTool/prompt.js.map +1 -1
  216. package/dist/tools/TaskOutputTool/TaskOutputTool.js +3 -2
  217. package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +2 -2
  218. package/dist/tools/TaskTool/TaskTool.js +8 -0
  219. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  220. package/dist/utils/CircuitBreaker.js +242 -0
  221. package/dist/utils/CircuitBreaker.js.map +7 -0
  222. package/dist/utils/ask.js +2 -0
  223. package/dist/utils/ask.js.map +2 -2
  224. package/dist/utils/config.js +47 -5
  225. package/dist/utils/config.js.map +2 -2
  226. package/dist/utils/credentials/CredentialStore.js +1 -0
  227. package/dist/utils/credentials/CredentialStore.js.map +7 -0
  228. package/dist/utils/credentials/EncryptedFileStore.js +157 -0
  229. package/dist/utils/credentials/EncryptedFileStore.js.map +7 -0
  230. package/dist/utils/credentials/index.js +37 -0
  231. package/dist/utils/credentials/index.js.map +7 -0
  232. package/dist/utils/credentials/migration.js +82 -0
  233. package/dist/utils/credentials/migration.js.map +7 -0
  234. package/dist/utils/markdown.js +13 -1
  235. package/dist/utils/markdown.js.map +2 -2
  236. package/dist/utils/permissions/filesystem.js +5 -1
  237. package/dist/utils/permissions/filesystem.js.map +2 -2
  238. package/dist/utils/safePath.js +132 -0
  239. package/dist/utils/safePath.js.map +7 -0
  240. package/dist/utils/sensitiveFiles.js +125 -0
  241. package/dist/utils/sensitiveFiles.js.map +7 -0
  242. package/dist/utils/taskDisplayUtils.js +9 -9
  243. package/dist/utils/taskDisplayUtils.js.map +2 -2
  244. package/dist/utils/theme.js +6 -6
  245. package/dist/utils/theme.js.map +1 -1
  246. package/dist/utils/toolRiskClassification.js +207 -0
  247. package/dist/utils/toolRiskClassification.js.map +7 -0
  248. package/dist/utils/tooling/safeRender.js +5 -4
  249. package/dist/utils/tooling/safeRender.js.map +2 -2
  250. package/dist/version.js +2 -2
  251. package/dist/version.js.map +1 -1
  252. package/package.json +9 -7
  253. package/dist/hooks/useCancelRequest.js +0 -31
  254. package/dist/hooks/useCancelRequest.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/AskUserQuestionDialog/QuestionView.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { Select } from '@components/CustomSelect/select'\nimport {\n type UserQuestion,\n type QuestionOption,\n} from '@minto-types/askUserQuestion'\nimport { Option } from '@inkjs/ui'\nimport { getTheme } from '@utils/theme'\n\ninterface QuestionViewProps {\n question: UserQuestion\n questionIndex: number\n totalQuestions: number\n selectedOptionIndex: number\n onOptionChange: (optionIndex: number) => void\n}\n\nexport function QuestionView({\n question,\n questionIndex,\n totalQuestions,\n selectedOptionIndex,\n onOptionChange,\n}: QuestionViewProps): React.ReactElement {\n const theme = getTheme()\n\n // Build options for the Select component\n const options: Option[] = React.useMemo(() => {\n if (!question.options || question.options.length === 0) {\n return []\n }\n\n const selectOptions = question.options.map((opt, index) => ({\n label: opt.label,\n value: String(index),\n }))\n\n // Always add \"Other (custom input)\" option\n selectOptions.push({\n label: 'Other (custom input)',\n value: 'other',\n })\n\n return selectOptions\n }, [question.options])\n\n return (\n <Box flexDirection=\"column\" paddingX={2} paddingY={1}>\n {/* Header with question counter */}\n <Box marginBottom={1}>\n <Text color={theme.primary} bold>\n \uD83E\uDD14 AI needs your input\n </Text>\n {totalQuestions > 1 && (\n <Text color={theme.secondaryText}>\n {' '}\n (Question {questionIndex + 1} of {totalQuestions})\n </Text>\n )}\n </Box>\n\n {/* Question header tag */}\n {question.header && (\n <Box marginBottom={1}>\n <Text color={theme.minto}>[{question.header}]</Text>\n </Box>\n )}\n\n {/* Question text */}\n <Box marginBottom={1}>\n <Text bold>{question.question}</Text>\n </Box>\n\n {/* Options list */}\n {question.options && question.options.length > 0 && (\n <Box marginBottom={1}>\n <Select\n options={options}\n defaultValue={String(selectedOptionIndex)}\n onChange={value => {\n if (value === 'other') {\n onOptionChange(-1) // -1 indicates \"Other\"\n } else {\n onOptionChange(Number(value))\n }\n }}\n />\n </Box>\n )}\n\n {/* Show option descriptions */}\n {question.options &&\n question.options.length > 0 &&\n selectedOptionIndex >= 0 &&\n selectedOptionIndex < question.options.length && (\n <Box marginLeft={2} marginBottom={1}>\n <Text color={theme.secondaryText} dimColor>\n {question.options[selectedOptionIndex]?.description || ''}\n </Text>\n </Box>\n )}\n\n {/* Help text */}\n <Box\n marginTop={1}\n borderStyle=\"single\"\n borderColor={theme.secondaryBorder}\n paddingX={1}\n >\n <Text color={theme.secondaryText}>\n [\u2191/\u2193 Navigate] [Enter Confirm]\n {totalQuestions > 1 && ' [\u2190/\u2192 Switch Questions]'} [Esc Cancel]\n </Text>\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,cAAc;AAMvB,SAAS,gBAAgB;AAUlB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,QAAQ,SAAS;AAGvB,QAAM,UAAoB,MAAM,QAAQ,MAAM;AAC5C,QAAI,CAAC,SAAS,WAAW,SAAS,QAAQ,WAAW,GAAG;AACtD,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,SAAS,QAAQ,IAAI,CAAC,KAAK,WAAW;AAAA,MAC1D,OAAO,IAAI;AAAA,MACX,OAAO,OAAO,KAAK;AAAA,IACrB,EAAE;AAGF,kBAAc,KAAK;AAAA,MACjB,OAAO;AAAA,MACP,OAAO;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,CAAC;AAErB,SACE,oCAAC,OAAI,eAAc,UAAS,UAAU,GAAG,UAAU,KAEjD,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAO,MAAM,SAAS,MAAI,QAAC,+BAEjC,GACC,iBAAiB,KAChB,oCAAC,QAAK,OAAO,MAAM,iBAChB,KAAI,cACM,gBAAgB,GAAE,QAAK,gBAAe,GACnD,CAEJ,GAGC,SAAS,UACR,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAO,MAAM,SAAO,KAAE,SAAS,QAAO,GAAC,CAC/C,GAIF,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,MAAI,QAAE,SAAS,QAAS,CAChC,GAGC,SAAS,WAAW,SAAS,QAAQ,SAAS,KAC7C,oCAAC,OAAI,cAAc,KACjB;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAc,OAAO,mBAAmB;AAAA,MACxC,UAAU,WAAS;AACjB,YAAI,UAAU,SAAS;AACrB,yBAAe,EAAE;AAAA,QACnB,OAAO;AACL,yBAAe,OAAO,KAAK,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA;AAAA,EACF,CACF,GAID,SAAS,WACR,SAAS,QAAQ,SAAS,KAC1B,uBAAuB,KACvB,sBAAsB,SAAS,QAAQ,UACrC,oCAAC,OAAI,YAAY,GAAG,cAAc,KAChC,oCAAC,QAAK,OAAO,MAAM,eAAe,UAAQ,QACvC,SAAS,QAAQ,mBAAmB,GAAG,eAAe,EACzD,CACF,GAIJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,MACX,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,UAAU;AAAA;AAAA,IAEV,oCAAC,QAAK,OAAO,MAAM,iBAAe,4CAE/B,iBAAiB,KAAK,qCAA0B,eACnD;AAAA,EACF,CACF;AAEJ;",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { Select } from '@components/CustomSelect/select'\nimport {\n type UserQuestion,\n type QuestionOption,\n} from '@minto-types/askUserQuestion'\nimport { Option } from '@inkjs/ui'\nimport { getTheme } from '@utils/theme'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ninterface QuestionViewProps {\n question: UserQuestion\n questionIndex: number\n totalQuestions: number\n selectedOptionIndex: number\n onOptionChange: (optionIndex: number) => void\n}\n\nexport function QuestionView({\n question,\n questionIndex,\n totalQuestions,\n selectedOptionIndex,\n onOptionChange,\n}: QuestionViewProps): React.ReactElement {\n const theme = getTheme()\n\n // Build options for the Select component\n const options: Option[] = React.useMemo(() => {\n if (!question.options || question.options.length === 0) {\n return []\n }\n\n const selectOptions = question.options.map((opt, index) => ({\n label: opt.label,\n value: String(index),\n }))\n\n // Always add \"Other (custom input)\" option\n selectOptions.push({\n label: 'Other (custom input)',\n value: 'other',\n })\n\n return selectOptions\n }, [question.options])\n\n return (\n <Box flexDirection=\"column\" paddingX={2} paddingY={1}>\n {/* Header with question counter */}\n <Box marginBottom={1}>\n <Text color={theme.primary} bold>\n \uD83E\uDD14 AI needs your input\n </Text>\n {totalQuestions > 1 && (\n <Text color={theme.secondaryText}>\n {' '}\n (Question {questionIndex + 1} of {totalQuestions})\n </Text>\n )}\n </Box>\n\n {/* Question header tag */}\n {question.header && (\n <Box marginBottom={1}>\n <Text color={theme.minto}>[{question.header}]</Text>\n </Box>\n )}\n\n {/* Question text */}\n <Box marginBottom={1}>\n <Text bold>{question.question}</Text>\n </Box>\n\n {/* Options list */}\n {question.options && question.options.length > 0 && (\n <Box marginBottom={1}>\n <Select\n options={options}\n defaultValue={String(selectedOptionIndex)}\n onChange={value => {\n if (value === 'other') {\n onOptionChange(-1) // -1 indicates \"Other\"\n } else {\n onOptionChange(Number(value))\n }\n }}\n />\n </Box>\n )}\n\n {/* Show option descriptions */}\n {question.options &&\n question.options.length > 0 &&\n selectedOptionIndex >= 0 &&\n selectedOptionIndex < question.options.length && (\n <Box marginLeft={2} marginBottom={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {question.options[selectedOptionIndex]?.description || ''}\n </Text>\n </Box>\n )}\n\n {/* Help text */}\n <Box\n marginTop={1}\n borderStyle=\"single\"\n borderColor={theme.secondaryBorder}\n paddingX={1}\n >\n <Text color={theme.secondaryText}>\n [\u2191/\u2193 Navigate] [Enter Confirm]\n {totalQuestions > 1 && ' [\u2190/\u2192 Switch Questions]'} [Esc Cancel]\n </Text>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,cAAc;AAMvB,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAUzB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,QAAM,QAAQ,SAAS;AAGvB,QAAM,UAAoB,MAAM,QAAQ,MAAM;AAC5C,QAAI,CAAC,SAAS,WAAW,SAAS,QAAQ,WAAW,GAAG;AACtD,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,SAAS,QAAQ,IAAI,CAAC,KAAK,WAAW;AAAA,MAC1D,OAAO,IAAI;AAAA,MACX,OAAO,OAAO,KAAK;AAAA,IACrB,EAAE;AAGF,kBAAc,KAAK;AAAA,MACjB,OAAO;AAAA,MACP,OAAO;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,CAAC;AAErB,SACE,oCAAC,OAAI,eAAc,UAAS,UAAU,GAAG,UAAU,KAEjD,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAO,MAAM,SAAS,MAAI,QAAC,+BAEjC,GACC,iBAAiB,KAChB,oCAAC,QAAK,OAAO,MAAM,iBAChB,KAAI,cACM,gBAAgB,GAAE,QAAK,gBAAe,GACnD,CAEJ,GAGC,SAAS,UACR,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAO,MAAM,SAAO,KAAE,SAAS,QAAO,GAAC,CAC/C,GAIF,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,MAAI,QAAE,SAAS,QAAS,CAChC,GAGC,SAAS,WAAW,SAAS,QAAQ,SAAS,KAC7C,oCAAC,OAAI,cAAc,KACjB;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAc,OAAO,mBAAmB;AAAA,MACxC,UAAU,WAAS;AACjB,YAAI,UAAU,SAAS;AACrB,yBAAe,EAAE;AAAA,QACnB,OAAO;AACL,yBAAe,OAAO,KAAK,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA;AAAA,EACF,CACF,GAID,SAAS,WACR,SAAS,QAAQ,SAAS,KAC1B,uBAAuB,KACvB,sBAAsB,SAAS,QAAQ,UACrC,oCAAC,OAAI,YAAY,GAAG,cAAc,KAChC,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,SAAS,QAAQ,mBAAmB,GAAG,eAAe,EACzD,CACF,GAIJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,MACX,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,UAAU;AAAA;AAAA,IAEV,oCAAC,QAAK,OAAO,MAAM,iBAAe,4CAE/B,iBAAiB,KAAK,qCAA0B,eACnD;AAAA,EACF,CACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,13 @@
1
1
  import React from "react";
2
2
  import { Text } from "ink";
3
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
3
4
  function CollapsibleHint({
4
5
  canExpand,
5
6
  shortcut = "ctrl+o",
6
7
  action = "expand"
7
8
  }) {
8
9
  if (!canExpand) return null;
9
- return /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " ", "(", shortcut, " to ", action, ")");
10
+ return /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "(", shortcut, " to ", action, ")");
10
11
  }
11
12
  export {
12
13
  CollapsibleHint
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/CollapsibleHint.tsx"],
4
- "sourcesContent": ["/**\n * Collapsible Hint Component\n *\n * Displays a keyboard shortcut hint for expandable content.\n * Shows \"(ctrl+o to expand)\" or similar hint when content can be expanded.\n */\n\nimport React from 'react'\nimport { Text } from 'ink'\n\ninterface Props {\n /** Whether the content can be expanded */\n canExpand: boolean\n /** The keyboard shortcut text (default: \"ctrl+o\") */\n shortcut?: string\n /** The action text (default: \"expand\") */\n action?: string\n}\n\nexport function CollapsibleHint({\n canExpand,\n shortcut = 'ctrl+o',\n action = 'expand',\n}: Props): React.ReactNode {\n if (!canExpand) return null\n\n return (\n <Text dimColor>\n {' '}\n ({shortcut} to {action})\n </Text>\n )\n}\n"],
5
- "mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,YAAY;AAWd,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AACX,GAA2B;AACzB,MAAI,CAAC,UAAW,QAAO;AAEvB,SACE,oCAAC,QAAK,UAAQ,QACX,KAAI,KACH,UAAS,QAAK,QAAO,GACzB;AAEJ;",
4
+ "sourcesContent": ["/**\n * Collapsible Hint Component\n *\n * Displays a keyboard shortcut hint for expandable content.\n * Shows \"(ctrl+o to expand)\" or similar hint when content can be expanded.\n */\n\nimport React from 'react'\nimport { Text } from 'ink'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ninterface Props {\n /** Whether the content can be expanded */\n canExpand: boolean\n /** The keyboard shortcut text (default: \"ctrl+o\") */\n shortcut?: string\n /** The action text (default: \"expand\") */\n action?: string\n}\n\nexport function CollapsibleHint({\n canExpand,\n shortcut = 'ctrl+o',\n action = 'expand',\n}: Props): React.ReactNode {\n if (!canExpand) return null\n\n return (\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n ({shortcut} to {action})\n </Text>\n )\n}\n"],
5
+ "mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,YAAY;AACrB,SAAS,uBAAuB;AAWzB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AACX,GAA2B;AACzB,MAAI,CAAC,UAAW,QAAO;AAEvB,SACE,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,KAAI,KACH,UAAS,QAAK,QAAO,GACzB;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@ import { saveGlobalConfig, getGlobalConfig } from "../utils/config.js";
7
7
  import { useExitOnCtrlCD } from "../hooks/useExitOnCtrlCD.js";
8
8
  import { getModelManager } from "../utils/model.js";
9
9
  import { getCompressionMode, setCompressionMode } from "../utils/compressionMode.js";
10
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
10
11
  function Config({ onClose }) {
11
12
  const [globalConfig, setGlobalConfig] = useState(getGlobalConfig());
12
13
  const initialConfig = React.useRef(getGlobalConfig());
@@ -169,8 +170,8 @@ function Config({ onClose }) {
169
170
  color: setting.disabled ? theme.secondaryText : theme.suggestion
170
171
  },
171
172
  setting.type === "boolean" ? setting.value ? "enabled" : "disabled" : setting.type === "enum" ? setting.value : String(setting.value)
172
- )), index === selectedIndex && editingString && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, "Enter new value: ", currentInput), inputError && /* @__PURE__ */ React.createElement(Text, { color: "red" }, inputError))))),
173
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, editingString ? "Enter to save \xB7 Esc to cancel" : /* @__PURE__ */ React.createElement(React.Fragment, null, "\u2191/\u2193 to navigate \xB7 Enter to change \xB7 Esc to close", /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, " ", "\xB7 Use /model for model config"))))
173
+ )), index === selectedIndex && editingString && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, "Enter new value: ", currentInput), inputError && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, inputError))))),
174
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, editingString ? "Enter to save \xB7 Esc to cancel" : /* @__PURE__ */ React.createElement(React.Fragment, null, "\u2191/\u2193 to navigate \xB7 Enter to change \xB7 Esc to close", /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, " ", "\xB7 Use /model for model config"))))
174
175
  ));
175
176
  }
176
177
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/Config.tsx"],
4
- "sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useState } from 'react'\nimport figures from 'figures'\nimport { getTheme } from '@utils/theme'\nimport { GlobalConfig, saveGlobalConfig, getGlobalConfig } from '@utils/config'\nimport chalk from 'chalk'\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\nimport { getModelManager } from '@utils/model'\nimport { getCompressionMode, setCompressionMode } from '@utils/compressionMode'\nimport type { CompressionMode } from '@constants/compressionPrompts'\n\ntype Props = {\n onClose: () => void\n}\n\ntype Setting =\n | {\n id: string\n label: string\n value: boolean\n onChange(value: boolean): void\n type: 'boolean'\n disabled?: boolean\n }\n | {\n id: string\n label: string\n value: string\n options: string[]\n onChange(value: string): void\n type: 'enum'\n disabled?: boolean\n }\n | {\n id: string\n label: string\n value: string\n onChange(value: string): void\n type: 'string'\n disabled?: boolean\n }\n | {\n id: string\n label: string\n value: number\n onChange(value: number): void\n type: 'number'\n disabled?: boolean\n }\n\nexport function Config({ onClose }: Props): React.ReactNode {\n const [globalConfig, setGlobalConfig] = useState(getGlobalConfig())\n const initialConfig = React.useRef(getGlobalConfig())\n const [selectedIndex, setSelectedIndex] = useState(0)\n const exitState = useExitOnCtrlCD(() => process.exit(0))\n const [editingString, setEditingString] = useState(false)\n const [currentInput, setCurrentInput] = useState('')\n const [inputError, setInputError] = useState<string | null>(null)\n\n const modelManager = getModelManager()\n const activeProfiles = modelManager.getAvailableModels()\n\n const settings: Setting[] = [\n // Global settings\n {\n id: 'theme',\n label: 'Theme',\n value: globalConfig.theme ?? 'dark',\n options: ['dark', 'light'],\n onChange(theme: string) {\n const config = { ...getGlobalConfig(), theme: theme as any }\n saveGlobalConfig(config)\n setGlobalConfig(config)\n },\n type: 'enum',\n },\n {\n id: 'verbose',\n label: 'Verbose mode',\n value: globalConfig.verbose ?? false,\n onChange(verbose: boolean) {\n const config = { ...getGlobalConfig(), verbose }\n saveGlobalConfig(config)\n setGlobalConfig(config)\n },\n type: 'boolean',\n },\n {\n id: 'stream',\n label: 'Stream responses',\n value: globalConfig.stream ?? true,\n onChange(stream: boolean) {\n const config = { ...getGlobalConfig(), stream }\n saveGlobalConfig(config)\n setGlobalConfig(config)\n },\n type: 'boolean',\n },\n {\n id: 'compressionMode',\n label: 'Compression mode (/compact)',\n value: getCompressionMode(),\n options: ['business', 'code'],\n onChange(mode: string) {\n setCompressionMode(mode as CompressionMode)\n const config = {\n ...getGlobalConfig(),\n compressionMode: mode as CompressionMode,\n }\n setGlobalConfig(config)\n },\n type: 'enum',\n },\n ]\n\n const theme = getTheme()\n\n useInput((input, key) => {\n if (editingString) {\n if (key.return) {\n const currentSetting = settings[selectedIndex]\n if (currentSetting?.type === 'string') {\n try {\n currentSetting.onChange(currentInput)\n setEditingString(false)\n setCurrentInput('')\n setInputError(null)\n } catch (error) {\n setInputError(\n error instanceof Error ? error.message : 'Invalid input',\n )\n }\n } else if (currentSetting?.type === 'number') {\n const numValue = parseFloat(currentInput)\n if (isNaN(numValue)) {\n setInputError('Please enter a valid number')\n } else {\n try {\n ;(currentSetting as any).onChange(numValue)\n setEditingString(false)\n setCurrentInput('')\n setInputError(null)\n } catch (error) {\n setInputError(\n error instanceof Error ? error.message : 'Invalid input',\n )\n }\n }\n }\n } else if (key.escape) {\n setEditingString(false)\n setCurrentInput('')\n setInputError(null)\n } else if (key.delete || key.backspace) {\n setCurrentInput(prev => prev.slice(0, -1))\n } else if (input) {\n setCurrentInput(prev => prev + input)\n }\n return\n }\n\n if (key.upArrow && !exitState.pending) {\n setSelectedIndex(prev => Math.max(0, prev - 1))\n } else if (key.downArrow && !exitState.pending) {\n setSelectedIndex(prev => Math.min(settings.length - 1, prev + 1))\n } else if (key.return && !exitState.pending) {\n const currentSetting = settings[selectedIndex]\n if (currentSetting?.disabled) return\n\n if (currentSetting?.type === 'boolean') {\n currentSetting.onChange(!currentSetting.value)\n } else if (currentSetting?.type === 'enum') {\n const currentIndex = currentSetting.options.indexOf(\n currentSetting.value,\n )\n const nextIndex = (currentIndex + 1) % currentSetting.options.length\n currentSetting.onChange(currentSetting.options[nextIndex])\n } else if (\n currentSetting?.type === 'string' ||\n currentSetting?.type === 'number'\n ) {\n setCurrentInput(String(currentSetting.value))\n setEditingString(true)\n setInputError(null)\n }\n } else if (key.escape && !exitState.pending) {\n // Check if config has changed\n const currentConfigString = JSON.stringify(getGlobalConfig())\n const initialConfigString = JSON.stringify(initialConfig.current)\n\n if (currentConfigString !== initialConfigString) {\n // Config has changed, save it\n saveGlobalConfig(getGlobalConfig())\n }\n\n onClose()\n }\n })\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.secondaryBorder}\n paddingX={2}\n paddingY={1}\n gap={1}\n >\n <Text bold>\n Configuration{' '}\n {exitState.pending\n ? `(press ${exitState.keyName} again to exit)`\n : ''}\n </Text>\n\n {/* Model Configuration Summary */}\n <Box flexDirection=\"column\" marginY={1}>\n <Text bold color={theme.success}>\n Model Configuration:\n </Text>\n {activeProfiles.length === 0 ? (\n <Text color={theme.secondaryText}>\n No models configured. Use /model to add models.\n </Text>\n ) : (\n <Box flexDirection=\"column\" marginLeft={2}>\n {activeProfiles.map(profile => (\n <React.Fragment key={profile.modelName}>\n <Text color={theme.secondaryText}>\n \u2022 {profile.name} ({profile.provider})\n </Text>\n </React.Fragment>\n ))}\n <Box marginTop={1}>\n <Text color={theme.suggestion}>\n Use /model to manage model configurations\n </Text>\n </Box>\n </Box>\n )}\n </Box>\n\n {/* Settings List */}\n <Box flexDirection=\"column\">\n {settings.map((setting, index) => (\n <Box key={setting.id} flexDirection=\"column\">\n <Box flexDirection=\"row\" gap={1}>\n <Text\n color={\n index === selectedIndex\n ? theme.success\n : setting.disabled\n ? theme.secondaryText\n : theme.text\n }\n >\n {index === selectedIndex ? figures.pointer : ' '}{' '}\n {setting.label}\n </Text>\n <Text\n color={\n setting.disabled ? theme.secondaryText : theme.suggestion\n }\n >\n {setting.type === 'boolean'\n ? setting.value\n ? 'enabled'\n : 'disabled'\n : setting.type === 'enum'\n ? setting.value\n : String(setting.value)}\n </Text>\n </Box>\n {index === selectedIndex && editingString && (\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={theme.suggestion}>\n Enter new value: {currentInput}\n </Text>\n {inputError && <Text color=\"red\">{inputError}</Text>}\n </Box>\n )}\n </Box>\n ))}\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n {editingString ? (\n 'Enter to save \u00B7 Esc to cancel'\n ) : (\n <>\n \u2191/\u2193 to navigate \u00B7 Enter to change \u00B7 Esc to close\n <Text color={theme.suggestion}>\n {' '}\n \u00B7 Use /model for model config\n </Text>\n </>\n )}\n </Text>\n </Box>\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useState } from 'react'\nimport figures from 'figures'\nimport { getTheme } from '@utils/theme'\nimport { GlobalConfig, saveGlobalConfig, getGlobalConfig } from '@utils/config'\nimport chalk from 'chalk'\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\nimport { getModelManager } from '@utils/model'\nimport { getCompressionMode, setCompressionMode } from '@utils/compressionMode'\nimport type { CompressionMode } from '@constants/compressionPrompts'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype Props = {\n onClose: () => void\n}\n\ntype Setting =\n | {\n id: string\n label: string\n value: boolean\n onChange(value: boolean): void\n type: 'boolean'\n disabled?: boolean\n }\n | {\n id: string\n label: string\n value: string\n options: string[]\n onChange(value: string): void\n type: 'enum'\n disabled?: boolean\n }\n | {\n id: string\n label: string\n value: string\n onChange(value: string): void\n type: 'string'\n disabled?: boolean\n }\n | {\n id: string\n label: string\n value: number\n onChange(value: number): void\n type: 'number'\n disabled?: boolean\n }\n\nexport function Config({ onClose }: Props): React.ReactNode {\n const [globalConfig, setGlobalConfig] = useState(getGlobalConfig())\n const initialConfig = React.useRef(getGlobalConfig())\n const [selectedIndex, setSelectedIndex] = useState(0)\n const exitState = useExitOnCtrlCD(() => process.exit(0))\n const [editingString, setEditingString] = useState(false)\n const [currentInput, setCurrentInput] = useState('')\n const [inputError, setInputError] = useState<string | null>(null)\n\n const modelManager = getModelManager()\n const activeProfiles = modelManager.getAvailableModels()\n\n const settings: Setting[] = [\n // Global settings\n {\n id: 'theme',\n label: 'Theme',\n value: globalConfig.theme ?? 'dark',\n options: ['dark', 'light'],\n onChange(theme: string) {\n const config = { ...getGlobalConfig(), theme: theme as any }\n saveGlobalConfig(config)\n setGlobalConfig(config)\n },\n type: 'enum',\n },\n {\n id: 'verbose',\n label: 'Verbose mode',\n value: globalConfig.verbose ?? false,\n onChange(verbose: boolean) {\n const config = { ...getGlobalConfig(), verbose }\n saveGlobalConfig(config)\n setGlobalConfig(config)\n },\n type: 'boolean',\n },\n {\n id: 'stream',\n label: 'Stream responses',\n value: globalConfig.stream ?? true,\n onChange(stream: boolean) {\n const config = { ...getGlobalConfig(), stream }\n saveGlobalConfig(config)\n setGlobalConfig(config)\n },\n type: 'boolean',\n },\n {\n id: 'compressionMode',\n label: 'Compression mode (/compact)',\n value: getCompressionMode(),\n options: ['business', 'code'],\n onChange(mode: string) {\n setCompressionMode(mode as CompressionMode)\n const config = {\n ...getGlobalConfig(),\n compressionMode: mode as CompressionMode,\n }\n setGlobalConfig(config)\n },\n type: 'enum',\n },\n ]\n\n const theme = getTheme()\n\n useInput((input, key) => {\n if (editingString) {\n if (key.return) {\n const currentSetting = settings[selectedIndex]\n if (currentSetting?.type === 'string') {\n try {\n currentSetting.onChange(currentInput)\n setEditingString(false)\n setCurrentInput('')\n setInputError(null)\n } catch (error) {\n setInputError(\n error instanceof Error ? error.message : 'Invalid input',\n )\n }\n } else if (currentSetting?.type === 'number') {\n const numValue = parseFloat(currentInput)\n if (isNaN(numValue)) {\n setInputError('Please enter a valid number')\n } else {\n try {\n ;(currentSetting as any).onChange(numValue)\n setEditingString(false)\n setCurrentInput('')\n setInputError(null)\n } catch (error) {\n setInputError(\n error instanceof Error ? error.message : 'Invalid input',\n )\n }\n }\n }\n } else if (key.escape) {\n setEditingString(false)\n setCurrentInput('')\n setInputError(null)\n } else if (key.delete || key.backspace) {\n setCurrentInput(prev => prev.slice(0, -1))\n } else if (input) {\n setCurrentInput(prev => prev + input)\n }\n return\n }\n\n if (key.upArrow && !exitState.pending) {\n setSelectedIndex(prev => Math.max(0, prev - 1))\n } else if (key.downArrow && !exitState.pending) {\n setSelectedIndex(prev => Math.min(settings.length - 1, prev + 1))\n } else if (key.return && !exitState.pending) {\n const currentSetting = settings[selectedIndex]\n if (currentSetting?.disabled) return\n\n if (currentSetting?.type === 'boolean') {\n currentSetting.onChange(!currentSetting.value)\n } else if (currentSetting?.type === 'enum') {\n const currentIndex = currentSetting.options.indexOf(\n currentSetting.value,\n )\n const nextIndex = (currentIndex + 1) % currentSetting.options.length\n currentSetting.onChange(currentSetting.options[nextIndex])\n } else if (\n currentSetting?.type === 'string' ||\n currentSetting?.type === 'number'\n ) {\n setCurrentInput(String(currentSetting.value))\n setEditingString(true)\n setInputError(null)\n }\n } else if (key.escape && !exitState.pending) {\n // Check if config has changed\n const currentConfigString = JSON.stringify(getGlobalConfig())\n const initialConfigString = JSON.stringify(initialConfig.current)\n\n if (currentConfigString !== initialConfigString) {\n // Config has changed, save it\n saveGlobalConfig(getGlobalConfig())\n }\n\n onClose()\n }\n })\n\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.secondaryBorder}\n paddingX={2}\n paddingY={1}\n gap={1}\n >\n <Text bold>\n Configuration{' '}\n {exitState.pending\n ? `(press ${exitState.keyName} again to exit)`\n : ''}\n </Text>\n\n {/* Model Configuration Summary */}\n <Box flexDirection=\"column\" marginY={1}>\n <Text bold color={theme.success}>\n Model Configuration:\n </Text>\n {activeProfiles.length === 0 ? (\n <Text color={theme.secondaryText}>\n No models configured. Use /model to add models.\n </Text>\n ) : (\n <Box flexDirection=\"column\" marginLeft={2}>\n {activeProfiles.map(profile => (\n <React.Fragment key={profile.modelName}>\n <Text color={theme.secondaryText}>\n \u2022 {profile.name} ({profile.provider})\n </Text>\n </React.Fragment>\n ))}\n <Box marginTop={1}>\n <Text color={theme.suggestion}>\n Use /model to manage model configurations\n </Text>\n </Box>\n </Box>\n )}\n </Box>\n\n {/* Settings List */}\n <Box flexDirection=\"column\">\n {settings.map((setting, index) => (\n <Box key={setting.id} flexDirection=\"column\">\n <Box flexDirection=\"row\" gap={1}>\n <Text\n color={\n index === selectedIndex\n ? theme.success\n : setting.disabled\n ? theme.secondaryText\n : theme.text\n }\n >\n {index === selectedIndex ? figures.pointer : ' '}{' '}\n {setting.label}\n </Text>\n <Text\n color={\n setting.disabled ? theme.secondaryText : theme.suggestion\n }\n >\n {setting.type === 'boolean'\n ? setting.value\n ? 'enabled'\n : 'disabled'\n : setting.type === 'enum'\n ? setting.value\n : String(setting.value)}\n </Text>\n </Box>\n {index === selectedIndex && editingString && (\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={theme.suggestion}>\n Enter new value: {currentInput}\n </Text>\n {inputError && (\n <Text color={SEMANTIC_COLORS.error}>{inputError}</Text>\n )}\n </Box>\n )}\n </Box>\n ))}\n </Box>\n\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {editingString ? (\n 'Enter to save \u00B7 Esc to cancel'\n ) : (\n <>\n \u2191/\u2193 to navigate \u00B7 Enter to change \u00B7 Esc to close\n <Text color={theme.suggestion}>\n {' '}\n \u00B7 Use /model for model config\n </Text>\n </>\n )}\n </Text>\n </Box>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["theme"]
7
7
  }
@@ -11,6 +11,7 @@ import { SimpleSpinner } from "./Spinner.js";
11
11
  import { WelcomeBox } from "./Onboarding.js";
12
12
  import { PRODUCT_NAME } from "../constants/product.js";
13
13
  import { sendNotification } from "../services/notifier.js";
14
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
14
15
  const PASTE_HERE_MSG = "Paste code here if prompted > ";
15
16
  function ConsoleOAuthFlow({ onDone }) {
16
17
  const [oauthStatus, setOAuthStatus] = useState({
@@ -162,7 +163,7 @@ function ConsoleOAuthFlow({ onDone }) {
162
163
  staticItems.header = /* @__PURE__ */ React.createElement(Box, { key: "header", flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement(WelcomeBox, null), /* @__PURE__ */ React.createElement(Box, { paddingBottom: 1, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(AsciiLogo, null)));
163
164
  }
164
165
  if (oauthStatus.state === "waiting_for_login" && showPastePrompt) {
165
- staticItems.urlToCopy = /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", key: "urlToCopy", gap: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(Box, { paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Browser didn't open? Use the url below to sign in:")), /* @__PURE__ */ React.createElement(Box, { width: 1e3 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, oauthStatus.url)));
166
+ staticItems.urlToCopy = /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", key: "urlToCopy", gap: 1, paddingBottom: 1 }, /* @__PURE__ */ React.createElement(Box, { paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Browser didn't open? Use the url below to sign in:")), /* @__PURE__ */ React.createElement(Box, { width: 1e3 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, oauthStatus.url)));
166
167
  }
167
168
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement(
168
169
  Static,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/ConsoleOAuthFlow.tsx"],
4
- "sourcesContent": ["import React, { useEffect, useState, useCallback } from 'react'\nimport { Static, Box, Text, useInput } from 'ink'\nimport TextInput from './TextInput'\nimport { OAuthService, createAndStoreApiKey } from '@services/oauth'\nimport { getTheme } from '@utils/theme'\nimport { AsciiLogo } from './AsciiLogo'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { logError } from '@utils/log'\nimport { clearTerminal } from '@utils/terminal'\nimport { SimpleSpinner } from './Spinner'\nimport { WelcomeBox } from './Onboarding'\nimport { PRODUCT_NAME } from '@constants/product'\nimport { sendNotification } from '@services/notifier'\n\ntype Props = {\n onDone(): void\n}\n\ntype OAuthStatus =\n | { state: 'idle' }\n | { state: 'ready_to_start' }\n | { state: 'waiting_for_login'; url: string }\n | { state: 'creating_api_key' }\n | { state: 'about_to_retry'; nextState: OAuthStatus }\n | { state: 'success'; apiKey: string }\n | {\n state: 'error'\n message: string\n toRetry?: OAuthStatus\n }\n\nconst PASTE_HERE_MSG = 'Paste code here if prompted > '\n\nexport function ConsoleOAuthFlow({ onDone }: Props): React.ReactNode {\n const [oauthStatus, setOAuthStatus] = useState<OAuthStatus>({\n state: 'idle',\n })\n const theme = getTheme()\n\n const [pastedCode, setPastedCode] = useState('')\n const [cursorOffset, setCursorOffset] = useState(0)\n const [oauthService] = useState(() => new OAuthService())\n // After a few seconds we suggest the user to copy/paste url if the\n // browser did not open automatically. In this flow we expect the user to\n // copy the code from the browser and paste it in the terminal\n const [showPastePrompt, setShowPastePrompt] = useState(false)\n // we need a special clearing state to correctly re-render Static elements\n const [isClearing, setIsClearing] = useState(false)\n\n const textInputColumns = useTerminalSize().columns - PASTE_HERE_MSG.length - 1\n\n useEffect(() => {\n if (isClearing) {\n clearTerminal()\n setIsClearing(false)\n }\n }, [isClearing])\n\n // Retry logic\n useEffect(() => {\n if (oauthStatus.state === 'about_to_retry') {\n setIsClearing(true)\n setTimeout(() => {\n setOAuthStatus(oauthStatus.nextState)\n }, 1000)\n }\n }, [oauthStatus])\n\n useInput(async (_, key) => {\n if (key.return) {\n if (oauthStatus.state === 'idle') {\n setOAuthStatus({ state: 'ready_to_start' })\n } else if (oauthStatus.state === 'success') {\n await clearTerminal() // needed to clear out Static components\n onDone()\n } else if (oauthStatus.state === 'error' && oauthStatus.toRetry) {\n setPastedCode('')\n setOAuthStatus({\n state: 'about_to_retry',\n nextState: oauthStatus.toRetry,\n })\n }\n }\n })\n\n async function handleSubmitCode(value: string, url: string) {\n try {\n // Expecting format \"authorizationCode#state\" from the authorization callback URL\n const [authorizationCode, state] = value.split('#')\n\n if (!authorizationCode || !state) {\n setOAuthStatus({\n state: 'error',\n message: 'Invalid code. Please make sure the full code was copied',\n toRetry: { state: 'waiting_for_login', url },\n })\n return\n }\n\n // Track which path the user is taking (manual code entry)\n\n oauthService.processCallback({\n authorizationCode,\n state,\n useManualRedirect: true,\n })\n } catch (err) {\n logError(err)\n setOAuthStatus({\n state: 'error',\n message: (err as Error).message,\n toRetry: { state: 'waiting_for_login', url },\n })\n }\n }\n\n const startOAuth = useCallback(async () => {\n try {\n const result = await oauthService\n .startOAuthFlow(async url => {\n setOAuthStatus({ state: 'waiting_for_login', url })\n setTimeout(() => setShowPastePrompt(true), 3000)\n })\n .catch(err => {\n // Handle token exchange errors specifically\n if (err.message.includes('Token exchange failed')) {\n setOAuthStatus({\n state: 'error',\n message:\n 'Failed to exchange authorization code for access token. Please try again.',\n toRetry: { state: 'ready_to_start' },\n })\n } else {\n // Handle other errors\n setOAuthStatus({\n state: 'error',\n message: err.message,\n toRetry: { state: 'ready_to_start' },\n })\n }\n throw err\n })\n\n setOAuthStatus({ state: 'creating_api_key' })\n\n const apiKey = await createAndStoreApiKey(result.accessToken).catch(\n err => {\n setOAuthStatus({\n state: 'error',\n message: 'Failed to create API key: ' + err.message,\n toRetry: { state: 'ready_to_start' },\n })\n\n throw err\n },\n )\n\n if (apiKey) {\n setOAuthStatus({ state: 'success', apiKey })\n sendNotification({ message: 'Minto login successful' })\n } else {\n setOAuthStatus({\n state: 'error',\n message:\n \"Unable to create API key. The server accepted the request but didn't return a key.\",\n toRetry: { state: 'ready_to_start' },\n })\n }\n } catch (err) {\n const errorMessage = (err as Error).message\n }\n }, [oauthService, setShowPastePrompt])\n\n useEffect(() => {\n if (oauthStatus.state === 'ready_to_start') {\n startOAuth()\n }\n }, [oauthStatus.state, startOAuth])\n\n // Helper function to render the appropriate status message\n function renderStatusMessage(): React.ReactNode {\n switch (oauthStatus.state) {\n case 'idle':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text bold>\n {PRODUCT_NAME} is billed based on API usage through your Anthropic\n Console account.\n </Text>\n\n <Box>\n <Text>\n Pricing may evolve as we move towards general availability.\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <Text color={theme.permission}>\n Press <Text bold>Enter</Text> to login to your Anthropic Console\n account\u2026\n </Text>\n </Box>\n </Box>\n )\n\n case 'waiting_for_login':\n return (\n <Box flexDirection=\"column\" gap={1}>\n {!showPastePrompt && (\n <Box>\n <SimpleSpinner />\n <Text>Opening browser to sign in\u2026</Text>\n </Box>\n )}\n\n {showPastePrompt && (\n <Box>\n <Text>{PASTE_HERE_MSG}</Text>\n <TextInput\n value={pastedCode}\n onChange={setPastedCode}\n onSubmit={(value: string) =>\n handleSubmitCode(value, oauthStatus.url)\n }\n cursorOffset={cursorOffset}\n onChangeCursorOffset={setCursorOffset}\n columns={textInputColumns}\n />\n </Box>\n )}\n </Box>\n )\n\n case 'creating_api_key':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box>\n <SimpleSpinner />\n <Text>Creating API key for Minto\u2026</Text>\n </Box>\n </Box>\n )\n\n case 'about_to_retry':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color={theme.permission}>Retrying\u2026</Text>\n </Box>\n )\n\n case 'success':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color={theme.success}>\n Login successful. Press <Text bold>Enter</Text> to continue\u2026\n </Text>\n </Box>\n )\n\n case 'error':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color={theme.error}>OAuth error: {oauthStatus.message}</Text>\n\n {oauthStatus.toRetry && (\n <Box marginTop={1}>\n <Text color={theme.permission}>\n Press <Text bold>Enter</Text> to retry.\n </Text>\n </Box>\n )}\n </Box>\n )\n\n default:\n return null\n }\n }\n\n // We need to render the copy-able URL statically to prevent Ink <Text> from inserting\n // newlines in the middle of the URL (this breaks Safari). Because <Static> components are\n // only rendered once top-to-bottom, we also need to make everything above the URL static.\n const staticItems: Record<string, React.JSX.Element> = {}\n if (!isClearing) {\n staticItems.header = (\n <Box key=\"header\" flexDirection=\"column\" gap={1}>\n <WelcomeBox />\n <Box paddingBottom={1} paddingLeft={1}>\n <AsciiLogo />\n </Box>\n </Box>\n )\n }\n if (oauthStatus.state === 'waiting_for_login' && showPastePrompt) {\n staticItems.urlToCopy = (\n <Box flexDirection=\"column\" key=\"urlToCopy\" gap={1} paddingBottom={1}>\n <Box paddingX={1}>\n <Text dimColor>\n Browser didn&apos;t open? Use the url below to sign in:\n </Text>\n </Box>\n <Box width={1000}>\n <Text dimColor>{oauthStatus.url}</Text>\n </Box>\n </Box>\n )\n }\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Static\n items={Object.keys(staticItems)}\n children={(item: string) => staticItems[item]}\n />\n <Box paddingLeft={1} flexDirection=\"column\" gap={1}>\n {renderStatusMessage()}\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React, { useEffect, useState, useCallback } from 'react'\nimport { Static, Box, Text, useInput } from 'ink'\nimport TextInput from './TextInput'\nimport { OAuthService, createAndStoreApiKey } from '@services/oauth'\nimport { getTheme } from '@utils/theme'\nimport { AsciiLogo } from './AsciiLogo'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { logError } from '@utils/log'\nimport { clearTerminal } from '@utils/terminal'\nimport { SimpleSpinner } from './Spinner'\nimport { WelcomeBox } from './Onboarding'\nimport { PRODUCT_NAME } from '@constants/product'\nimport { sendNotification } from '@services/notifier'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype Props = {\n onDone(): void\n}\n\ntype OAuthStatus =\n | { state: 'idle' }\n | { state: 'ready_to_start' }\n | { state: 'waiting_for_login'; url: string }\n | { state: 'creating_api_key' }\n | { state: 'about_to_retry'; nextState: OAuthStatus }\n | { state: 'success'; apiKey: string }\n | {\n state: 'error'\n message: string\n toRetry?: OAuthStatus\n }\n\nconst PASTE_HERE_MSG = 'Paste code here if prompted > '\n\nexport function ConsoleOAuthFlow({ onDone }: Props): React.ReactNode {\n const [oauthStatus, setOAuthStatus] = useState<OAuthStatus>({\n state: 'idle',\n })\n const theme = getTheme()\n\n const [pastedCode, setPastedCode] = useState('')\n const [cursorOffset, setCursorOffset] = useState(0)\n const [oauthService] = useState(() => new OAuthService())\n // After a few seconds we suggest the user to copy/paste url if the\n // browser did not open automatically. In this flow we expect the user to\n // copy the code from the browser and paste it in the terminal\n const [showPastePrompt, setShowPastePrompt] = useState(false)\n // we need a special clearing state to correctly re-render Static elements\n const [isClearing, setIsClearing] = useState(false)\n\n const textInputColumns = useTerminalSize().columns - PASTE_HERE_MSG.length - 1\n\n useEffect(() => {\n if (isClearing) {\n clearTerminal()\n setIsClearing(false)\n }\n }, [isClearing])\n\n // Retry logic\n useEffect(() => {\n if (oauthStatus.state === 'about_to_retry') {\n setIsClearing(true)\n setTimeout(() => {\n setOAuthStatus(oauthStatus.nextState)\n }, 1000)\n }\n }, [oauthStatus])\n\n useInput(async (_, key) => {\n if (key.return) {\n if (oauthStatus.state === 'idle') {\n setOAuthStatus({ state: 'ready_to_start' })\n } else if (oauthStatus.state === 'success') {\n await clearTerminal() // needed to clear out Static components\n onDone()\n } else if (oauthStatus.state === 'error' && oauthStatus.toRetry) {\n setPastedCode('')\n setOAuthStatus({\n state: 'about_to_retry',\n nextState: oauthStatus.toRetry,\n })\n }\n }\n })\n\n async function handleSubmitCode(value: string, url: string) {\n try {\n // Expecting format \"authorizationCode#state\" from the authorization callback URL\n const [authorizationCode, state] = value.split('#')\n\n if (!authorizationCode || !state) {\n setOAuthStatus({\n state: 'error',\n message: 'Invalid code. Please make sure the full code was copied',\n toRetry: { state: 'waiting_for_login', url },\n })\n return\n }\n\n // Track which path the user is taking (manual code entry)\n\n oauthService.processCallback({\n authorizationCode,\n state,\n useManualRedirect: true,\n })\n } catch (err) {\n logError(err)\n setOAuthStatus({\n state: 'error',\n message: (err as Error).message,\n toRetry: { state: 'waiting_for_login', url },\n })\n }\n }\n\n const startOAuth = useCallback(async () => {\n try {\n const result = await oauthService\n .startOAuthFlow(async url => {\n setOAuthStatus({ state: 'waiting_for_login', url })\n setTimeout(() => setShowPastePrompt(true), 3000)\n })\n .catch(err => {\n // Handle token exchange errors specifically\n if (err.message.includes('Token exchange failed')) {\n setOAuthStatus({\n state: 'error',\n message:\n 'Failed to exchange authorization code for access token. Please try again.',\n toRetry: { state: 'ready_to_start' },\n })\n } else {\n // Handle other errors\n setOAuthStatus({\n state: 'error',\n message: err.message,\n toRetry: { state: 'ready_to_start' },\n })\n }\n throw err\n })\n\n setOAuthStatus({ state: 'creating_api_key' })\n\n const apiKey = await createAndStoreApiKey(result.accessToken).catch(\n err => {\n setOAuthStatus({\n state: 'error',\n message: 'Failed to create API key: ' + err.message,\n toRetry: { state: 'ready_to_start' },\n })\n\n throw err\n },\n )\n\n if (apiKey) {\n setOAuthStatus({ state: 'success', apiKey })\n sendNotification({ message: 'Minto login successful' })\n } else {\n setOAuthStatus({\n state: 'error',\n message:\n \"Unable to create API key. The server accepted the request but didn't return a key.\",\n toRetry: { state: 'ready_to_start' },\n })\n }\n } catch (err) {\n const errorMessage = (err as Error).message\n }\n }, [oauthService, setShowPastePrompt])\n\n useEffect(() => {\n if (oauthStatus.state === 'ready_to_start') {\n startOAuth()\n }\n }, [oauthStatus.state, startOAuth])\n\n // Helper function to render the appropriate status message\n function renderStatusMessage(): React.ReactNode {\n switch (oauthStatus.state) {\n case 'idle':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text bold>\n {PRODUCT_NAME} is billed based on API usage through your Anthropic\n Console account.\n </Text>\n\n <Box>\n <Text>\n Pricing may evolve as we move towards general availability.\n </Text>\n </Box>\n\n <Box marginTop={1}>\n <Text color={theme.permission}>\n Press <Text bold>Enter</Text> to login to your Anthropic Console\n account\u2026\n </Text>\n </Box>\n </Box>\n )\n\n case 'waiting_for_login':\n return (\n <Box flexDirection=\"column\" gap={1}>\n {!showPastePrompt && (\n <Box>\n <SimpleSpinner />\n <Text>Opening browser to sign in\u2026</Text>\n </Box>\n )}\n\n {showPastePrompt && (\n <Box>\n <Text>{PASTE_HERE_MSG}</Text>\n <TextInput\n value={pastedCode}\n onChange={setPastedCode}\n onSubmit={(value: string) =>\n handleSubmitCode(value, oauthStatus.url)\n }\n cursorOffset={cursorOffset}\n onChangeCursorOffset={setCursorOffset}\n columns={textInputColumns}\n />\n </Box>\n )}\n </Box>\n )\n\n case 'creating_api_key':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Box>\n <SimpleSpinner />\n <Text>Creating API key for Minto\u2026</Text>\n </Box>\n </Box>\n )\n\n case 'about_to_retry':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color={theme.permission}>Retrying\u2026</Text>\n </Box>\n )\n\n case 'success':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color={theme.success}>\n Login successful. Press <Text bold>Enter</Text> to continue\u2026\n </Text>\n </Box>\n )\n\n case 'error':\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Text color={theme.error}>OAuth error: {oauthStatus.message}</Text>\n\n {oauthStatus.toRetry && (\n <Box marginTop={1}>\n <Text color={theme.permission}>\n Press <Text bold>Enter</Text> to retry.\n </Text>\n </Box>\n )}\n </Box>\n )\n\n default:\n return null\n }\n }\n\n // We need to render the copy-able URL statically to prevent Ink <Text> from inserting\n // newlines in the middle of the URL (this breaks Safari). Because <Static> components are\n // only rendered once top-to-bottom, we also need to make everything above the URL static.\n const staticItems: Record<string, React.JSX.Element> = {}\n if (!isClearing) {\n staticItems.header = (\n <Box key=\"header\" flexDirection=\"column\" gap={1}>\n <WelcomeBox />\n <Box paddingBottom={1} paddingLeft={1}>\n <AsciiLogo />\n </Box>\n </Box>\n )\n }\n if (oauthStatus.state === 'waiting_for_login' && showPastePrompt) {\n staticItems.urlToCopy = (\n <Box flexDirection=\"column\" key=\"urlToCopy\" gap={1} paddingBottom={1}>\n <Box paddingX={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n Browser didn&apos;t open? Use the url below to sign in:\n </Text>\n </Box>\n <Box width={1000}>\n <Text color={SEMANTIC_COLORS.dim}>{oauthStatus.url}</Text>\n </Box>\n </Box>\n )\n }\n return (\n <Box flexDirection=\"column\" gap={1}>\n <Static\n items={Object.keys(staticItems)}\n children={(item: string) => staticItems[item]}\n />\n <Box paddingLeft={1} flexDirection=\"column\" gap={1}>\n {renderStatusMessage()}\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,11 +1,12 @@
1
1
  import * as React from "react";
2
2
  import { Box, Text } from "ink";
3
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
3
4
  function Cost({ costUSD, durationMs, debug }) {
4
5
  if (!debug) {
5
6
  return null;
6
7
  }
7
8
  const durationInSeconds = (durationMs / 1e3).toFixed(1);
8
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", minWidth: 23, width: 23 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Cost: $", costUSD.toFixed(4), " (", durationInSeconds, "s)"));
9
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", minWidth: 23, width: 23 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Cost: $", costUSD.toFixed(4), " (", durationInSeconds, "s)"));
9
10
  }
10
11
  export {
11
12
  Cost
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/Cost.tsx"],
4
- "sourcesContent": ["import * as React from 'react'\nimport { Box, Text } from 'ink'\n\ntype Props = {\n costUSD: number\n durationMs: number\n debug: boolean\n}\n\nexport function Cost({ costUSD, durationMs, debug }: Props): React.ReactNode {\n if (!debug) {\n return null\n }\n\n const durationInSeconds = (durationMs / 1000).toFixed(1)\n return (\n <Box flexDirection=\"column\" minWidth={23} width={23}>\n <Text dimColor>\n Cost: ${costUSD.toFixed(4)} ({durationInSeconds}s)\n </Text>\n </Box>\n )\n}\n"],
5
- "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,KAAK,YAAY;AAQnB,SAAS,KAAK,EAAE,SAAS,YAAY,MAAM,GAA2B;AAC3E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,aAAa,KAAM,QAAQ,CAAC;AACvD,SACE,oCAAC,OAAI,eAAc,UAAS,UAAU,IAAI,OAAO,MAC/C,oCAAC,QAAK,UAAQ,QAAC,WACL,QAAQ,QAAQ,CAAC,GAAE,MAAG,mBAAkB,IAClD,CACF;AAEJ;",
4
+ "sourcesContent": ["import * as React from 'react'\nimport { Box, Text } from 'ink'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype Props = {\n costUSD: number\n durationMs: number\n debug: boolean\n}\n\nexport function Cost({ costUSD, durationMs, debug }: Props): React.ReactNode {\n if (!debug) {\n return null\n }\n\n const durationInSeconds = (durationMs / 1000).toFixed(1)\n return (\n <Box flexDirection=\"column\" minWidth={23} width={23}>\n <Text color={SEMANTIC_COLORS.dim}>\n Cost: ${costUSD.toFixed(4)} ({durationInSeconds}s)\n </Text>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;AACvB,SAAS,KAAK,YAAY;AAC1B,SAAS,uBAAuB;AAQzB,SAAS,KAAK,EAAE,SAAS,YAAY,MAAM,GAA2B;AAC3E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,aAAa,KAAM,QAAQ,CAAC;AACvD,SACE,oCAAC,OAAI,eAAc,UAAS,UAAU,IAAI,OAAO,MAC/C,oCAAC,QAAK,OAAO,gBAAgB,OAAK,WACxB,QAAQ,QAAQ,CAAC,GAAE,MAAG,mBAAkB,IAClD,CACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { Box, Text } from "ink";
3
3
  import { getTheme } from "../utils/theme.js";
4
4
  import { getCwd } from "../utils/state.js";
5
5
  import { getModelManager } from "../utils/model.js";
6
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
6
7
  function HeaderBar({
7
8
  tokenUsage = 0,
8
9
  mcpClients = [],
@@ -14,41 +15,45 @@ function HeaderBar({
14
15
  const cwd = getCwd();
15
16
  const contextPercentage = currentModel ? Math.round(tokenUsage / currentModel.contextLength * 100) : 0;
16
17
  const formatTokens = (tokens) => `${Math.round(tokens / 1e3)}k`;
18
+ const getDisplayModelName = (modelName) => {
19
+ if (!modelName) return "AI \u52A9\u624B";
20
+ const simplified = modelName.replace(/^(claude-|gpt-|glm-)/, "").replace(/-\d+.*$/, "").replace(/-latest$/, "");
21
+ return simplified.charAt(0).toUpperCase() + simplified.slice(1);
22
+ };
17
23
  return /* @__PURE__ */ React.createElement(
18
24
  Box,
19
25
  {
20
26
  flexDirection: "column",
21
- borderColor: theme.brand,
27
+ borderColor: BRAND_GRADIENT.START,
22
28
  borderStyle: "round",
23
29
  paddingX: 1,
24
30
  marginBottom: 1
25
31
  },
26
- /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: theme.brand, bold: true }, "minto"), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryTextNew }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryTextNew }, cwd)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, currentModel?.modelName || "No model"), currentModel && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(
32
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START, bold: true }, "Min"), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.END, bold: true }, "to"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, cwd)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, getDisplayModelName(currentModel?.modelName)), currentModel && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " \xB7 "), /* @__PURE__ */ React.createElement(
27
33
  Text,
28
34
  {
29
- color: contextPercentage > 80 ? theme.warning : contextPercentage > 60 ? theme.dimmedText : theme.mutedText
35
+ color: contextPercentage > 80 ? SEMANTIC_COLORS.error : contextPercentage > 60 ? SEMANTIC_COLORS.running : SEMANTIC_COLORS.muted
30
36
  },
31
37
  formatTokens(tokenUsage),
32
38
  "/",
33
39
  formatTokens(currentModel.contextLength)
34
40
  )))),
35
- mcpClients.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 0 }, /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, "MCP: "), mcpClients.map((client, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
41
+ mcpClients.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 0 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, "MCP: "), mcpClients.map((client, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: idx }, /* @__PURE__ */ React.createElement(
36
42
  Text,
37
43
  {
38
- color: client.type === "connected" ? theme.success : theme.error
44
+ color: client.type === "connected" ? SEMANTIC_COLORS.success : SEMANTIC_COLORS.error
39
45
  },
40
46
  client.name
41
- ), idx < mcpClients.length - 1 && /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, ", "))))
47
+ ), idx < mcpClients.length - 1 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, ", "))))
42
48
  );
43
49
  }
44
50
  function MinimalHeaderBar({
45
51
  tokenUsage = 0
46
52
  }) {
47
- const theme = getTheme();
48
53
  const modelManager = getModelManager();
49
54
  const currentModel = modelManager.getModel("main");
50
55
  const cwd = getCwd();
51
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between", paddingX: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryTextNew }, /* @__PURE__ */ React.createElement(Text, { color: theme.brand, bold: true }, "minto"), " ", "\xB7 ", cwd), currentModel && /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, currentModel.modelName, " \xB7 ", Math.round(tokenUsage / 1e3), "k/", Math.round(currentModel.contextLength / 1e3), "k"));
56
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between", paddingX: 2 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START, bold: true }, "Min"), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.END, bold: true }, "to"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, cwd)), currentModel && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, Math.round(tokenUsage / 1e3), "k/", Math.round(currentModel.contextLength / 1e3), "k"));
52
57
  }
53
58
  export {
54
59
  HeaderBar,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/HeaderBar.tsx"],
4
- "sourcesContent": ["/**\n * HeaderBar - Claude Code CLI \u98CE\u683C\u7684\u9875\u7709\u7EC4\u4EF6\n *\n * \u8BBE\u8BA1\u539F\u5219\uFF1A\n * 1. **\u56FA\u5B9A\u9876\u90E8** - \u59CB\u7EC8\u53EF\u89C1\uFF0C\u4E0D\u968F\u5185\u5BB9\u6EDA\u52A8\n * 2. **\u4FE1\u606F\u5BC6\u96C6** - \u663E\u793A\u5173\u952E\u4E0A\u4E0B\u6587\uFF08\u5DE5\u4F5C\u76EE\u5F55\u3001\u6A21\u578B\u3001\u4E0A\u4E0B\u6587\u4F7F\u7528\uFF09\n * 3. **\u89C6\u89C9\u7CBE\u7B80** - \u4E0D\u5360\u7528\u8FC7\u591A\u5782\u76F4\u7A7A\u95F4\n * 4. **\u72B6\u6001\u6E05\u6670** - \u4E00\u773C\u4E86\u89E3\u5F53\u524D\u73AF\u5883\n *\n * \u8FD9\u66FF\u4EE3\u4E86\u539F\u6709\u7684 Logo \u7EC4\u4EF6\uFF0C\u66F4\u7B26\u5408 Claude Code CLI \u7684\u8BBE\u8BA1\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { getCwd } from '@utils/state'\nimport { getModelManager } from '@utils/model'\nimport type { WrappedClient } from '@services/mcpClient'\n\ninterface Props {\n /** \u5F53\u524D Token \u4F7F\u7528\u91CF */\n tokenUsage?: number\n\n /** MCP \u5BA2\u6237\u7AEF (\u53EF\u9009) */\n mcpClients?: WrappedClient[]\n\n /** \u662F\u5426\u662F\u9ED8\u8BA4\u6A21\u578B */\n isDefaultModel?: boolean\n}\n\n/**\n * HeaderBar - \u8F7B\u91CF\u7EA7\u9875\u7709\u72B6\u6001\u680F\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 minto \u00B7 /path/to/project \u00B7 claude-sonnet-4 \u00B7 50k/200k\u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ```\n */\nexport function HeaderBar({\n tokenUsage = 0,\n mcpClients = [],\n isDefaultModel = true,\n}: Props): React.ReactNode {\n const theme = getTheme()\n const modelManager = getModelManager()\n const currentModel = modelManager.getModel('main')\n const cwd = getCwd()\n\n // \u8BA1\u7B97\u4E0A\u4E0B\u6587\u4F7F\u7528\u767E\u5206\u6BD4\n const contextPercentage = currentModel\n ? Math.round((tokenUsage / currentModel.contextLength) * 100)\n : 0\n\n // \u683C\u5F0F\u5316 Token \u6570\u91CF (k \u4E3A\u5355\u4F4D)\n const formatTokens = (tokens: number) => `${Math.round(tokens / 1000)}k`\n\n return (\n <Box\n flexDirection=\"column\"\n borderColor={theme.brand}\n borderStyle=\"round\"\n paddingX={1}\n marginBottom={1}\n >\n {/* \u4E3B\u4FE1\u606F\u884C */}\n <Box flexDirection=\"row\" justifyContent=\"space-between\">\n {/* \u5DE6\u4FA7\uFF1A\u4EA7\u54C1\u540D\u79F0 + \u5DE5\u4F5C\u76EE\u5F55 */}\n <Box flexDirection=\"row\">\n <Text color={theme.brand} bold>\n minto\n </Text>\n <Text color={theme.secondaryTextNew}> \u00B7 </Text>\n <Text color={theme.secondaryTextNew}>{cwd}</Text>\n </Box>\n\n {/* \u53F3\u4FA7\uFF1A\u6A21\u578B\u4FE1\u606F + \u4E0A\u4E0B\u6587\u4F7F\u7528 */}\n <Box flexDirection=\"row\">\n <Text color={theme.dimmedText}>\n {currentModel?.modelName || 'No model'}\n </Text>\n {currentModel && (\n <>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text\n color={\n contextPercentage > 80\n ? theme.warning\n : contextPercentage > 60\n ? theme.dimmedText\n : theme.mutedText\n }\n >\n {formatTokens(tokenUsage)}/\n {formatTokens(currentModel.contextLength)}\n </Text>\n </>\n )}\n </Box>\n </Box>\n\n {/* MCP \u670D\u52A1\u5668\u72B6\u6001 (\u5982\u679C\u6709) */}\n {mcpClients.length > 0 && (\n <Box flexDirection=\"row\" marginTop={0}>\n <Text color={theme.mutedText}>MCP: </Text>\n {mcpClients.map((client, idx) => (\n <React.Fragment key={idx}>\n <Text\n color={\n client.type === 'connected' ? theme.success : theme.error\n }\n >\n {client.name}\n </Text>\n {idx < mcpClients.length - 1 && (\n <Text color={theme.mutedText}>, </Text>\n )}\n </React.Fragment>\n ))}\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * \u6781\u7B80\u7248\u9875\u7709 (\u53EA\u663E\u793A\u57FA\u672C\u4FE1\u606F)\n */\nexport function MinimalHeaderBar({\n tokenUsage = 0,\n}: {\n tokenUsage?: number\n}): React.ReactNode {\n const theme = getTheme()\n const modelManager = getModelManager()\n const currentModel = modelManager.getModel('main')\n const cwd = getCwd()\n\n return (\n <Box flexDirection=\"row\" justifyContent=\"space-between\" paddingX={2}>\n {/* \u5DE5\u4F5C\u76EE\u5F55 */}\n <Text color={theme.secondaryTextNew}>\n <Text color={theme.brand} bold>\n minto\n </Text>{' '}\n \u00B7 {cwd}\n </Text>\n\n {/* \u6A21\u578B + Token */}\n {currentModel && (\n <Text color={theme.dimmedText}>\n {currentModel.modelName} \u00B7 {Math.round(tokenUsage / 1000)}k/\n {Math.round(currentModel.contextLength / 1000)}k\n </Text>\n )}\n </Box>\n )\n}\n"],
5
- "mappings": "AAYA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAwBzB,SAAS,UAAU;AAAA,EACxB,aAAa;AAAA,EACb,aAAa,CAAC;AAAA,EACd,iBAAiB;AACnB,GAA2B;AACzB,QAAM,QAAQ,SAAS;AACvB,QAAM,eAAe,gBAAgB;AACrC,QAAM,eAAe,aAAa,SAAS,MAAM;AACjD,QAAM,MAAM,OAAO;AAGnB,QAAM,oBAAoB,eACtB,KAAK,MAAO,aAAa,aAAa,gBAAiB,GAAG,IAC1D;AAGJ,QAAM,eAAe,CAAC,WAAmB,GAAG,KAAK,MAAM,SAAS,GAAI,CAAC;AAErE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,aAAa,MAAM;AAAA,MACnB,aAAY;AAAA,MACZ,UAAU;AAAA,MACV,cAAc;AAAA;AAAA,IAGd,oCAAC,OAAI,eAAc,OAAM,gBAAe,mBAEtC,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAO,MAAM,OAAO,MAAI,QAAC,OAE/B,GACA,oCAAC,QAAK,OAAO,MAAM,oBAAkB,QAAG,GACxC,oCAAC,QAAK,OAAO,MAAM,oBAAmB,GAAI,CAC5C,GAGA,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAO,MAAM,cAChB,cAAc,aAAa,UAC9B,GACC,gBACC,0DACE,oCAAC,QAAK,OAAO,MAAM,aAAW,QAAG,GACjC;AAAA,MAAC;AAAA;AAAA,QACC,OACE,oBAAoB,KAChB,MAAM,UACN,oBAAoB,KAClB,MAAM,aACN,MAAM;AAAA;AAAA,MAGb,aAAa,UAAU;AAAA,MAAE;AAAA,MACzB,aAAa,aAAa,aAAa;AAAA,IAC1C,CACF,CAEJ,CACF;AAAA,IAGC,WAAW,SAAS,KACnB,oCAAC,OAAI,eAAc,OAAM,WAAW,KAClC,oCAAC,QAAK,OAAO,MAAM,aAAW,OAAK,GAClC,WAAW,IAAI,CAAC,QAAQ,QACvB,oCAAC,MAAM,UAAN,EAAe,KAAK,OACnB;AAAA,MAAC;AAAA;AAAA,QACC,OACE,OAAO,SAAS,cAAc,MAAM,UAAU,MAAM;AAAA;AAAA,MAGrD,OAAO;AAAA,IACV,GACC,MAAM,WAAW,SAAS,KACzB,oCAAC,QAAK,OAAO,MAAM,aAAW,IAAE,CAEpC,CACD,CACH;AAAA,EAEJ;AAEJ;AAKO,SAAS,iBAAiB;AAAA,EAC/B,aAAa;AACf,GAEoB;AAClB,QAAM,QAAQ,SAAS;AACvB,QAAM,eAAe,gBAAgB;AACrC,QAAM,eAAe,aAAa,SAAS,MAAM;AACjD,QAAM,MAAM,OAAO;AAEnB,SACE,oCAAC,OAAI,eAAc,OAAM,gBAAe,iBAAgB,UAAU,KAEhE,oCAAC,QAAK,OAAO,MAAM,oBACjB,oCAAC,QAAK,OAAO,MAAM,OAAO,MAAI,QAAC,OAE/B,GAAQ,KAAI,SACT,GACL,GAGC,gBACC,oCAAC,QAAK,OAAO,MAAM,cAChB,aAAa,WAAU,UAAI,KAAK,MAAM,aAAa,GAAI,GAAE,MACzD,KAAK,MAAM,aAAa,gBAAgB,GAAI,GAAE,GACjD,CAEJ;AAEJ;",
4
+ "sourcesContent": ["/**\n * HeaderBar - Minto \u54C1\u724C\u9875\u7709\u7EC4\u4EF6\n *\n * \u8BBE\u8BA1\u539F\u5219\uFF1A\n * 1. **\u54C1\u724C\u8BC6\u522B** - \u7D2B\u84DD\u2192\u73CA\u745A\u6E10\u53D8\uFF0C\u4F20\u9012\u4E13\u4E1A\u4E0E\u70ED\u60C5\n * 2. **\u4FE1\u606F\u6E05\u6670** - \u663E\u793A\u5173\u952E\u4FE1\u606F\uFF08\u9879\u76EE\u4F4D\u7F6E\u3001AI \u6A21\u578B\u3001\u4F7F\u7528\u91CF\uFF09\n * 3. **\u5546\u52A1\u53CB\u597D** - \u6E29\u6696\u3001\u4E13\u4E1A\u3001\u6613\u4E8E\u7406\u89E3\n * 4. **\u89C6\u89C9\u7CBE\u7B80** - \u4E0D\u5360\u7528\u8FC7\u591A\u5782\u76F4\u7A7A\u95F4\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { getCwd } from '@utils/state'\nimport { getModelManager } from '@utils/model'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport type { WrappedClient } from '@services/mcpClient'\n\ninterface Props {\n /** \u5F53\u524D Token \u4F7F\u7528\u91CF */\n tokenUsage?: number\n\n /** MCP \u5BA2\u6237\u7AEF (\u53EF\u9009) */\n mcpClients?: WrappedClient[]\n\n /** \u662F\u5426\u662F\u9ED8\u8BA4\u6A21\u578B */\n isDefaultModel?: boolean\n}\n\n/**\n * HeaderBar - \u54C1\u724C\u9875\u7709\u72B6\u6001\u680F\n *\n * \u5E03\u5C40\uFF1A\n * ```\n * \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n * \u2502 \u25C6 Minto \u00B7 /path/to/project AI Model \u00B7 50k/200k\u2502\n * \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F\n * ```\n */\nexport function HeaderBar({\n tokenUsage = 0,\n mcpClients = [],\n isDefaultModel = true,\n}: Props): React.ReactNode {\n const theme = getTheme()\n const modelManager = getModelManager()\n const currentModel = modelManager.getModel('main')\n const cwd = getCwd()\n\n // \u8BA1\u7B97\u4E0A\u4E0B\u6587\u4F7F\u7528\u767E\u5206\u6BD4\n const contextPercentage = currentModel\n ? Math.round((tokenUsage / currentModel.contextLength) * 100)\n : 0\n\n // \u683C\u5F0F\u5316 Token \u6570\u91CF (k \u4E3A\u5355\u4F4D)\n const formatTokens = (tokens: number) => `${Math.round(tokens / 1000)}k`\n\n // \u83B7\u53D6\u7B80\u5316\u7684\u6A21\u578B\u663E\u793A\u540D\u79F0\uFF08\u5BF9\u975E\u6280\u672F\u7528\u6237\u66F4\u53CB\u597D\uFF09\n const getDisplayModelName = (modelName: string | undefined) => {\n if (!modelName) return 'AI \u52A9\u624B'\n // \u63D0\u53D6\u6A21\u578B\u7B80\u79F0\uFF0C\u79FB\u9664\u7248\u672C\u53F7\u7B49\u6280\u672F\u7EC6\u8282\n const simplified = modelName\n .replace(/^(claude-|gpt-|glm-)/, '')\n .replace(/-\\d+.*$/, '')\n .replace(/-latest$/, '')\n return simplified.charAt(0).toUpperCase() + simplified.slice(1)\n }\n\n return (\n <Box\n flexDirection=\"column\"\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"round\"\n paddingX={1}\n marginBottom={1}\n >\n {/* \u4E3B\u4FE1\u606F\u884C */}\n <Box flexDirection=\"row\" justifyContent=\"space-between\">\n {/* \u5DE6\u4FA7\uFF1A\u54C1\u724C\u6807\u8BC6 + \u9879\u76EE\u4F4D\u7F6E */}\n <Box flexDirection=\"row\">\n <Text color={BRAND_GRADIENT.START}>\u25C6</Text>\n <Text> </Text>\n <Text color={BRAND_GRADIENT.START} bold>\n Min\n </Text>\n <Text color={BRAND_GRADIENT.END} bold>\n to\n </Text>\n <Text color={SEMANTIC_COLORS.dim}> \u00B7 </Text>\n <Text color={SEMANTIC_COLORS.secondary}>{cwd}</Text>\n </Box>\n\n {/* \u53F3\u4FA7\uFF1AAI \u6A21\u578B + \u4F7F\u7528\u91CF */}\n <Box flexDirection=\"row\">\n <Text color={SEMANTIC_COLORS.dim}>\n {getDisplayModelName(currentModel?.modelName)}\n </Text>\n {currentModel && (\n <>\n <Text color={SEMANTIC_COLORS.muted}> \u00B7 </Text>\n <Text\n color={\n contextPercentage > 80\n ? SEMANTIC_COLORS.error\n : contextPercentage > 60\n ? SEMANTIC_COLORS.running\n : SEMANTIC_COLORS.muted\n }\n >\n {formatTokens(tokenUsage)}/\n {formatTokens(currentModel.contextLength)}\n </Text>\n </>\n )}\n </Box>\n </Box>\n\n {/* \u6269\u5C55\u670D\u52A1\u72B6\u6001 (\u5982\u679C\u6709) */}\n {mcpClients.length > 0 && (\n <Box flexDirection=\"row\" marginTop={0}>\n <Text color={SEMANTIC_COLORS.muted}>MCP: </Text>\n {mcpClients.map((client, idx) => (\n <React.Fragment key={idx}>\n <Text\n color={\n client.type === 'connected'\n ? SEMANTIC_COLORS.success\n : SEMANTIC_COLORS.error\n }\n >\n {client.name}\n </Text>\n {idx < mcpClients.length - 1 && (\n <Text color={SEMANTIC_COLORS.muted}>, </Text>\n )}\n </React.Fragment>\n ))}\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * \u6781\u7B80\u7248\u9875\u7709 (\u53EA\u663E\u793A\u57FA\u672C\u4FE1\u606F)\n */\nexport function MinimalHeaderBar({\n tokenUsage = 0,\n}: {\n tokenUsage?: number\n}): React.ReactNode {\n const modelManager = getModelManager()\n const currentModel = modelManager.getModel('main')\n const cwd = getCwd()\n\n return (\n <Box flexDirection=\"row\" justifyContent=\"space-between\" paddingX={2}>\n {/* \u54C1\u724C + \u9879\u76EE\u4F4D\u7F6E */}\n <Box flexDirection=\"row\">\n <Text color={BRAND_GRADIENT.START}>\u25C6</Text>\n <Text> </Text>\n <Text color={BRAND_GRADIENT.START} bold>\n Min\n </Text>\n <Text color={BRAND_GRADIENT.END} bold>\n to\n </Text>\n <Text color={SEMANTIC_COLORS.dim}> \u00B7 </Text>\n <Text color={SEMANTIC_COLORS.secondary}>{cwd}</Text>\n </Box>\n\n {/* AI \u6A21\u578B + \u4F7F\u7528\u91CF */}\n {currentModel && (\n <Text color={SEMANTIC_COLORS.dim}>\n {Math.round(tokenUsage / 1000)}k/\n {Math.round(currentModel.contextLength / 1000)}k\n </Text>\n )}\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  import { Box, Text } from "ink";
2
2
  import * as React from "react";
3
3
  import { getTheme } from "../utils/theme.js";
4
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
4
5
  function HistorySearchOverlay({
5
6
  searchTerm,
6
7
  results,
@@ -24,9 +25,9 @@ function HistorySearchOverlay({
24
25
  paddingX: 1,
25
26
  marginBottom: 1
26
27
  },
27
- /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.minto }, "Ctrl-R History Search"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " (\u2191/\u2193: navigate, Enter: select, Esc: cancel)")),
28
- /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Search: "), /* @__PURE__ */ React.createElement(Text, { color: theme.success }, searchTerm || /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "(type to search)"))),
29
- results.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, searchTerm ? "No matches found" : "No history available")) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, results.length, " ", results.length === 1 ? "match" : "matches", results.length > maxVisible && ` (showing ${maxVisible})`)), visibleResults.map((result, displayIndex) => {
28
+ /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.minto }, "Ctrl-R History Search"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "(\u2191/\u2193: navigate, Enter: select, Esc: cancel)")),
29
+ /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Search: "), /* @__PURE__ */ React.createElement(Text, { color: theme.success }, searchTerm || /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(type to search)"))),
30
+ results.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, searchTerm ? "No matches found" : "No history available")) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, results.length, " ", results.length === 1 ? "match" : "matches", results.length > maxVisible && ` (showing ${maxVisible})`)), visibleResults.map((result, displayIndex) => {
30
31
  const isSelected = displayIndex === adjustedSelectedIndex;
31
32
  const actualIndex = startIndex + displayIndex;
32
33
  return /* @__PURE__ */ React.createElement(Box, { key: actualIndex, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/HistorySearchOverlay.tsx"],
4
- "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\nimport type { HistorySearchResult } from '@hooks/useHistorySearch'\n\ntype Props = {\n searchTerm: string\n results: HistorySearchResult[]\n selectedIndex: number\n maxVisible?: number\n}\n\nexport function HistorySearchOverlay({\n searchTerm,\n results,\n selectedIndex,\n maxVisible = 10,\n}: Props) {\n const theme = getTheme()\n\n // Calculate visible range (show selected item in the middle when possible)\n const halfVisible = Math.floor(maxVisible / 2)\n const startIndex = Math.max(\n 0,\n Math.min(selectedIndex - halfVisible, results.length - maxVisible),\n )\n const visibleResults = results.slice(startIndex, startIndex + maxVisible)\n const adjustedSelectedIndex = selectedIndex - startIndex\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.secondaryBorder}\n paddingX={1}\n marginBottom={1}\n >\n {/* Header */}\n <Box marginBottom={1}>\n <Text bold color={theme.minto}>\n Ctrl-R History Search\n </Text>\n <Text dimColor> (\u2191/\u2193: navigate, Enter: select, Esc: cancel)</Text>\n </Box>\n\n {/* Search input display */}\n <Box marginBottom={1}>\n <Text>Search: </Text>\n <Text color={theme.success}>\n {searchTerm || <Text dimColor>(type to search)</Text>}\n </Text>\n </Box>\n\n {/* Results */}\n {results.length === 0 ? (\n <Box>\n <Text dimColor>\n {searchTerm ? 'No matches found' : 'No history available'}\n </Text>\n </Box>\n ) : (\n <>\n {/* Results count */}\n <Box marginBottom={1}>\n <Text dimColor>\n {results.length} {results.length === 1 ? 'match' : 'matches'}\n {results.length > maxVisible && ` (showing ${maxVisible})`}\n </Text>\n </Box>\n\n {/* Result list */}\n {visibleResults.map((result, displayIndex) => {\n const isSelected = displayIndex === adjustedSelectedIndex\n const actualIndex = startIndex + displayIndex\n\n return (\n <Box key={actualIndex} paddingLeft={1}>\n <Text\n bold={isSelected}\n color={isSelected ? theme.minto : theme.text}\n backgroundColor={isSelected ? theme.suggestion : undefined}\n >\n {isSelected ? '\u25BA ' : ' '}\n {result.item.length > 80\n ? result.item.substring(0, 77) + '...'\n : result.item}\n </Text>\n </Box>\n )\n })}\n </>\n )}\n </Box>\n )\n}\n"],
5
- "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,gBAAgB;AAUlB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAAU;AACR,QAAM,QAAQ,SAAS;AAGvB,QAAM,cAAc,KAAK,MAAM,aAAa,CAAC;AAC7C,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,KAAK,IAAI,gBAAgB,aAAa,QAAQ,SAAS,UAAU;AAAA,EACnE;AACA,QAAM,iBAAiB,QAAQ,MAAM,YAAY,aAAa,UAAU;AACxE,QAAM,wBAAwB,gBAAgB;AAE9C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,UAAU;AAAA,MACV,cAAc;AAAA;AAAA,IAGd,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,SAAO,uBAE/B,GACA,oCAAC,QAAK,UAAQ,QAAC,wDAA4C,CAC7D;AAAA,IAGA,oCAAC,OAAI,cAAc,KACjB,oCAAC,YAAK,UAAQ,GACd,oCAAC,QAAK,OAAO,MAAM,WAChB,cAAc,oCAAC,QAAK,UAAQ,QAAC,kBAAgB,CAChD,CACF;AAAA,IAGC,QAAQ,WAAW,IAClB,oCAAC,WACC,oCAAC,QAAK,UAAQ,QACX,aAAa,qBAAqB,sBACrC,CACF,IAEA,0DAEE,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,UAAQ,QACX,QAAQ,QAAO,KAAE,QAAQ,WAAW,IAAI,UAAU,WAClD,QAAQ,SAAS,cAAc,aAAa,UAAU,GACzD,CACF,GAGC,eAAe,IAAI,CAAC,QAAQ,iBAAiB;AAC5C,YAAM,aAAa,iBAAiB;AACpC,YAAM,cAAc,aAAa;AAEjC,aACE,oCAAC,OAAI,KAAK,aAAa,aAAa,KAClC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,OAAO,aAAa,MAAM,QAAQ,MAAM;AAAA,UACxC,iBAAiB,aAAa,MAAM,aAAa;AAAA;AAAA,QAEhD,aAAa,YAAO;AAAA,QACpB,OAAO,KAAK,SAAS,KAClB,OAAO,KAAK,UAAU,GAAG,EAAE,IAAI,QAC/B,OAAO;AAAA,MACb,CACF;AAAA,IAEJ,CAAC,CACH;AAAA,EAEJ;AAEJ;",
4
+ "sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\nimport type { HistorySearchResult } from '@hooks/useHistorySearch'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype Props = {\n searchTerm: string\n results: HistorySearchResult[]\n selectedIndex: number\n maxVisible?: number\n}\n\nexport function HistorySearchOverlay({\n searchTerm,\n results,\n selectedIndex,\n maxVisible = 10,\n}: Props) {\n const theme = getTheme()\n\n // Calculate visible range (show selected item in the middle when possible)\n const halfVisible = Math.floor(maxVisible / 2)\n const startIndex = Math.max(\n 0,\n Math.min(selectedIndex - halfVisible, results.length - maxVisible),\n )\n const visibleResults = results.slice(startIndex, startIndex + maxVisible)\n const adjustedSelectedIndex = selectedIndex - startIndex\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.secondaryBorder}\n paddingX={1}\n marginBottom={1}\n >\n {/* Header */}\n <Box marginBottom={1}>\n <Text bold color={theme.minto}>\n Ctrl-R History Search\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n (\u2191/\u2193: navigate, Enter: select, Esc: cancel)\n </Text>\n </Box>\n\n {/* Search input display */}\n <Box marginBottom={1}>\n <Text>Search: </Text>\n <Text color={theme.success}>\n {searchTerm || (\n <Text color={SEMANTIC_COLORS.dim}>(type to search)</Text>\n )}\n </Text>\n </Box>\n\n {/* Results */}\n {results.length === 0 ? (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>\n {searchTerm ? 'No matches found' : 'No history available'}\n </Text>\n </Box>\n ) : (\n <>\n {/* Results count */}\n <Box marginBottom={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {results.length} {results.length === 1 ? 'match' : 'matches'}\n {results.length > maxVisible && ` (showing ${maxVisible})`}\n </Text>\n </Box>\n\n {/* Result list */}\n {visibleResults.map((result, displayIndex) => {\n const isSelected = displayIndex === adjustedSelectedIndex\n const actualIndex = startIndex + displayIndex\n\n return (\n <Box key={actualIndex} paddingLeft={1}>\n <Text\n bold={isSelected}\n color={isSelected ? theme.minto : theme.text}\n backgroundColor={isSelected ? theme.suggestion : undefined}\n >\n {isSelected ? '\u25BA ' : ' '}\n {result.item.length > 80\n ? result.item.substring(0, 77) + '...'\n : result.item}\n </Text>\n </Box>\n )\n })}\n </>\n )}\n </Box>\n )\n}\n"],
5
+ "mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,gBAAgB;AAEzB,SAAS,uBAAuB;AASzB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAAU;AACR,QAAM,QAAQ,SAAS;AAGvB,QAAM,cAAc,KAAK,MAAM,aAAa,CAAC;AAC7C,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,KAAK,IAAI,gBAAgB,aAAa,QAAQ,SAAS,UAAU;AAAA,EACnE;AACA,QAAM,iBAAiB,QAAQ,MAAM,YAAY,aAAa,UAAU;AACxE,QAAM,wBAAwB,gBAAgB;AAE9C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,UAAU;AAAA,MACV,cAAc;AAAA;AAAA,IAGd,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,SAAO,uBAE/B,GACA,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,KAAI,uDAEP,CACF;AAAA,IAGA,oCAAC,OAAI,cAAc,KACjB,oCAAC,YAAK,UAAQ,GACd,oCAAC,QAAK,OAAO,MAAM,WAChB,cACC,oCAAC,QAAK,OAAO,gBAAgB,OAAK,kBAAgB,CAEtD,CACF;AAAA,IAGC,QAAQ,WAAW,IAClB,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,aAAa,qBAAqB,sBACrC,CACF,IAEA,0DAEE,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,QAAQ,QAAO,KAAE,QAAQ,WAAW,IAAI,UAAU,WAClD,QAAQ,SAAS,cAAc,aAAa,UAAU,GACzD,CACF,GAGC,eAAe,IAAI,CAAC,QAAQ,iBAAiB;AAC5C,YAAM,aAAa,iBAAiB;AACpC,YAAM,cAAc,aAAa;AAEjC,aACE,oCAAC,OAAI,KAAK,aAAa,aAAa,KAClC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN,OAAO,aAAa,MAAM,QAAQ,MAAM;AAAA,UACxC,iBAAiB,aAAa,MAAM,aAAa;AAAA;AAAA,QAEhD,aAAa,YAAO;AAAA,QACpB,OAAO,KAAK,SAAS,KAClB,OAAO,KAAK,UAAU,GAAG,EAAE,IAAI,QAC/B,OAAO;AAAA,MACb,CACF;AAAA,IAEJ,CAAC,CACH;AAAA,EAEJ;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { Box, Text, useInput } from "ink";
2
2
  import * as React from "react";
3
- import { getTheme } from "../utils/theme.js";
4
3
  import { t } from "../i18n/index.js";
4
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
5
5
  const HOTKEY_GROUPS = [
6
6
  {
7
7
  title: "Navigation",
@@ -43,7 +43,6 @@ function HotkeyHelpPanel({
43
43
  onClose,
44
44
  isVisible
45
45
  }) {
46
- const theme = getTheme();
47
46
  useInput(
48
47
  (input, key) => {
49
48
  if (key.escape || key.ctrl && (input === "?" || input === "/")) {
@@ -60,19 +59,18 @@ function HotkeyHelpPanel({
60
59
  {
61
60
  flexDirection: "column",
62
61
  borderStyle: "round",
63
- borderColor: theme.minto,
62
+ borderColor: BRAND_GRADIENT.START,
64
63
  paddingX: 2,
65
64
  paddingY: 1,
66
65
  marginBottom: 1
67
66
  },
68
- /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.minto }, "\u2328\uFE0F ", t("ui.hints.shortcuts")), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, " (", t("ui.hints.pressEsc"), ")")),
69
- /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", gap: 4 }, HOTKEY_GROUPS.map((group, groupIndex) => /* @__PURE__ */ React.createElement(Box, { key: groupIndex, flexDirection: "column", minWidth: 28 }, /* @__PURE__ */ React.createElement(Text, { bold: true, underline: true, color: theme.primary }, group.title), group.hotkeys.map((hotkey, hotkeyIndex) => /* @__PURE__ */ React.createElement(Box, { key: hotkeyIndex }, /* @__PURE__ */ React.createElement(Box, { width: 12 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.warning }, hotkey.keys)), /* @__PURE__ */ React.createElement(Text, { color: theme.text }, hotkey.description)))))),
70
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, t("ui.hints.tip")))
67
+ /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, "\u2328\uFE0F ", t("ui.hints.shortcuts")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " ", "(", t("ui.hints.pressEsc"), ")")),
68
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", gap: 4 }, HOTKEY_GROUPS.map((group, groupIndex) => /* @__PURE__ */ React.createElement(Box, { key: groupIndex, flexDirection: "column", minWidth: 28 }, /* @__PURE__ */ React.createElement(Text, { bold: true, underline: true, color: SEMANTIC_COLORS.secondary }, group.title), group.hotkeys.map((hotkey, hotkeyIndex) => /* @__PURE__ */ React.createElement(Box, { key: hotkeyIndex }, /* @__PURE__ */ React.createElement(Box, { width: 12 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.MIDDLE }, hotkey.keys)), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.primary }, hotkey.description)))))),
69
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("ui.hints.tip")))
71
70
  );
72
71
  }
73
72
  function HotkeyHint() {
74
- const theme = getTheme();
75
- return /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "Ctrl+? for shortcuts");
73
+ return /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Ctrl+? for shortcuts");
76
74
  }
77
75
  function getContextHints(context) {
78
76
  switch (context) {
@@ -122,12 +120,11 @@ function ContextAwareHints({
122
120
  context,
123
121
  compact = true
124
122
  }) {
125
- const theme = getTheme();
126
123
  const hints = getContextHints(context);
127
124
  if (compact) {
128
- return /* @__PURE__ */ React.createElement(Box, null, hints.map((hint, i) => /* @__PURE__ */ React.createElement(React.Fragment, { key: i }, i > 0 && /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, hint.keys, " ", hint.description))));
125
+ return /* @__PURE__ */ React.createElement(Box, null, hints.map((hint, i) => /* @__PURE__ */ React.createElement(React.Fragment, { key: i }, i > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, hint.keys, " ", hint.description))));
129
126
  }
130
- return /* @__PURE__ */ React.createElement(Box, { gap: 2 }, hints.map((hint, i) => /* @__PURE__ */ React.createElement(Box, { key: i }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.warning }, hint.keys), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, " ", hint.description))));
127
+ return /* @__PURE__ */ React.createElement(Box, { gap: 2 }, hints.map((hint, i) => /* @__PURE__ */ React.createElement(Box, { key: i }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.MIDDLE }, hint.keys), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " ", hint.description))));
131
128
  }
132
129
  export {
133
130
  ContextAwareHints,