@within-7/minto 0.3.6 → 0.3.9

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 (153) hide show
  1. package/{cli.js → cli.cjs} +25 -23
  2. package/dist/commands/language.js +137 -0
  3. package/dist/commands/language.js.map +7 -0
  4. package/dist/commands/new.js +56 -0
  5. package/dist/commands/new.js.map +7 -0
  6. package/dist/commands/resume.js +251 -16
  7. package/dist/commands/resume.js.map +2 -2
  8. package/dist/commands/sessions.js +224 -0
  9. package/dist/commands/sessions.js.map +7 -0
  10. package/dist/commands/setup.js +3 -2
  11. package/dist/commands/setup.js.map +2 -2
  12. package/dist/commands/stats.js +235 -0
  13. package/dist/commands/stats.js.map +7 -0
  14. package/dist/commands/status.js +11 -5
  15. package/dist/commands/status.js.map +2 -2
  16. package/dist/commands/undo.js +26 -16
  17. package/dist/commands/undo.js.map +2 -2
  18. package/dist/commands.js +6 -0
  19. package/dist/commands.js.map +2 -2
  20. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
  21. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  22. package/dist/components/Config.js +9 -8
  23. package/dist/components/Config.js.map +2 -2
  24. package/dist/components/HeaderBar.js +2 -1
  25. package/dist/components/HeaderBar.js.map +2 -2
  26. package/dist/components/Help.js +2 -1
  27. package/dist/components/Help.js.map +2 -2
  28. package/dist/components/HotkeyHelpPanel.js +46 -44
  29. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  30. package/dist/components/Logo.js +5 -2
  31. package/dist/components/Logo.js.map +2 -2
  32. package/dist/components/MCPServerApprovalDialog.js +6 -5
  33. package/dist/components/MCPServerApprovalDialog.js.map +2 -2
  34. package/dist/components/MCPServerMultiselectDialog.js +5 -4
  35. package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
  36. package/dist/components/MessageSelector.js +4 -3
  37. package/dist/components/MessageSelector.js.map +2 -2
  38. package/dist/components/ModelConfig.js +13 -12
  39. package/dist/components/ModelConfig.js.map +2 -2
  40. package/dist/components/ModelListManager.js +4 -3
  41. package/dist/components/ModelListManager.js.map +2 -2
  42. package/dist/components/PromptInput.js +72 -39
  43. package/dist/components/PromptInput.js.map +2 -2
  44. package/dist/components/SensitiveFileWarning.js +12 -8
  45. package/dist/components/SensitiveFileWarning.js.map +2 -2
  46. package/dist/components/TabbedListView/ScrollableList.js +91 -0
  47. package/dist/components/TabbedListView/ScrollableList.js.map +7 -0
  48. package/dist/components/TabbedListView/SearchInput.js +23 -0
  49. package/dist/components/TabbedListView/SearchInput.js.map +7 -0
  50. package/dist/components/TabbedListView/TabBar.js +20 -0
  51. package/dist/components/TabbedListView/TabBar.js.map +7 -0
  52. package/dist/components/TabbedListView/TabbedListView.js +171 -0
  53. package/dist/components/TabbedListView/TabbedListView.js.map +7 -0
  54. package/dist/components/TabbedListView/index.js +11 -0
  55. package/dist/components/TabbedListView/index.js.map +7 -0
  56. package/dist/components/TabbedListView/types.js +1 -0
  57. package/dist/components/TabbedListView/types.js.map +7 -0
  58. package/dist/components/TodoChangeBlock.js +6 -5
  59. package/dist/components/TodoChangeBlock.js.map +3 -3
  60. package/dist/components/TodoPanel.js +6 -3
  61. package/dist/components/TodoPanel.js.map +3 -3
  62. package/dist/components/TrustDialog.js +6 -5
  63. package/dist/components/TrustDialog.js.map +2 -2
  64. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +2 -1
  65. package/dist/components/messages/UserToolResultMessage/UserToolCanceledMessage.js.map +2 -2
  66. package/dist/constants/macros.js +1 -1
  67. package/dist/constants/macros.js.map +1 -1
  68. package/dist/constants/product.js +2 -2
  69. package/dist/constants/product.js.map +1 -1
  70. package/dist/constants/prompts.js +17 -0
  71. package/dist/constants/prompts.js.map +2 -2
  72. package/dist/constants/toolInputExamples.js +5 -1
  73. package/dist/constants/toolInputExamples.js.map +2 -2
  74. package/dist/core/tokenStatsManager.js +5 -0
  75. package/dist/core/tokenStatsManager.js.map +2 -2
  76. package/dist/entrypoints/bootstrap.js +54 -0
  77. package/dist/entrypoints/bootstrap.js.map +7 -0
  78. package/dist/entrypoints/cli.js +132 -23
  79. package/dist/entrypoints/cli.js.map +3 -3
  80. package/dist/history.js +75 -15
  81. package/dist/history.js.map +2 -2
  82. package/dist/i18n/index.js +2 -2
  83. package/dist/i18n/index.js.map +2 -2
  84. package/dist/i18n/locales/en.js +283 -1
  85. package/dist/i18n/locales/en.js.map +2 -2
  86. package/dist/i18n/locales/zh-CN.js +283 -1
  87. package/dist/i18n/locales/zh-CN.js.map +2 -2
  88. package/dist/i18n/types.js.map +1 -1
  89. package/dist/index.js +1 -1
  90. package/dist/index.js.map +2 -2
  91. package/dist/messages.js +11 -0
  92. package/dist/messages.js.map +2 -2
  93. package/dist/permissions.js.map +2 -2
  94. package/dist/query.js +9 -0
  95. package/dist/query.js.map +2 -2
  96. package/dist/screens/REPL.js +45 -7
  97. package/dist/screens/REPL.js.map +2 -2
  98. package/dist/services/customCommands.js +14 -8
  99. package/dist/services/customCommands.js.map +2 -2
  100. package/dist/tools/TaskTool/TaskTool.js +176 -1
  101. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  102. package/dist/tools/TodoWriteTool/prompt.js +21 -0
  103. package/dist/tools/TodoWriteTool/prompt.js.map +2 -2
  104. package/dist/tools/URLFetcherTool/prompt.js +14 -9
  105. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  106. package/dist/tools/WebSearchTool/prompt.js +12 -6
  107. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  108. package/dist/types/PermissionMode.js +30 -1
  109. package/dist/types/PermissionMode.js.map +2 -2
  110. package/dist/types/plugin.js.map +2 -2
  111. package/dist/utils/agentHookExecutor.js +106 -0
  112. package/dist/utils/agentHookExecutor.js.map +7 -0
  113. package/dist/utils/agentLoader.js +212 -26
  114. package/dist/utils/agentLoader.js.map +2 -2
  115. package/dist/utils/agentMemory.js +134 -0
  116. package/dist/utils/agentMemory.js.map +7 -0
  117. package/dist/utils/config.js +51 -1
  118. package/dist/utils/config.js.map +2 -2
  119. package/dist/utils/configPaths.js +199 -0
  120. package/dist/utils/configPaths.js.map +7 -0
  121. package/dist/utils/historyManager.js +234 -0
  122. package/dist/utils/historyManager.js.map +7 -0
  123. package/dist/utils/messages.js +13 -8
  124. package/dist/utils/messages.js.map +2 -2
  125. package/dist/utils/migration/index.js +37 -0
  126. package/dist/utils/migration/index.js.map +7 -0
  127. package/dist/utils/migration/migrateHistory.js +273 -0
  128. package/dist/utils/migration/migrateHistory.js.map +7 -0
  129. package/dist/utils/migration/migrateTodos.js +323 -0
  130. package/dist/utils/migration/migrateTodos.js.map +7 -0
  131. package/dist/utils/pasteCache.js +309 -0
  132. package/dist/utils/pasteCache.js.map +7 -0
  133. package/dist/utils/pluginLoader.js +6 -3
  134. package/dist/utils/pluginLoader.js.map +2 -2
  135. package/dist/utils/sessionIndex.js +192 -0
  136. package/dist/utils/sessionIndex.js.map +7 -0
  137. package/dist/utils/sessionTracker.js +170 -0
  138. package/dist/utils/sessionTracker.js.map +7 -0
  139. package/dist/utils/skillLoader.js +91 -5
  140. package/dist/utils/skillLoader.js.map +2 -2
  141. package/dist/utils/stats.js +417 -0
  142. package/dist/utils/stats.js.map +7 -0
  143. package/dist/utils/stringSubstitution.js +107 -0
  144. package/dist/utils/stringSubstitution.js.map +7 -0
  145. package/dist/utils/teamConfig.js +3 -1
  146. package/dist/utils/teamConfig.js.map +2 -2
  147. package/dist/utils/todoStorage.js +51 -19
  148. package/dist/utils/todoStorage.js.map +2 -2
  149. package/dist/utils/tooling/safeRender.js.map +2 -2
  150. package/dist/version.js +2 -2
  151. package/dist/version.js.map +1 -1
  152. package/package.json +71 -28
  153. package/scripts/{postinstall.js → postinstall.cjs} +1 -1
@@ -147,31 +147,33 @@ function showInstallationHelp() {
147
147
 
148
148
  // ============ Main Execution Logic ============
149
149
 
150
- // Priority 1: Try native binary (best option)
151
- const nativeBinary = getNativeBinaryPath();
152
- if (nativeBinary) {
153
- runAndExit(nativeBinary, args);
154
- return; // Note: runAndExit handles process exit
155
- }
150
+ (function main() {
151
+ // Priority 1: Try native binary (best option)
152
+ const nativeBinary = getNativeBinaryPath();
153
+ if (nativeBinary) {
154
+ runAndExit(nativeBinary, args);
155
+ return; // Note: runAndExit handles process exit via async callback
156
+ }
156
157
 
157
- // Priority 2: Try Bun runtime
158
- if (isRuntimeAvailable('bun')) {
159
- const distPath = path.join(mintoDir, 'dist', 'index.js');
160
- if (existsSync(distPath)) {
161
- runAndExit('bun', ['run', distPath, ...args]);
162
- return;
158
+ // Priority 2: Try Bun runtime
159
+ if (isRuntimeAvailable('bun')) {
160
+ const distPath = path.join(mintoDir, 'dist', 'index.js');
161
+ if (existsSync(distPath)) {
162
+ runAndExit('bun', ['run', distPath, ...args]);
163
+ return;
164
+ }
163
165
  }
164
- }
165
166
 
166
- // Priority 3: Try Node.js runtime
167
- if (isRuntimeAvailable('node')) {
168
- const distPath = path.join(mintoDir, 'dist', 'index.js');
169
- if (existsSync(distPath)) {
170
- runAndExit('node', [distPath, ...args]);
171
- return;
167
+ // Priority 3: Try Node.js runtime
168
+ if (isRuntimeAvailable('node')) {
169
+ const distPath = path.join(mintoDir, 'dist', 'index.js');
170
+ if (existsSync(distPath)) {
171
+ runAndExit('node', [distPath, ...args]);
172
+ return;
173
+ }
172
174
  }
173
- }
174
175
 
175
- // No execution method available
176
- showInstallationHelp();
177
- process.exit(1);
176
+ // No execution method available
177
+ showInstallationHelp();
178
+ process.exit(1);
179
+ })();
@@ -0,0 +1,137 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { SEMANTIC_COLORS, BRAND_GRADIENT } from "../constants/colors.js";
4
+ import {
5
+ t,
6
+ getLanguage,
7
+ setLanguage,
8
+ getSupportedLanguages,
9
+ getLanguageDisplayName
10
+ } from "../i18n/index.js";
11
+ import { getGlobalConfig, saveGlobalConfig } from "../utils/config.js";
12
+ import { triggerLanguageChange } from "../messages.js";
13
+ const LanguageSelector = ({
14
+ currentLanguage,
15
+ onSelect,
16
+ onDone
17
+ }) => {
18
+ const languages = getSupportedLanguages();
19
+ const [selectedIndex, setSelectedIndex] = useState(
20
+ languages.indexOf(currentLanguage)
21
+ );
22
+ useInput((input, key) => {
23
+ if (key.upArrow || input === "k") {
24
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : languages.length - 1);
25
+ } else if (key.downArrow || input === "j") {
26
+ setSelectedIndex((prev) => prev < languages.length - 1 ? prev + 1 : 0);
27
+ } else if (key.return) {
28
+ const selected = languages[selectedIndex];
29
+ if (selected) {
30
+ onSelect(selected);
31
+ }
32
+ } else if (input === "q" || key.escape) {
33
+ onDone();
34
+ }
35
+ });
36
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, "Language Settings"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " / "), /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.END }, "\u8BED\u8A00\u8BBE\u7F6E")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.language.current"), ":", " "), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.success }, getLanguageDisplayName(currentLanguage))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary, bold: true }, t("commands.language.select"), ":"), languages.map((lang, index) => {
37
+ const isSelected = index === selectedIndex;
38
+ const isCurrent = lang === currentLanguage;
39
+ return /* @__PURE__ */ React.createElement(Box, { key: lang, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(
40
+ Text,
41
+ {
42
+ color: isSelected ? BRAND_GRADIENT.START : SEMANTIC_COLORS.secondary,
43
+ bold: isSelected
44
+ },
45
+ isSelected ? "\u203A " : " ",
46
+ getLanguageDisplayName(lang),
47
+ isCurrent && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, " ", "(", t("commands.language.current"), ")")
48
+ ));
49
+ })), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, t("commands.language.navigate"))));
50
+ };
51
+ async function applyLanguageChange(newLang) {
52
+ setLanguage(newLang);
53
+ await triggerLanguageChange();
54
+ }
55
+ const command = {
56
+ name: "language",
57
+ aliases: ["lang"],
58
+ description: t("commands.language.description"),
59
+ isEnabled: true,
60
+ isHidden: false,
61
+ type: "local-jsx",
62
+ userFacingName() {
63
+ return this.name;
64
+ },
65
+ async call(onDone, _context, args) {
66
+ const currentLang = getLanguage();
67
+ if (args) {
68
+ const arg = args.trim().toLowerCase();
69
+ let targetLang = null;
70
+ if (arg === "en" || arg === "english") {
71
+ targetLang = "en";
72
+ } else if (arg === "zh-cn" || arg === "zh" || arg === "chinese" || arg === "\u4E2D\u6587") {
73
+ targetLang = "zh-CN";
74
+ }
75
+ if (targetLang && targetLang !== currentLang) {
76
+ const config = getGlobalConfig();
77
+ saveGlobalConfig({ ...config, language: targetLang });
78
+ const DirectChangeConfirm = () => {
79
+ const [applied, setApplied] = useState(false);
80
+ useEffect(() => {
81
+ if (!applied) {
82
+ setApplied(true);
83
+ setTimeout(async () => {
84
+ onDone();
85
+ await new Promise((resolve) => setTimeout(resolve, 50));
86
+ await applyLanguageChange(targetLang);
87
+ }, 100);
88
+ }
89
+ }, [applied]);
90
+ return /* @__PURE__ */ React.createElement(Box, { paddingY: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "\u2713 "), /* @__PURE__ */ React.createElement(Text, null, t("commands.language.changed"), " ", getLanguageDisplayName(targetLang)));
91
+ };
92
+ return /* @__PURE__ */ React.createElement(DirectChangeConfirm, null);
93
+ } else if (targetLang === currentLang) {
94
+ return /* @__PURE__ */ React.createElement(Box, { paddingY: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.language.alreadyUsing"), " ", getLanguageDisplayName(targetLang)));
95
+ }
96
+ }
97
+ const LanguageWrapper = () => {
98
+ const [pendingLang, setPendingLang] = useState(null);
99
+ useEffect(() => {
100
+ if (pendingLang) {
101
+ const applyChange = async () => {
102
+ onDone();
103
+ await new Promise((resolve) => setTimeout(resolve, 50));
104
+ await applyLanguageChange(pendingLang);
105
+ };
106
+ applyChange();
107
+ }
108
+ }, [pendingLang]);
109
+ const handleSelect = (lang) => {
110
+ if (lang !== currentLang) {
111
+ const config = getGlobalConfig();
112
+ saveGlobalConfig({ ...config, language: lang });
113
+ setPendingLang(lang);
114
+ } else {
115
+ onDone();
116
+ }
117
+ };
118
+ if (pendingLang) {
119
+ return /* @__PURE__ */ React.createElement(Box, { paddingY: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "\u2713 "), /* @__PURE__ */ React.createElement(Text, null, t("commands.language.changed"), " ", getLanguageDisplayName(pendingLang)));
120
+ }
121
+ return /* @__PURE__ */ React.createElement(
122
+ LanguageSelector,
123
+ {
124
+ currentLanguage: currentLang,
125
+ onSelect: handleSelect,
126
+ onDone
127
+ }
128
+ );
129
+ };
130
+ return /* @__PURE__ */ React.createElement(LanguageWrapper, null);
131
+ }
132
+ };
133
+ var language_default = command;
134
+ export {
135
+ language_default as default
136
+ };
137
+ //# sourceMappingURL=language.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/language.tsx"],
4
+ "sourcesContent": ["/**\n * Language Command\n *\n * Interactive language switching for Minto CLI.\n * Allows users to easily switch between English and Chinese interfaces.\n *\n * Flow:\n * 1. User selects new language\n * 2. Save preference to config\n * 3. Update runtime language\n * 4. Exit menu and return to input state\n * 5. Clear screen and re-render UI with new language (preserving conversation history)\n */\n\nimport React, { useState, useEffect } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport type { Command } from '@commands'\nimport { SEMANTIC_COLORS, BRAND_GRADIENT } from '@constants/colors'\nimport {\n t,\n getLanguage,\n setLanguage,\n getSupportedLanguages,\n getLanguageDisplayName,\n type Language,\n} from '@i18n'\nimport { getGlobalConfig, saveGlobalConfig } from '@utils/config'\nimport { triggerLanguageChange } from '@messages'\n\ninterface LanguageSelectorProps {\n currentLanguage: Language\n onSelect: (lang: Language) => void\n onDone: () => void\n}\n\nconst LanguageSelector = ({\n currentLanguage,\n onSelect,\n onDone,\n}: LanguageSelectorProps) => {\n const languages = getSupportedLanguages()\n const [selectedIndex, setSelectedIndex] = useState(\n languages.indexOf(currentLanguage),\n )\n\n useInput((input, key) => {\n if (key.upArrow || input === 'k') {\n setSelectedIndex(prev => (prev > 0 ? prev - 1 : languages.length - 1))\n } else if (key.downArrow || input === 'j') {\n setSelectedIndex(prev => (prev < languages.length - 1 ? prev + 1 : 0))\n } else if (key.return) {\n const selected = languages[selectedIndex]\n if (selected) {\n onSelect(selected)\n }\n } else if (input === 'q' || key.escape) {\n onDone()\n }\n })\n\n return (\n <Box flexDirection=\"column\" paddingY={1}>\n {/* Header - bilingual display */}\n <Box marginBottom={1}>\n <Text color={BRAND_GRADIENT.START}>\u25C6</Text>\n <Text> </Text>\n <Text bold color={BRAND_GRADIENT.START}>\n Language Settings\n </Text>\n <Text color={SEMANTIC_COLORS.dim}> / </Text>\n <Text bold color={BRAND_GRADIENT.END}>\n \u8BED\u8A00\u8BBE\u7F6E\n </Text>\n </Box>\n\n {/* Current language */}\n <Box marginBottom={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('commands.language.current')}:{' '}\n </Text>\n <Text bold color={SEMANTIC_COLORS.success}>\n {getLanguageDisplayName(currentLanguage)}\n </Text>\n </Box>\n\n {/* Language options */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text color={SEMANTIC_COLORS.secondary} bold>\n {t('commands.language.select')}:\n </Text>\n {languages.map((lang, index) => {\n const isSelected = index === selectedIndex\n const isCurrent = lang === currentLanguage\n\n return (\n <Box key={lang} paddingLeft={1}>\n <Text\n color={\n isSelected ? BRAND_GRADIENT.START : SEMANTIC_COLORS.secondary\n }\n bold={isSelected}\n >\n {isSelected ? '\u203A ' : ' '}\n {getLanguageDisplayName(lang)}\n {isCurrent && (\n <Text color={SEMANTIC_COLORS.success}>\n {' '}\n ({t('commands.language.current')})\n </Text>\n )}\n </Text>\n </Box>\n )\n })}\n </Box>\n\n {/* Help text */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.language.navigate')}\n </Text>\n </Box>\n </Box>\n )\n}\n\n/**\n * Apply language change\n * 1. Update runtime language\n * 2. Trigger UI re-render (preserves conversation history)\n */\nasync function applyLanguageChange(newLang: Language) {\n // Update runtime language\n setLanguage(newLang)\n\n // Trigger full UI re-render (similar to verbose toggle flow)\n // This clears the screen and re-renders all content with new language\n await triggerLanguageChange()\n}\n\nconst command: Command = {\n name: 'language',\n aliases: ['lang'],\n description: t('commands.language.description'),\n isEnabled: true,\n isHidden: false,\n type: 'local-jsx',\n\n userFacingName() {\n return this.name\n },\n\n async call(onDone, _context, args) {\n const currentLang = getLanguage()\n\n // Handle direct language argument: /language en or /language zh-CN\n if (args) {\n const arg = args.trim().toLowerCase()\n let targetLang: Language | null = null\n\n if (arg === 'en' || arg === 'english') {\n targetLang = 'en'\n } else if (\n arg === 'zh-cn' ||\n arg === 'zh' ||\n arg === 'chinese' ||\n arg === '\u4E2D\u6587'\n ) {\n targetLang = 'zh-CN'\n }\n\n if (targetLang && targetLang !== currentLang) {\n // Save to config first\n const config = getGlobalConfig()\n saveGlobalConfig({ ...config, language: targetLang })\n\n // Show brief confirmation then apply change\n const DirectChangeConfirm = () => {\n const [applied, setApplied] = useState(false)\n\n useEffect(() => {\n if (!applied) {\n setApplied(true)\n // Small delay to show the message, then apply change\n setTimeout(async () => {\n onDone()\n // Wait a tick for dialog to close\n await new Promise(resolve => setTimeout(resolve, 50))\n await applyLanguageChange(targetLang!)\n }, 100)\n }\n }, [applied])\n\n return (\n <Box paddingY={1}>\n <Text color={SEMANTIC_COLORS.success}>\u2713 </Text>\n <Text>\n {t('commands.language.changed')}{' '}\n {getLanguageDisplayName(targetLang!)}\n </Text>\n </Box>\n )\n }\n\n return <DirectChangeConfirm />\n } else if (targetLang === currentLang) {\n // Already using this language\n return (\n <Box paddingY={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('commands.language.alreadyUsing')}{' '}\n {getLanguageDisplayName(targetLang)}\n </Text>\n </Box>\n )\n }\n // Invalid argument - fall through to interactive mode\n }\n\n // Interactive mode\n const LanguageWrapper = () => {\n const [pendingLang, setPendingLang] = useState<Language | null>(null)\n\n useEffect(() => {\n if (pendingLang) {\n // Language was selected, exit menu and apply change\n const applyChange = async () => {\n onDone()\n // Wait a tick for dialog to close\n await new Promise(resolve => setTimeout(resolve, 50))\n await applyLanguageChange(pendingLang)\n }\n applyChange()\n }\n }, [pendingLang])\n\n const handleSelect = (lang: Language) => {\n if (lang !== currentLang) {\n // Save to config first\n const config = getGlobalConfig()\n saveGlobalConfig({ ...config, language: lang })\n\n // Set pending to trigger effect\n setPendingLang(lang)\n } else {\n onDone()\n }\n }\n\n // Show brief message while applying change\n if (pendingLang) {\n return (\n <Box paddingY={1}>\n <Text color={SEMANTIC_COLORS.success}>\u2713 </Text>\n <Text>\n {t('commands.language.changed')}{' '}\n {getLanguageDisplayName(pendingLang)}\n </Text>\n </Box>\n )\n }\n\n return (\n <LanguageSelector\n currentLanguage={currentLang}\n onSelect={handleSelect}\n onDone={onDone}\n />\n )\n }\n\n return <LanguageWrapper />\n },\n}\n\nexport default command\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,56 @@
1
+ import React from "react";
2
+ import { render } from "ink";
3
+ import { t } from "../i18n/index.js";
4
+ import { dateToFilename } from "../utils/log.js";
5
+ import { isDefaultSlowAndCapableModel } from "../utils/model.js";
6
+ import { prepareTerminalForREPL } from "../utils/terminal.js";
7
+ import { REPL } from "../screens/REPL.js";
8
+ import { clearConversation } from "./clear.js";
9
+ var new_default = {
10
+ type: "local-jsx",
11
+ name: "new",
12
+ description: t("commands.new.description"),
13
+ isEnabled: true,
14
+ isHidden: false,
15
+ aliases: ["n"],
16
+ userFacingName() {
17
+ return "new";
18
+ },
19
+ async call(onDone, context) {
20
+ const { commands = [], tools = [], verbose = false } = context.options || {};
21
+ const unmount = context.unmount;
22
+ await clearConversation(context);
23
+ const isDefaultModel = await isDefaultSlowAndCapableModel();
24
+ const messageLogName = dateToFilename(/* @__PURE__ */ new Date());
25
+ onDone();
26
+ if (unmount) {
27
+ unmount();
28
+ }
29
+ await prepareTerminalForREPL();
30
+ render(
31
+ /* @__PURE__ */ React.createElement(
32
+ REPL,
33
+ {
34
+ messageLogName,
35
+ initialPrompt: "",
36
+ shouldShowPromptInput: true,
37
+ verbose,
38
+ commands,
39
+ tools,
40
+ initialMessages: [],
41
+ initialForkNumber: 1,
42
+ isDefaultModel,
43
+ isResumedConversation: false
44
+ }
45
+ ),
46
+ {
47
+ exitOnCtrlC: false
48
+ }
49
+ );
50
+ return null;
51
+ }
52
+ };
53
+ export {
54
+ new_default as default
55
+ };
56
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/new.tsx"],
4
+ "sourcesContent": ["/**\n * New Command\n *\n * Start a new conversation (skip auto-resume).\n * Same effect as starting with `-n, --new` CLI parameter.\n *\n * Usage:\n * /new # Start a new conversation\n * /n # Alias\n */\n\nimport React from 'react'\nimport { render } from 'ink'\nimport type { Command } from '@commands'\nimport { t } from '@i18n'\nimport { dateToFilename } from '@utils/log'\nimport { isDefaultSlowAndCapableModel } from '@utils/model'\nimport { prepareTerminalForREPL } from '@utils/terminal'\nimport { REPL } from '@screens/REPL'\nimport { clearConversation } from './clear'\n\nexport default {\n type: 'local-jsx',\n name: 'new',\n description: t('commands.new.description'),\n isEnabled: true,\n isHidden: false,\n aliases: ['n'],\n userFacingName() {\n return 'new'\n },\n async call(onDone, context) {\n const { commands = [], tools = [], verbose = false } = context.options || {}\n const unmount = context.unmount\n\n // Clear current conversation state\n await clearConversation(context)\n\n // Check if using default model before unmounting\n const isDefaultModel = await isDefaultSlowAndCapableModel()\n\n // Generate new message log name (timestamp-based)\n const messageLogName = dateToFilename(new Date())\n\n // Close the command UI\n onDone()\n\n // Unmount current REPL before creating new one\n if (unmount) {\n unmount()\n }\n\n // Clear screen and prepare terminal for REPL\n await prepareTerminalForREPL()\n\n // Render a new REPL with fresh state\n render(\n <REPL\n messageLogName={messageLogName}\n initialPrompt=\"\"\n shouldShowPromptInput={true}\n verbose={verbose}\n commands={commands}\n tools={tools}\n initialMessages={[]}\n initialForkNumber={1}\n isDefaultModel={isDefaultModel}\n isResumedConversation={false}\n />,\n {\n exitOnCtrlC: false,\n },\n )\n\n return null\n },\n} satisfies Command\n"],
5
+ "mappings": "AAWA,OAAO,WAAW;AAClB,SAAS,cAAc;AAEvB,SAAS,SAAS;AAClB,SAAS,sBAAsB;AAC/B,SAAS,oCAAoC;AAC7C,SAAS,8BAA8B;AACvC,SAAS,YAAY;AACrB,SAAS,yBAAyB;AAElC,IAAO,cAAQ;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,aAAa,EAAE,0BAA0B;AAAA,EACzC,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS,CAAC,GAAG;AAAA,EACb,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,KAAK,QAAQ,SAAS;AAC1B,UAAM,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,UAAU,MAAM,IAAI,QAAQ,WAAW,CAAC;AAC3E,UAAM,UAAU,QAAQ;AAGxB,UAAM,kBAAkB,OAAO;AAG/B,UAAM,iBAAiB,MAAM,6BAA6B;AAG1D,UAAM,iBAAiB,eAAe,oBAAI,KAAK,CAAC;AAGhD,WAAO;AAGP,QAAI,SAAS;AACX,cAAQ;AAAA,IACV;AAGA,UAAM,uBAAuB;AAG7B;AAAA,MACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,eAAc;AAAA,UACd,uBAAuB;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA,iBAAiB,CAAC;AAAA,UAClB,mBAAmB;AAAA,UACnB;AAAA,UACA,uBAAuB;AAAA;AAAA,MACzB;AAAA,MACA;AAAA,QACE,aAAa;AAAA,MACf;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -1,33 +1,268 @@
1
- import * as React from "react";
2
- import { ResumeConversation } from "../screens/ResumeConversation.js";
1
+ import React, { useState, useMemo } from "react";
3
2
  import { render } from "ink";
3
+ import path from "path";
4
+ import { t } from "../i18n/index.js";
5
+ import { getCwd } from "../utils/state.js";
4
6
  import { CACHE_PATHS, loadLogList } from "../utils/log.js";
7
+ import { deserializeMessages } from "../utils/conversationRecovery.js";
8
+ import { getNextAvailableLogForkNumber, logError } from "../utils/log.js";
9
+ import { isDefaultSlowAndCapableModel } from "../utils/model.js";
10
+ import { prepareTerminalForREPL } from "../utils/terminal.js";
11
+ import { REPL } from "../screens/REPL.js";
12
+ import {
13
+ TabbedListView
14
+ } from "../components/TabbedListView/index.js";
15
+ function formatDate(date) {
16
+ const now = /* @__PURE__ */ new Date();
17
+ const hours = date.getHours().toString().padStart(2, "0");
18
+ const minutes = date.getMinutes().toString().padStart(2, "0");
19
+ const timeStr = `${hours}:${minutes}`;
20
+ const isToday = date.getDate() === now.getDate() && date.getMonth() === now.getMonth() && date.getFullYear() === now.getFullYear();
21
+ if (isToday) {
22
+ return `${t("commands.sessions.today")} ${timeStr}`;
23
+ }
24
+ const yesterday = new Date(now);
25
+ yesterday.setDate(yesterday.getDate() - 1);
26
+ const isYesterday = date.getDate() === yesterday.getDate() && date.getMonth() === yesterday.getMonth() && date.getFullYear() === yesterday.getFullYear();
27
+ if (isYesterday) {
28
+ return `${t("commands.sessions.yesterday")} ${timeStr}`;
29
+ }
30
+ const month = (date.getMonth() + 1).toString().padStart(2, "0");
31
+ const day = date.getDate().toString().padStart(2, "0");
32
+ return `${month}-${day} ${timeStr}`;
33
+ }
34
+ function truncate(str, maxLength) {
35
+ if (str.length <= maxLength) return str;
36
+ return str.slice(0, maxLength - 3) + "...";
37
+ }
38
+ function wasCleared(log) {
39
+ for (let i = log.messages.length - 1; i >= 0; i--) {
40
+ const msg = log.messages[i];
41
+ if (msg.type === "user") {
42
+ const content = typeof msg.message?.content === "string" ? msg.message.content : Array.isArray(msg.message?.content) ? msg.message.content.filter((c) => c.type === "text").map((c) => c.text).join("") : "";
43
+ return content.includes("<command-name>clear</command-name>");
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+ function deduplicateLogForks(logs) {
49
+ const groupedByDate = /* @__PURE__ */ new Map();
50
+ for (const log of logs) {
51
+ const existing = groupedByDate.get(log.date) || [];
52
+ existing.push(log);
53
+ groupedByDate.set(log.date, existing);
54
+ }
55
+ const deduped = [];
56
+ for (const [, group] of groupedByDate) {
57
+ const sorted = group.sort((a, b) => {
58
+ const forkDiff = (b.forkNumber ?? 0) - (a.forkNumber ?? 0);
59
+ if (forkDiff !== 0) return forkDiff;
60
+ return b.modified.getTime() - a.modified.getTime();
61
+ });
62
+ if (sorted[0]) {
63
+ deduped.push(sorted[0]);
64
+ }
65
+ }
66
+ return deduped.sort((a, b) => b.modified.getTime() - a.modified.getTime());
67
+ }
68
+ function getLogProjectPath(log) {
69
+ const firstMessage = log.messages[0];
70
+ return firstMessage?.cwd || null;
71
+ }
72
+ function getProjectName(projectPath) {
73
+ return path.basename(projectPath) || projectPath;
74
+ }
75
+ function extractFirstPrompt(log) {
76
+ for (const msg of log.messages) {
77
+ if (msg.type === "user") {
78
+ let content = "";
79
+ if (typeof msg.message?.content === "string") {
80
+ content = msg.message.content;
81
+ } else if (Array.isArray(msg.message?.content)) {
82
+ content = msg.message.content.filter((c) => c.type === "text").map((c) => c.text).join("");
83
+ }
84
+ const trimmed = content.trim();
85
+ if (trimmed.startsWith("<system-reminder>") || trimmed.startsWith("<command-name>") || trimmed.startsWith("<") && trimmed.includes("</")) {
86
+ continue;
87
+ }
88
+ const firstLine = content.split("\n")[0]?.trim() || "";
89
+ if (firstLine) {
90
+ return firstLine;
91
+ }
92
+ }
93
+ }
94
+ return log.firstPrompt || "No prompt";
95
+ }
96
+ function countToolCalls(log) {
97
+ let count = 0;
98
+ for (const msg of log.messages) {
99
+ if (msg.type === "assistant" && Array.isArray(msg.message?.content)) {
100
+ for (const block of msg.message.content) {
101
+ if (block.type === "tool_use") {
102
+ count++;
103
+ }
104
+ }
105
+ }
106
+ }
107
+ return count;
108
+ }
109
+ function logToListItem(log) {
110
+ const dateStr = formatDate(log.modified);
111
+ const projectPath = getLogProjectPath(log) || "";
112
+ const projectName = projectPath ? truncate(getProjectName(projectPath), 15) : "";
113
+ const msgCount = log.messageCount;
114
+ const toolCount = countToolCalls(log);
115
+ const firstPrompt = extractFirstPrompt(log);
116
+ return {
117
+ id: log.fullPath,
118
+ // Use fullPath as unique id (date can be duplicated for forks)
119
+ label: truncate(firstPrompt, 45),
120
+ description: projectName || void 0,
121
+ metadata: `${dateStr} \xB7 ${msgCount} msgs \xB7 ${toolCount} tools`,
122
+ category: projectName || "Unknown",
123
+ data: log
124
+ };
125
+ }
126
+ function ResumeDisplay({
127
+ recentLogs,
128
+ projectLogs,
129
+ allLogs,
130
+ tools,
131
+ commands,
132
+ verbose,
133
+ onClose,
134
+ unmount
135
+ }) {
136
+ const [activeTab, setActiveTab] = useState("recent");
137
+ const [searchQuery, setSearchQuery] = useState("");
138
+ const tabs = useMemo(
139
+ () => [
140
+ {
141
+ id: "recent",
142
+ label: t("commands.sessions.title"),
143
+ badge: recentLogs.length
144
+ },
145
+ {
146
+ id: "project",
147
+ label: t("commands.sessions.headerProject"),
148
+ badge: projectLogs.length
149
+ },
150
+ {
151
+ id: "all",
152
+ label: t("common.all"),
153
+ badge: allLogs.length
154
+ }
155
+ ],
156
+ [recentLogs.length, projectLogs.length, allLogs.length]
157
+ );
158
+ const items = useMemo(() => {
159
+ let logs;
160
+ switch (activeTab) {
161
+ case "project":
162
+ logs = projectLogs;
163
+ break;
164
+ case "all":
165
+ logs = allLogs;
166
+ break;
167
+ case "recent":
168
+ default:
169
+ logs = recentLogs;
170
+ }
171
+ return logs.map(logToListItem);
172
+ }, [activeTab, recentLogs, projectLogs, allLogs]);
173
+ const handleSelect = async (item) => {
174
+ const log = item.data;
175
+ try {
176
+ onClose();
177
+ const isDefaultModel = await isDefaultSlowAndCapableModel();
178
+ unmount();
179
+ await prepareTerminalForREPL();
180
+ render(
181
+ /* @__PURE__ */ React.createElement(
182
+ REPL,
183
+ {
184
+ messageLogName: log.date,
185
+ initialPrompt: "",
186
+ shouldShowPromptInput: true,
187
+ verbose,
188
+ commands,
189
+ tools,
190
+ initialMessages: deserializeMessages(log.messages, tools),
191
+ initialForkNumber: getNextAvailableLogForkNumber(
192
+ log.date,
193
+ log.forkNumber ?? 1,
194
+ 0
195
+ ),
196
+ isDefaultModel,
197
+ isResumedConversation: true
198
+ }
199
+ ),
200
+ {
201
+ exitOnCtrlC: false
202
+ }
203
+ );
204
+ } catch (e) {
205
+ logError(`Failed to load conversation: ${e}`);
206
+ throw e;
207
+ }
208
+ };
209
+ return /* @__PURE__ */ React.createElement(
210
+ TabbedListView,
211
+ {
212
+ title: t("commands.resume.title"),
213
+ tabs,
214
+ activeTab,
215
+ onTabChange: setActiveTab,
216
+ items,
217
+ searchEnabled: true,
218
+ searchPlaceholder: t("ui.tabbedList.search"),
219
+ searchQuery,
220
+ onSearchChange: setSearchQuery,
221
+ onSelect: handleSelect,
222
+ onClose,
223
+ emptyText: t("commands.resume.noSessions"),
224
+ footerHint: t("commands.resume.navigationHint"),
225
+ groupByCategory: activeTab === "all"
226
+ }
227
+ );
228
+ }
5
229
  var resume_default = {
6
230
  type: "local-jsx",
7
231
  name: "resume",
8
- description: "Resume a previous conversation from this project",
232
+ description: t("commands.resume.description"),
9
233
  isEnabled: true,
10
234
  isHidden: false,
235
+ showBelowPrompt: true,
11
236
  aliases: ["r"],
12
237
  userFacingName() {
13
238
  return "resume";
14
239
  },
15
240
  async call(onDone, context) {
16
241
  const { commands = [], tools = [], verbose = false } = context.options || {};
17
- const logs = await loadLogList(CACHE_PATHS.messages());
18
- render(
19
- /* @__PURE__ */ React.createElement(
20
- ResumeConversation,
21
- {
22
- commands,
23
- context: { unmount: onDone },
24
- logs,
25
- tools,
26
- verbose
27
- }
28
- )
242
+ const cwd = getCwd();
243
+ const allRawLogs = await loadLogList(CACHE_PATHS.messages());
244
+ const validLogs = deduplicateLogForks(
245
+ allRawLogs.filter((log) => !wasCleared(log))
246
+ );
247
+ const recentLogs = validLogs.slice(0, 20);
248
+ const projectLogs = validLogs.filter((log) => {
249
+ const logPath = getLogProjectPath(log);
250
+ return logPath === cwd;
251
+ });
252
+ const allLogs = validLogs.slice(0, 100);
253
+ return /* @__PURE__ */ React.createElement(
254
+ ResumeDisplay,
255
+ {
256
+ recentLogs,
257
+ projectLogs,
258
+ allLogs,
259
+ tools,
260
+ commands,
261
+ verbose,
262
+ onClose: onDone,
263
+ unmount: context.unmount
264
+ }
29
265
  );
30
- return null;
31
266
  }
32
267
  };
33
268
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/resume.tsx"],
4
- "sourcesContent": ["import * as React from 'react'\nimport type { Command } from '@commands'\nimport { ResumeConversation } from '@screens/ResumeConversation'\nimport { render } from 'ink'\nimport { CACHE_PATHS, loadLogList } from '@utils/log'\n\nexport default {\n type: 'local-jsx',\n name: 'resume',\n description: 'Resume a previous conversation from this project',\n isEnabled: true,\n isHidden: false,\n aliases: ['r'],\n userFacingName() {\n return 'resume'\n },\n async call(onDone, context) {\n const { commands = [], tools = [], verbose = false } = context.options || {}\n const logs = await loadLogList(CACHE_PATHS.messages())\n render(\n <ResumeConversation\n commands={commands}\n context={{ unmount: onDone }}\n logs={logs}\n tools={tools}\n verbose={verbose}\n />,\n )\n // This return is here for type only\n return null\n },\n} satisfies Command\n"],
5
- "mappings": "AAAA,YAAY,WAAW;AAEvB,SAAS,0BAA0B;AACnC,SAAS,cAAc;AACvB,SAAS,aAAa,mBAAmB;AAEzC,IAAO,iBAAQ;AAAA,EACb,MAAM;AAAA,EACN,MAAM;AAAA,EACN,aAAa;AAAA,EACb,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS,CAAC,GAAG;AAAA,EACb,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,KAAK,QAAQ,SAAS;AAC1B,UAAM,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,UAAU,MAAM,IAAI,QAAQ,WAAW,CAAC;AAC3E,UAAM,OAAO,MAAM,YAAY,YAAY,SAAS,CAAC;AACrD;AAAA,MACE;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,SAAS,EAAE,SAAS,OAAO;AAAA,UAC3B;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;",
4
+ "sourcesContent": ["/**\n * Resume Command\n *\n * Resume a previous conversation.\n * Uses TabbedListView with 3 tabs: Recent, Project, All.\n *\n * Usage:\n * /resume # Show sessions with tabs\n * /r # Alias\n */\n\nimport React, { useState, useMemo } from 'react'\nimport { render } from 'ink'\nimport path from 'path'\nimport type { Command } from '@commands'\nimport { t } from '@i18n'\nimport { getCwd } from '@utils/state'\nimport { CACHE_PATHS, loadLogList } from '@utils/log'\nimport type { LogOption } from '@minto-types/logs'\nimport { deserializeMessages } from '@utils/conversationRecovery'\nimport { getNextAvailableLogForkNumber, logError } from '@utils/log'\nimport { isDefaultSlowAndCapableModel } from '@utils/model'\nimport { prepareTerminalForREPL } from '@utils/terminal'\nimport { REPL } from '@screens/REPL'\nimport type { Tool } from '@tool'\nimport {\n TabbedListView,\n type ListItem,\n type TabDefinition,\n} from '@components/TabbedListView'\n\n/**\n * Format date for display\n * - Today: \"Today HH:mm\"\n * - Yesterday: \"Yesterday HH:mm\"\n * - Other: \"MM-DD HH:mm\"\n */\nfunction formatDate(date: Date): string {\n const now = new Date()\n\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n const timeStr = `${hours}:${minutes}`\n\n // Check if it's today\n const isToday =\n date.getDate() === now.getDate() &&\n date.getMonth() === now.getMonth() &&\n date.getFullYear() === now.getFullYear()\n\n if (isToday) {\n return `${t('commands.sessions.today')} ${timeStr}`\n }\n\n // Check if it's yesterday\n const yesterday = new Date(now)\n yesterday.setDate(yesterday.getDate() - 1)\n const isYesterday =\n date.getDate() === yesterday.getDate() &&\n date.getMonth() === yesterday.getMonth() &&\n date.getFullYear() === yesterday.getFullYear()\n\n if (isYesterday) {\n return `${t('commands.sessions.yesterday')} ${timeStr}`\n }\n\n // Default format: MM-DD HH:mm\n const month = (date.getMonth() + 1).toString().padStart(2, '0')\n const day = date.getDate().toString().padStart(2, '0')\n return `${month}-${day} ${timeStr}`\n}\n\n/**\n * Truncate string with ellipsis\n */\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str\n return str.slice(0, maxLength - 3) + '...'\n}\n\n/**\n * Check if the conversation was discarded (last user message is /clear)\n */\nfunction wasCleared(log: LogOption): boolean {\n // Find the last user message by iterating backwards\n for (let i = log.messages.length - 1; i >= 0; i--) {\n const msg = log.messages[i]\n if (msg.type === 'user') {\n const content =\n typeof msg.message?.content === 'string'\n ? msg.message.content\n : Array.isArray(msg.message?.content)\n ? msg.message.content\n .filter((c: any) => c.type === 'text')\n .map((c: any) => c.text)\n .join('')\n : ''\n // Check if the last user message is a /clear command\n return content.includes('<command-name>clear</command-name>')\n }\n }\n return false\n}\n\n/**\n * Deduplicate logs by keeping only the latest fork for each base conversation.\n * Groups logs by their base date (timestamp without fork number) and keeps\n * the one with the highest fork number or most recent modification.\n */\nfunction deduplicateLogForks(logs: LogOption[]): LogOption[] {\n // Group by base date (the original conversation timestamp)\n const groupedByDate = new Map<string, LogOption[]>()\n\n for (const log of logs) {\n const existing = groupedByDate.get(log.date) || []\n existing.push(log)\n groupedByDate.set(log.date, existing)\n }\n\n // For each group, keep the one with highest fork number (most recent state)\n const deduped: LogOption[] = []\n for (const [, group] of groupedByDate) {\n // Sort by forkNumber desc (higher = more recent), then by modified desc\n const sorted = group.sort((a, b) => {\n const forkDiff = (b.forkNumber ?? 0) - (a.forkNumber ?? 0)\n if (forkDiff !== 0) return forkDiff\n return b.modified.getTime() - a.modified.getTime()\n })\n // Keep only the first one (highest fork / most recently modified)\n if (sorted[0]) {\n deduped.push(sorted[0])\n }\n }\n\n // Re-sort by modified time descending\n return deduped.sort((a, b) => b.modified.getTime() - a.modified.getTime())\n}\n\n/**\n * Get project path from log's first message\n */\nfunction getLogProjectPath(log: LogOption): string | null {\n const firstMessage = log.messages[0]\n return firstMessage?.cwd || null\n}\n\n/**\n * Get project name from path\n */\nfunction getProjectName(projectPath: string): string {\n return path.basename(projectPath) || projectPath\n}\n\n/**\n * Extract clean first prompt from log (skip system messages and XML tags)\n */\nfunction extractFirstPrompt(log: LogOption): string {\n for (const msg of log.messages) {\n if (msg.type === 'user') {\n let content = ''\n if (typeof msg.message?.content === 'string') {\n content = msg.message.content\n } else if (Array.isArray(msg.message?.content)) {\n content = msg.message.content\n .filter((c: any) => c.type === 'text')\n .map((c: any) => c.text)\n .join('')\n }\n\n // Skip system messages (XML tags like <system-reminder>, <command-name>, etc.)\n const trimmed = content.trim()\n if (\n trimmed.startsWith('<system-reminder>') ||\n trimmed.startsWith('<command-name>') ||\n (trimmed.startsWith('<') && trimmed.includes('</'))\n ) {\n continue\n }\n\n // Return first line, cleaned up\n const firstLine = content.split('\\n')[0]?.trim() || ''\n if (firstLine) {\n return firstLine\n }\n }\n }\n return log.firstPrompt || 'No prompt'\n}\n\n/**\n * Count tool calls in a log\n */\nfunction countToolCalls(log: LogOption): number {\n let count = 0\n for (const msg of log.messages) {\n if (msg.type === 'assistant' && Array.isArray(msg.message?.content)) {\n for (const block of msg.message.content) {\n if (block.type === 'tool_use') {\n count++\n }\n }\n }\n }\n return count\n}\n\n/**\n * Convert LogOption to ListItem for TabbedListView\n */\nfunction logToListItem(log: LogOption): ListItem {\n const dateStr = formatDate(log.modified)\n const projectPath = getLogProjectPath(log) || ''\n const projectName = projectPath\n ? truncate(getProjectName(projectPath), 15)\n : ''\n const msgCount = log.messageCount\n const toolCount = countToolCalls(log)\n const firstPrompt = extractFirstPrompt(log)\n\n return {\n id: log.fullPath, // Use fullPath as unique id (date can be duplicated for forks)\n label: truncate(firstPrompt, 45),\n description: projectName || undefined,\n metadata: `${dateStr} \u00B7 ${msgCount} msgs \u00B7 ${toolCount} tools`,\n category: projectName || 'Unknown',\n data: log,\n }\n}\n\ninterface ResumeDisplayProps {\n recentLogs: LogOption[]\n projectLogs: LogOption[]\n allLogs: LogOption[]\n tools: Tool[]\n commands: Command[]\n verbose: boolean | undefined\n onClose: () => void\n unmount: () => void\n}\n\n/**\n * Resume display component with TabbedListView\n */\nfunction ResumeDisplay({\n recentLogs,\n projectLogs,\n allLogs,\n tools,\n commands,\n verbose,\n onClose,\n unmount,\n}: ResumeDisplayProps) {\n const [activeTab, setActiveTab] = useState('recent')\n const [searchQuery, setSearchQuery] = useState('')\n\n // Tab definitions\n const tabs: TabDefinition[] = useMemo(\n () => [\n {\n id: 'recent',\n label: t('commands.sessions.title'),\n badge: recentLogs.length,\n },\n {\n id: 'project',\n label: t('commands.sessions.headerProject'),\n badge: projectLogs.length,\n },\n {\n id: 'all',\n label: t('common.all'),\n badge: allLogs.length,\n },\n ],\n [recentLogs.length, projectLogs.length, allLogs.length],\n )\n\n // Get items based on active tab\n const items: ListItem[] = useMemo(() => {\n let logs: LogOption[]\n\n switch (activeTab) {\n case 'project':\n logs = projectLogs\n break\n case 'all':\n logs = allLogs\n break\n case 'recent':\n default:\n logs = recentLogs\n }\n\n return logs.map(logToListItem)\n }, [activeTab, recentLogs, projectLogs, allLogs])\n\n // Handle item selection - load and resume conversation\n const handleSelect = async (item: ListItem) => {\n const log = item.data as LogOption\n\n try {\n // First close the selection UI\n onClose()\n\n // Check if using default model before unmounting\n const isDefaultModel = await isDefaultSlowAndCapableModel()\n\n // Unmount current REPL before creating new one\n // This prevents two Ink instances from conflicting\n unmount()\n\n // Clear screen and prepare terminal for REPL\n await prepareTerminalForREPL()\n\n render(\n <REPL\n messageLogName={log.date}\n initialPrompt=\"\"\n shouldShowPromptInput={true}\n verbose={verbose}\n commands={commands}\n tools={tools}\n initialMessages={deserializeMessages(log.messages, tools)}\n initialForkNumber={getNextAvailableLogForkNumber(\n log.date,\n log.forkNumber ?? 1,\n 0,\n )}\n isDefaultModel={isDefaultModel}\n isResumedConversation={true}\n />,\n {\n exitOnCtrlC: false,\n },\n )\n } catch (e) {\n logError(`Failed to load conversation: ${e}`)\n throw e\n }\n }\n\n return (\n <TabbedListView\n title={t('commands.resume.title')}\n tabs={tabs}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n items={items}\n searchEnabled={true}\n searchPlaceholder={t('ui.tabbedList.search')}\n searchQuery={searchQuery}\n onSearchChange={setSearchQuery}\n onSelect={handleSelect}\n onClose={onClose}\n emptyText={t('commands.resume.noSessions')}\n footerHint={t('commands.resume.navigationHint')}\n groupByCategory={activeTab === 'all'}\n />\n )\n}\n\nexport default {\n type: 'local-jsx',\n name: 'resume',\n description: t('commands.resume.description'),\n isEnabled: true,\n isHidden: false,\n showBelowPrompt: true,\n aliases: ['r'],\n userFacingName() {\n return 'resume'\n },\n async call(onDone, context) {\n const { commands = [], tools = [], verbose = false } = context.options || {}\n const cwd = getCwd()\n\n // Load all logs\n const allRawLogs = await loadLogList(CACHE_PATHS.messages())\n\n // Filter out cleared conversations, then deduplicate forks\n // (keep only the latest fork for each base conversation)\n const validLogs = deduplicateLogForks(\n allRawLogs.filter(log => !wasCleared(log)),\n )\n\n // Recent: first 20 logs (already sorted by modified time)\n const recentLogs = validLogs.slice(0, 20)\n\n // Project: logs from current project\n const projectLogs = validLogs.filter(log => {\n const logPath = getLogProjectPath(log)\n return logPath === cwd\n })\n\n // All: all valid logs (up to 100)\n const allLogs = validLogs.slice(0, 100)\n\n return (\n <ResumeDisplay\n recentLogs={recentLogs}\n projectLogs={projectLogs}\n allLogs={allLogs}\n tools={tools}\n commands={commands}\n verbose={verbose}\n onClose={onDone}\n unmount={context.unmount}\n />\n )\n },\n} satisfies Command\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }