@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
@@ -3,6 +3,7 @@ import { Box, Text } from "ink";
3
3
  import { getMessagesGetter } from "../messages.js";
4
4
  import { countTokens } from "../utils/tokens.js";
5
5
  import { getModelManager } from "../utils/model.js";
6
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
6
7
  function createProgressBar(percent, width = 30) {
7
8
  const filled = Math.round(percent / 100 * width);
8
9
  const empty = width - filled;
@@ -41,7 +42,7 @@ const ContextVisualizer = ({
41
42
  maxTokens,
42
43
  messageCount
43
44
  );
44
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Context Usage"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " (", modelName, ")")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color }, createProgressBar(percent)), /* @__PURE__ */ React.createElement(Text, null, " ", percent.toFixed(1), "%")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Tokens:"), " ", formatTokens(usedTokens), " /", " ", formatTokens(maxTokens))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Remaining:"), " ", formatTokens(maxTokens - usedTokens), " ", "tokens")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Messages:"), " ", messageCount)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Est. turns remaining:"), " ~", remainingTurns)), percent >= 70 && percent < 95 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "\u26A0 Context usage is high. Consider using /compact to free up space.")), percent >= 95 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "red" }, "\u26A0 Context is nearly full! Run /compact now to avoid auto-compaction.")));
45
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Context Usage"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " (", modelName, ")")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color }, createProgressBar(percent)), /* @__PURE__ */ React.createElement(Text, null, " ", percent.toFixed(1), "%")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Tokens:"), " ", formatTokens(usedTokens), " /", " ", formatTokens(maxTokens))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Remaining:"), " ", formatTokens(maxTokens - usedTokens), " ", "tokens")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Messages:"), " ", messageCount)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Est. turns remaining:"), " ~", remainingTurns)), percent >= 70 && percent < 95 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "\u26A0 Context usage is high. Consider using /compact to free up space.")), percent >= 95 && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "red" }, "\u26A0 Context is nearly full! Run /compact now to avoid auto-compaction.")));
45
46
  };
46
47
  const command = {
47
48
  name: "context",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/context.tsx"],
4
- "sourcesContent": ["/**\n * Context Visualization Command\n *\n * Shows a visual representation of current context usage\n * with token counts, progress bars, and estimates.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport type { Command } from '@commands'\nimport type { Tool } from '@tool'\nimport { getMessagesGetter } from '@messages'\nimport { countTokens } from '@utils/tokens'\nimport { getModelManager } from '@utils/model'\n\n/**\n * Create a visual progress bar\n */\nfunction createProgressBar(percent: number, width: number = 30): string {\n const filled = Math.round((percent / 100) * width)\n const empty = width - filled\n const filledChar = '\u2588'\n const emptyChar = '\u2591'\n\n return filledChar.repeat(filled) + emptyChar.repeat(empty)\n}\n\n/**\n * Get color based on usage percentage\n */\nfunction getUsageColor(percent: number): 'green' | 'yellow' | 'red' {\n if (percent < 50) return 'green'\n if (percent < 80) return 'yellow'\n return 'red'\n}\n\n/**\n * Format token count with k/M suffix\n */\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) {\n return `${(tokens / 1_000_000).toFixed(1)}M`\n }\n if (tokens >= 1000) {\n return `${(tokens / 1000).toFixed(1)}k`\n }\n return tokens.toString()\n}\n\n/**\n * Estimate remaining turns based on average token usage\n */\nfunction estimateRemainingTurns(\n usedTokens: number,\n maxTokens: number,\n messageCount: number,\n): number {\n if (messageCount < 2) return Math.floor((maxTokens - usedTokens) / 2000) // Default estimate\n const avgPerTurn = usedTokens / (messageCount / 2) // Divide by 2 for user/assistant pairs\n const remaining = maxTokens - usedTokens\n return Math.max(0, Math.floor(remaining / avgPerTurn))\n}\n\nconst ContextVisualizer = ({\n tokenInfo,\n}: {\n tokenInfo: {\n usedTokens: number\n maxTokens: number\n messageCount: number\n modelName: string\n }\n}) => {\n const { usedTokens, maxTokens, messageCount, modelName } = tokenInfo\n const percent = Math.min(100, (usedTokens / maxTokens) * 100)\n const color = getUsageColor(percent)\n const remainingTurns = estimateRemainingTurns(\n usedTokens,\n maxTokens,\n messageCount,\n )\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold>Context Usage</Text>\n <Text dimColor> ({modelName})</Text>\n </Box>\n\n {/* Progress bar */}\n <Box>\n <Text color={color}>{createProgressBar(percent)}</Text>\n <Text> {percent.toFixed(1)}%</Text>\n </Box>\n\n {/* Token counts */}\n <Box marginTop={1}>\n <Text>\n <Text bold>Tokens:</Text> {formatTokens(usedTokens)} /{' '}\n {formatTokens(maxTokens)}\n </Text>\n </Box>\n\n {/* Remaining capacity */}\n <Box>\n <Text>\n <Text bold>Remaining:</Text> {formatTokens(maxTokens - usedTokens)}{' '}\n tokens\n </Text>\n </Box>\n\n {/* Message count */}\n <Box>\n <Text>\n <Text bold>Messages:</Text> {messageCount}\n </Text>\n </Box>\n\n {/* Estimated turns */}\n <Box>\n <Text>\n <Text bold>Est. turns remaining:</Text> ~{remainingTurns}\n </Text>\n </Box>\n\n {/* Warning if usage is high */}\n {percent >= 70 && percent < 95 && (\n <Box marginTop={1}>\n <Text color=\"yellow\">\n \u26A0 Context usage is high. Consider using /compact to free up space.\n </Text>\n </Box>\n )}\n {percent >= 95 && (\n <Box marginTop={1}>\n <Text color=\"red\">\n \u26A0 Context is nearly full! Run /compact now to avoid\n auto-compaction.\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n\nconst command: Command = {\n name: 'context',\n description:\n 'Visualize current context usage with token counts and estimates',\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n aliases: ['ctx'],\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone) {\n const messages = getMessagesGetter()()\n const usedTokens = countTokens(messages)\n\n // Get max context from current model\n let maxTokens = 200_000 // Default for Claude\n let modelName = 'unknown'\n\n try {\n const modelManager = getModelManager()\n const profile = modelManager.resolveModel('main')\n if (profile) {\n maxTokens = profile.contextLength || maxTokens\n modelName = profile.name || profile.modelName\n }\n } catch {\n // Use defaults\n }\n\n const tokenInfo = {\n usedTokens,\n maxTokens,\n messageCount: messages.length,\n modelName,\n }\n\n // Render and immediately complete\n setTimeout(() => onDone(), 100)\n\n return <ContextVisualizer tokenInfo={tokenInfo} />\n },\n}\n\nexport default command\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Context Visualization Command\n *\n * Shows a visual representation of current context usage\n * with token counts, progress bars, and estimates.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport type { Command } from '@commands'\nimport type { Tool } from '@tool'\nimport { getMessagesGetter } from '@messages'\nimport { countTokens } from '@utils/tokens'\nimport { getModelManager } from '@utils/model'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\n/**\n * Create a visual progress bar\n */\nfunction createProgressBar(percent: number, width: number = 30): string {\n const filled = Math.round((percent / 100) * width)\n const empty = width - filled\n const filledChar = '\u2588'\n const emptyChar = '\u2591'\n\n return filledChar.repeat(filled) + emptyChar.repeat(empty)\n}\n\n/**\n * Get color based on usage percentage\n */\nfunction getUsageColor(percent: number): 'green' | 'yellow' | 'red' {\n if (percent < 50) return 'green'\n if (percent < 80) return 'yellow'\n return 'red'\n}\n\n/**\n * Format token count with k/M suffix\n */\nfunction formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) {\n return `${(tokens / 1_000_000).toFixed(1)}M`\n }\n if (tokens >= 1000) {\n return `${(tokens / 1000).toFixed(1)}k`\n }\n return tokens.toString()\n}\n\n/**\n * Estimate remaining turns based on average token usage\n */\nfunction estimateRemainingTurns(\n usedTokens: number,\n maxTokens: number,\n messageCount: number,\n): number {\n if (messageCount < 2) return Math.floor((maxTokens - usedTokens) / 2000) // Default estimate\n const avgPerTurn = usedTokens / (messageCount / 2) // Divide by 2 for user/assistant pairs\n const remaining = maxTokens - usedTokens\n return Math.max(0, Math.floor(remaining / avgPerTurn))\n}\n\nconst ContextVisualizer = ({\n tokenInfo,\n}: {\n tokenInfo: {\n usedTokens: number\n maxTokens: number\n messageCount: number\n modelName: string\n }\n}) => {\n const { usedTokens, maxTokens, messageCount, modelName } = tokenInfo\n const percent = Math.min(100, (usedTokens / maxTokens) * 100)\n const color = getUsageColor(percent)\n const remainingTurns = estimateRemainingTurns(\n usedTokens,\n maxTokens,\n messageCount,\n )\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold>Context Usage</Text>\n <Text color={SEMANTIC_COLORS.dim}> ({modelName})</Text>\n </Box>\n\n {/* Progress bar */}\n <Box>\n <Text color={color}>{createProgressBar(percent)}</Text>\n <Text> {percent.toFixed(1)}%</Text>\n </Box>\n\n {/* Token counts */}\n <Box marginTop={1}>\n <Text>\n <Text bold>Tokens:</Text> {formatTokens(usedTokens)} /{' '}\n {formatTokens(maxTokens)}\n </Text>\n </Box>\n\n {/* Remaining capacity */}\n <Box>\n <Text>\n <Text bold>Remaining:</Text> {formatTokens(maxTokens - usedTokens)}{' '}\n tokens\n </Text>\n </Box>\n\n {/* Message count */}\n <Box>\n <Text>\n <Text bold>Messages:</Text> {messageCount}\n </Text>\n </Box>\n\n {/* Estimated turns */}\n <Box>\n <Text>\n <Text bold>Est. turns remaining:</Text> ~{remainingTurns}\n </Text>\n </Box>\n\n {/* Warning if usage is high */}\n {percent >= 70 && percent < 95 && (\n <Box marginTop={1}>\n <Text color=\"yellow\">\n \u26A0 Context usage is high. Consider using /compact to free up space.\n </Text>\n </Box>\n )}\n {percent >= 95 && (\n <Box marginTop={1}>\n <Text color=\"red\">\n \u26A0 Context is nearly full! Run /compact now to avoid\n auto-compaction.\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n\nconst command: Command = {\n name: 'context',\n description:\n 'Visualize current context usage with token counts and estimates',\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n aliases: ['ctx'],\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone) {\n const messages = getMessagesGetter()()\n const usedTokens = countTokens(messages)\n\n // Get max context from current model\n let maxTokens = 200_000 // Default for Claude\n let modelName = 'unknown'\n\n try {\n const modelManager = getModelManager()\n const profile = modelManager.resolveModel('main')\n if (profile) {\n maxTokens = profile.contextLength || maxTokens\n modelName = profile.name || profile.modelName\n }\n } catch {\n // Use defaults\n }\n\n const tokenInfo = {\n usedTokens,\n maxTokens,\n messageCount: messages.length,\n modelName,\n }\n\n // Render and immediately complete\n setTimeout(() => onDone(), 100)\n\n return <ContextVisualizer tokenInfo={tokenInfo} />\n },\n}\n\nexport default command\n"],
5
+ "mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAG1B,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAKhC,SAAS,kBAAkB,SAAiB,QAAgB,IAAY;AACtE,QAAM,SAAS,KAAK,MAAO,UAAU,MAAO,KAAK;AACjD,QAAM,QAAQ,QAAQ;AACtB,QAAM,aAAa;AACnB,QAAM,YAAY;AAElB,SAAO,WAAW,OAAO,MAAM,IAAI,UAAU,OAAO,KAAK;AAC3D;AAKA,SAAS,cAAc,SAA6C;AAClE,MAAI,UAAU,GAAI,QAAO;AACzB,MAAI,UAAU,GAAI,QAAO;AACzB,SAAO;AACT;AAKA,SAAS,aAAa,QAAwB;AAC5C,MAAI,UAAU,KAAW;AACvB,WAAO,IAAI,SAAS,KAAW,QAAQ,CAAC,CAAC;AAAA,EAC3C;AACA,MAAI,UAAU,KAAM;AAClB,WAAO,IAAI,SAAS,KAAM,QAAQ,CAAC,CAAC;AAAA,EACtC;AACA,SAAO,OAAO,SAAS;AACzB;AAKA,SAAS,uBACP,YACA,WACA,cACQ;AACR,MAAI,eAAe,EAAG,QAAO,KAAK,OAAO,YAAY,cAAc,GAAI;AACvE,QAAM,aAAa,cAAc,eAAe;AAChD,QAAM,YAAY,YAAY;AAC9B,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,UAAU,CAAC;AACvD;AAEA,MAAM,oBAAoB,CAAC;AAAA,EACzB;AACF,MAOM;AACJ,QAAM,EAAE,YAAY,WAAW,cAAc,UAAU,IAAI;AAC3D,QAAM,UAAU,KAAK,IAAI,KAAM,aAAa,YAAa,GAAG;AAC5D,QAAM,QAAQ,cAAc,OAAO;AACnC,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SACE,oCAAC,OAAI,eAAc,UAAS,SAAS,KACnC,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,MAAI,QAAC,eAAa,GACxB,oCAAC,QAAK,OAAO,gBAAgB,OAAK,MAAG,WAAU,GAAC,CAClD,GAGA,oCAAC,WACC,oCAAC,QAAK,SAAe,kBAAkB,OAAO,CAAE,GAChD,oCAAC,YAAK,KAAE,QAAQ,QAAQ,CAAC,GAAE,GAAC,CAC9B,GAGA,oCAAC,OAAI,WAAW,KACd,oCAAC,YACC,oCAAC,QAAK,MAAI,QAAC,SAAO,GAAO,KAAE,aAAa,UAAU,GAAE,MAAG,KACtD,aAAa,SAAS,CACzB,CACF,GAGA,oCAAC,WACC,oCAAC,YACC,oCAAC,QAAK,MAAI,QAAC,YAAU,GAAO,KAAE,aAAa,YAAY,UAAU,GAAG,KAAI,QAE1E,CACF,GAGA,oCAAC,WACC,oCAAC,YACC,oCAAC,QAAK,MAAI,QAAC,WAAS,GAAO,KAAE,YAC/B,CACF,GAGA,oCAAC,WACC,oCAAC,YACC,oCAAC,QAAK,MAAI,QAAC,uBAAqB,GAAO,MAAG,cAC5C,CACF,GAGC,WAAW,MAAM,UAAU,MAC1B,oCAAC,OAAI,WAAW,KACd,oCAAC,QAAK,OAAM,YAAS,yEAErB,CACF,GAED,WAAW,MACV,oCAAC,OAAI,WAAW,KACd,oCAAC,QAAK,OAAM,SAAM,2EAGlB,CACF,CAEJ;AAEJ;AAEA,MAAM,UAAmB;AAAA,EACvB,MAAM;AAAA,EACN,aACE;AAAA,EACF,WAAW;AAAA,EACX,UAAU;AAAA,EACV,MAAM;AAAA,EACN,SAAS,CAAC,KAAK;AAAA,EAEf,iBAAiB;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,KAAK,QAAQ;AACjB,UAAM,WAAW,kBAAkB,EAAE;AACrC,UAAM,aAAa,YAAY,QAAQ;AAGvC,QAAI,YAAY;AAChB,QAAI,YAAY;AAEhB,QAAI;AACF,YAAM,eAAe,gBAAgB;AACrC,YAAM,UAAU,aAAa,aAAa,MAAM;AAChD,UAAI,SAAS;AACX,oBAAY,QAAQ,iBAAiB;AACrC,oBAAY,QAAQ,QAAQ,QAAQ;AAAA,MACtC;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA,cAAc,SAAS;AAAA,MACvB;AAAA,IACF;AAGA,eAAW,MAAM,OAAO,GAAG,GAAG;AAE9B,WAAO,oCAAC,qBAAkB,WAAsB;AAAA,EAClD;AACF;AAEA,IAAO,kBAAQ;",
6
6
  "names": []
7
7
  }
@@ -5,6 +5,7 @@ import { join } from "path";
5
5
  import { getMessagesGetter } from "../messages.js";
6
6
  import { getCwd } from "../utils/state.js";
7
7
  import { loadGlobalConfig, loadProjectConfig } from "../core/config/index.js";
8
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
8
9
  const EXPORT_OPTIONS = [
9
10
  {
10
11
  type: "conversation",
@@ -91,7 +92,7 @@ const ExportMenu = ({ onDone }) => {
91
92
  setExporting(false);
92
93
  }
93
94
  };
94
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, "Export Data")), !result ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, EXPORT_OPTIONS.map((option, index) => /* @__PURE__ */ React.createElement(Box, { key: option.type, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: index === selectedIndex ? "cyan" : void 0 }, index === selectedIndex ? "\u25B6 " : " ", /* @__PURE__ */ React.createElement(Text, { bold: true }, option.label), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " - ", option.description))))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2191/\u2193: Navigate | Enter: Export | q/Esc: Cancel"))) : /* @__PURE__ */ React.createElement(Box, null, result.success ? /* @__PURE__ */ React.createElement(Text, { color: "green" }, "\u2713 ", result.message) : /* @__PURE__ */ React.createElement(Text, { color: "red" }, "\u2717 ", result.message)), exporting && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Exporting...")));
95
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, "Export Data")), !result ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, EXPORT_OPTIONS.map((option, index) => /* @__PURE__ */ React.createElement(Box, { key: option.type, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: index === selectedIndex ? "cyan" : void 0 }, index === selectedIndex ? "\u25B6 " : " ", /* @__PURE__ */ React.createElement(Text, { bold: true }, option.label), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "- ", option.description))))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\u2191/\u2193: Navigate | Enter: Export | q/Esc: Cancel"))) : /* @__PURE__ */ React.createElement(Box, null, result.success ? /* @__PURE__ */ React.createElement(Text, { color: "green" }, "\u2713 ", result.message) : /* @__PURE__ */ React.createElement(Text, { color: "red" }, "\u2717 ", result.message)), exporting && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "Exporting...")));
95
96
  };
96
97
  function generateSummary(messages) {
97
98
  const lines = [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/export.tsx"],
4
- "sourcesContent": ["/**\n * Export Command\n *\n * Export session data, configuration, or conversation history.\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { writeFile } from 'fs/promises'\nimport { join } from 'path'\nimport type { Command } from '@commands'\nimport { getMessagesGetter } from '@messages'\nimport { getCwd } from '@utils/state'\nimport { loadGlobalConfig, loadProjectConfig } from '../core/config'\n\ntype ExportType = 'conversation' | 'config' | 'summary'\n\ninterface ExportOption {\n type: ExportType\n label: string\n description: string\n}\n\nconst EXPORT_OPTIONS: ExportOption[] = [\n {\n type: 'conversation',\n label: 'Conversation',\n description: 'Export full conversation history as JSON',\n },\n {\n type: 'config',\n label: 'Configuration',\n description: 'Export current configuration settings',\n },\n {\n type: 'summary',\n label: 'Summary',\n description: 'Export a markdown summary of the session',\n },\n]\n\ninterface ExportMenuProps {\n onDone: (result?: string) => void\n}\n\nconst ExportMenu = ({ onDone }: ExportMenuProps) => {\n const [selectedIndex, setSelectedIndex] = useState(0)\n const [exporting, setExporting] = useState(false)\n const [result, setResult] = useState<{\n success: boolean\n message: string\n } | null>(null)\n\n useInput(async (input, key) => {\n if (exporting) return\n\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1))\n } else if (key.downArrow) {\n setSelectedIndex(Math.min(EXPORT_OPTIONS.length - 1, selectedIndex + 1))\n } else if (key.return) {\n await handleExport(EXPORT_OPTIONS[selectedIndex]!.type)\n } else if (input === 'q' || key.escape) {\n onDone()\n }\n })\n\n const handleExport = async (type: ExportType) => {\n setExporting(true)\n\n try {\n const cwd = getCwd()\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\n let filename: string\n let content: string\n\n switch (type) {\n case 'conversation': {\n const messages = getMessagesGetter()()\n filename = `minto-conversation-${timestamp}.json`\n content = JSON.stringify(messages, null, 2)\n break\n }\n case 'config': {\n const [globalConfig, projectConfig] = await Promise.all([\n Promise.resolve(loadGlobalConfig()),\n Promise.resolve(loadProjectConfig(cwd)),\n ])\n filename = `minto-config-${timestamp}.json`\n content = JSON.stringify(\n {\n global: globalConfig,\n project: projectConfig,\n },\n null,\n 2,\n )\n break\n }\n case 'summary': {\n const messages = getMessagesGetter()()\n filename = `minto-summary-${timestamp}.md`\n content = generateSummary(messages)\n break\n }\n }\n\n const filepath = join(cwd, filename)\n await writeFile(filepath, content, 'utf-8')\n\n setResult({\n success: true,\n message: `Exported to ${filename}`,\n })\n\n // Auto-dismiss after 2 seconds\n setTimeout(() => onDone(`Exported to ${filepath}`), 2000)\n } catch (error) {\n setResult({\n success: false,\n message: `Export failed: ${error instanceof Error ? error.message : String(error)}`,\n })\n } finally {\n setExporting(false)\n }\n }\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n Export Data\n </Text>\n </Box>\n\n {!result ? (\n <>\n <Box flexDirection=\"column\" marginBottom={1}>\n {EXPORT_OPTIONS.map((option, index) => (\n <Box key={option.type} paddingLeft={1}>\n <Text color={index === selectedIndex ? 'cyan' : undefined}>\n {index === selectedIndex ? '\u25B6 ' : ' '}\n <Text bold>{option.label}</Text>\n <Text dimColor> - {option.description}</Text>\n </Text>\n </Box>\n ))}\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\u2191/\u2193: Navigate | Enter: Export | q/Esc: Cancel</Text>\n </Box>\n </>\n ) : (\n <Box>\n {result.success ? (\n <Text color=\"green\">\u2713 {result.message}</Text>\n ) : (\n <Text color=\"red\">\u2717 {result.message}</Text>\n )}\n </Box>\n )}\n\n {exporting && (\n <Box>\n <Text color=\"yellow\">Exporting...</Text>\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * Generate a markdown summary of the conversation\n */\nfunction generateSummary(messages: unknown[]): string {\n const lines: string[] = [\n '# Minto Session Summary',\n '',\n `Generated: ${new Date().toISOString()}`,\n '',\n '## Conversation Overview',\n '',\n `Total messages: ${messages.length}`,\n '',\n '## Message Summary',\n '',\n ]\n\n for (const msg of messages) {\n const m = msg as { role?: string; content?: unknown }\n if (!m.role) continue\n\n const role = m.role === 'user' ? '\uD83D\uDC64 User' : '\uD83E\uDD16 Assistant'\n\n if (typeof m.content === 'string') {\n const preview = m.content.slice(0, 200).replace(/\\n/g, ' ')\n lines.push(`### ${role}`)\n lines.push('')\n lines.push(`> ${preview}${m.content.length > 200 ? '...' : ''}`)\n lines.push('')\n } else if (Array.isArray(m.content)) {\n lines.push(`### ${role}`)\n lines.push('')\n for (const block of m.content) {\n if (block.type === 'text') {\n const preview = String(block.text || '')\n .slice(0, 200)\n .replace(/\\n/g, ' ')\n lines.push(\n `> ${preview}${String(block.text || '').length > 200 ? '...' : ''}`,\n )\n } else if (block.type === 'tool_use') {\n lines.push(`- Tool: \\`${block.name}\\``)\n } else if (block.type === 'tool_result') {\n lines.push(`- Tool result received`)\n }\n }\n lines.push('')\n }\n }\n\n return lines.join('\\n')\n}\n\nconst command: Command = {\n name: 'export',\n description: 'Export session data, configuration, or conversation history',\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone) {\n return <ExportMenu onDone={onDone} />\n },\n}\n\nexport default command\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Export Command\n *\n * Export session data, configuration, or conversation history.\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { writeFile } from 'fs/promises'\nimport { join } from 'path'\nimport type { Command } from '@commands'\nimport { getMessagesGetter } from '@messages'\nimport { getCwd } from '@utils/state'\nimport { loadGlobalConfig, loadProjectConfig } from '../core/config'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype ExportType = 'conversation' | 'config' | 'summary'\n\ninterface ExportOption {\n type: ExportType\n label: string\n description: string\n}\n\nconst EXPORT_OPTIONS: ExportOption[] = [\n {\n type: 'conversation',\n label: 'Conversation',\n description: 'Export full conversation history as JSON',\n },\n {\n type: 'config',\n label: 'Configuration',\n description: 'Export current configuration settings',\n },\n {\n type: 'summary',\n label: 'Summary',\n description: 'Export a markdown summary of the session',\n },\n]\n\ninterface ExportMenuProps {\n onDone: (result?: string) => void\n}\n\nconst ExportMenu = ({ onDone }: ExportMenuProps) => {\n const [selectedIndex, setSelectedIndex] = useState(0)\n const [exporting, setExporting] = useState(false)\n const [result, setResult] = useState<{\n success: boolean\n message: string\n } | null>(null)\n\n useInput(async (input, key) => {\n if (exporting) return\n\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1))\n } else if (key.downArrow) {\n setSelectedIndex(Math.min(EXPORT_OPTIONS.length - 1, selectedIndex + 1))\n } else if (key.return) {\n await handleExport(EXPORT_OPTIONS[selectedIndex]!.type)\n } else if (input === 'q' || key.escape) {\n onDone()\n }\n })\n\n const handleExport = async (type: ExportType) => {\n setExporting(true)\n\n try {\n const cwd = getCwd()\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\n let filename: string\n let content: string\n\n switch (type) {\n case 'conversation': {\n const messages = getMessagesGetter()()\n filename = `minto-conversation-${timestamp}.json`\n content = JSON.stringify(messages, null, 2)\n break\n }\n case 'config': {\n const [globalConfig, projectConfig] = await Promise.all([\n Promise.resolve(loadGlobalConfig()),\n Promise.resolve(loadProjectConfig(cwd)),\n ])\n filename = `minto-config-${timestamp}.json`\n content = JSON.stringify(\n {\n global: globalConfig,\n project: projectConfig,\n },\n null,\n 2,\n )\n break\n }\n case 'summary': {\n const messages = getMessagesGetter()()\n filename = `minto-summary-${timestamp}.md`\n content = generateSummary(messages)\n break\n }\n }\n\n const filepath = join(cwd, filename)\n await writeFile(filepath, content, 'utf-8')\n\n setResult({\n success: true,\n message: `Exported to ${filename}`,\n })\n\n // Auto-dismiss after 2 seconds\n setTimeout(() => onDone(`Exported to ${filepath}`), 2000)\n } catch (error) {\n setResult({\n success: false,\n message: `Export failed: ${error instanceof Error ? error.message : String(error)}`,\n })\n } finally {\n setExporting(false)\n }\n }\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color=\"cyan\">\n Export Data\n </Text>\n </Box>\n\n {!result ? (\n <>\n <Box flexDirection=\"column\" marginBottom={1}>\n {EXPORT_OPTIONS.map((option, index) => (\n <Box key={option.type} paddingLeft={1}>\n <Text color={index === selectedIndex ? 'cyan' : undefined}>\n {index === selectedIndex ? '\u25B6 ' : ' '}\n <Text bold>{option.label}</Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n - {option.description}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n \u2191/\u2193: Navigate | Enter: Export | q/Esc: Cancel\n </Text>\n </Box>\n </>\n ) : (\n <Box>\n {result.success ? (\n <Text color=\"green\">\u2713 {result.message}</Text>\n ) : (\n <Text color=\"red\">\u2717 {result.message}</Text>\n )}\n </Box>\n )}\n\n {exporting && (\n <Box>\n <Text color=\"yellow\">Exporting...</Text>\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * Generate a markdown summary of the conversation\n */\nfunction generateSummary(messages: unknown[]): string {\n const lines: string[] = [\n '# Minto Session Summary',\n '',\n `Generated: ${new Date().toISOString()}`,\n '',\n '## Conversation Overview',\n '',\n `Total messages: ${messages.length}`,\n '',\n '## Message Summary',\n '',\n ]\n\n for (const msg of messages) {\n const m = msg as { role?: string; content?: unknown }\n if (!m.role) continue\n\n const role = m.role === 'user' ? '\uD83D\uDC64 User' : '\uD83E\uDD16 Assistant'\n\n if (typeof m.content === 'string') {\n const preview = m.content.slice(0, 200).replace(/\\n/g, ' ')\n lines.push(`### ${role}`)\n lines.push('')\n lines.push(`> ${preview}${m.content.length > 200 ? '...' : ''}`)\n lines.push('')\n } else if (Array.isArray(m.content)) {\n lines.push(`### ${role}`)\n lines.push('')\n for (const block of m.content) {\n if (block.type === 'text') {\n const preview = String(block.text || '')\n .slice(0, 200)\n .replace(/\\n/g, ' ')\n lines.push(\n `> ${preview}${String(block.text || '').length > 200 ? '...' : ''}`,\n )\n } else if (block.type === 'tool_use') {\n lines.push(`- Tool: \\`${block.name}\\``)\n } else if (block.type === 'tool_result') {\n lines.push(`- Tool result received`)\n }\n }\n lines.push('')\n }\n }\n\n return lines.join('\\n')\n}\n\nconst command: Command = {\n name: 'export',\n description: 'Export session data, configuration, or conversation history',\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone) {\n return <ExportMenu onDone={onDone} />\n },\n}\n\nexport default command\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { Select } from "../components/CustomSelect/select.js";
4
4
  import { getTheme } from "../utils/theme.js";
5
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
5
6
  import {
6
7
  listMCPServers,
7
8
  getClients,
@@ -47,7 +48,7 @@ const MainMenu = ({ onNavigate, onExit, isActive = true }) => {
47
48
  }
48
49
  }
49
50
  ),
50
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to exit"))
51
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to exit"))
51
52
  );
52
53
  };
53
54
  const ServerList = ({ onNavigate, onBack, isActive = true }) => {
@@ -90,13 +91,13 @@ const ServerList = ({ onNavigate, onBack, isActive = true }) => {
90
91
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(SimpleSpinner, { label: "Loading MCP servers..." }));
91
92
  }
92
93
  if (servers.length === 0) {
93
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Text, null, "No MCP servers configured."), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to go back")));
94
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Text, null, "No MCP servers configured."), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to go back")));
94
95
  }
95
96
  const options = servers.map((server) => {
96
97
  const statusIcon = server.status === "connected" ? "\u2713" : "\u2717";
97
98
  const statusColor = server.status === "connected" ? theme.success : theme.error;
98
99
  return {
99
- label: /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIcon), " ", server.name, " ", /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "(", server.config.scope, ")")),
100
+ label: /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIcon), " ", server.name, " ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(", server.config.scope, ")")),
100
101
  value: server.name
101
102
  };
102
103
  });
@@ -110,7 +111,7 @@ const ServerList = ({ onNavigate, onBack, isActive = true }) => {
110
111
  },
111
112
  /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.primary }, "MCP Servers")),
112
113
  /* @__PURE__ */ React.createElement(Select, { options, onChange: handleServerSelect }),
113
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to go back"))
114
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to go back"))
114
115
  );
115
116
  };
116
117
  const ServerDetails = ({ serverName, onBack, onRefresh, isActive = true }) => {
@@ -204,7 +205,7 @@ const ServerDetails = ({ serverName, onBack, onRefresh, isActive = true }) => {
204
205
  padding: 1
205
206
  },
206
207
  /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.primary }, server.name)),
207
- /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Status: ", /* @__PURE__ */ React.createElement(Text, { color: statusColor }, server.status)), /* @__PURE__ */ React.createElement(Text, null, "Enabled: ", /* @__PURE__ */ React.createElement(Text, { color: enabledColor }, isEnabled ? "Yes" : "No")), /* @__PURE__ */ React.createElement(Text, null, "Scope: ", /* @__PURE__ */ React.createElement(Text, { dimColor: true }, server.config.scope)), /* @__PURE__ */ React.createElement(Text, null, "Type: ", /* @__PURE__ */ React.createElement(Text, { dimColor: true }, server.config.type))),
208
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "Status: ", /* @__PURE__ */ React.createElement(Text, { color: statusColor }, server.status)), /* @__PURE__ */ React.createElement(Text, null, "Enabled: ", /* @__PURE__ */ React.createElement(Text, { color: enabledColor }, isEnabled ? "Yes" : "No")), /* @__PURE__ */ React.createElement(Text, null, "Scope: ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, server.config.scope)), /* @__PURE__ */ React.createElement(Text, null, "Type: ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, server.config.type))),
208
209
  toggling ? /* @__PURE__ */ React.createElement(SimpleSpinner, { label: "Toggling server..." }) : /* @__PURE__ */ React.createElement(
209
210
  Select,
210
211
  {
@@ -218,7 +219,7 @@ const ServerDetails = ({ serverName, onBack, onRefresh, isActive = true }) => {
218
219
  }
219
220
  }
220
221
  ),
221
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to go back"))
222
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "ESC"), " to go back"))
222
223
  );
223
224
  };
224
225
  const MCPInteractive = ({ onDone }) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/mcp-interactive.tsx"],
4
- "sourcesContent": ["/**\n * Interactive MCP Server Management UI\n *\n * Complete interactive interface for MCP server management with navigation\n */\n\nimport React, { useState, useEffect, useCallback } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { Select } from '@components/CustomSelect/select'\nimport { getTheme } from '@utils/theme'\nimport { Command } from '@commands'\nimport {\n listMCPServers,\n getClients,\n refreshMCPConnections,\n getMcpServer,\n addMcpServer,\n removeMcpServer,\n type ScopedMcpServerConfig,\n} from '@services/mcpClient'\nimport { SimpleSpinner } from '@components/Spinner'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n} from '@utils/config'\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype Screen = 'main-menu' | 'server-list' | 'server-details'\n\ntype NavigationState = {\n screen: Screen\n serverName?: string\n}\n\ntype ServerStatus = {\n name: string\n status: 'connected' | 'failed'\n config: ScopedMcpServerConfig\n}\n\n// =============================================================================\n// Main Menu\n// =============================================================================\n\nconst MainMenu: React.FC<{\n onNavigate: (state: NavigationState) => void\n onExit: () => void\n isActive?: boolean\n}> = ({ onNavigate, onExit, isActive = true }) => {\n const theme = getTheme()\n\n const options = [\n { label: '\uD83D\uDCCB View all MCP servers', value: 'list' },\n { label: '\uD83D\uDD04 Refresh connections', value: 'refresh' },\n ]\n\n // Only listen when this component is active\n useInput(\n (input, key) => {\n if (key.escape) onExit()\n },\n { isActive },\n )\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.primary}>\n MCP Server Manager\n </Text>\n </Box>\n\n <Select\n options={options}\n onChange={value => {\n if (value === 'list') onNavigate({ screen: 'server-list' })\n else if (value === 'refresh') {\n refreshMCPConnections()\n onNavigate({ screen: 'server-list' })\n }\n }}\n />\n\n <Box marginTop={1}>\n <Text dimColor>\n Press <Text bold>ESC</Text> to exit\n </Text>\n </Box>\n </Box>\n )\n}\n\n// =============================================================================\n// Server List\n// =============================================================================\n\nconst ServerList: React.FC<{\n onNavigate: (state: NavigationState) => void\n onBack: () => void\n isActive?: boolean\n}> = ({ onNavigate, onBack, isActive = true }) => {\n const theme = getTheme()\n const [loading, setLoading] = useState(true)\n const [servers, setServers] = useState<ServerStatus[]>([])\n\n useEffect(() => {\n const loadServers = async () => {\n const serverConfigs = listMCPServers()\n const clients = await getClients()\n\n const serverStatuses: ServerStatus[] = Object.entries(serverConfigs).map(\n ([name, _]) => {\n const client = clients.find(c => c.name === name)\n const config = getMcpServer(name)!\n return {\n name,\n status: client?.type === 'connected' ? 'connected' : 'failed',\n config,\n }\n },\n )\n\n setServers(serverStatuses)\n setLoading(false)\n }\n\n loadServers()\n }, [])\n\n // Memoize the onChange handler to prevent infinite re-renders\n const handleServerSelect = useCallback(\n (serverName: string) => {\n onNavigate({ screen: 'server-details', serverName })\n },\n [onNavigate],\n )\n\n // Only listen when this component is active\n useInput(\n (input, key) => {\n if (key.escape) onBack()\n },\n { isActive },\n )\n\n if (loading) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <SimpleSpinner label=\"Loading MCP servers...\" />\n </Box>\n )\n }\n\n if (servers.length === 0) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text>No MCP servers configured.</Text>\n <Box marginTop={1}>\n <Text dimColor>\n Press <Text bold>ESC</Text> to go back\n </Text>\n </Box>\n </Box>\n )\n }\n\n const options = servers.map(server => {\n const statusIcon = server.status === 'connected' ? '\u2713' : '\u2717'\n const statusColor =\n server.status === 'connected' ? theme.success : theme.error\n return {\n label: (\n <Text>\n <Text color={statusColor}>{statusIcon}</Text> {server.name}{' '}\n <Text dimColor>({server.config.scope})</Text>\n </Text>\n ),\n value: server.name,\n }\n })\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.primary}>\n MCP Servers\n </Text>\n </Box>\n\n <Select options={options} onChange={handleServerSelect} />\n\n <Box marginTop={1}>\n <Text dimColor>\n Press <Text bold>ESC</Text> to go back\n </Text>\n </Box>\n </Box>\n )\n}\n\n// =============================================================================\n// Server Details\n// =============================================================================\n\nconst ServerDetails: React.FC<{\n serverName: string\n onBack: () => void\n onRefresh: () => void\n isActive?: boolean\n}> = ({ serverName, onBack, onRefresh, isActive = true }) => {\n const theme = getTheme()\n const [loading, setLoading] = useState(true)\n const [server, setServer] = useState<ServerStatus | null>(null)\n const [toggling, setToggling] = useState(false)\n\n useEffect(() => {\n const loadServer = async () => {\n const config = getMcpServer(serverName)\n if (!config) {\n onBack()\n return\n }\n\n const clients = await getClients()\n const client = clients.find(c => c.name === serverName)\n\n setServer({\n name: serverName,\n status: client?.type === 'connected' ? 'connected' : 'failed',\n config,\n })\n setLoading(false)\n }\n\n loadServer()\n }, [serverName])\n\n const toggleEnabled = async () => {\n if (!server) return\n\n setToggling(true)\n\n // Get current project config\n const projectConfig = getCurrentProjectConfig()\n const currentServer = projectConfig.mcpServers?.[serverName]\n\n if (currentServer) {\n // Toggle in project config\n const newEnabled = !(currentServer.enabled ?? true)\n await saveCurrentProjectConfig({\n ...projectConfig,\n mcpServers: {\n ...projectConfig.mcpServers,\n [serverName]: {\n ...currentServer,\n enabled: newEnabled,\n },\n },\n })\n } else {\n // Server is from global or mcprc, copy to project and disable\n const serverConfig = getMcpServer(serverName)\n if (serverConfig) {\n await saveCurrentProjectConfig({\n ...projectConfig,\n mcpServers: {\n ...projectConfig.mcpServers,\n [serverName]: {\n ...serverConfig,\n enabled: false,\n },\n },\n })\n }\n }\n\n setToggling(false)\n refreshMCPConnections()\n onRefresh()\n }\n\n // Only listen when this component is active\n useInput(\n (input, key) => {\n if (key.escape) onBack()\n },\n { isActive },\n )\n\n if (loading) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <SimpleSpinner label=\"Loading server details...\" />\n </Box>\n )\n }\n\n if (!server) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text color={theme.error}>Server not found</Text>\n </Box>\n )\n }\n\n const isEnabled = 'enabled' in server.config ? server.config.enabled : true\n const statusColor =\n server.status === 'connected' ? theme.success : theme.error\n const enabledColor = isEnabled ? theme.success : theme.error\n\n const options = [\n {\n label: isEnabled ? '\uD83D\uDD34 Disable server' : '\uD83D\uDFE2 Enable server',\n value: 'toggle',\n },\n { label: '\uD83D\uDD04 Refresh connection', value: 'refresh' },\n { label: '\u2190 Back to list', value: 'back' },\n ]\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.primary}>\n {server.name}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text>\n Status: <Text color={statusColor}>{server.status}</Text>\n </Text>\n <Text>\n Enabled: <Text color={enabledColor}>{isEnabled ? 'Yes' : 'No'}</Text>\n </Text>\n <Text>\n Scope: <Text dimColor>{server.config.scope}</Text>\n </Text>\n <Text>\n Type: <Text dimColor>{server.config.type}</Text>\n </Text>\n </Box>\n\n {toggling ? (\n <SimpleSpinner label=\"Toggling server...\" />\n ) : (\n <Select\n options={options}\n onChange={value => {\n if (value === 'toggle') toggleEnabled()\n else if (value === 'refresh') {\n refreshMCPConnections()\n onRefresh()\n } else if (value === 'back') onBack()\n }}\n />\n )}\n\n <Box marginTop={1}>\n <Text dimColor>\n Press <Text bold>ESC</Text> to go back\n </Text>\n </Box>\n </Box>\n )\n}\n\n// =============================================================================\n// Main Interactive Component\n// =============================================================================\n\nconst MCPInteractive: React.FC<{\n onDone: (result?: string) => void\n}> = ({ onDone }) => {\n const [navState, setNavState] = useState<NavigationState>({\n screen: 'main-menu',\n })\n\n const handleNavigate = (state: NavigationState) => {\n setNavState(state)\n }\n\n const handleBack = () => {\n if (navState.screen === 'server-details') {\n setNavState({ screen: 'server-list' })\n } else {\n setNavState({ screen: 'main-menu' })\n }\n }\n\n const handleRefresh = () => {\n // Reload current screen\n setNavState({ ...navState })\n }\n\n switch (navState.screen) {\n case 'main-menu':\n return <MainMenu onNavigate={handleNavigate} onExit={() => onDone()} />\n\n case 'server-list':\n return <ServerList onNavigate={handleNavigate} onBack={handleBack} />\n\n case 'server-details':\n return (\n <ServerDetails\n serverName={navState.serverName!}\n onBack={handleBack}\n onRefresh={handleRefresh}\n />\n )\n\n default:\n return <Text>Unknown screen</Text>\n }\n}\n\n// =============================================================================\n// Command Definition\n// =============================================================================\n\nconst mcpInteractive = {\n type: 'local-jsx',\n name: 'mcp',\n description: 'Interactive MCP server management',\n isEnabled: true,\n isHidden: false,\n async call(onDone: (result?: string) => void) {\n return <MCPInteractive onDone={onDone} />\n },\n userFacingName() {\n return 'mcp'\n },\n} satisfies Command\n\nexport default mcpInteractive\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Interactive MCP Server Management UI\n *\n * Complete interactive interface for MCP server management with navigation\n */\n\nimport React, { useState, useEffect, useCallback } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { Select } from '@components/CustomSelect/select'\nimport { getTheme } from '@utils/theme'\nimport { SEMANTIC_COLORS } from '@constants/colors'\nimport { Command } from '@commands'\nimport {\n listMCPServers,\n getClients,\n refreshMCPConnections,\n getMcpServer,\n addMcpServer,\n removeMcpServer,\n type ScopedMcpServerConfig,\n} from '@services/mcpClient'\nimport { SimpleSpinner } from '@components/Spinner'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n} from '@utils/config'\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype Screen = 'main-menu' | 'server-list' | 'server-details'\n\ntype NavigationState = {\n screen: Screen\n serverName?: string\n}\n\ntype ServerStatus = {\n name: string\n status: 'connected' | 'failed'\n config: ScopedMcpServerConfig\n}\n\n// =============================================================================\n// Main Menu\n// =============================================================================\n\nconst MainMenu: React.FC<{\n onNavigate: (state: NavigationState) => void\n onExit: () => void\n isActive?: boolean\n}> = ({ onNavigate, onExit, isActive = true }) => {\n const theme = getTheme()\n\n const options = [\n { label: '\uD83D\uDCCB View all MCP servers', value: 'list' },\n { label: '\uD83D\uDD04 Refresh connections', value: 'refresh' },\n ]\n\n // Only listen when this component is active\n useInput(\n (input, key) => {\n if (key.escape) onExit()\n },\n { isActive },\n )\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.primary}>\n MCP Server Manager\n </Text>\n </Box>\n\n <Select\n options={options}\n onChange={value => {\n if (value === 'list') onNavigate({ screen: 'server-list' })\n else if (value === 'refresh') {\n refreshMCPConnections()\n onNavigate({ screen: 'server-list' })\n }\n }}\n />\n\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>ESC</Text> to exit\n </Text>\n </Box>\n </Box>\n )\n}\n\n// =============================================================================\n// Server List\n// =============================================================================\n\nconst ServerList: React.FC<{\n onNavigate: (state: NavigationState) => void\n onBack: () => void\n isActive?: boolean\n}> = ({ onNavigate, onBack, isActive = true }) => {\n const theme = getTheme()\n const [loading, setLoading] = useState(true)\n const [servers, setServers] = useState<ServerStatus[]>([])\n\n useEffect(() => {\n const loadServers = async () => {\n const serverConfigs = listMCPServers()\n const clients = await getClients()\n\n const serverStatuses: ServerStatus[] = Object.entries(serverConfigs).map(\n ([name, _]) => {\n const client = clients.find(c => c.name === name)\n const config = getMcpServer(name)!\n return {\n name,\n status: client?.type === 'connected' ? 'connected' : 'failed',\n config,\n }\n },\n )\n\n setServers(serverStatuses)\n setLoading(false)\n }\n\n loadServers()\n }, [])\n\n // Memoize the onChange handler to prevent infinite re-renders\n const handleServerSelect = useCallback(\n (serverName: string) => {\n onNavigate({ screen: 'server-details', serverName })\n },\n [onNavigate],\n )\n\n // Only listen when this component is active\n useInput(\n (input, key) => {\n if (key.escape) onBack()\n },\n { isActive },\n )\n\n if (loading) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <SimpleSpinner label=\"Loading MCP servers...\" />\n </Box>\n )\n }\n\n if (servers.length === 0) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text>No MCP servers configured.</Text>\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>ESC</Text> to go back\n </Text>\n </Box>\n </Box>\n )\n }\n\n const options = servers.map(server => {\n const statusIcon = server.status === 'connected' ? '\u2713' : '\u2717'\n const statusColor =\n server.status === 'connected' ? theme.success : theme.error\n return {\n label: (\n <Text>\n <Text color={statusColor}>{statusIcon}</Text> {server.name}{' '}\n <Text color={SEMANTIC_COLORS.dim}>({server.config.scope})</Text>\n </Text>\n ),\n value: server.name,\n }\n })\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.primary}>\n MCP Servers\n </Text>\n </Box>\n\n <Select options={options} onChange={handleServerSelect} />\n\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>ESC</Text> to go back\n </Text>\n </Box>\n </Box>\n )\n}\n\n// =============================================================================\n// Server Details\n// =============================================================================\n\nconst ServerDetails: React.FC<{\n serverName: string\n onBack: () => void\n onRefresh: () => void\n isActive?: boolean\n}> = ({ serverName, onBack, onRefresh, isActive = true }) => {\n const theme = getTheme()\n const [loading, setLoading] = useState(true)\n const [server, setServer] = useState<ServerStatus | null>(null)\n const [toggling, setToggling] = useState(false)\n\n useEffect(() => {\n const loadServer = async () => {\n const config = getMcpServer(serverName)\n if (!config) {\n onBack()\n return\n }\n\n const clients = await getClients()\n const client = clients.find(c => c.name === serverName)\n\n setServer({\n name: serverName,\n status: client?.type === 'connected' ? 'connected' : 'failed',\n config,\n })\n setLoading(false)\n }\n\n loadServer()\n }, [serverName])\n\n const toggleEnabled = async () => {\n if (!server) return\n\n setToggling(true)\n\n // Get current project config\n const projectConfig = getCurrentProjectConfig()\n const currentServer = projectConfig.mcpServers?.[serverName]\n\n if (currentServer) {\n // Toggle in project config\n const newEnabled = !(currentServer.enabled ?? true)\n await saveCurrentProjectConfig({\n ...projectConfig,\n mcpServers: {\n ...projectConfig.mcpServers,\n [serverName]: {\n ...currentServer,\n enabled: newEnabled,\n },\n },\n })\n } else {\n // Server is from global or mcprc, copy to project and disable\n const serverConfig = getMcpServer(serverName)\n if (serverConfig) {\n await saveCurrentProjectConfig({\n ...projectConfig,\n mcpServers: {\n ...projectConfig.mcpServers,\n [serverName]: {\n ...serverConfig,\n enabled: false,\n },\n },\n })\n }\n }\n\n setToggling(false)\n refreshMCPConnections()\n onRefresh()\n }\n\n // Only listen when this component is active\n useInput(\n (input, key) => {\n if (key.escape) onBack()\n },\n { isActive },\n )\n\n if (loading) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <SimpleSpinner label=\"Loading server details...\" />\n </Box>\n )\n }\n\n if (!server) {\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Text color={theme.error}>Server not found</Text>\n </Box>\n )\n }\n\n const isEnabled = 'enabled' in server.config ? server.config.enabled : true\n const statusColor =\n server.status === 'connected' ? theme.success : theme.error\n const enabledColor = isEnabled ? theme.success : theme.error\n\n const options = [\n {\n label: isEnabled ? '\uD83D\uDD34 Disable server' : '\uD83D\uDFE2 Enable server',\n value: 'toggle',\n },\n { label: '\uD83D\uDD04 Refresh connection', value: 'refresh' },\n { label: '\u2190 Back to list', value: 'back' },\n ]\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Box marginBottom={1}>\n <Text bold color={theme.primary}>\n {server.name}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text>\n Status: <Text color={statusColor}>{server.status}</Text>\n </Text>\n <Text>\n Enabled: <Text color={enabledColor}>{isEnabled ? 'Yes' : 'No'}</Text>\n </Text>\n <Text>\n Scope: <Text color={SEMANTIC_COLORS.dim}>{server.config.scope}</Text>\n </Text>\n <Text>\n Type: <Text color={SEMANTIC_COLORS.dim}>{server.config.type}</Text>\n </Text>\n </Box>\n\n {toggling ? (\n <SimpleSpinner label=\"Toggling server...\" />\n ) : (\n <Select\n options={options}\n onChange={value => {\n if (value === 'toggle') toggleEnabled()\n else if (value === 'refresh') {\n refreshMCPConnections()\n onRefresh()\n } else if (value === 'back') onBack()\n }}\n />\n )}\n\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>ESC</Text> to go back\n </Text>\n </Box>\n </Box>\n )\n}\n\n// =============================================================================\n// Main Interactive Component\n// =============================================================================\n\nconst MCPInteractive: React.FC<{\n onDone: (result?: string) => void\n}> = ({ onDone }) => {\n const [navState, setNavState] = useState<NavigationState>({\n screen: 'main-menu',\n })\n\n const handleNavigate = (state: NavigationState) => {\n setNavState(state)\n }\n\n const handleBack = () => {\n if (navState.screen === 'server-details') {\n setNavState({ screen: 'server-list' })\n } else {\n setNavState({ screen: 'main-menu' })\n }\n }\n\n const handleRefresh = () => {\n // Reload current screen\n setNavState({ ...navState })\n }\n\n switch (navState.screen) {\n case 'main-menu':\n return <MainMenu onNavigate={handleNavigate} onExit={() => onDone()} />\n\n case 'server-list':\n return <ServerList onNavigate={handleNavigate} onBack={handleBack} />\n\n case 'server-details':\n return (\n <ServerDetails\n serverName={navState.serverName!}\n onBack={handleBack}\n onRefresh={handleRefresh}\n />\n )\n\n default:\n return <Text>Unknown screen</Text>\n }\n}\n\n// =============================================================================\n// Command Definition\n// =============================================================================\n\nconst mcpInteractive = {\n type: 'local-jsx',\n name: 'mcp',\n description: 'Interactive MCP server management',\n isEnabled: true,\n isHidden: false,\n async call(onDone: (result?: string) => void) {\n return <MCPInteractive onDone={onDone} />\n },\n userFacingName() {\n return 'mcp'\n },\n} satisfies Command\n\nexport default mcpInteractive\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -6,6 +6,7 @@ import { triggerModelConfigChange } from "../messages.js";
6
6
  import { getModelManager } from "../utils/model.js";
7
7
  import { getTheme } from "../utils/theme.js";
8
8
  import { useExitOnCtrlCD } from "../hooks/useExitOnCtrlCD.js";
9
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
9
10
  function ModelCommand({ onClose, abortController }) {
10
11
  const [mode, setMode] = useState("status");
11
12
  const theme = getTheme();
@@ -63,7 +64,7 @@ function ModelCommand({ onClose, abortController }) {
63
64
  }
64
65
  }),
65
66
  /* @__PURE__ */ React.createElement(Text, null, " "),
66
- /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Enter"), " or ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "C"), " to configure models"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Esc"), " to close"))
67
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Enter"), " or ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "C"), " to configure models"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Esc"), " to close"))
67
68
  );
68
69
  } catch (error) {
69
70
  return /* @__PURE__ */ React.createElement(
@@ -78,7 +79,7 @@ function ModelCommand({ onClose, abortController }) {
78
79
  /* @__PURE__ */ React.createElement(Text, { bold: true }, "\u{1F4CA} Model Status Error"),
79
80
  /* @__PURE__ */ React.createElement(Text, { color: theme.error }, "Error reading model status: ", String(error)),
80
81
  /* @__PURE__ */ React.createElement(Text, null, " "),
81
- /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Enter"), " to configure models")
82
+ /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Enter"), " to configure models")
82
83
  );
83
84
  }
84
85
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/model.tsx"],
4
- "sourcesContent": ["import React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { ModelConfig } from '@components/ModelConfig'\nimport { enableConfigs } from '@utils/config'\nimport { triggerModelConfigChange } from '@messages'\nimport { getModelManager } from '@utils/model'\nimport { getTheme } from '@utils/theme'\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\nimport type { Command } from '@commands'\n\ntype Props = {\n onClose: () => void\n abortController?: AbortController\n}\n\n/**\n * Combined Model Command - Shows status and provides configuration\n *\n * This merges the functionality of /model and /modelstatus into a single command.\n * First shows current model status, then allows entering configuration mode.\n */\nfunction ModelCommand({ onClose, abortController }: Props): React.ReactNode {\n const [mode, setMode] = useState<'status' | 'config'>('status')\n const theme = getTheme()\n const exitState = useExitOnCtrlCD(onClose)\n\n // Only listen for input when in status mode\n // When in config mode, ModelConfig handles its own input\n useInput(\n (input, key) => {\n if (key.return || input === 'c' || input === 'C') {\n enableConfigs()\n abortController?.abort?.()\n setMode('config')\n } else if (key.escape) {\n onClose()\n }\n },\n { isActive: mode === 'status' },\n )\n\n if (mode === 'config') {\n return (\n <ModelConfig\n onClose={() => {\n import('@utils/model').then(({ reloadModelManager }) => {\n reloadModelManager()\n triggerModelConfigChange()\n // Return to status mode instead of exiting completely\n setMode('status')\n })\n }}\n />\n )\n }\n\n // Status mode - show current model configuration\n try {\n const modelManager = getModelManager()\n const pointers = ['main', 'task', 'reasoning', 'quick', 'compact'] as const\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.secondaryBorder}\n paddingX={2}\n paddingY={1}\n >\n <Text bold>\n \uD83D\uDCCA Model Status{' '}\n {exitState.pending\n ? `(press ${exitState.keyName} again to exit)`\n : ''}\n </Text>\n <Text> </Text>\n\n {pointers.map(pointer => {\n try {\n const model = modelManager.getModel(pointer)\n if (model && model.name && model.provider) {\n return (\n <Box key={pointer}>\n <Text>\n <Text bold color={theme.minto}>\n {pointer.toUpperCase().padEnd(10)}\n </Text>{' '}\n \u2192 {model.name}{' '}\n <Text color={theme.secondaryText}>\n ({model.provider}, {model.modelName || 'unknown'})\n </Text>\n </Text>\n </Box>\n )\n } else {\n return (\n <Box key={pointer}>\n <Text>\n <Text bold color={theme.minto}>\n {pointer.toUpperCase().padEnd(10)}\n </Text>{' '}\n \u2192 <Text color={theme.error}>Not configured</Text>\n </Text>\n </Box>\n )\n }\n } catch {\n return (\n <Box key={pointer}>\n <Text>\n <Text bold color={theme.minto}>\n {pointer.toUpperCase().padEnd(10)}\n </Text>{' '}\n \u2192 <Text color={theme.error}>Error</Text>\n </Text>\n </Box>\n )\n }\n })}\n\n <Text> </Text>\n <Box flexDirection=\"column\">\n <Text dimColor>\n Press <Text bold>Enter</Text> or <Text bold>C</Text> to configure\n models\n </Text>\n <Text dimColor>\n Press <Text bold>Esc</Text> to close\n </Text>\n </Box>\n </Box>\n )\n } catch (error) {\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.error}\n paddingX={2}\n paddingY={1}\n >\n <Text bold>\uD83D\uDCCA Model Status Error</Text>\n <Text color={theme.error}>\n Error reading model status: {String(error)}\n </Text>\n <Text> </Text>\n <Text dimColor>\n Press <Text bold>Enter</Text> to configure models\n </Text>\n </Box>\n )\n }\n}\n\nconst model: Command = {\n name: 'model',\n description: 'View model status and configure AI provider settings',\n aliases: ['ms', 'modelstatus', 'model-status'],\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n userFacingName() {\n return 'model'\n },\n async call(onDone, context) {\n const { abortController } = context || {}\n return <ModelCommand onClose={onDone} abortController={abortController} />\n },\n}\n\nexport default model\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { ModelConfig } from '@components/ModelConfig'\nimport { enableConfigs } from '@utils/config'\nimport { triggerModelConfigChange } from '@messages'\nimport { getModelManager } from '@utils/model'\nimport { getTheme } from '@utils/theme'\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\nimport type { Command } from '@commands'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype Props = {\n onClose: () => void\n abortController?: AbortController\n}\n\n/**\n * Combined Model Command - Shows status and provides configuration\n *\n * This merges the functionality of /model and /modelstatus into a single command.\n * First shows current model status, then allows entering configuration mode.\n */\nfunction ModelCommand({ onClose, abortController }: Props): React.ReactNode {\n const [mode, setMode] = useState<'status' | 'config'>('status')\n const theme = getTheme()\n const exitState = useExitOnCtrlCD(onClose)\n\n // Only listen for input when in status mode\n // When in config mode, ModelConfig handles its own input\n useInput(\n (input, key) => {\n if (key.return || input === 'c' || input === 'C') {\n enableConfigs()\n abortController?.abort?.()\n setMode('config')\n } else if (key.escape) {\n onClose()\n }\n },\n { isActive: mode === 'status' },\n )\n\n if (mode === 'config') {\n return (\n <ModelConfig\n onClose={() => {\n import('@utils/model').then(({ reloadModelManager }) => {\n reloadModelManager()\n triggerModelConfigChange()\n // Return to status mode instead of exiting completely\n setMode('status')\n })\n }}\n />\n )\n }\n\n // Status mode - show current model configuration\n try {\n const modelManager = getModelManager()\n const pointers = ['main', 'task', 'reasoning', 'quick', 'compact'] as const\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.secondaryBorder}\n paddingX={2}\n paddingY={1}\n >\n <Text bold>\n \uD83D\uDCCA Model Status{' '}\n {exitState.pending\n ? `(press ${exitState.keyName} again to exit)`\n : ''}\n </Text>\n <Text> </Text>\n\n {pointers.map(pointer => {\n try {\n const model = modelManager.getModel(pointer)\n if (model && model.name && model.provider) {\n return (\n <Box key={pointer}>\n <Text>\n <Text bold color={theme.minto}>\n {pointer.toUpperCase().padEnd(10)}\n </Text>{' '}\n \u2192 {model.name}{' '}\n <Text color={theme.secondaryText}>\n ({model.provider}, {model.modelName || 'unknown'})\n </Text>\n </Text>\n </Box>\n )\n } else {\n return (\n <Box key={pointer}>\n <Text>\n <Text bold color={theme.minto}>\n {pointer.toUpperCase().padEnd(10)}\n </Text>{' '}\n \u2192 <Text color={theme.error}>Not configured</Text>\n </Text>\n </Box>\n )\n }\n } catch {\n return (\n <Box key={pointer}>\n <Text>\n <Text bold color={theme.minto}>\n {pointer.toUpperCase().padEnd(10)}\n </Text>{' '}\n \u2192 <Text color={theme.error}>Error</Text>\n </Text>\n </Box>\n )\n }\n })}\n\n <Text> </Text>\n <Box flexDirection=\"column\">\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>Enter</Text> or <Text bold>C</Text> to configure\n models\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>Esc</Text> to close\n </Text>\n </Box>\n </Box>\n )\n } catch (error) {\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.error}\n paddingX={2}\n paddingY={1}\n >\n <Text bold>\uD83D\uDCCA Model Status Error</Text>\n <Text color={theme.error}>\n Error reading model status: {String(error)}\n </Text>\n <Text> </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n Press <Text bold>Enter</Text> to configure models\n </Text>\n </Box>\n )\n }\n}\n\nconst model: Command = {\n name: 'model',\n description: 'View model status and configure AI provider settings',\n aliases: ['ms', 'modelstatus', 'model-status'],\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n userFacingName() {\n return 'model'\n },\n async call(onDone, context) {\n const { abortController } = context || {}\n return <ModelCommand onClose={onDone} abortController={abortController} />\n },\n}\n\nexport default model\n"],
5
+ "mappings": "AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,gCAAgC;AACzC,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAEhC,SAAS,uBAAuB;AAahC,SAAS,aAAa,EAAE,SAAS,gBAAgB,GAA2B;AAC1E,QAAM,CAAC,MAAM,OAAO,IAAI,SAA8B,QAAQ;AAC9D,QAAM,QAAQ,SAAS;AACvB,QAAM,YAAY,gBAAgB,OAAO;AAIzC;AAAA,IACE,CAAC,OAAO,QAAQ;AACd,UAAI,IAAI,UAAU,UAAU,OAAO,UAAU,KAAK;AAChD,sBAAc;AACd,yBAAiB,QAAQ;AACzB,gBAAQ,QAAQ;AAAA,MAClB,WAAW,IAAI,QAAQ;AACrB,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,EAAE,UAAU,SAAS,SAAS;AAAA,EAChC;AAEA,MAAI,SAAS,UAAU;AACrB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM;AACb,iBAAO,cAAc,EAAE,KAAK,CAAC,EAAE,mBAAmB,MAAM;AACtD,+BAAmB;AACnB,qCAAyB;AAEzB,oBAAQ,QAAQ;AAAA,UAClB,CAAC;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ;AAGA,MAAI;AACF,UAAM,eAAe,gBAAgB;AACrC,UAAM,WAAW,CAAC,QAAQ,QAAQ,aAAa,SAAS,SAAS;AAEjE,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAc;AAAA,QACd,aAAY;AAAA,QACZ,aAAa,MAAM;AAAA,QACnB,UAAU;AAAA,QACV,UAAU;AAAA;AAAA,MAEV,oCAAC,QAAK,MAAI,QAAC,0BACO,KACf,UAAU,UACP,UAAU,UAAU,OAAO,oBAC3B,EACN;AAAA,MACA,oCAAC,YAAK,GAAC;AAAA,MAEN,SAAS,IAAI,aAAW;AACvB,YAAI;AACF,gBAAMA,SAAQ,aAAa,SAAS,OAAO;AAC3C,cAAIA,UAASA,OAAM,QAAQA,OAAM,UAAU;AACzC,mBACE,oCAAC,OAAI,KAAK,WACR,oCAAC,YACC,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,SACrB,QAAQ,YAAY,EAAE,OAAO,EAAE,CAClC,GAAQ,KAAI,WACTA,OAAM,MAAM,KACf,oCAAC,QAAK,OAAO,MAAM,iBAAe,KAC9BA,OAAM,UAAS,MAAGA,OAAM,aAAa,WAAU,GACnD,CACF,CACF;AAAA,UAEJ,OAAO;AACL,mBACE,oCAAC,OAAI,KAAK,WACR,oCAAC,YACC,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,SACrB,QAAQ,YAAY,EAAE,OAAO,EAAE,CAClC,GAAQ,KAAI,WACV,oCAAC,QAAK,OAAO,MAAM,SAAO,gBAAc,CAC5C,CACF;AAAA,UAEJ;AAAA,QACF,QAAQ;AACN,iBACE,oCAAC,OAAI,KAAK,WACR,oCAAC,YACC,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,SACrB,QAAQ,YAAY,EAAE,OAAO,EAAE,CAClC,GAAQ,KAAI,WACV,oCAAC,QAAK,OAAO,MAAM,SAAO,OAAK,CACnC,CACF;AAAA,QAEJ;AAAA,MACF,CAAC;AAAA,MAED,oCAAC,YAAK,GAAC;AAAA,MACP,oCAAC,OAAI,eAAc,YACjB,oCAAC,QAAK,OAAO,gBAAgB,OAAK,UAC1B,oCAAC,QAAK,MAAI,QAAC,OAAK,GAAO,QAAI,oCAAC,QAAK,MAAI,QAAC,GAAC,GAAO,sBAEtD,GACA,oCAAC,QAAK,OAAO,gBAAgB,OAAK,UAC1B,oCAAC,QAAK,MAAI,QAAC,KAAG,GAAO,WAC7B,CACF;AAAA,IACF;AAAA,EAEJ,SAAS,OAAO;AACd,WACE;AAAA,MAAC;AAAA;AAAA,QACC,eAAc;AAAA,QACd,aAAY;AAAA,QACZ,aAAa,MAAM;AAAA,QACnB,UAAU;AAAA,QACV,UAAU;AAAA;AAAA,MAEV,oCAAC,QAAK,MAAI,QAAC,8BAAqB;AAAA,MAChC,oCAAC,QAAK,OAAO,MAAM,SAAO,gCACK,OAAO,KAAK,CAC3C;AAAA,MACA,oCAAC,YAAK,GAAC;AAAA,MACP,oCAAC,QAAK,OAAO,gBAAgB,OAAK,UAC1B,oCAAC,QAAK,MAAI,QAAC,OAAK,GAAO,sBAC/B;AAAA,IACF;AAAA,EAEJ;AACF;AAEA,MAAM,QAAiB;AAAA,EACrB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,SAAS,CAAC,MAAM,eAAe,cAAc;AAAA,EAC7C,WAAW;AAAA,EACX,UAAU;AAAA,EACV,MAAM;AAAA,EACN,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,KAAK,QAAQ,SAAS;AAC1B,UAAM,EAAE,gBAAgB,IAAI,WAAW,CAAC;AACxC,WAAO,oCAAC,gBAAa,SAAS,QAAQ,iBAAkC;AAAA,EAC1E;AACF;AAEA,IAAO,gBAAQ;",
6
6
  "names": ["model"]
7
7
  }
@@ -3,6 +3,7 @@ import { Box, Text, useInput } from "ink";
3
3
  import {
4
4
  getPermissionRuleEngine
5
5
  } from "../core/permissions/index.js";
6
+ import { SEMANTIC_COLORS } from "../constants/colors.js";
6
7
  const PermissionList = ({
7
8
  rules,
8
9
  defaultDecision,
@@ -42,10 +43,10 @@ const PermissionList = ({
42
43
  };
43
44
  const renderRule = (rule, index) => {
44
45
  const isSelected = index === selectedIndex;
45
- return /* @__PURE__ */ React.createElement(Box, { key: rule.id, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u25B6 " : " ", /* @__PURE__ */ React.createElement(Text, { color: getDecisionColor(rule.decision) }, formatDecision(rule.decision).padEnd(10)), /* @__PURE__ */ React.createElement(Text, { bold: true }, rule.pattern.padEnd(30)), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "P", rule.priority), rule.description && /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " - ", rule.description)));
46
+ return /* @__PURE__ */ React.createElement(Box, { key: rule.id, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? "cyan" : void 0 }, isSelected ? "\u25B6 " : " ", /* @__PURE__ */ React.createElement(Text, { color: getDecisionColor(rule.decision) }, formatDecision(rule.decision).padEnd(10)), /* @__PURE__ */ React.createElement(Text, { bold: true }, rule.pattern.padEnd(30)), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "P", rule.priority), rule.description && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " - ", rule.description)));
46
47
  };
47
48
  let displayIndex = 0;
48
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Permission Rules")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Default decision: "), /* @__PURE__ */ React.createElement(Text, { color: getDecisionColor(defaultDecision), bold: true }, formatDecision(defaultDecision)))), projectRules.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "blue" }, "Project Rules (", projectRules.length, ")")), projectRules.map((rule) => {
49
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Permission Rules")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Default decision: "), /* @__PURE__ */ React.createElement(Text, { color: getDecisionColor(defaultDecision), bold: true }, formatDecision(defaultDecision)))), projectRules.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "blue" }, "Project Rules (", projectRules.length, ")")), projectRules.map((rule) => {
49
50
  const result = renderRule(rule, displayIndex);
50
51
  displayIndex++;
51
52
  return result;
@@ -53,7 +54,7 @@ const PermissionList = ({
53
54
  const result = renderRule(rule, displayIndex);
54
55
  displayIndex++;
55
56
  return result;
56
- })), rules.length === 0 && /* @__PURE__ */ React.createElement(Box, { paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "No custom rules defined. Using default rules.")), /* @__PURE__ */ React.createElement(Box, { marginTop: 2 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2191/\u2193: Navigate | q/Esc: Exit")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Legend: ", /* @__PURE__ */ React.createElement(Text, { color: "green" }, "ALLOW"), " = auto-approve,", " ", /* @__PURE__ */ React.createElement(Text, { color: "red" }, "DENY"), " = block, ", /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "ASK"), " ", "= prompt user")));
57
+ })), rules.length === 0 && /* @__PURE__ */ React.createElement(Box, { paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "No custom rules defined. Using default rules.")), /* @__PURE__ */ React.createElement(Box, { marginTop: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\u2191/\u2193: Navigate | q/Esc: Exit")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Legend: ", /* @__PURE__ */ React.createElement(Text, { color: "green" }, "ALLOW"), " = auto-approve,", " ", /* @__PURE__ */ React.createElement(Text, { color: "red" }, "DENY"), " = block, ", /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, "ASK"), " ", "= prompt user")));
57
58
  };
58
59
  const command = {
59
60
  name: "permissions",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/permissions.tsx"],
4
- "sourcesContent": ["/**\n * Permissions Command\n *\n * View and manage permission rules for tool access.\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport type { Command } from '@commands'\nimport {\n getPermissionRuleEngine,\n type PatternPermissionRule,\n type RulePermissionDecision,\n} from '../core/permissions'\n\ninterface PermissionListProps {\n rules: PatternPermissionRule[]\n defaultDecision: RulePermissionDecision\n onDone: (result?: string) => void\n}\n\nconst PermissionList = ({\n rules,\n defaultDecision,\n onDone,\n}: PermissionListProps) => {\n const [selectedIndex, setSelectedIndex] = useState(0)\n\n useInput((input, key) => {\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1))\n } else if (key.downArrow) {\n setSelectedIndex(Math.min(rules.length - 1, selectedIndex + 1))\n } else if (input === 'q' || key.escape) {\n onDone()\n }\n })\n\n // Group rules by scope\n const globalRules = rules.filter(r => r.scope === 'global')\n const projectRules = rules.filter(r => r.scope === 'project')\n\n const getDecisionColor = (decision: RulePermissionDecision) => {\n switch (decision) {\n case 'allow':\n return 'green'\n case 'deny':\n return 'red'\n case 'ask':\n return 'yellow'\n }\n }\n\n const formatDecision = (decision: RulePermissionDecision) => {\n switch (decision) {\n case 'allow':\n return '\u2713 ALLOW'\n case 'deny':\n return '\u2717 DENY'\n case 'ask':\n return '? ASK'\n }\n }\n\n const renderRule = (rule: PatternPermissionRule, index: number) => {\n const isSelected = index === selectedIndex\n return (\n <Box key={rule.id} paddingLeft={1}>\n <Text color={isSelected ? 'cyan' : undefined}>\n {isSelected ? '\u25B6 ' : ' '}\n <Text color={getDecisionColor(rule.decision)}>\n {formatDecision(rule.decision).padEnd(10)}\n </Text>\n <Text bold>{rule.pattern.padEnd(30)}</Text>\n <Text dimColor>P{rule.priority}</Text>\n {rule.description && <Text dimColor> - {rule.description}</Text>}\n </Text>\n </Box>\n )\n }\n\n let displayIndex = 0\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold>Permission Rules</Text>\n </Box>\n\n {/* Default decision */}\n <Box marginBottom={1}>\n <Text>\n <Text dimColor>Default decision: </Text>\n <Text color={getDecisionColor(defaultDecision)} bold>\n {formatDecision(defaultDecision)}\n </Text>\n </Text>\n </Box>\n\n {/* Project rules */}\n {projectRules.length > 0 && (\n <>\n <Box marginTop={1}>\n <Text bold color=\"blue\">\n Project Rules ({projectRules.length})\n </Text>\n </Box>\n {projectRules.map(rule => {\n const result = renderRule(rule, displayIndex)\n displayIndex++\n return result\n })}\n </>\n )}\n\n {/* Global rules */}\n {globalRules.length > 0 && (\n <>\n <Box marginTop={1}>\n <Text bold color=\"magenta\">\n Global Rules ({globalRules.length})\n </Text>\n </Box>\n {globalRules.map(rule => {\n const result = renderRule(rule, displayIndex)\n displayIndex++\n return result\n })}\n </>\n )}\n\n {rules.length === 0 && (\n <Box paddingLeft={1}>\n <Text dimColor>No custom rules defined. Using default rules.</Text>\n </Box>\n )}\n\n {/* Help */}\n <Box marginTop={2}>\n <Text dimColor>\u2191/\u2193: Navigate | q/Esc: Exit</Text>\n </Box>\n\n {/* Legend */}\n <Box marginTop={1}>\n <Text dimColor>\n Legend: <Text color=\"green\">ALLOW</Text> = auto-approve,{' '}\n <Text color=\"red\">DENY</Text> = block, <Text color=\"yellow\">ASK</Text>{' '}\n = prompt user\n </Text>\n </Box>\n </Box>\n )\n}\n\nconst command: Command = {\n name: 'permissions',\n description: 'View and manage permission rules for tool access',\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n aliases: ['perms'],\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone, _context) {\n const engine = getPermissionRuleEngine()\n const rules = engine.getRules()\n const defaultDecision = engine.getDefaultDecision()\n\n return (\n <PermissionList\n rules={rules}\n defaultDecision={defaultDecision}\n onDone={onDone}\n />\n )\n },\n}\n\nexport default command\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Permissions Command\n *\n * View and manage permission rules for tool access.\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport type { Command } from '@commands'\nimport {\n getPermissionRuleEngine,\n type PatternPermissionRule,\n type RulePermissionDecision,\n} from '../core/permissions'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ninterface PermissionListProps {\n rules: PatternPermissionRule[]\n defaultDecision: RulePermissionDecision\n onDone: (result?: string) => void\n}\n\nconst PermissionList = ({\n rules,\n defaultDecision,\n onDone,\n}: PermissionListProps) => {\n const [selectedIndex, setSelectedIndex] = useState(0)\n\n useInput((input, key) => {\n if (key.upArrow) {\n setSelectedIndex(Math.max(0, selectedIndex - 1))\n } else if (key.downArrow) {\n setSelectedIndex(Math.min(rules.length - 1, selectedIndex + 1))\n } else if (input === 'q' || key.escape) {\n onDone()\n }\n })\n\n // Group rules by scope\n const globalRules = rules.filter(r => r.scope === 'global')\n const projectRules = rules.filter(r => r.scope === 'project')\n\n const getDecisionColor = (decision: RulePermissionDecision) => {\n switch (decision) {\n case 'allow':\n return 'green'\n case 'deny':\n return 'red'\n case 'ask':\n return 'yellow'\n }\n }\n\n const formatDecision = (decision: RulePermissionDecision) => {\n switch (decision) {\n case 'allow':\n return '\u2713 ALLOW'\n case 'deny':\n return '\u2717 DENY'\n case 'ask':\n return '? ASK'\n }\n }\n\n const renderRule = (rule: PatternPermissionRule, index: number) => {\n const isSelected = index === selectedIndex\n return (\n <Box key={rule.id} paddingLeft={1}>\n <Text color={isSelected ? 'cyan' : undefined}>\n {isSelected ? '\u25B6 ' : ' '}\n <Text color={getDecisionColor(rule.decision)}>\n {formatDecision(rule.decision).padEnd(10)}\n </Text>\n <Text bold>{rule.pattern.padEnd(30)}</Text>\n <Text color={SEMANTIC_COLORS.dim}>P{rule.priority}</Text>\n {rule.description && (\n <Text color={SEMANTIC_COLORS.dim}> - {rule.description}</Text>\n )}\n </Text>\n </Box>\n )\n }\n\n let displayIndex = 0\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold>Permission Rules</Text>\n </Box>\n\n {/* Default decision */}\n <Box marginBottom={1}>\n <Text>\n <Text color={SEMANTIC_COLORS.dim}>Default decision: </Text>\n <Text color={getDecisionColor(defaultDecision)} bold>\n {formatDecision(defaultDecision)}\n </Text>\n </Text>\n </Box>\n\n {/* Project rules */}\n {projectRules.length > 0 && (\n <>\n <Box marginTop={1}>\n <Text bold color=\"blue\">\n Project Rules ({projectRules.length})\n </Text>\n </Box>\n {projectRules.map(rule => {\n const result = renderRule(rule, displayIndex)\n displayIndex++\n return result\n })}\n </>\n )}\n\n {/* Global rules */}\n {globalRules.length > 0 && (\n <>\n <Box marginTop={1}>\n <Text bold color=\"magenta\">\n Global Rules ({globalRules.length})\n </Text>\n </Box>\n {globalRules.map(rule => {\n const result = renderRule(rule, displayIndex)\n displayIndex++\n return result\n })}\n </>\n )}\n\n {rules.length === 0 && (\n <Box paddingLeft={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n No custom rules defined. Using default rules.\n </Text>\n </Box>\n )}\n\n {/* Help */}\n <Box marginTop={2}>\n <Text color={SEMANTIC_COLORS.dim}>\u2191/\u2193: Navigate | q/Esc: Exit</Text>\n </Box>\n\n {/* Legend */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n Legend: <Text color=\"green\">ALLOW</Text> = auto-approve,{' '}\n <Text color=\"red\">DENY</Text> = block, <Text color=\"yellow\">ASK</Text>{' '}\n = prompt user\n </Text>\n </Box>\n </Box>\n )\n}\n\nconst command: Command = {\n name: 'permissions',\n description: 'View and manage permission rules for tool access',\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n aliases: ['perms'],\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone, _context) {\n const engine = getPermissionRuleEngine()\n const rules = engine.getRules()\n const defaultDecision = engine.getDefaultDecision()\n\n return (\n <PermissionList\n rules={rules}\n defaultDecision={defaultDecision}\n onDone={onDone}\n />\n )\n },\n}\n\nexport default command\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,6 +5,7 @@ import TextInput from "../../components/TextInput.js";
5
5
  import { addMarketplace } from "../../utils/marketplaceManager.js";
6
6
  import { MarketplaceError } from "../../types/marketplace.js";
7
7
  import { getTheme } from "../../utils/theme.js";
8
+ import { SEMANTIC_COLORS } from "../../constants/colors.js";
8
9
  const AddMarketplaceForm = ({
9
10
  onNavigate,
10
11
  onBack
@@ -55,7 +56,7 @@ const AddMarketplaceForm = ({
55
56
  padding: 1
56
57
  },
57
58
  /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.primary }, "Add Marketplace"),
58
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Enter marketplace source:"), /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Examples:"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2022 owner/repo (GitHub shorthand)"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2022 git@github.com:owner/repo.git (SSH URL)"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2022 https://github.com/owner/repo.git (HTTPS URL)"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2022 ./path/to/local/marketplace (Local path)"))),
59
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Enter marketplace source:"), /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "Examples:"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "\u2022 owner/repo (GitHub shorthand)"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "\u2022 git@github.com:owner/repo.git (SSH URL)"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "\u2022 https://github.com/owner/repo.git (HTTPS URL)"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "\u2022 ./path/to/local/marketplace (Local path)"))),
59
60
  /* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: theme.success }, "Source: "), /* @__PURE__ */ React.createElement(
60
61
  TextInput,
61
62
  {
@@ -81,7 +82,7 @@ const AddMarketplaceForm = ({
81
82
  /* @__PURE__ */ React.createElement(Text, { color: theme.error }, "\u2717 ", error)
82
83
  ),
83
84
  adding && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: theme.primary }, " Adding marketplace...")),
84
- !adding && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, /* @__PURE__ */ React.createElement(Text, { color: theme.success }, "Enter"), " to add \xB7", " ", /* @__PURE__ */ React.createElement(Text, { color: theme.error }, "Esc"), " to cancel"))
85
+ !adding && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, /* @__PURE__ */ React.createElement(Text, { color: theme.success }, "Enter"), " to add \xB7", " ", /* @__PURE__ */ React.createElement(Text, { color: theme.error }, "Esc"), " to cancel"))
85
86
  );
86
87
  };
87
88
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/commands/plugin/AddMarketplaceForm.tsx"],
4
- "sourcesContent": ["/**\n * AddMarketplaceForm Component\n *\n * Interactive form for adding new plugin marketplaces\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { SimpleSpinner } from '@components/Spinner'\nimport TextInput from '@components/TextInput'\nimport { addMarketplace } from '@utils/marketplaceManager'\nimport { MarketplaceError } from '../../types/marketplace'\nimport { getTheme } from '@utils/theme'\n\nexport interface NavigationProps {\n onNavigate: (params: { screen: string; [key: string]: any }) => void\n onBack: () => void\n}\n\nexport const AddMarketplaceForm: React.FC<NavigationProps> = ({\n onNavigate,\n onBack,\n}) => {\n const [source, setSource] = useState('')\n const [adding, setAdding] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [cursorOffset, setCursorOffset] = useState(0)\n const theme = getTheme()\n\n const handleSubmit = async () => {\n if (!source.trim()) {\n setError('Source cannot be empty')\n return\n }\n\n setAdding(true)\n setError(null)\n\n try {\n const marketplace = await addMarketplace(source)\n // Success - navigate back to marketplace manager\n onBack()\n } catch (err) {\n if (err instanceof MarketplaceError) {\n setError(err.message)\n } else {\n setError(\n err instanceof Error ? err.message : 'Failed to add marketplace',\n )\n }\n } finally {\n setAdding(false)\n }\n }\n\n useInput(\n (input, key) => {\n if (key.escape && !adding) {\n onBack()\n } else if (key.return && !adding) {\n handleSubmit()\n }\n },\n { isActive: !adding },\n )\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Text bold color={theme.primary}>\n Add Marketplace\n </Text>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Text>Enter marketplace source:</Text>\n <Box marginTop={1} flexDirection=\"column\" marginLeft={2}>\n <Text dimColor>Examples:</Text>\n <Text dimColor> \u2022 owner/repo (GitHub shorthand)</Text>\n <Text dimColor> \u2022 git@github.com:owner/repo.git (SSH URL)</Text>\n <Text dimColor> \u2022 https://github.com/owner/repo.git (HTTPS URL)</Text>\n <Text dimColor> \u2022 ./path/to/local/marketplace (Local path)</Text>\n </Box>\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Box>\n <Text color={theme.success}>Source: </Text>\n <TextInput\n value={source}\n onChange={setSource}\n placeholder=\"Enter source...\"\n focus={!adding}\n showCursor={!adding}\n isDimmed={adding}\n columns={60}\n cursorOffset={cursorOffset}\n onChangeCursorOffset={setCursorOffset}\n />\n </Box>\n </Box>\n\n {error && (\n <Box\n marginTop={1}\n borderStyle=\"round\"\n borderColor={theme.error}\n padding={1}\n >\n <Text color={theme.error}>\u2717 {error}</Text>\n </Box>\n )}\n\n {adding && (\n <Box marginTop={1}>\n <SimpleSpinner />\n <Text color={theme.primary}> Adding marketplace...</Text>\n </Box>\n )}\n\n {!adding && (\n <Box marginTop={1}>\n <Text dimColor>\n <Text color={theme.success}>Enter</Text> to add \u00B7{' '}\n <Text color={theme.error}>Esc</Text> to cancel\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * AddMarketplaceForm Component\n *\n * Interactive form for adding new plugin marketplaces\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { SimpleSpinner } from '@components/Spinner'\nimport TextInput from '@components/TextInput'\nimport { addMarketplace } from '@utils/marketplaceManager'\nimport { MarketplaceError } from '../../types/marketplace'\nimport { getTheme } from '@utils/theme'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nexport interface NavigationProps {\n onNavigate: (params: { screen: string; [key: string]: any }) => void\n onBack: () => void\n}\n\nexport const AddMarketplaceForm: React.FC<NavigationProps> = ({\n onNavigate,\n onBack,\n}) => {\n const [source, setSource] = useState('')\n const [adding, setAdding] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [cursorOffset, setCursorOffset] = useState(0)\n const theme = getTheme()\n\n const handleSubmit = async () => {\n if (!source.trim()) {\n setError('Source cannot be empty')\n return\n }\n\n setAdding(true)\n setError(null)\n\n try {\n const marketplace = await addMarketplace(source)\n // Success - navigate back to marketplace manager\n onBack()\n } catch (err) {\n if (err instanceof MarketplaceError) {\n setError(err.message)\n } else {\n setError(\n err instanceof Error ? err.message : 'Failed to add marketplace',\n )\n }\n } finally {\n setAdding(false)\n }\n }\n\n useInput(\n (input, key) => {\n if (key.escape && !adding) {\n onBack()\n } else if (key.return && !adding) {\n handleSubmit()\n }\n },\n { isActive: !adding },\n )\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={theme.primary}\n padding={1}\n >\n <Text bold color={theme.primary}>\n Add Marketplace\n </Text>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Text>Enter marketplace source:</Text>\n <Box marginTop={1} flexDirection=\"column\" marginLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>Examples:</Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n \u2022 owner/repo (GitHub shorthand)\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n \u2022 git@github.com:owner/repo.git (SSH URL)\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n \u2022 https://github.com/owner/repo.git (HTTPS URL)\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n \u2022 ./path/to/local/marketplace (Local path)\n </Text>\n </Box>\n </Box>\n\n <Box marginTop={1} flexDirection=\"column\">\n <Box>\n <Text color={theme.success}>Source: </Text>\n <TextInput\n value={source}\n onChange={setSource}\n placeholder=\"Enter source...\"\n focus={!adding}\n showCursor={!adding}\n isDimmed={adding}\n columns={60}\n cursorOffset={cursorOffset}\n onChangeCursorOffset={setCursorOffset}\n />\n </Box>\n </Box>\n\n {error && (\n <Box\n marginTop={1}\n borderStyle=\"round\"\n borderColor={theme.error}\n padding={1}\n >\n <Text color={theme.error}>\u2717 {error}</Text>\n </Box>\n )}\n\n {adding && (\n <Box marginTop={1}>\n <SimpleSpinner />\n <Text color={theme.primary}> Adding marketplace...</Text>\n </Box>\n )}\n\n {!adding && (\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n <Text color={theme.success}>Enter</Text> to add \u00B7{' '}\n <Text color={theme.error}>Esc</Text> to cancel\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { getTheme } from "../../utils/theme.js";
4
+ import { SEMANTIC_COLORS } from "../../constants/colors.js";
4
5
  const ConfirmDialog = ({
5
6
  title,
6
7
  message,
@@ -74,7 +75,7 @@ const ConfirmDialog = ({
74
75
  cancelText
75
76
  )
76
77
  )),
77
- /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2190 \u2192 navigate \xB7 ", /* @__PURE__ */ React.createElement(Text, { color: theme.success }, "Enter"), " confirm \xB7", " ", /* @__PURE__ */ React.createElement(Text, { color: theme.error }, "Esc"), " cancel"))
78
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\u2190 \u2192 navigate \xB7 ", /* @__PURE__ */ React.createElement(Text, { color: theme.success }, "Enter"), " confirm \xB7", " ", /* @__PURE__ */ React.createElement(Text, { color: theme.error }, "Esc"), " cancel"))
78
79
  );
79
80
  };
80
81
  export {