@within-7/minto 0.3.6 → 0.3.10

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 (238) hide show
  1. package/{cli.js → cli.cjs} +25 -23
  2. package/dist/commands/agents/AgentsCommand.js +459 -655
  3. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  4. package/dist/commands/agents/types.js +1 -0
  5. package/dist/commands/agents/types.js.map +2 -2
  6. package/dist/commands/agents/utils/fileOperations.js +96 -36
  7. package/dist/commands/agents/utils/fileOperations.js.map +3 -3
  8. package/dist/commands/agents/utils/index.js +3 -1
  9. package/dist/commands/agents/utils/index.js.map +2 -2
  10. package/dist/commands/context.js +54 -23
  11. package/dist/commands/context.js.map +2 -2
  12. package/dist/commands/export.js +673 -93
  13. package/dist/commands/export.js.map +2 -2
  14. package/dist/commands/language.js +110 -0
  15. package/dist/commands/language.js.map +7 -0
  16. package/dist/commands/mcp-interactive.js +419 -217
  17. package/dist/commands/mcp-interactive.js.map +2 -2
  18. package/dist/commands/model.js +415 -66
  19. package/dist/commands/model.js.map +2 -2
  20. package/dist/commands/new.js +56 -0
  21. package/dist/commands/new.js.map +7 -0
  22. package/dist/commands/permissions.js +75 -49
  23. package/dist/commands/permissions.js.map +2 -2
  24. package/dist/commands/plugin.js +882 -185
  25. package/dist/commands/plugin.js.map +3 -3
  26. package/dist/commands/resume.js +251 -16
  27. package/dist/commands/resume.js.map +2 -2
  28. package/dist/commands/sandbox.js +168 -70
  29. package/dist/commands/sandbox.js.map +2 -2
  30. package/dist/commands/sessions.js +224 -0
  31. package/dist/commands/sessions.js.map +7 -0
  32. package/dist/commands/setup.js +596 -109
  33. package/dist/commands/setup.js.map +2 -2
  34. package/dist/commands/stats.js +292 -0
  35. package/dist/commands/stats.js.map +7 -0
  36. package/dist/commands/status.js +75 -7
  37. package/dist/commands/status.js.map +2 -2
  38. package/dist/commands/undo.js +154 -180
  39. package/dist/commands/undo.js.map +2 -2
  40. package/dist/commands.js +6 -0
  41. package/dist/commands.js.map +2 -2
  42. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
  43. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  44. package/dist/components/Config.js +9 -8
  45. package/dist/components/Config.js.map +2 -2
  46. package/dist/components/HeaderBar.js +2 -1
  47. package/dist/components/HeaderBar.js.map +2 -2
  48. package/dist/components/Help.js +166 -32
  49. package/dist/components/Help.js.map +2 -2
  50. package/dist/components/HotkeyHelpPanel.js +46 -44
  51. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  52. package/dist/components/InfoPanel/InfoPanel.js +123 -0
  53. package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
  54. package/dist/components/InfoPanel/index.js +5 -0
  55. package/dist/components/InfoPanel/index.js.map +7 -0
  56. package/dist/components/InfoPanel/types.js +1 -0
  57. package/dist/components/InfoPanel/types.js.map +7 -0
  58. package/dist/components/Logo.js +5 -2
  59. package/dist/components/Logo.js.map +2 -2
  60. package/dist/components/MCPServerApprovalDialog.js +6 -5
  61. package/dist/components/MCPServerApprovalDialog.js.map +2 -2
  62. package/dist/components/MCPServerMultiselectDialog.js +5 -4
  63. package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
  64. package/dist/components/MessageSelector.js +4 -3
  65. package/dist/components/MessageSelector.js.map +2 -2
  66. package/dist/components/ModelConfig.js +13 -12
  67. package/dist/components/ModelConfig.js.map +2 -2
  68. package/dist/components/ModelListManager.js +4 -3
  69. package/dist/components/ModelListManager.js.map +2 -2
  70. package/dist/components/ModelSelector/BrandTextInput.js +43 -0
  71. package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
  72. package/dist/components/ModelSelector/ModelSelector.js +419 -501
  73. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  74. package/dist/components/ModelSelector/WizardContainer.js +45 -0
  75. package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
  76. package/dist/components/ModelSelector/index.js +1 -3
  77. package/dist/components/ModelSelector/index.js.map +2 -2
  78. package/dist/components/PromptInput.js +77 -44
  79. package/dist/components/PromptInput.js.map +2 -2
  80. package/dist/components/SensitiveFileWarning.js +12 -8
  81. package/dist/components/SensitiveFileWarning.js.map +2 -2
  82. package/dist/components/SimpleSelector/SimpleSelector.js +154 -0
  83. package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
  84. package/dist/components/SimpleSelector/index.js +5 -0
  85. package/dist/components/SimpleSelector/index.js.map +7 -0
  86. package/dist/components/SimpleSelector/types.js +1 -0
  87. package/dist/components/SimpleSelector/types.js.map +7 -0
  88. package/dist/components/StatusOverlayContent.js +21 -0
  89. package/dist/components/StatusOverlayContent.js.map +7 -0
  90. package/dist/components/TabbedListView/ScrollableList.js +117 -0
  91. package/dist/components/TabbedListView/ScrollableList.js.map +7 -0
  92. package/dist/components/TabbedListView/SearchInput.js +23 -0
  93. package/dist/components/TabbedListView/SearchInput.js.map +7 -0
  94. package/dist/components/TabbedListView/TabBar.js +20 -0
  95. package/dist/components/TabbedListView/TabBar.js.map +7 -0
  96. package/dist/components/TabbedListView/TabbedListView.js +246 -0
  97. package/dist/components/TabbedListView/TabbedListView.js.map +7 -0
  98. package/dist/components/TabbedListView/index.js +11 -0
  99. package/dist/components/TabbedListView/index.js.map +7 -0
  100. package/dist/components/TabbedListView/types.js +1 -0
  101. package/dist/components/TabbedListView/types.js.map +7 -0
  102. package/dist/components/TodoChangeBlock.js +6 -5
  103. package/dist/components/TodoChangeBlock.js.map +3 -3
  104. package/dist/components/TodoPanel.js +6 -3
  105. package/dist/components/TodoPanel.js.map +3 -3
  106. package/dist/components/TrustDialog.js +6 -5
  107. package/dist/components/TrustDialog.js.map +2 -2
  108. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +2 -1
  109. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js.map +2 -2
  110. package/dist/constants/macros.js +1 -1
  111. package/dist/constants/macros.js.map +1 -1
  112. package/dist/constants/product.js +2 -2
  113. package/dist/constants/product.js.map +1 -1
  114. package/dist/constants/prompts.js +17 -0
  115. package/dist/constants/prompts.js.map +2 -2
  116. package/dist/constants/toolInputExamples.js +5 -1
  117. package/dist/constants/toolInputExamples.js.map +2 -2
  118. package/dist/core/backupHook.js +29 -0
  119. package/dist/core/backupHook.js.map +7 -0
  120. package/dist/core/config/defaults.js +8 -2
  121. package/dist/core/config/defaults.js.map +2 -2
  122. package/dist/core/config/schema.js +14 -2
  123. package/dist/core/config/schema.js.map +2 -2
  124. package/dist/core/costTracker.js +0 -16
  125. package/dist/core/costTracker.js.map +2 -2
  126. package/dist/core/tokenStatsManager.js +5 -0
  127. package/dist/core/tokenStatsManager.js.map +2 -2
  128. package/dist/cost-tracker.js +0 -16
  129. package/dist/cost-tracker.js.map +2 -2
  130. package/dist/entrypoints/bootstrap.js +56 -0
  131. package/dist/entrypoints/bootstrap.js.map +7 -0
  132. package/dist/entrypoints/cli.js +164 -23
  133. package/dist/entrypoints/cli.js.map +3 -3
  134. package/dist/history.js +75 -15
  135. package/dist/history.js.map +2 -2
  136. package/dist/i18n/index.js +2 -2
  137. package/dist/i18n/index.js.map +2 -2
  138. package/dist/i18n/locales/en.js +582 -1
  139. package/dist/i18n/locales/en.js.map +2 -2
  140. package/dist/i18n/locales/zh-CN.js +582 -1
  141. package/dist/i18n/locales/zh-CN.js.map +2 -2
  142. package/dist/i18n/types.js.map +1 -1
  143. package/dist/index.js +1 -1
  144. package/dist/index.js.map +2 -2
  145. package/dist/messages.js +11 -0
  146. package/dist/messages.js.map +2 -2
  147. package/dist/permissions.js.map +2 -2
  148. package/dist/query.js +9 -0
  149. package/dist/query.js.map +2 -2
  150. package/dist/screens/REPL.js +45 -7
  151. package/dist/screens/REPL.js.map +2 -2
  152. package/dist/services/customCommands.js +44 -16
  153. package/dist/services/customCommands.js.map +2 -2
  154. package/dist/services/plugins/lspServers.js +1 -1
  155. package/dist/services/plugins/lspServers.js.map +2 -2
  156. package/dist/services/plugins/pluginRuntime.js +2 -1
  157. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  158. package/dist/services/plugins/pluginValidation.js +10 -3
  159. package/dist/services/plugins/pluginValidation.js.map +2 -2
  160. package/dist/services/plugins/skillMarketplace.js +16 -8
  161. package/dist/services/plugins/skillMarketplace.js.map +2 -2
  162. package/dist/services/systemReminder.js +17 -6
  163. package/dist/services/systemReminder.js.map +2 -2
  164. package/dist/tools/FileEditTool/FileEditTool.js +7 -0
  165. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  166. package/dist/tools/FileWriteTool/FileWriteTool.js +7 -0
  167. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  168. package/dist/tools/MultiEditTool/MultiEditTool.js +7 -0
  169. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  170. package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
  171. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  172. package/dist/tools/TaskTool/TaskTool.js +179 -1
  173. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  174. package/dist/tools/TodoWriteTool/prompt.js +21 -0
  175. package/dist/tools/TodoWriteTool/prompt.js.map +2 -2
  176. package/dist/tools/URLFetcherTool/prompt.js +14 -9
  177. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  178. package/dist/tools/WebSearchTool/prompt.js +12 -6
  179. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  180. package/dist/types/PermissionMode.js +30 -1
  181. package/dist/types/PermissionMode.js.map +2 -2
  182. package/dist/types/plugin.js +2 -4
  183. package/dist/types/plugin.js.map +2 -2
  184. package/dist/utils/agentHookExecutor.js +103 -0
  185. package/dist/utils/agentHookExecutor.js.map +7 -0
  186. package/dist/utils/agentLoader.js +272 -32
  187. package/dist/utils/agentLoader.js.map +2 -2
  188. package/dist/utils/agentMemory.js +134 -0
  189. package/dist/utils/agentMemory.js.map +7 -0
  190. package/dist/utils/claudeCodeSync.js +439 -0
  191. package/dist/utils/claudeCodeSync.js.map +7 -0
  192. package/dist/utils/config.js +52 -24
  193. package/dist/utils/config.js.map +2 -2
  194. package/dist/utils/configPaths.js +199 -0
  195. package/dist/utils/configPaths.js.map +7 -0
  196. package/dist/utils/execFileNoThrow.js +2 -1
  197. package/dist/utils/execFileNoThrow.js.map +2 -2
  198. package/dist/utils/historyManager.js +234 -0
  199. package/dist/utils/historyManager.js.map +7 -0
  200. package/dist/utils/marketplaceManager.js +80 -43
  201. package/dist/utils/marketplaceManager.js.map +2 -2
  202. package/dist/utils/messages.js +13 -8
  203. package/dist/utils/messages.js.map +2 -2
  204. package/dist/utils/migration/index.js +37 -0
  205. package/dist/utils/migration/index.js.map +7 -0
  206. package/dist/utils/migration/migrateHistory.js +273 -0
  207. package/dist/utils/migration/migrateHistory.js.map +7 -0
  208. package/dist/utils/migration/migrateTodos.js +323 -0
  209. package/dist/utils/migration/migrateTodos.js.map +7 -0
  210. package/dist/utils/pasteCache.js +309 -0
  211. package/dist/utils/pasteCache.js.map +7 -0
  212. package/dist/utils/pluginInstaller.js +34 -24
  213. package/dist/utils/pluginInstaller.js.map +2 -2
  214. package/dist/utils/pluginLoader.js +54 -28
  215. package/dist/utils/pluginLoader.js.map +2 -2
  216. package/dist/utils/repoFetcher.js +110 -0
  217. package/dist/utils/repoFetcher.js.map +7 -0
  218. package/dist/utils/sessionIndex.js +192 -0
  219. package/dist/utils/sessionIndex.js.map +7 -0
  220. package/dist/utils/sessionTracker.js +170 -0
  221. package/dist/utils/sessionTracker.js.map +7 -0
  222. package/dist/utils/skillLoader.js +103 -5
  223. package/dist/utils/skillLoader.js.map +2 -2
  224. package/dist/utils/stats.js +417 -0
  225. package/dist/utils/stats.js.map +7 -0
  226. package/dist/utils/stringSubstitution.js +106 -0
  227. package/dist/utils/stringSubstitution.js.map +7 -0
  228. package/dist/utils/teamConfig.js +156 -14
  229. package/dist/utils/teamConfig.js.map +2 -2
  230. package/dist/utils/terminal.js +1 -1
  231. package/dist/utils/terminal.js.map +2 -2
  232. package/dist/utils/todoStorage.js +51 -19
  233. package/dist/utils/todoStorage.js.map +2 -2
  234. package/dist/utils/tooling/safeRender.js.map +2 -2
  235. package/dist/version.js +2 -2
  236. package/dist/version.js.map +1 -1
  237. package/package.json +71 -28
  238. package/scripts/{postinstall.js → postinstall.cjs} +1 -1
@@ -1,99 +1,17 @@
1
- import React, { useState } from "react";
2
- import { Box, Text, useInput } from "ink";
3
- import { writeFile } from "fs/promises";
1
+ import React, { useState, useCallback, useMemo } from "react";
2
+ import { writeFile, readFile } from "fs/promises";
3
+ import { existsSync, readdirSync } from "fs";
4
4
  import { join } from "path";
5
+ import { homedir } from "os";
5
6
  import { getMessagesGetter } from "../messages.js";
6
7
  import { getCwd } from "../utils/state.js";
7
8
  import { loadGlobalConfig, loadProjectConfig } from "../core/config/index.js";
8
- import { SEMANTIC_COLORS } from "../constants/colors.js";
9
- const EXPORT_OPTIONS = [
10
- {
11
- type: "conversation",
12
- label: "Conversation",
13
- description: "Export full conversation history as JSON"
14
- },
15
- {
16
- type: "config",
17
- label: "Configuration",
18
- description: "Export current configuration settings"
19
- },
20
- {
21
- type: "summary",
22
- label: "Summary",
23
- description: "Export a markdown summary of the session"
24
- }
25
- ];
26
- const ExportMenu = ({ onDone }) => {
27
- const [selectedIndex, setSelectedIndex] = useState(0);
28
- const [exporting, setExporting] = useState(false);
29
- const [result, setResult] = useState(null);
30
- useInput(async (input, key) => {
31
- if (exporting) return;
32
- if (key.upArrow) {
33
- setSelectedIndex(Math.max(0, selectedIndex - 1));
34
- } else if (key.downArrow) {
35
- setSelectedIndex(Math.min(EXPORT_OPTIONS.length - 1, selectedIndex + 1));
36
- } else if (key.return) {
37
- await handleExport(EXPORT_OPTIONS[selectedIndex].type);
38
- } else if (input === "q" || key.escape) {
39
- onDone();
40
- }
41
- });
42
- const handleExport = async (type) => {
43
- setExporting(true);
44
- try {
45
- const cwd = getCwd();
46
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
47
- let filename;
48
- let content;
49
- switch (type) {
50
- case "conversation": {
51
- const messages = getMessagesGetter()();
52
- filename = `minto-conversation-${timestamp}.json`;
53
- content = JSON.stringify(messages, null, 2);
54
- break;
55
- }
56
- case "config": {
57
- const [globalConfig, projectConfig] = await Promise.all([
58
- Promise.resolve(loadGlobalConfig()),
59
- Promise.resolve(loadProjectConfig(cwd))
60
- ]);
61
- filename = `minto-config-${timestamp}.json`;
62
- content = JSON.stringify(
63
- {
64
- global: globalConfig,
65
- project: projectConfig
66
- },
67
- null,
68
- 2
69
- );
70
- break;
71
- }
72
- case "summary": {
73
- const messages = getMessagesGetter()();
74
- filename = `minto-summary-${timestamp}.md`;
75
- content = generateSummary(messages);
76
- break;
77
- }
78
- }
79
- const filepath = join(cwd, filename);
80
- await writeFile(filepath, content, "utf-8");
81
- setResult({
82
- success: true,
83
- message: `Exported to ${filename}`
84
- });
85
- setTimeout(() => onDone(`Exported to ${filepath}`), 2e3);
86
- } catch (error) {
87
- setResult({
88
- success: false,
89
- message: `Export failed: ${error instanceof Error ? error.message : String(error)}`
90
- });
91
- } finally {
92
- setExporting(false);
93
- }
94
- };
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...")));
96
- };
9
+ import { t } from "../i18n/index.js";
10
+ import { listMarketplaces } from "../utils/marketplaceManager.js";
11
+ import { loadAllPlugins } from "../utils/pluginLoader.js";
12
+ import { loadAllSkills } from "../utils/skillLoader.js";
13
+ import { loadCustomCommands } from "../services/customCommands.js";
14
+ import { TabbedListView } from "../components/TabbedListView/TabbedListView.js";
97
15
  function generateSummary(messages) {
98
16
  const lines = [
99
17
  "# Minto Session Summary",
@@ -137,11 +55,673 @@ function generateSummary(messages) {
137
55
  }
138
56
  return lines.join("\n");
139
57
  }
58
+ function parseHooksFile(content) {
59
+ try {
60
+ const parsed = JSON.parse(content);
61
+ if (!parsed.hooks) {
62
+ return null;
63
+ }
64
+ const result = {};
65
+ if (parsed.hooks.SessionStart) {
66
+ result.sessionStart = parsed.hooks.SessionStart.flatMap(
67
+ (m) => m.hooks || []
68
+ );
69
+ }
70
+ if (parsed.hooks.SessionEnd) {
71
+ result.sessionEnd = parsed.hooks.SessionEnd.flatMap(
72
+ (m) => m.hooks || []
73
+ );
74
+ }
75
+ if (parsed.hooks.UserPromptSubmit) {
76
+ result.userPromptSubmit = parsed.hooks.UserPromptSubmit.flatMap(
77
+ (m) => m.hooks || []
78
+ );
79
+ }
80
+ if (parsed.hooks.PreToolUse) {
81
+ result.preToolUse = parsed.hooks.PreToolUse;
82
+ }
83
+ if (parsed.hooks.PostToolUse) {
84
+ result.postToolUse = parsed.hooks.PostToolUse;
85
+ }
86
+ return result;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+ async function loadHooksConfigByScope(scope) {
92
+ let userHooks = null;
93
+ let projectHooks = null;
94
+ if (scope === "user" || scope === "all") {
95
+ const mintoPath = join(homedir(), ".minto", "hooks.json");
96
+ const claudePath = join(homedir(), ".claude", "hooks.json");
97
+ const hooksPath = existsSync(mintoPath) ? mintoPath : existsSync(claudePath) ? claudePath : null;
98
+ if (hooksPath) {
99
+ try {
100
+ const content = await readFile(hooksPath, "utf-8");
101
+ userHooks = parseHooksFile(content);
102
+ } catch {
103
+ }
104
+ }
105
+ }
106
+ if (scope === "project" || scope === "all") {
107
+ const cwd = getCwd();
108
+ const mintoPath = join(cwd, ".minto", "hooks.json");
109
+ const claudePath = join(cwd, ".claude", "hooks.json");
110
+ const hooksPath = existsSync(mintoPath) ? mintoPath : existsSync(claudePath) ? claudePath : null;
111
+ if (hooksPath) {
112
+ try {
113
+ const content = await readFile(hooksPath, "utf-8");
114
+ projectHooks = parseHooksFile(content);
115
+ } catch {
116
+ }
117
+ }
118
+ }
119
+ return { userHooks, projectHooks };
120
+ }
121
+ function parseAgentFile(content) {
122
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
123
+ if (!frontmatterMatch) return null;
124
+ const frontmatter = frontmatterMatch[1];
125
+ const body = frontmatterMatch[2].trim();
126
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
127
+ const descMatch = frontmatter.match(/^description:\s*"?([^"\n]+)"?$/m);
128
+ const toolsMatch = frontmatter.match(/^tools:\s*(.+)$/m);
129
+ const modelMatch = frontmatter.match(/^model_name:\s*(.+)$/m);
130
+ const colorMatch = frontmatter.match(/^color:\s*"?([^"\n]+)"?$/m);
131
+ if (!nameMatch || !descMatch) return null;
132
+ let tools = "*";
133
+ if (toolsMatch) {
134
+ const toolsValue = toolsMatch[1].trim();
135
+ if (toolsValue === "*") {
136
+ tools = "*";
137
+ } else {
138
+ try {
139
+ tools = JSON.parse(toolsValue);
140
+ } catch {
141
+ tools = "*";
142
+ }
143
+ }
144
+ }
145
+ return {
146
+ name: nameMatch[1].trim(),
147
+ description: descMatch[1].trim(),
148
+ tools,
149
+ systemPrompt: body,
150
+ model: modelMatch ? modelMatch[1].trim() : void 0,
151
+ color: colorMatch ? colorMatch[1].trim() : void 0
152
+ };
153
+ }
154
+ async function scanAgentsDir(agentsDir) {
155
+ const agentMap = /* @__PURE__ */ new Map();
156
+ if (!existsSync(agentsDir)) return agentMap;
157
+ try {
158
+ const files = readdirSync(agentsDir);
159
+ for (const file of files) {
160
+ if (!file.endsWith(".md")) continue;
161
+ const filePath = join(agentsDir, file);
162
+ const content = await readFile(filePath, "utf-8");
163
+ const agent = parseAgentFile(content);
164
+ if (agent) {
165
+ agentMap.set(agent.name, agent);
166
+ }
167
+ }
168
+ } catch {
169
+ }
170
+ return agentMap;
171
+ }
172
+ async function loadAgentsConfigByScope(scope) {
173
+ const userAgentMap = /* @__PURE__ */ new Map();
174
+ const projectAgentMap = /* @__PURE__ */ new Map();
175
+ if (scope === "user" || scope === "all") {
176
+ const claudeAgents = await scanAgentsDir(
177
+ join(homedir(), ".claude", "agents")
178
+ );
179
+ const mintoAgents = await scanAgentsDir(join(homedir(), ".minto", "agents"));
180
+ for (const [name, agent] of claudeAgents) {
181
+ userAgentMap.set(name, agent);
182
+ }
183
+ for (const [name, agent] of mintoAgents) {
184
+ userAgentMap.set(name, agent);
185
+ }
186
+ }
187
+ if (scope === "project" || scope === "all") {
188
+ const cwd = getCwd();
189
+ const claudeAgents = await scanAgentsDir(join(cwd, ".claude", "agents"));
190
+ const mintoAgents = await scanAgentsDir(join(cwd, ".minto", "agents"));
191
+ for (const [name, agent] of claudeAgents) {
192
+ projectAgentMap.set(name, agent);
193
+ }
194
+ for (const [name, agent] of mintoAgents) {
195
+ projectAgentMap.set(name, agent);
196
+ }
197
+ }
198
+ return {
199
+ userAgents: Array.from(userAgentMap.values()),
200
+ projectAgents: Array.from(projectAgentMap.values())
201
+ };
202
+ }
203
+ function getPluginScope(location) {
204
+ const cwd = getCwd();
205
+ if (location.startsWith(join(cwd, ".minto")) || location.startsWith(join(cwd, ".claude"))) {
206
+ return "project";
207
+ }
208
+ return "user";
209
+ }
210
+ async function getInstalledPluginSourcesByScope(scope) {
211
+ const plugins = loadAllPlugins();
212
+ const userPlugins = [];
213
+ const projectPlugins = [];
214
+ for (const plugin of plugins) {
215
+ const pluginScope = getPluginScope(plugin.location);
216
+ if (scope === "user" && pluginScope !== "user") continue;
217
+ if (scope === "project" && pluginScope !== "project") continue;
218
+ const metaPath = join(plugin.location, ".marketplace-meta.json");
219
+ let pluginName;
220
+ if (existsSync(metaPath)) {
221
+ try {
222
+ const content = await readFile(metaPath, "utf-8");
223
+ const meta = JSON.parse(content);
224
+ pluginName = meta.plugin && meta.marketplace ? `${meta.plugin}@${meta.marketplace}` : meta.plugin || plugin.name;
225
+ } catch {
226
+ pluginName = plugin.name;
227
+ }
228
+ } else {
229
+ pluginName = plugin.name;
230
+ }
231
+ if (pluginScope === "user") {
232
+ userPlugins.push(pluginName);
233
+ } else {
234
+ projectPlugins.push(pluginName);
235
+ }
236
+ }
237
+ return { userPlugins, projectPlugins };
238
+ }
239
+ function loadStandaloneSkillsByScope(scope) {
240
+ const allSkills = loadAllSkills();
241
+ const userSkills = [];
242
+ const projectSkills = [];
243
+ for (const skill of allSkills) {
244
+ if (skill.pluginName !== "standalone") continue;
245
+ const teamSkill = {
246
+ name: skill.name,
247
+ description: skill.config.description,
248
+ content: skill.config.content || "",
249
+ argumentHint: skill.config.argumentHint,
250
+ disableModelInvocation: skill.config.disableModelInvocation,
251
+ userInvocable: skill.config.userInvocable,
252
+ allowedTools: skill.config.allowedTools,
253
+ model: skill.config.model,
254
+ context: skill.config.context,
255
+ agent: skill.config.agent
256
+ };
257
+ if (skill.source === "user" && (scope === "user" || scope === "all")) {
258
+ userSkills.push(teamSkill);
259
+ } else if (skill.source === "project" && (scope === "project" || scope === "all")) {
260
+ projectSkills.push(teamSkill);
261
+ }
262
+ }
263
+ return { userSkills, projectSkills };
264
+ }
265
+ async function loadStandaloneCommandsByScope(scope) {
266
+ const allCommands = await loadCustomCommands();
267
+ const userCommands = [];
268
+ const projectCommands = [];
269
+ for (const cmd of allCommands) {
270
+ if (cmd.name.startsWith("plugin:")) continue;
271
+ const teamCmd = {
272
+ name: cmd.name,
273
+ description: cmd.description,
274
+ content: "",
275
+ // Will be populated from getPromptForCommand
276
+ aliases: cmd.aliases,
277
+ enabled: cmd.isEnabled,
278
+ hidden: cmd.isHidden,
279
+ progressMessage: cmd.progressMessage,
280
+ argNames: cmd.argNames
281
+ };
282
+ try {
283
+ const messages = await cmd.getPromptForCommand("");
284
+ if (messages.length > 0) {
285
+ const firstMsg = messages[0];
286
+ if (typeof firstMsg.content === "string") {
287
+ teamCmd.content = firstMsg.content;
288
+ }
289
+ }
290
+ } catch {
291
+ continue;
292
+ }
293
+ if (cmd.scope === "user" && (scope === "user" || scope === "all")) {
294
+ userCommands.push(teamCmd);
295
+ } else if (cmd.scope === "project" && (scope === "project" || scope === "all")) {
296
+ projectCommands.push(teamCmd);
297
+ }
298
+ }
299
+ return { userCommands, projectCommands };
300
+ }
301
+ function getMarketplaceUrls() {
302
+ const marketplaces = listMarketplaces();
303
+ const urls = [];
304
+ for (const mp of marketplaces) {
305
+ if (mp.source.type === "github") {
306
+ urls.push(`https://github.com/${mp.source.repo}.git`);
307
+ } else if (mp.source.type === "url") {
308
+ urls.push(mp.source.url);
309
+ } else if (mp.source.type === "local") {
310
+ urls.push(mp.source.path);
311
+ }
312
+ }
313
+ return urls;
314
+ }
315
+ function buildMcpServersConfig(mcpServers, usePlaceholders) {
316
+ const result = {};
317
+ for (const [name, server] of Object.entries(mcpServers)) {
318
+ if (server.type === "sse") {
319
+ result[name] = {
320
+ type: "sse",
321
+ url: server.url,
322
+ enabled: server.enabled
323
+ };
324
+ } else {
325
+ const env = server.env ? usePlaceholders ? Object.fromEntries(
326
+ Object.entries(server.env).map(([key, value]) => {
327
+ const isSecret = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("token") || key.toLowerCase().includes("password");
328
+ return [key, isSecret ? `\${${key}}` : value];
329
+ })
330
+ ) : server.env : void 0;
331
+ result[name] = {
332
+ type: "stdio",
333
+ command: server.command,
334
+ args: server.args,
335
+ env,
336
+ enabled: server.enabled
337
+ };
338
+ }
339
+ }
340
+ return result;
341
+ }
342
+ async function buildTeamConfig(scope, usePlaceholders) {
343
+ const cwd = getCwd();
344
+ const globalConfig = loadGlobalConfig();
345
+ const projectConfig = loadProjectConfig(cwd);
346
+ const scopeLabel = scope === "user" ? "User Configuration" : scope === "project" ? `Project: ${cwd.split("/").pop()}` : `All: ${cwd.split("/").pop()}`;
347
+ const config = {
348
+ version: "1.0",
349
+ name: scopeLabel,
350
+ description: `Exported from Minto on ${(/* @__PURE__ */ new Date()).toISOString()}`,
351
+ scope
352
+ };
353
+ if (scope !== "project") {
354
+ if (globalConfig.modelProfiles && globalConfig.modelProfiles.length > 0) {
355
+ config.models = {
356
+ profiles: globalConfig.modelProfiles.map((profile) => ({
357
+ name: profile.name,
358
+ provider: profile.provider,
359
+ modelName: profile.modelName,
360
+ baseURL: profile.baseURL,
361
+ apiKey: usePlaceholders ? `\${${profile.provider.toUpperCase()}_API_KEY}` : profile.apiKey,
362
+ maxTokens: profile.maxTokens,
363
+ contextLength: profile.contextLength,
364
+ reasoningEffort: profile.reasoningEffort,
365
+ isActive: profile.isActive
366
+ })),
367
+ pointers: globalConfig.modelPointers,
368
+ defaultModel: globalConfig.defaultModelName
369
+ };
370
+ }
371
+ }
372
+ if (scope === "user") {
373
+ if (globalConfig.mcpServers && Object.keys(globalConfig.mcpServers).length > 0) {
374
+ config.mcpServers = buildMcpServersConfig(
375
+ globalConfig.mcpServers,
376
+ usePlaceholders
377
+ );
378
+ }
379
+ } else if (scope === "project") {
380
+ if (projectConfig.mcpServers && Object.keys(projectConfig.mcpServers).length > 0) {
381
+ config.mcpServers = buildMcpServersConfig(
382
+ projectConfig.mcpServers,
383
+ usePlaceholders
384
+ );
385
+ }
386
+ } else {
387
+ const merged = {
388
+ ...globalConfig.mcpServers,
389
+ ...projectConfig.mcpServers
390
+ };
391
+ if (Object.keys(merged).length > 0) {
392
+ config.mcpServers = buildMcpServersConfig(merged, usePlaceholders);
393
+ }
394
+ }
395
+ const marketplaceUrls = getMarketplaceUrls();
396
+ const { userPlugins, projectPlugins } = await getInstalledPluginSourcesByScope(scope);
397
+ if (marketplaceUrls.length > 0 || userPlugins.length > 0 || projectPlugins.length > 0) {
398
+ config.plugins = {};
399
+ if (marketplaceUrls.length > 0) {
400
+ config.plugins.marketplaces = marketplaceUrls;
401
+ }
402
+ if (userPlugins.length > 0) {
403
+ config.plugins.userInstall = userPlugins;
404
+ }
405
+ if (projectPlugins.length > 0) {
406
+ config.plugins.projectInstall = projectPlugins;
407
+ }
408
+ }
409
+ const { userAgents, projectAgents } = await loadAgentsConfigByScope(scope);
410
+ if (userAgents.length > 0 || projectAgents.length > 0) {
411
+ config.agents = {};
412
+ if (userAgents.length > 0) {
413
+ config.agents.userAgents = userAgents;
414
+ }
415
+ if (projectAgents.length > 0) {
416
+ config.agents.projectAgents = projectAgents;
417
+ }
418
+ }
419
+ const { userSkills, projectSkills } = loadStandaloneSkillsByScope(scope);
420
+ if (userSkills.length > 0 || projectSkills.length > 0) {
421
+ config.skills = {};
422
+ if (userSkills.length > 0) {
423
+ config.skills.userSkills = userSkills;
424
+ }
425
+ if (projectSkills.length > 0) {
426
+ config.skills.projectSkills = projectSkills;
427
+ }
428
+ }
429
+ const { userCommands, projectCommands } = await loadStandaloneCommandsByScope(scope);
430
+ if (userCommands.length > 0 || projectCommands.length > 0) {
431
+ config.commands = {};
432
+ if (userCommands.length > 0) {
433
+ config.commands.userCommands = userCommands;
434
+ }
435
+ if (projectCommands.length > 0) {
436
+ config.commands.projectCommands = projectCommands;
437
+ }
438
+ }
439
+ const { userHooks, projectHooks } = await loadHooksConfigByScope(scope);
440
+ if (userHooks) {
441
+ config.hooks = userHooks;
442
+ }
443
+ if (projectHooks) {
444
+ config.projectHooks = projectHooks;
445
+ }
446
+ if (scope !== "project") {
447
+ config.settings = {
448
+ theme: globalConfig.theme,
449
+ verbose: globalConfig.verbose,
450
+ compressionMode: globalConfig.compressionMode,
451
+ thinking: globalConfig.thinking,
452
+ proxy: globalConfig.proxy,
453
+ stream: globalConfig.stream,
454
+ language: globalConfig.language,
455
+ safetyMode: globalConfig.safetyMode,
456
+ skipOnboarding: globalConfig.hasCompletedOnboarding
457
+ };
458
+ }
459
+ if (usePlaceholders) {
460
+ config.postInstallInstructions = `
461
+ 1. Set environment variables for API keys (e.g., ANTHROPIC_API_KEY, OPENAI_API_KEY)
462
+ 2. Run 'minto' to start using your configured setup
463
+ `.trim();
464
+ }
465
+ return config;
466
+ }
467
+ async function exportRuntimeConfig(scope) {
468
+ const cwd = getCwd();
469
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
470
+ if (scope === "user") {
471
+ const globalConfig = loadGlobalConfig();
472
+ return {
473
+ content: JSON.stringify({ global: globalConfig }, null, 2),
474
+ filename: `minto-config-user-${timestamp}.json`
475
+ };
476
+ } else if (scope === "project") {
477
+ const projectConfig = loadProjectConfig(cwd);
478
+ return {
479
+ content: JSON.stringify({ project: projectConfig }, null, 2),
480
+ filename: `minto-config-project-${timestamp}.json`
481
+ };
482
+ } else {
483
+ const globalConfig = loadGlobalConfig();
484
+ const projectConfig = loadProjectConfig(cwd);
485
+ return {
486
+ content: JSON.stringify(
487
+ { global: globalConfig, project: projectConfig },
488
+ null,
489
+ 2
490
+ ),
491
+ filename: `minto-config-all-${timestamp}.json`
492
+ };
493
+ }
494
+ }
495
+ async function exportTeamTemplate(scope, usePlaceholders) {
496
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
497
+ const teamConfig = await buildTeamConfig(scope, usePlaceholders);
498
+ return {
499
+ content: JSON.stringify(teamConfig, null, 2),
500
+ filename: `minto-team-${scope}-${timestamp}.json`
501
+ };
502
+ }
503
+ const EXPORT_TABS = [
504
+ { id: "team", label: t("commands.export.typeTeam") },
505
+ { id: "runtime", label: t("commands.export.typeRuntime") },
506
+ { id: "conversation", label: t("commands.export.typeConversation") },
507
+ { id: "summary", label: t("commands.export.typeSummary") }
508
+ ];
509
+ function getItemsForTab(tabId) {
510
+ switch (tabId) {
511
+ case "team":
512
+ return [
513
+ {
514
+ id: "team-user-include",
515
+ label: t("commands.export.itemTeamUserInclude"),
516
+ description: t("commands.export.scopeUserDesc"),
517
+ data: {
518
+ category: "team",
519
+ scope: "user",
520
+ sensitive: "include"
521
+ }
522
+ },
523
+ {
524
+ id: "team-user-placeholder",
525
+ label: t("commands.export.itemTeamUserPlaceholder"),
526
+ description: t("commands.export.scopeUserDesc"),
527
+ data: {
528
+ category: "team",
529
+ scope: "user",
530
+ sensitive: "placeholder"
531
+ }
532
+ },
533
+ {
534
+ id: "team-project-include",
535
+ label: t("commands.export.itemTeamProjectInclude"),
536
+ description: t("commands.export.scopeProjectDesc"),
537
+ data: {
538
+ category: "team",
539
+ scope: "project",
540
+ sensitive: "include"
541
+ }
542
+ },
543
+ {
544
+ id: "team-project-placeholder",
545
+ label: t("commands.export.itemTeamProjectPlaceholder"),
546
+ description: t("commands.export.scopeProjectDesc"),
547
+ data: {
548
+ category: "team",
549
+ scope: "project",
550
+ sensitive: "placeholder"
551
+ }
552
+ },
553
+ {
554
+ id: "team-all-include",
555
+ label: t("commands.export.itemTeamAllInclude"),
556
+ description: t("commands.export.scopeAllDesc"),
557
+ data: {
558
+ category: "team",
559
+ scope: "all",
560
+ sensitive: "include"
561
+ }
562
+ },
563
+ {
564
+ id: "team-all-placeholder",
565
+ label: t("commands.export.itemTeamAllPlaceholder"),
566
+ description: t("commands.export.scopeAllDesc"),
567
+ data: {
568
+ category: "team",
569
+ scope: "all",
570
+ sensitive: "placeholder"
571
+ }
572
+ }
573
+ ];
574
+ case "runtime":
575
+ return [
576
+ {
577
+ id: "runtime-user",
578
+ label: t("commands.export.itemRuntimeUser"),
579
+ description: t("commands.export.scopeUserDesc"),
580
+ data: {
581
+ category: "runtime",
582
+ scope: "user",
583
+ sensitive: "include"
584
+ }
585
+ },
586
+ {
587
+ id: "runtime-project",
588
+ label: t("commands.export.itemRuntimeProject"),
589
+ description: t("commands.export.scopeProjectDesc"),
590
+ data: {
591
+ category: "runtime",
592
+ scope: "project",
593
+ sensitive: "include"
594
+ }
595
+ },
596
+ {
597
+ id: "runtime-all",
598
+ label: t("commands.export.itemRuntimeAll"),
599
+ description: t("commands.export.scopeAllDesc"),
600
+ data: {
601
+ category: "runtime",
602
+ scope: "all",
603
+ sensitive: "include"
604
+ }
605
+ }
606
+ ];
607
+ case "conversation":
608
+ return [
609
+ {
610
+ id: "conversation",
611
+ label: t("commands.export.itemConversation"),
612
+ description: t("commands.export.typeConversationDesc"),
613
+ data: {
614
+ category: "conversation",
615
+ scope: "user",
616
+ sensitive: "include"
617
+ }
618
+ }
619
+ ];
620
+ case "summary":
621
+ return [
622
+ {
623
+ id: "summary",
624
+ label: t("commands.export.itemSummary"),
625
+ description: t("commands.export.typeSummaryDesc"),
626
+ data: {
627
+ category: "summary",
628
+ scope: "user",
629
+ sensitive: "include"
630
+ }
631
+ }
632
+ ];
633
+ default:
634
+ return [];
635
+ }
636
+ }
637
+ const ExportMenu = ({ onDone }) => {
638
+ const [activeTab, setActiveTab] = useState("team");
639
+ const [statusOverlay, setStatusOverlay] = useState(null);
640
+ const [searchQuery, setSearchQuery] = useState("");
641
+ const items = useMemo(() => getItemsForTab(activeTab), [activeTab]);
642
+ const handleSelect = useCallback(async (item) => {
643
+ const data = item.data;
644
+ setStatusOverlay({
645
+ type: "loading",
646
+ message: t("commands.export.exporting")
647
+ });
648
+ try {
649
+ const cwd = getCwd();
650
+ let filename;
651
+ let content;
652
+ switch (data.category) {
653
+ case "conversation": {
654
+ const messages = getMessagesGetter()();
655
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
656
+ filename = `minto-conversation-${timestamp}.json`;
657
+ content = JSON.stringify(messages, null, 2);
658
+ break;
659
+ }
660
+ case "summary": {
661
+ const messages = getMessagesGetter()();
662
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
663
+ filename = `minto-summary-${timestamp}.md`;
664
+ content = generateSummary(messages);
665
+ break;
666
+ }
667
+ case "runtime": {
668
+ const result = await exportRuntimeConfig(data.scope);
669
+ filename = result.filename;
670
+ content = result.content;
671
+ break;
672
+ }
673
+ case "team": {
674
+ const usePlaceholders = data.sensitive === "placeholder";
675
+ const result = await exportTeamTemplate(data.scope, usePlaceholders);
676
+ filename = result.filename;
677
+ content = result.content;
678
+ break;
679
+ }
680
+ }
681
+ const filepath = join(cwd, filename);
682
+ await writeFile(filepath, content, "utf-8");
683
+ setStatusOverlay({
684
+ type: "success",
685
+ message: `${t("commands.export.success")} ${filename}`
686
+ });
687
+ } catch (error) {
688
+ setStatusOverlay({
689
+ type: "error",
690
+ message: `${t("commands.export.failed")}: ${error instanceof Error ? error.message : String(error)}`
691
+ });
692
+ }
693
+ }, []);
694
+ const handleClose = useCallback(() => {
695
+ onDone();
696
+ }, [onDone]);
697
+ return /* @__PURE__ */ React.createElement(
698
+ TabbedListView,
699
+ {
700
+ title: t("commands.export.title"),
701
+ tabs: EXPORT_TABS,
702
+ activeTab,
703
+ onTabChange: (tab) => {
704
+ setActiveTab(tab);
705
+ setSearchQuery("");
706
+ },
707
+ items,
708
+ searchEnabled: false,
709
+ searchQuery,
710
+ onSearchChange: setSearchQuery,
711
+ onSelect: handleSelect,
712
+ onClose: handleClose,
713
+ footerHint: t("commands.export.footerHint"),
714
+ statusOverlay,
715
+ statusDismissHint: "Esc Close"
716
+ }
717
+ );
718
+ };
140
719
  const command = {
141
720
  name: "export",
142
- description: "Export session data, configuration, or conversation history",
721
+ description: t("commands.export.description"),
143
722
  isEnabled: true,
144
723
  isHidden: false,
724
+ hidePromptInput: true,
145
725
  type: "local-jsx",
146
726
  userFacingName() {
147
727
  return this.name;