@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
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
4
+ function TabBar({ tabs, activeTab, onTabChange }) {
5
+ return /* @__PURE__ */ React.createElement(Box, null, tabs.map((tab, index) => {
6
+ const isActive = tab.id === activeTab;
7
+ const isLast = index === tabs.length - 1;
8
+ return /* @__PURE__ */ React.createElement(Box, { key: tab.id }, isActive ? (
9
+ // Active tab: background highlight with brand color
10
+ /* @__PURE__ */ React.createElement(Text, { backgroundColor: BRAND_GRADIENT.START, color: "black", bold: true }, " ", tab.label, tab.badge !== void 0 && tab.badge > 0 ? ` (${tab.badge})` : "", " ")
11
+ ) : (
12
+ // Inactive tab: dim text
13
+ /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", tab.label, tab.badge !== void 0 && tab.badge > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " (", tab.badge, ")"), " ")
14
+ ), !isLast && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, "\u2502"));
15
+ }), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " Tab/\u2190\u2192"));
16
+ }
17
+ export {
18
+ TabBar
19
+ };
20
+ //# sourceMappingURL=TabBar.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/TabbedListView/TabBar.tsx"],
4
+ "sourcesContent": ["/**\n * TabBar Component\n *\n * Displays tab navigation matching the brand style.\n * Uses background color for active tab selection.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport type { TabBarProps } from './types'\n\nexport function TabBar({ tabs, activeTab, onTabChange }: TabBarProps) {\n return (\n <Box>\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab\n const isLast = index === tabs.length - 1\n\n return (\n <Box key={tab.id}>\n {isActive ? (\n // Active tab: background highlight with brand color\n <Text backgroundColor={BRAND_GRADIENT.START} color=\"black\" bold>\n {' '}\n {tab.label}\n {tab.badge !== undefined && tab.badge > 0\n ? ` (${tab.badge})`\n : ''}{' '}\n </Text>\n ) : (\n // Inactive tab: dim text\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {tab.label}\n {tab.badge !== undefined && tab.badge > 0 && (\n <Text color={SEMANTIC_COLORS.muted}> ({tab.badge})</Text>\n )}{' '}\n </Text>\n )}\n {!isLast && <Text color={SEMANTIC_COLORS.muted}>\u2502</Text>}\n </Box>\n )\n })}\n <Text color={SEMANTIC_COLORS.muted}> Tab/\u2190\u2192</Text>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB,uBAAuB;AAGzC,SAAS,OAAO,EAAE,MAAM,WAAW,YAAY,GAAgB;AACpE,SACE,oCAAC,WACE,KAAK,IAAI,CAAC,KAAK,UAAU;AACxB,UAAM,WAAW,IAAI,OAAO;AAC5B,UAAM,SAAS,UAAU,KAAK,SAAS;AAEvC,WACE,oCAAC,OAAI,KAAK,IAAI,MACX;AAAA;AAAA,MAEC,oCAAC,QAAK,iBAAiB,eAAe,OAAO,OAAM,SAAQ,MAAI,QAC5D,KACA,IAAI,OACJ,IAAI,UAAU,UAAa,IAAI,QAAQ,IACpC,KAAK,IAAI,KAAK,MACd,IAAI,GACV;AAAA;AAAA;AAAA,MAGA,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,KACA,IAAI,OACJ,IAAI,UAAU,UAAa,IAAI,QAAQ,KACtC,oCAAC,QAAK,OAAO,gBAAgB,SAAO,MAAG,IAAI,OAAM,GAAC,GACjD,GACL;AAAA,OAED,CAAC,UAAU,oCAAC,QAAK,OAAO,gBAAgB,SAAO,QAAC,CACnD;AAAA,EAEJ,CAAC,GACD,oCAAC,QAAK,OAAO,gBAAgB,SAAO,mBAAO,CAC7C;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,171 @@
1
+ import React, { useState, useCallback, useMemo } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
4
+ import { TabBar } from "./TabBar.js";
5
+ import { SearchInput } from "./SearchInput.js";
6
+ import { ScrollableList } from "./ScrollableList.js";
7
+ import { SimpleSpinner } from "../Spinner.js";
8
+ const MAX_VISIBLE_ITEMS = 8;
9
+ function TabbedListView({
10
+ title,
11
+ tabs,
12
+ activeTab,
13
+ onTabChange,
14
+ items,
15
+ searchEnabled = true,
16
+ searchPlaceholder = "Search...",
17
+ searchQuery = "",
18
+ onSearchChange,
19
+ onSelect,
20
+ onClose,
21
+ footerHint,
22
+ isLoading = false,
23
+ loadingText = "Loading...",
24
+ emptyText = "No items found",
25
+ groupByCategory = false,
26
+ renderItem
27
+ }) {
28
+ const [focusArea, setFocusArea] = useState(
29
+ searchEnabled ? "search" : "list"
30
+ );
31
+ const [focusedIndex, setFocusedIndex] = useState(0);
32
+ const filteredItems = useMemo(() => {
33
+ if (!searchQuery.trim()) return items;
34
+ const query = searchQuery.toLowerCase();
35
+ return items.filter(
36
+ (item) => item.label.toLowerCase().includes(query) || item.description?.toLowerCase().includes(query) || item.category?.toLowerCase().includes(query)
37
+ );
38
+ }, [items, searchQuery]);
39
+ React.useEffect(() => {
40
+ setFocusedIndex(0);
41
+ }, [filteredItems.length, activeTab]);
42
+ const cycleTab = useCallback(
43
+ (direction) => {
44
+ const currentIndex = tabs.findIndex((t) => t.id === activeTab);
45
+ let newIndex;
46
+ if (direction === "right") {
47
+ newIndex = (currentIndex + 1) % tabs.length;
48
+ } else {
49
+ newIndex = currentIndex - 1 < 0 ? tabs.length - 1 : currentIndex - 1;
50
+ }
51
+ onTabChange(tabs[newIndex].id);
52
+ },
53
+ [tabs, activeTab, onTabChange]
54
+ );
55
+ const handleSelect = useCallback(
56
+ (item) => {
57
+ if (onSelect) {
58
+ onSelect(item);
59
+ }
60
+ },
61
+ [onSelect]
62
+ );
63
+ useInput((input, key) => {
64
+ if (key.escape) {
65
+ onClose();
66
+ return;
67
+ }
68
+ if (key.tab) {
69
+ cycleTab(key.shift ? "left" : "right");
70
+ return;
71
+ }
72
+ if (focusArea === "tabs" || focusArea === "search") {
73
+ if (key.leftArrow) {
74
+ cycleTab("left");
75
+ return;
76
+ }
77
+ if (key.rightArrow) {
78
+ cycleTab("right");
79
+ return;
80
+ }
81
+ }
82
+ if (key.downArrow) {
83
+ if (focusArea === "search") {
84
+ setFocusArea("list");
85
+ return;
86
+ }
87
+ if (focusArea === "list" && filteredItems.length > 0) {
88
+ setFocusedIndex(
89
+ (prev) => prev < filteredItems.length - 1 ? prev + 1 : prev
90
+ );
91
+ return;
92
+ }
93
+ }
94
+ if (key.upArrow) {
95
+ if (focusArea === "list") {
96
+ if (focusedIndex > 0) {
97
+ setFocusedIndex((prev) => prev - 1);
98
+ } else if (searchEnabled) {
99
+ setFocusArea("search");
100
+ }
101
+ return;
102
+ }
103
+ }
104
+ if (key.return && focusArea === "list" && filteredItems.length > 0) {
105
+ handleSelect(filteredItems[focusedIndex]);
106
+ return;
107
+ }
108
+ if (input === "/" && searchEnabled && focusArea !== "search") {
109
+ setFocusArea("search");
110
+ return;
111
+ }
112
+ });
113
+ const defaultHint = "\u2191\u2193 Navigate \xB7 Enter Select \xB7 Tab/\u2190\u2192 Switch \xB7 Esc Close";
114
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React.createElement(
115
+ Box,
116
+ {
117
+ borderTop: true,
118
+ borderBottom: false,
119
+ borderLeft: false,
120
+ borderRight: false,
121
+ borderColor: BRAND_GRADIENT.START,
122
+ borderStyle: "single",
123
+ width: "100%",
124
+ paddingX: 1,
125
+ flexDirection: "column"
126
+ },
127
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, " ", title), filteredItems.length > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " (", filteredItems.length, ")")),
128
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(TabBar, { tabs, activeTab, onTabChange }))
129
+ ), /* @__PURE__ */ React.createElement(
130
+ Box,
131
+ {
132
+ flexDirection: "column",
133
+ borderTop: false,
134
+ borderBottom: true,
135
+ borderLeft: false,
136
+ borderRight: false,
137
+ borderColor: BRAND_GRADIENT.START,
138
+ borderStyle: "single",
139
+ width: "100%",
140
+ paddingX: 1,
141
+ paddingY: 1
142
+ },
143
+ searchEnabled && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(
144
+ SearchInput,
145
+ {
146
+ value: searchQuery,
147
+ onChange: onSearchChange || (() => {
148
+ }),
149
+ placeholder: searchPlaceholder,
150
+ isActive: focusArea === "search"
151
+ }
152
+ )),
153
+ /* @__PURE__ */ React.createElement(Box, { key: `content-${activeTab}`, flexDirection: "column" }, isLoading ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", loadingText)) : filteredItems.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, emptyText)) : /* @__PURE__ */ React.createElement(
154
+ ScrollableList,
155
+ {
156
+ items: filteredItems,
157
+ focusedIndex,
158
+ onFocusChange: setFocusedIndex,
159
+ onSelect: handleSelect,
160
+ visibleCount: MAX_VISIBLE_ITEMS,
161
+ groupByCategory,
162
+ renderItem
163
+ }
164
+ )),
165
+ /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, footerHint || defaultHint))
166
+ ));
167
+ }
168
+ export {
169
+ TabbedListView
170
+ };
171
+ //# sourceMappingURL=TabbedListView.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/TabbedListView/TabbedListView.tsx"],
4
+ "sourcesContent": ["/**\n * TabbedListView Component\n *\n * A reusable component matching the /command suggestion UI pattern:\n * - Tab navigation (\u2190/\u2192 or Tab key)\n * - Search input (/ to focus)\n * - Scrollable list with \u25C6 selection indicator\n * - Brand gradient colors for selection\n * - Consistent height control (MAX_VISIBLE = 8)\n *\n * Based on Claude Code CLI's /plugins UI pattern.\n */\n\nimport React, { useState, useCallback, useMemo } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { TabBar } from './TabBar'\nimport { SearchInput } from './SearchInput'\nimport { ScrollableList } from './ScrollableList'\nimport { SimpleSpinner } from '@components/Spinner'\nimport type { TabbedListViewProps, ListItem } from './types'\n\ntype FocusArea = 'tabs' | 'search' | 'list'\n\n// Match command suggestion visible count\nconst MAX_VISIBLE_ITEMS = 8\n\nexport function TabbedListView({\n title,\n tabs,\n activeTab,\n onTabChange,\n items,\n searchEnabled = true,\n searchPlaceholder = 'Search...',\n searchQuery = '',\n onSearchChange,\n onSelect,\n onClose,\n footerHint,\n isLoading = false,\n loadingText = 'Loading...',\n emptyText = 'No items found',\n groupByCategory = false,\n renderItem,\n}: TabbedListViewProps) {\n // Focus state: which area is currently active\n const [focusArea, setFocusArea] = useState<FocusArea>(\n searchEnabled ? 'search' : 'list',\n )\n\n // Index of focused item in the list\n const [focusedIndex, setFocusedIndex] = useState(0)\n\n // Filter items based on search query\n const filteredItems = useMemo(() => {\n if (!searchQuery.trim()) return items\n\n const query = searchQuery.toLowerCase()\n return items.filter(\n item =>\n item.label.toLowerCase().includes(query) ||\n item.description?.toLowerCase().includes(query) ||\n item.category?.toLowerCase().includes(query),\n )\n }, [items, searchQuery])\n\n // Reset focus index when items change\n React.useEffect(() => {\n setFocusedIndex(0)\n }, [filteredItems.length, activeTab])\n\n // Handle tab cycling\n const cycleTab = useCallback(\n (direction: 'left' | 'right') => {\n const currentIndex = tabs.findIndex(t => t.id === activeTab)\n let newIndex: number\n\n if (direction === 'right') {\n newIndex = (currentIndex + 1) % tabs.length\n } else {\n newIndex = currentIndex - 1 < 0 ? tabs.length - 1 : currentIndex - 1\n }\n\n onTabChange(tabs[newIndex].id)\n },\n [tabs, activeTab, onTabChange],\n )\n\n // Handle item selection\n const handleSelect = useCallback(\n (item: ListItem) => {\n if (onSelect) {\n onSelect(item)\n }\n },\n [onSelect],\n )\n\n // Keyboard input handling\n useInput((input, key) => {\n // Escape to close\n if (key.escape) {\n onClose()\n return\n }\n\n // Tab key cycles through tabs\n if (key.tab) {\n cycleTab(key.shift ? 'left' : 'right')\n return\n }\n\n // Left/Right arrows for tab navigation when in tabs or search area\n if (focusArea === 'tabs' || focusArea === 'search') {\n if (key.leftArrow) {\n cycleTab('left')\n return\n }\n if (key.rightArrow) {\n cycleTab('right')\n return\n }\n }\n\n // Handle focus area navigation\n if (key.downArrow) {\n if (focusArea === 'search') {\n setFocusArea('list')\n return\n }\n if (focusArea === 'list' && filteredItems.length > 0) {\n setFocusedIndex(prev =>\n prev < filteredItems.length - 1 ? prev + 1 : prev,\n )\n return\n }\n }\n\n if (key.upArrow) {\n if (focusArea === 'list') {\n if (focusedIndex > 0) {\n setFocusedIndex(prev => prev - 1)\n } else if (searchEnabled) {\n setFocusArea('search')\n }\n return\n }\n }\n\n // Enter to select\n if (key.return && focusArea === 'list' && filteredItems.length > 0) {\n handleSelect(filteredItems[focusedIndex])\n return\n }\n\n // '/' to focus search\n if (input === '/' && searchEnabled && focusArea !== 'search') {\n setFocusArea('search')\n return\n }\n })\n\n // Build default footer hint\n const defaultHint = '\u2191\u2193 Navigate \u00B7 Enter Select \u00B7 Tab/\u2190\u2192 Switch \u00B7 Esc Close'\n\n return (\n <Box flexDirection=\"column\" width=\"100%\">\n {/* Header bar with top border - mimics PromptInput separator */}\n <Box\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n flexDirection=\"column\"\n >\n {/* Title with brand color */}\n <Box>\n <Text color={BRAND_GRADIENT.START}>\u25C6</Text>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {' '}\n {title}\n </Text>\n {filteredItems.length > 0 && (\n <Text color={SEMANTIC_COLORS.dim}> ({filteredItems.length})</Text>\n )}\n </Box>\n\n {/* Tab Bar - left aligned */}\n <Box marginTop={1}>\n <TabBar tabs={tabs} activeTab={activeTab} onTabChange={onTabChange} />\n </Box>\n </Box>\n\n {/* Content container with bottom border */}\n <Box\n flexDirection=\"column\"\n borderTop={false}\n borderBottom={true}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n paddingY={1}\n >\n {/* Search Input */}\n {searchEnabled && (\n <Box marginBottom={1}>\n <SearchInput\n value={searchQuery}\n onChange={onSearchChange || (() => {})}\n placeholder={searchPlaceholder}\n isActive={focusArea === 'search'}\n />\n </Box>\n )}\n\n {/* Content Area - key forces re-render on tab change */}\n <Box key={`content-${activeTab}`} flexDirection=\"column\">\n {isLoading ? (\n <Box>\n <SimpleSpinner />\n <Text color={SEMANTIC_COLORS.dim}> {loadingText}</Text>\n </Box>\n ) : filteredItems.length === 0 ? (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>{emptyText}</Text>\n </Box>\n ) : (\n <ScrollableList\n items={filteredItems}\n focusedIndex={focusedIndex}\n onFocusChange={setFocusedIndex}\n onSelect={handleSelect}\n visibleCount={MAX_VISIBLE_ITEMS}\n groupByCategory={groupByCategory}\n renderItem={renderItem}\n />\n )}\n </Box>\n\n {/* Footer Hint - compact style */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.muted}>{footerHint || defaultHint}</Text>\n </Box>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ import { TabbedListView } from "./TabbedListView.js";
2
+ import { TabBar } from "./TabBar.js";
3
+ import { SearchInput } from "./SearchInput.js";
4
+ import { ScrollableList } from "./ScrollableList.js";
5
+ export {
6
+ ScrollableList,
7
+ SearchInput,
8
+ TabBar,
9
+ TabbedListView
10
+ };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/TabbedListView/index.ts"],
4
+ "sourcesContent": ["/**\n * TabbedListView Component Exports\n *\n * A reusable tabbed list view component based on Claude Code CLI's /plugins pattern.\n */\n\nexport { TabbedListView } from './TabbedListView'\nexport { TabBar } from './TabBar'\nexport { SearchInput } from './SearchInput'\nexport { ScrollableList } from './ScrollableList'\nexport type {\n TabbedListViewProps,\n TabDefinition,\n ListItem,\n CategoryGroup,\n TabBarProps,\n SearchInputProps,\n ScrollableListProps,\n} from './types'\n"],
5
+ "mappings": "AAMA,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AACvB,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -2,6 +2,7 @@ import { Box, Text } from "ink";
2
2
  import React from "react";
3
3
  import { TodoChangeLine } from "./TodoChangeLine.js";
4
4
  import { getTheme } from "../utils/theme.js";
5
+ import { t } from "../i18n/index.js";
5
6
  function TodoChangeBlock({
6
7
  changes,
7
8
  todos,
@@ -9,18 +10,18 @@ function TodoChangeBlock({
9
10
  }) {
10
11
  const theme = getTheme();
11
12
  const stats = {
12
- pending: todos.filter((t) => t.status === "pending").length,
13
- inProgress: todos.filter((t) => t.status === "in_progress").length,
14
- completed: todos.filter((t) => t.status === "completed").length
13
+ pending: todos.filter((t2) => t2.status === "pending").length,
14
+ inProgress: todos.filter((t2) => t2.status === "in_progress").length,
15
+ completed: todos.filter((t2) => t2.status === "completed").length
15
16
  };
16
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: indent * 2 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: theme.brand }, "\u{1F527} "), /* @__PURE__ */ React.createElement(Text, null, "Updated task list")), changes.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, changes.map((change, idx) => /* @__PURE__ */ React.createElement(Box, { key: `${change.todoId}-${idx}` }, /* @__PURE__ */ React.createElement(TodoChangeLine, { change })))), /* @__PURE__ */ React.createElement(
17
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: indent * 2 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: theme.brand }, "\u{1F527} "), /* @__PURE__ */ React.createElement(Text, null, t("ui.todo.updatedTaskList"))), changes.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, changes.map((change, idx) => /* @__PURE__ */ React.createElement(Box, { key: `${change.todoId}-${idx}` }, /* @__PURE__ */ React.createElement(TodoChangeLine, { change })))), /* @__PURE__ */ React.createElement(
17
18
  Box,
18
19
  {
19
20
  flexDirection: "row",
20
21
  marginLeft: 2,
21
22
  marginTop: changes.length > 0 ? 1 : 0
22
23
  },
23
- /* @__PURE__ */ React.createElement(Text, { color: theme.dim }, stats.pending, " pending \xB7 ", stats.inProgress, " in progress \xB7", " ", stats.completed, " done")
24
+ /* @__PURE__ */ React.createElement(Text, { color: theme.dim }, stats.pending, " ", t("ui.todo.pending"), " \xB7 ", stats.inProgress, " ", t("ui.todo.inProgress"), " \xB7 ", stats.completed, " ", t("ui.todo.done"))
24
25
  ));
25
26
  }
26
27
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/TodoChangeBlock.tsx"],
4
- "sourcesContent": ["/**\n * TodoChangeBlock - Renders Todo changes in the conversation flow\n *\n * Displays:\n * - Tool call header \"\uD83D\uDD27 Updated task list\"\n * - Individual changes via TodoChangeLine\n * - Summary statistics (pending/in_progress/completed)\n *\n * When TodoWriteTool is called, this component shows what changed\n * in the conversation timeline, separate from the TodoPanel.\n */\n\nimport { Box, Text } from 'ink'\nimport React from 'react'\nimport type { TodoChange } from '@utils/todoChangeCalculator'\nimport type { TodoItem } from '@utils/todoStorage'\nimport { TodoChangeLine } from './TodoChangeLine'\nimport { getTheme } from '@utils/theme'\n\ninterface TodoChangeBlockProps {\n /** List of changes to display */\n changes: TodoChange[]\n /** Current complete todo list (for statistics) */\n todos: TodoItem[]\n /** Indentation level (default: 1) */\n indent?: number\n}\n\nexport function TodoChangeBlock({\n changes,\n todos,\n indent = 1,\n}: TodoChangeBlockProps) {\n const theme = getTheme()\n\n // Calculate statistics\n const stats = {\n pending: todos.filter(t => t.status === 'pending').length,\n inProgress: todos.filter(t => t.status === 'in_progress').length,\n completed: todos.filter(t => t.status === 'completed').length,\n }\n\n return (\n <Box flexDirection=\"column\" marginLeft={indent * 2}>\n {/* Tool call header */}\n <Box flexDirection=\"row\">\n <Text color={theme.brand}>\uD83D\uDD27 </Text>\n <Text>Updated task list</Text>\n </Box>\n\n {/* Changes display */}\n {changes.length > 0 && (\n <Box flexDirection=\"column\" marginLeft={2}>\n {changes.map((change, idx) => (\n <Box key={`${change.todoId}-${idx}`}>\n <TodoChangeLine change={change} />\n </Box>\n ))}\n </Box>\n )}\n\n {/* Summary statistics */}\n <Box\n flexDirection=\"row\"\n marginLeft={2}\n marginTop={changes.length > 0 ? 1 : 0}\n >\n <Text color={theme.dim}>\n {stats.pending} pending \u00B7 {stats.inProgress} in progress \u00B7{' '}\n {stats.completed} done\n </Text>\n </Box>\n </Box>\n )\n}\n"],
5
- "mappings": "AAYA,SAAS,KAAK,YAAY;AAC1B,OAAO,WAAW;AAGlB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AAWlB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAyB;AACvB,QAAM,QAAQ,SAAS;AAGvB,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM,OAAO,OAAK,EAAE,WAAW,SAAS,EAAE;AAAA,IACnD,YAAY,MAAM,OAAO,OAAK,EAAE,WAAW,aAAa,EAAE;AAAA,IAC1D,WAAW,MAAM,OAAO,OAAK,EAAE,WAAW,WAAW,EAAE;AAAA,EACzD;AAEA,SACE,oCAAC,OAAI,eAAc,UAAS,YAAY,SAAS,KAE/C,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAO,MAAM,SAAO,YAAG,GAC7B,oCAAC,YAAK,mBAAiB,CACzB,GAGC,QAAQ,SAAS,KAChB,oCAAC,OAAI,eAAc,UAAS,YAAY,KACrC,QAAQ,IAAI,CAAC,QAAQ,QACpB,oCAAC,OAAI,KAAK,GAAG,OAAO,MAAM,IAAI,GAAG,MAC/B,oCAAC,kBAAe,QAAgB,CAClC,CACD,CACH,GAIF;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,YAAY;AAAA,MACZ,WAAW,QAAQ,SAAS,IAAI,IAAI;AAAA;AAAA,IAEpC,oCAAC,QAAK,OAAO,MAAM,OAChB,MAAM,SAAQ,kBAAY,MAAM,YAAW,qBAAe,KAC1D,MAAM,WAAU,OACnB;AAAA,EACF,CACF;AAEJ;",
6
- "names": []
4
+ "sourcesContent": ["/**\n * TodoChangeBlock - Renders Todo changes in the conversation flow\n *\n * Displays:\n * - Tool call header \"\uD83D\uDD27 Updated task list\"\n * - Individual changes via TodoChangeLine\n * - Summary statistics (pending/in_progress/completed)\n *\n * When TodoWriteTool is called, this component shows what changed\n * in the conversation timeline, separate from the TodoPanel.\n */\n\nimport { Box, Text } from 'ink'\nimport React from 'react'\nimport type { TodoChange } from '@utils/todoChangeCalculator'\nimport type { TodoItem } from '@utils/todoStorage'\nimport { TodoChangeLine } from './TodoChangeLine'\nimport { getTheme } from '@utils/theme'\nimport { t } from '@i18n'\n\ninterface TodoChangeBlockProps {\n /** List of changes to display */\n changes: TodoChange[]\n /** Current complete todo list (for statistics) */\n todos: TodoItem[]\n /** Indentation level (default: 1) */\n indent?: number\n}\n\nexport function TodoChangeBlock({\n changes,\n todos,\n indent = 1,\n}: TodoChangeBlockProps) {\n const theme = getTheme()\n\n // Calculate statistics\n const stats = {\n pending: todos.filter(t => t.status === 'pending').length,\n inProgress: todos.filter(t => t.status === 'in_progress').length,\n completed: todos.filter(t => t.status === 'completed').length,\n }\n\n return (\n <Box flexDirection=\"column\" marginLeft={indent * 2}>\n {/* Tool call header */}\n <Box flexDirection=\"row\">\n <Text color={theme.brand}>\uD83D\uDD27 </Text>\n <Text>{t('ui.todo.updatedTaskList')}</Text>\n </Box>\n\n {/* Changes display */}\n {changes.length > 0 && (\n <Box flexDirection=\"column\" marginLeft={2}>\n {changes.map((change, idx) => (\n <Box key={`${change.todoId}-${idx}`}>\n <TodoChangeLine change={change} />\n </Box>\n ))}\n </Box>\n )}\n\n {/* Summary statistics */}\n <Box\n flexDirection=\"row\"\n marginLeft={2}\n marginTop={changes.length > 0 ? 1 : 0}\n >\n <Text color={theme.dim}>\n {stats.pending} {t('ui.todo.pending')} \u00B7 {stats.inProgress}{' '}\n {t('ui.todo.inProgress')} \u00B7 {stats.completed} {t('ui.todo.done')}\n </Text>\n </Box>\n </Box>\n )\n}\n"],
5
+ "mappings": "AAYA,SAAS,KAAK,YAAY;AAC1B,OAAO,WAAW;AAGlB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AACzB,SAAS,SAAS;AAWX,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAyB;AACvB,QAAM,QAAQ,SAAS;AAGvB,QAAM,QAAQ;AAAA,IACZ,SAAS,MAAM,OAAO,CAAAA,OAAKA,GAAE,WAAW,SAAS,EAAE;AAAA,IACnD,YAAY,MAAM,OAAO,CAAAA,OAAKA,GAAE,WAAW,aAAa,EAAE;AAAA,IAC1D,WAAW,MAAM,OAAO,CAAAA,OAAKA,GAAE,WAAW,WAAW,EAAE;AAAA,EACzD;AAEA,SACE,oCAAC,OAAI,eAAc,UAAS,YAAY,SAAS,KAE/C,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAO,MAAM,SAAO,YAAG,GAC7B,oCAAC,YAAM,EAAE,yBAAyB,CAAE,CACtC,GAGC,QAAQ,SAAS,KAChB,oCAAC,OAAI,eAAc,UAAS,YAAY,KACrC,QAAQ,IAAI,CAAC,QAAQ,QACpB,oCAAC,OAAI,KAAK,GAAG,OAAO,MAAM,IAAI,GAAG,MAC/B,oCAAC,kBAAe,QAAgB,CAClC,CACD,CACH,GAIF;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,YAAY;AAAA,MACZ,WAAW,QAAQ,SAAS,IAAI,IAAI;AAAA;AAAA,IAEpC,oCAAC,QAAK,OAAO,MAAM,OAChB,MAAM,SAAQ,KAAE,EAAE,iBAAiB,GAAE,UAAI,MAAM,YAAY,KAC3D,EAAE,oBAAoB,GAAE,UAAI,MAAM,WAAU,KAAE,EAAE,cAAc,CACjE;AAAA,EACF,CACF;AAEJ;",
6
+ "names": ["t"]
7
7
  }
@@ -13,6 +13,7 @@ import {
13
13
  SYMBOL_COLORS
14
14
  } from "../constants/colors.js";
15
15
  import { getIndent } from "../constants/formatRules.js";
16
+ import { t } from "../i18n/index.js";
16
17
  const SHIMMER_COLORS = [
17
18
  BRAND_GRADIENT.START,
18
19
  // #667EEA purple-blue
@@ -53,7 +54,7 @@ const SpinnerLine = memo(function SpinnerLine2({
53
54
  if (currentTaskActiveForm) {
54
55
  return currentTaskActiveForm;
55
56
  }
56
- const inProgressTodo = todos.find((t) => t.status === "in_progress");
57
+ const inProgressTodo = todos.find((t2) => t2.status === "in_progress");
57
58
  if (inProgressTodo?.activeForm) {
58
59
  return inProgressTodo.activeForm;
59
60
  }
@@ -116,11 +117,13 @@ const TodoPanel = memo(function TodoPanel2({
116
117
  const theme = getTheme();
117
118
  const fallbackMessage = useRef(sample(SPINNER_MESSAGES) || "Thinking");
118
119
  const hasTodos = todos.length > 0;
119
- const hasIncompleteTasks = todos.some((t) => t.status !== "completed");
120
+ const hasIncompleteTasks = todos.some((t2) => t2.status !== "completed");
120
121
  const shouldShowTodos = hasTodos && hasIncompleteTasks && isVisible && showTodoList;
121
122
  if (!isLoading) {
122
123
  if (shouldShowTodos) {
123
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\u25CB "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, hasIncompleteTasks ? `${todos.filter((t) => t.status !== "completed").length} tasks remaining` : "All done")), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, todos.map((todo, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: `todo-${idx}-${todo.content.slice(0, 20)}` }, /* @__PURE__ */ React.createElement(
124
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\u25CB "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, hasIncompleteTasks ? t("ui.todo.tasksRemaining", {
125
+ count: todos.filter((todo) => todo.status !== "completed").length
126
+ }) : t("ui.todo.allDone"))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, todos.map((todo, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: `todo-${idx}-${todo.content.slice(0, 20)}` }, /* @__PURE__ */ React.createElement(
124
127
  TodoItemClaudeStyle,
125
128
  {
126
129
  todo,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/TodoPanel.tsx"],
4
- "sourcesContent": ["import React, { useRef, useMemo, memo } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { SYMBOLS, getTodoStatusSymbol } from '@constants/symbols'\nimport { formatNumber, formatTokenUsage } from '@utils/format'\nimport type { TodoItem as TodoItemType } from '@utils/todoStorage'\nimport { sample } from 'lodash-es'\nimport { getMainStreamingState } from './Spinner'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport {\n SEMANTIC_COLORS,\n BRAND_GRADIENT,\n SYMBOL_COLORS,\n} from '@constants/colors'\nimport { getIndent } from '@constants/formatRules'\n\n/**\n * Isolated Spinner component to prevent animation updates from re-rendering the entire panel\n * This component handles all animation state internally\n */\ninterface SpinnerLineProps {\n currentTaskActiveForm?: string\n todos: TodoItemType[]\n shouldShowTodos: boolean\n fallbackMessage: string\n}\n\n/**\n * Shimmer effect colors - creates a light sweep animation across text\n * Uses brand gradient colors cycling through: purple-blue \u2192 pink-purple \u2192 coral \u2192 pink-purple \u2192 purple-blue\n */\nconst SHIMMER_COLORS = [\n BRAND_GRADIENT.START, // #667EEA purple-blue\n '#8673D9', // blend\n BRAND_GRADIENT.MIDDLE, // #B668C8 pink-purple\n '#D560A0', // blend\n BRAND_GRADIENT.END, // #F5576C coral\n '#D560A0', // blend back\n BRAND_GRADIENT.MIDDLE, // #B668C8\n '#8673D9', // blend back\n] as const\n\n/**\n * Get shimmer color based on animation frame\n * Creates a smooth color transition effect\n */\nfunction getShimmerColor(frame: number): string {\n return SHIMMER_COLORS[frame % SHIMMER_COLORS.length]!\n}\n\nconst SpinnerLine = memo(function SpinnerLine({\n currentTaskActiveForm,\n todos,\n shouldShowTodos,\n fallbackMessage,\n}: SpinnerLineProps) {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Animation state is isolated in this component\n // Use 8 frames for shimmer effect (matching SHIMMER_COLORS length)\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: true,\n startTime: startTimeRef.current,\n spinnerFrameCount: SHIMMER_COLORS.length,\n componentId: 'todo-panel-spinner',\n })\n\n // Get streaming state - only updates when this component re-renders\n // Use main streaming state to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [spinnerFrame])\n\n // Get current task display\n const getCurrentTaskDisplay = (): string => {\n if (currentTaskActiveForm) {\n return currentTaskActiveForm\n }\n const inProgressTodo = todos.find(t => t.status === 'in_progress')\n if (inProgressTodo?.activeForm) {\n return inProgressTodo.activeForm\n }\n switch (streamState.phase) {\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n case 'generating':\n return 'Generating response'\n case 'waiting':\n return 'Waiting for response'\n case 'thinking':\n default:\n return fallbackMessage || 'Thinking'\n }\n }\n\n // Format time display\n const formatTime = (seconds: number): string => {\n if (seconds < 60) return `${seconds}s`\n const mins = Math.floor(seconds / 60)\n const secs = seconds % 60\n return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`\n }\n\n // Get shimmer color for the main text (light sweep effect)\n const shimmerColor = getShimmerColor(spinnerFrame)\n\n // Spinner icon uses thinking frames\n const spinnerIconFrame = spinnerFrame % SYMBOLS.THINKING_FRAMES.length\n\n // Get token usage from streaming state (API values or approximate from chars)\n const getTokenDisplay = () => {\n // Prefer API-provided token counts - always show bidirectional if available\n if (streamState.inputTokens || streamState.outputTokens) {\n return formatTokenUsage(streamState.inputTokens, streamState.outputTokens)\n }\n // Fallback: approximate from received characters (~3 chars per token for mixed content)\n // Only show output approximation since we don't have input char count in this path\n if (streamState.receivedChars && streamState.receivedChars > 0) {\n const approxOutputTokens = Math.round(streamState.receivedChars / 3)\n // If we have sentChars, show both directions\n if (streamState.sentChars && streamState.sentChars > 0) {\n const approxInputTokens = Math.round(streamState.sentChars / 3)\n return `\u2191 ~${formatNumber(approxInputTokens)} \u00B7 \u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return `\u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return ''\n }\n\n const tokenUsage = getTokenDisplay()\n\n // Get thinking duration if available\n const thinkingDuration = streamState.thinkingDurationMs\n ? Math.floor(streamState.thinkingDurationMs / 1000)\n : null\n\n return (\n <Box flexDirection=\"row\" flexWrap=\"nowrap\">\n {/* Spinner icon with shimmer effect */}\n <Text color={shimmerColor}>\n {SYMBOLS.THINKING_FRAMES[spinnerIconFrame]}{' '}\n </Text>\n {/* Main task description with shimmer effect */}\n <Text color={shimmerColor} bold>\n {getCurrentTaskDisplay()}\n </Text>\n <Text color={shimmerColor}>\u2026 </Text>\n {/* Meta info with brand gradient accent */}\n <Text color={BRAND_GRADIENT.START}>\n (<Text color={SEMANTIC_COLORS.secondary}>esc esc</Text> to cancel \u00B7{' '}\n <Text color={SEMANTIC_COLORS.secondary}>{formatTime(elapsedTime)}</Text>\n {tokenUsage && (\n <Text color={SEMANTIC_COLORS.secondary}> \u00B7 {tokenUsage}</Text>\n )}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 thinking {thinkingDuration}s\n </Text>\n )}\n {shouldShowTodos && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 <Text color={SEMANTIC_COLORS.secondary}>ctrl+t</Text> to hide\n </Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SYMBOL_COLORS.error}>\n {' '}\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n})\n\n// Spinner messages for fallback when no todos\nconst SPINNER_MESSAGES = [\n 'Thinking',\n 'Processing',\n 'Working',\n 'Computing',\n 'Analyzing',\n 'Generating',\n 'Executing',\n 'Preparing',\n]\n\ninterface TodoPanelProps {\n /** TODO \u5217\u8868 */\n todos: TodoItemType[]\n /** \u662F\u5426\u663E\u793A\u9762\u677F\uFF08\u7531 Ctrl+T \u63A7\u5236\uFF09 */\n isVisible: boolean\n /** \u5F53\u524D\u4E3B\u4EFB\u52A1\u7684 activeForm\uFF08\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u63CF\u8FF0\uFF09 */\n currentTaskActiveForm?: string\n /** \u8FD0\u884C\u65F6\u95F4\uFF08\u79D2\uFF09 */\n elapsedTime?: number\n /** \u662F\u5426\u6B63\u5728\u52A0\u8F7D\uFF08\u63A7\u5236\u52A8\u753B\uFF09 */\n isLoading?: boolean\n /** \u662F\u5426\u663E\u793A\u4EFB\u52A1\u5217\u8868\u8BE6\u60C5 */\n showTodoList?: boolean\n}\n\n/**\n * \u7EDF\u4E00\u7684 Spinner + TODO \u9762\u677F\u7EC4\u4EF6 - Claude Code CLI \u98CE\u683C\n *\n * \u5F53\u6709 TODO \u65F6\u663E\u793A\uFF1A\n * ```\n * \u273D Fixing async tool description bug\u2026 (esc to interrupt \u00B7 ctrl+t to hide todos \u00B7 2m 52s \u00B7 \u2191 5.1k tokens)\n * \u23BF \u2610 Phase 1.1: Fix async tool description bug\n * \u2610 Phase 1.2: Add memory safety fixes\n * ```\n *\n * \u65E0 TODO \u65F6\u663E\u793A\u666E\u901A Spinner\uFF1A\n * ```\n * \u273D Thinking\u2026 (3s \u00B7 esc to interrupt)\n * ```\n *\n * Performance optimization: Animation is isolated in SpinnerLine component\n * to prevent the entire panel from re-rendering on each animation frame.\n */\nexport const TodoPanel = memo(function TodoPanel({\n todos,\n isVisible,\n currentTaskActiveForm,\n elapsedTime: initialElapsedTime = 0,\n isLoading = true,\n showTodoList = true,\n}: TodoPanelProps) {\n const theme = getTheme()\n const fallbackMessage = useRef(sample(SPINNER_MESSAGES) || 'Thinking')\n\n // \u5224\u65AD\u662F\u5426\u6709\u5F85\u529E\u4E8B\u9879\n const hasTodos = todos.length > 0\n const hasIncompleteTasks = todos.some(t => t.status !== 'completed')\n const shouldShowTodos =\n hasTodos && hasIncompleteTasks && isVisible && showTodoList\n\n // \u5982\u679C\u4E0D\u5728\u52A0\u8F7D\u72B6\u6001\uFF0C\u53EA\u663E\u793A todo \u5217\u8868\uFF08\u5982\u679C\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\uFF09\n if (!isLoading) {\n // \u5373\u4F7F\u4E0D\u5728\u52A0\u8F7D\u4E2D\uFF0C\u5982\u679C\u6709\u672A\u5B8C\u6210\u7684\u4EFB\u52A1\u4E5F\u663E\u793A\u5217\u8868\n if (shouldShowTodos) {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u9759\u6001\u6807\u9898 - \u663E\u793A\u8FD8\u6709\u672A\u5B8C\u6210\u4EFB\u52A1 */}\n <Box flexDirection=\"row\">\n <Text color={SEMANTIC_COLORS.dim}>\u25CB </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {hasIncompleteTasks\n ? `${todos.filter(t => t.status !== 'completed').length} tasks remaining`\n : 'All done'}\n </Text>\n </Box>\n {/* TODO \u5217\u8868 */}\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={`todo-${idx}-${todo.content.slice(0, 20)}`}>\n <TodoItemClaudeStyle\n todo={todo}\n theme={theme}\n isFirst={idx === 0}\n />\n </React.Fragment>\n ))}\n </Box>\n </Box>\n )\n }\n return null\n }\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u7B2C\u4E00\u884C\uFF1A\u52A8\u753B + \u5F53\u524D\u4EFB\u52A1 + \u7EDF\u8BA1\u4FE1\u606F - \u9694\u79BB\u5728 SpinnerLine \u7EC4\u4EF6\u4E2D */}\n <SpinnerLine\n currentTaskActiveForm={currentTaskActiveForm}\n todos={todos}\n shouldShowTodos={shouldShowTodos}\n fallbackMessage={fallbackMessage.current}\n />\n\n {/* TODO \u5217\u8868 - \u4EC5\u5F53\u53EF\u89C1\u4E14\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\u65F6\u663E\u793A */}\n {shouldShowTodos && <TodoList todos={todos} theme={theme} />}\n </Box>\n )\n})\n\n/**\n * Memoized TODO list to prevent re-rendering when only the spinner updates\n */\ninterface TodoListProps {\n todos: TodoItemType[]\n theme: ReturnType<typeof getTheme>\n}\n\nconst TodoList = memo(function TodoList({ todos, theme }: TodoListProps) {\n return (\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={`todo-${idx}-${todo.content.slice(0, 20)}`}>\n <TodoItemClaudeStyle todo={todo} theme={theme} isFirst={idx === 0} />\n </React.Fragment>\n ))}\n </Box>\n )\n})\n\n/**\n * Claude Code \u98CE\u683C\u7684 TODO \u9879\n *\n * \u683C\u5F0F\uFF1A\n * ```\n * \u23BF \u2612 \u5DF2\u5B8C\u6210\u4EFB\u52A1 (\u7070\u8272 + \u5220\u9664\u7EBF)\n * \u2610 \u5F85\u5B8C\u6210\u4EFB\u52A1\n * ```\n */\ninterface TodoItemClaudeStyleProps {\n todo: TodoItemType\n theme: ReturnType<typeof getTheme>\n isFirst: boolean\n}\n\n/**\n * Memoized TODO item component with brand-consistent colors\n */\nconst TodoItemClaudeStyle = memo(function TodoItemClaudeStyle({\n todo,\n theme,\n isFirst,\n}: TodoItemClaudeStyleProps) {\n const isCompleted = todo.status === 'completed'\n const isInProgress = todo.status === 'in_progress'\n\n // \u7B26\u53F7\uFF1A\u2610 \u672A\u5B8C\u6210 / \u2612 \u5DF2\u5B8C\u6210\n const symbol = getTodoStatusSymbol(todo.status)\n\n // \u4F7F\u7528\u54C1\u724C\u914D\u8272\uFF1A\n // - \u5DF2\u5B8C\u6210\uFF1Adim \u7070\u8272\n // - \u8FDB\u884C\u4E2D\uFF1A\u54C1\u724C\u4E2D\u95F4\u8272\uFF08\u7C89\u7D2B\uFF09\n // - \u5F85\u5904\u7406\uFF1A\u54C1\u724C\u8D77\u59CB\u8272\uFF08\u7D2B\u84DD\uFF09\n const symbolColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : isInProgress\n ? BRAND_GRADIENT.MIDDLE\n : BRAND_GRADIENT.START\n\n const textColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : SEMANTIC_COLORS.secondary\n\n // \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7ED3\u6784\u7B26\u53F7\uFF1A\u7B2C\u4E00\u4E2A\u7528 \" \u23BF \"\uFF0C\u5176\u4ED6\u7528\u7F29\u8FDB\u5BF9\u9F50\n const indent = isFirst\n ? `${getIndent('L1')}${SYMBOLS.CHILD_OUTPUT} `\n : `${getIndent('L1')} `\n\n return (\n <Box flexDirection=\"row\">\n {/* \u7F29\u8FDB - \u4F7F\u7528\u54C1\u724C\u8272 */}\n <Text color={SYMBOL_COLORS.child}>{indent}</Text>\n\n {/* \u72B6\u6001\u7B26\u53F7 - \u4F7F\u7528\u54C1\u724C\u914D\u8272 */}\n <Text color={symbolColor}>{symbol} </Text>\n\n {/* \u4EFB\u52A1\u63CF\u8FF0 */}\n <Text color={textColor} strikethrough={isCompleted}>\n {todo.content}\n </Text>\n </Box>\n )\n})\n"],
5
- "mappings": "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",
6
- "names": ["SpinnerLine", "TodoPanel", "TodoList", "TodoItemClaudeStyle"]
4
+ "sourcesContent": ["import React, { useRef, useMemo, memo } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { SYMBOLS, getTodoStatusSymbol } from '@constants/symbols'\nimport { formatNumber, formatTokenUsage } from '@utils/format'\nimport type { TodoItem as TodoItemType } from '@utils/todoStorage'\nimport { sample } from 'lodash-es'\nimport { getMainStreamingState } from './Spinner'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport {\n SEMANTIC_COLORS,\n BRAND_GRADIENT,\n SYMBOL_COLORS,\n} from '@constants/colors'\nimport { getIndent } from '@constants/formatRules'\nimport { t } from '@i18n'\n\n/**\n * Isolated Spinner component to prevent animation updates from re-rendering the entire panel\n * This component handles all animation state internally\n */\ninterface SpinnerLineProps {\n currentTaskActiveForm?: string\n todos: TodoItemType[]\n shouldShowTodos: boolean\n fallbackMessage: string\n}\n\n/**\n * Shimmer effect colors - creates a light sweep animation across text\n * Uses brand gradient colors cycling through: purple-blue \u2192 pink-purple \u2192 coral \u2192 pink-purple \u2192 purple-blue\n */\nconst SHIMMER_COLORS = [\n BRAND_GRADIENT.START, // #667EEA purple-blue\n '#8673D9', // blend\n BRAND_GRADIENT.MIDDLE, // #B668C8 pink-purple\n '#D560A0', // blend\n BRAND_GRADIENT.END, // #F5576C coral\n '#D560A0', // blend back\n BRAND_GRADIENT.MIDDLE, // #B668C8\n '#8673D9', // blend back\n] as const\n\n/**\n * Get shimmer color based on animation frame\n * Creates a smooth color transition effect\n */\nfunction getShimmerColor(frame: number): string {\n return SHIMMER_COLORS[frame % SHIMMER_COLORS.length]!\n}\n\nconst SpinnerLine = memo(function SpinnerLine({\n currentTaskActiveForm,\n todos,\n shouldShowTodos,\n fallbackMessage,\n}: SpinnerLineProps) {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Animation state is isolated in this component\n // Use 8 frames for shimmer effect (matching SHIMMER_COLORS length)\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: true,\n startTime: startTimeRef.current,\n spinnerFrameCount: SHIMMER_COLORS.length,\n componentId: 'todo-panel-spinner',\n })\n\n // Get streaming state - only updates when this component re-renders\n // Use main streaming state to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [spinnerFrame])\n\n // Get current task display\n const getCurrentTaskDisplay = (): string => {\n if (currentTaskActiveForm) {\n return currentTaskActiveForm\n }\n const inProgressTodo = todos.find(t => t.status === 'in_progress')\n if (inProgressTodo?.activeForm) {\n return inProgressTodo.activeForm\n }\n switch (streamState.phase) {\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n case 'generating':\n return 'Generating response'\n case 'waiting':\n return 'Waiting for response'\n case 'thinking':\n default:\n return fallbackMessage || 'Thinking'\n }\n }\n\n // Format time display\n const formatTime = (seconds: number): string => {\n if (seconds < 60) return `${seconds}s`\n const mins = Math.floor(seconds / 60)\n const secs = seconds % 60\n return secs > 0 ? `${mins}m ${secs}s` : `${mins}m`\n }\n\n // Get shimmer color for the main text (light sweep effect)\n const shimmerColor = getShimmerColor(spinnerFrame)\n\n // Spinner icon uses thinking frames\n const spinnerIconFrame = spinnerFrame % SYMBOLS.THINKING_FRAMES.length\n\n // Get token usage from streaming state (API values or approximate from chars)\n const getTokenDisplay = () => {\n // Prefer API-provided token counts - always show bidirectional if available\n if (streamState.inputTokens || streamState.outputTokens) {\n return formatTokenUsage(streamState.inputTokens, streamState.outputTokens)\n }\n // Fallback: approximate from received characters (~3 chars per token for mixed content)\n // Only show output approximation since we don't have input char count in this path\n if (streamState.receivedChars && streamState.receivedChars > 0) {\n const approxOutputTokens = Math.round(streamState.receivedChars / 3)\n // If we have sentChars, show both directions\n if (streamState.sentChars && streamState.sentChars > 0) {\n const approxInputTokens = Math.round(streamState.sentChars / 3)\n return `\u2191 ~${formatNumber(approxInputTokens)} \u00B7 \u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return `\u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return ''\n }\n\n const tokenUsage = getTokenDisplay()\n\n // Get thinking duration if available\n const thinkingDuration = streamState.thinkingDurationMs\n ? Math.floor(streamState.thinkingDurationMs / 1000)\n : null\n\n return (\n <Box flexDirection=\"row\" flexWrap=\"nowrap\">\n {/* Spinner icon with shimmer effect */}\n <Text color={shimmerColor}>\n {SYMBOLS.THINKING_FRAMES[spinnerIconFrame]}{' '}\n </Text>\n {/* Main task description with shimmer effect */}\n <Text color={shimmerColor} bold>\n {getCurrentTaskDisplay()}\n </Text>\n <Text color={shimmerColor}>\u2026 </Text>\n {/* Meta info with brand gradient accent */}\n <Text color={BRAND_GRADIENT.START}>\n (<Text color={SEMANTIC_COLORS.secondary}>esc esc</Text> to cancel \u00B7{' '}\n <Text color={SEMANTIC_COLORS.secondary}>{formatTime(elapsedTime)}</Text>\n {tokenUsage && (\n <Text color={SEMANTIC_COLORS.secondary}> \u00B7 {tokenUsage}</Text>\n )}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 thinking {thinkingDuration}s\n </Text>\n )}\n {shouldShowTodos && (\n <Text color={SEMANTIC_COLORS.secondary}>\n {' '}\n \u00B7 <Text color={SEMANTIC_COLORS.secondary}>ctrl+t</Text> to hide\n </Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SYMBOL_COLORS.error}>\n {' '}\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n})\n\n// Spinner messages for fallback when no todos\nconst SPINNER_MESSAGES = [\n 'Thinking',\n 'Processing',\n 'Working',\n 'Computing',\n 'Analyzing',\n 'Generating',\n 'Executing',\n 'Preparing',\n]\n\ninterface TodoPanelProps {\n /** TODO \u5217\u8868 */\n todos: TodoItemType[]\n /** \u662F\u5426\u663E\u793A\u9762\u677F\uFF08\u7531 Ctrl+T \u63A7\u5236\uFF09 */\n isVisible: boolean\n /** \u5F53\u524D\u4E3B\u4EFB\u52A1\u7684 activeForm\uFF08\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u63CF\u8FF0\uFF09 */\n currentTaskActiveForm?: string\n /** \u8FD0\u884C\u65F6\u95F4\uFF08\u79D2\uFF09 */\n elapsedTime?: number\n /** \u662F\u5426\u6B63\u5728\u52A0\u8F7D\uFF08\u63A7\u5236\u52A8\u753B\uFF09 */\n isLoading?: boolean\n /** \u662F\u5426\u663E\u793A\u4EFB\u52A1\u5217\u8868\u8BE6\u60C5 */\n showTodoList?: boolean\n}\n\n/**\n * \u7EDF\u4E00\u7684 Spinner + TODO \u9762\u677F\u7EC4\u4EF6 - Claude Code CLI \u98CE\u683C\n *\n * \u5F53\u6709 TODO \u65F6\u663E\u793A\uFF1A\n * ```\n * \u273D Fixing async tool description bug\u2026 (esc to interrupt \u00B7 ctrl+t to hide todos \u00B7 2m 52s \u00B7 \u2191 5.1k tokens)\n * \u23BF \u2610 Phase 1.1: Fix async tool description bug\n * \u2610 Phase 1.2: Add memory safety fixes\n * ```\n *\n * \u65E0 TODO \u65F6\u663E\u793A\u666E\u901A Spinner\uFF1A\n * ```\n * \u273D Thinking\u2026 (3s \u00B7 esc to interrupt)\n * ```\n *\n * Performance optimization: Animation is isolated in SpinnerLine component\n * to prevent the entire panel from re-rendering on each animation frame.\n */\nexport const TodoPanel = memo(function TodoPanel({\n todos,\n isVisible,\n currentTaskActiveForm,\n elapsedTime: initialElapsedTime = 0,\n isLoading = true,\n showTodoList = true,\n}: TodoPanelProps) {\n const theme = getTheme()\n const fallbackMessage = useRef(sample(SPINNER_MESSAGES) || 'Thinking')\n\n // \u5224\u65AD\u662F\u5426\u6709\u5F85\u529E\u4E8B\u9879\n const hasTodos = todos.length > 0\n const hasIncompleteTasks = todos.some(t => t.status !== 'completed')\n const shouldShowTodos =\n hasTodos && hasIncompleteTasks && isVisible && showTodoList\n\n // \u5982\u679C\u4E0D\u5728\u52A0\u8F7D\u72B6\u6001\uFF0C\u53EA\u663E\u793A todo \u5217\u8868\uFF08\u5982\u679C\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\uFF09\n if (!isLoading) {\n // \u5373\u4F7F\u4E0D\u5728\u52A0\u8F7D\u4E2D\uFF0C\u5982\u679C\u6709\u672A\u5B8C\u6210\u7684\u4EFB\u52A1\u4E5F\u663E\u793A\u5217\u8868\n if (shouldShowTodos) {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u9759\u6001\u6807\u9898 - \u663E\u793A\u8FD8\u6709\u672A\u5B8C\u6210\u4EFB\u52A1 */}\n <Box flexDirection=\"row\">\n <Text color={SEMANTIC_COLORS.dim}>\u25CB </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {hasIncompleteTasks\n ? t('ui.todo.tasksRemaining', {\n count: todos.filter(todo => todo.status !== 'completed')\n .length,\n })\n : t('ui.todo.allDone')}\n </Text>\n </Box>\n {/* TODO \u5217\u8868 */}\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={`todo-${idx}-${todo.content.slice(0, 20)}`}>\n <TodoItemClaudeStyle\n todo={todo}\n theme={theme}\n isFirst={idx === 0}\n />\n </React.Fragment>\n ))}\n </Box>\n </Box>\n )\n }\n return null\n }\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {/* \u7B2C\u4E00\u884C\uFF1A\u52A8\u753B + \u5F53\u524D\u4EFB\u52A1 + \u7EDF\u8BA1\u4FE1\u606F - \u9694\u79BB\u5728 SpinnerLine \u7EC4\u4EF6\u4E2D */}\n <SpinnerLine\n currentTaskActiveForm={currentTaskActiveForm}\n todos={todos}\n shouldShowTodos={shouldShowTodos}\n fallbackMessage={fallbackMessage.current}\n />\n\n {/* TODO \u5217\u8868 - \u4EC5\u5F53\u53EF\u89C1\u4E14\u6709\u672A\u5B8C\u6210\u4EFB\u52A1\u65F6\u663E\u793A */}\n {shouldShowTodos && <TodoList todos={todos} theme={theme} />}\n </Box>\n )\n})\n\n/**\n * Memoized TODO list to prevent re-rendering when only the spinner updates\n */\ninterface TodoListProps {\n todos: TodoItemType[]\n theme: ReturnType<typeof getTheme>\n}\n\nconst TodoList = memo(function TodoList({ todos, theme }: TodoListProps) {\n return (\n <Box flexDirection=\"column\">\n {todos.map((todo, idx) => (\n <React.Fragment key={`todo-${idx}-${todo.content.slice(0, 20)}`}>\n <TodoItemClaudeStyle todo={todo} theme={theme} isFirst={idx === 0} />\n </React.Fragment>\n ))}\n </Box>\n )\n})\n\n/**\n * Claude Code \u98CE\u683C\u7684 TODO \u9879\n *\n * \u683C\u5F0F\uFF1A\n * ```\n * \u23BF \u2612 \u5DF2\u5B8C\u6210\u4EFB\u52A1 (\u7070\u8272 + \u5220\u9664\u7EBF)\n * \u2610 \u5F85\u5B8C\u6210\u4EFB\u52A1\n * ```\n */\ninterface TodoItemClaudeStyleProps {\n todo: TodoItemType\n theme: ReturnType<typeof getTheme>\n isFirst: boolean\n}\n\n/**\n * Memoized TODO item component with brand-consistent colors\n */\nconst TodoItemClaudeStyle = memo(function TodoItemClaudeStyle({\n todo,\n theme,\n isFirst,\n}: TodoItemClaudeStyleProps) {\n const isCompleted = todo.status === 'completed'\n const isInProgress = todo.status === 'in_progress'\n\n // \u7B26\u53F7\uFF1A\u2610 \u672A\u5B8C\u6210 / \u2612 \u5DF2\u5B8C\u6210\n const symbol = getTodoStatusSymbol(todo.status)\n\n // \u4F7F\u7528\u54C1\u724C\u914D\u8272\uFF1A\n // - \u5DF2\u5B8C\u6210\uFF1Adim \u7070\u8272\n // - \u8FDB\u884C\u4E2D\uFF1A\u54C1\u724C\u4E2D\u95F4\u8272\uFF08\u7C89\u7D2B\uFF09\n // - \u5F85\u5904\u7406\uFF1A\u54C1\u724C\u8D77\u59CB\u8272\uFF08\u7D2B\u84DD\uFF09\n const symbolColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : isInProgress\n ? BRAND_GRADIENT.MIDDLE\n : BRAND_GRADIENT.START\n\n const textColor = isCompleted\n ? SEMANTIC_COLORS.dim\n : SEMANTIC_COLORS.secondary\n\n // \u4F7F\u7528 REPL \u89C4\u8303\u5B9A\u4E49\u7684\u7ED3\u6784\u7B26\u53F7\uFF1A\u7B2C\u4E00\u4E2A\u7528 \" \u23BF \"\uFF0C\u5176\u4ED6\u7528\u7F29\u8FDB\u5BF9\u9F50\n const indent = isFirst\n ? `${getIndent('L1')}${SYMBOLS.CHILD_OUTPUT} `\n : `${getIndent('L1')} `\n\n return (\n <Box flexDirection=\"row\">\n {/* \u7F29\u8FDB - \u4F7F\u7528\u54C1\u724C\u8272 */}\n <Text color={SYMBOL_COLORS.child}>{indent}</Text>\n\n {/* \u72B6\u6001\u7B26\u53F7 - \u4F7F\u7528\u54C1\u724C\u914D\u8272 */}\n <Text color={symbolColor}>{symbol} </Text>\n\n {/* \u4EFB\u52A1\u63CF\u8FF0 */}\n <Text color={textColor} strikethrough={isCompleted}>\n {todo.content}\n </Text>\n </Box>\n )\n})\n"],
5
+ "mappings": "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",
6
+ "names": ["SpinnerLine", "t", "TodoPanel", "TodoList", "TodoItemClaudeStyle"]
7
7
  }
@@ -11,6 +11,7 @@ import { useExitOnCtrlCD } from "../hooks/useExitOnCtrlCD.js";
11
11
  import { homedir } from "os";
12
12
  import { getCwd } from "../utils/state.js";
13
13
  import { SEMANTIC_COLORS } from "../constants/colors.js";
14
+ import { t } from "../i18n/index.js";
14
15
  function TrustDialog({ onDone }) {
15
16
  const theme = getTheme();
16
17
  React.useEffect(() => {
@@ -51,20 +52,20 @@ function TrustDialog({ onDone }) {
51
52
  borderStyle: "round",
52
53
  borderColor: theme.warning
53
54
  },
54
- /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.warning }, "Do you trust the files in this folder?"),
55
+ /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.warning }, t("dialog.trustTitle")),
55
56
  /* @__PURE__ */ React.createElement(Text, { bold: true }, process.cwd()),
56
- /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement(Text, null, PRODUCT_NAME, " may read files in this folder. Reading untrusted files may lead to ", PRODUCT_NAME, " to behave in an unexpected ways."), /* @__PURE__ */ React.createElement(Text, null, "With your permission ", PRODUCT_NAME, " may execute files in this folder. Executing untrusted code is unsafe.")),
57
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement(Text, null, t("dialog.trustWarning1", { product: PRODUCT_NAME })), /* @__PURE__ */ React.createElement(Text, null, t("dialog.trustWarning2", { product: PRODUCT_NAME }))),
57
58
  /* @__PURE__ */ React.createElement(
58
59
  Select,
59
60
  {
60
61
  options: [
61
- { label: "Yes, proceed", value: "yes" },
62
- { label: "No, exit", value: "no" }
62
+ { label: t("dialog.yesProceed"), value: "yes" },
63
+ { label: t("dialog.noExit"), value: "no" }
63
64
  ],
64
65
  onChange: (value) => onChange(value)
65
66
  }
66
67
  )
67
- ), /* @__PURE__ */ React.createElement(Box, { marginLeft: 3 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, exitState.pending ? /* @__PURE__ */ React.createElement(React.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React.createElement(React.Fragment, null, "Enter to confirm \xB7 Esc to exit"))));
68
+ ), /* @__PURE__ */ React.createElement(Box, { marginLeft: 3 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, exitState.pending ? /* @__PURE__ */ React.createElement(React.Fragment, null, t("prompts.pressCtrlDAgain")) : /* @__PURE__ */ React.createElement(React.Fragment, null, t("dialog.confirmExitPrompt")))));
68
69
  }
69
70
  export {
70
71
  TrustDialog
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/TrustDialog.tsx"],
4
- "sourcesContent": ["import React from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { Select } from './CustomSelect/select'\nimport {\n saveCurrentProjectConfig,\n getCurrentProjectConfig,\n} from '@utils/config'\nimport { PRODUCT_NAME } from '@constants/product'\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\nimport { homedir } from 'os'\nimport { getCwd } from '@utils/state'\nimport Link from './Link'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ntype Props = {\n onDone(): void\n}\n\nexport function TrustDialog({ onDone }: Props): React.ReactNode {\n const theme = getTheme()\n React.useEffect(() => {}, [])\n\n function onChange(value: 'yes' | 'no') {\n const config = getCurrentProjectConfig()\n switch (value) {\n case 'yes': {\n const isHomeDir = homedir() === getCwd()\n\n if (!isHomeDir) {\n saveCurrentProjectConfig({\n ...config,\n hasTrustDialogAccepted: true,\n })\n }\n onDone()\n break\n }\n case 'no': {\n process.exit(1)\n break\n }\n }\n }\n\n const exitState = useExitOnCtrlCD(() => process.exit(0))\n\n useInput((_input, key) => {\n if (key.escape) {\n process.exit(0)\n return\n }\n })\n\n return (\n <>\n <Box\n flexDirection=\"column\"\n gap={1}\n padding={1}\n borderStyle=\"round\"\n borderColor={theme.warning}\n >\n <Text bold color={theme.warning}>\n Do you trust the files in this folder?\n </Text>\n <Text bold>{process.cwd()}</Text>\n\n <Box flexDirection=\"column\" gap={1}>\n <Text>\n {PRODUCT_NAME} may read files in this folder. Reading untrusted\n files may lead to {PRODUCT_NAME} to behave in an unexpected ways.\n </Text>\n <Text>\n With your permission {PRODUCT_NAME} may execute files in this\n folder. Executing untrusted code is unsafe.\n </Text>\n </Box>\n\n <Select\n options={[\n { label: 'Yes, proceed', value: 'yes' },\n { label: 'No, exit', value: 'no' },\n ]}\n onChange={value => onChange(value as 'yes' | 'no')}\n />\n </Box>\n <Box marginLeft={3}>\n <Text color={SEMANTIC_COLORS.dim}>\n {exitState.pending ? (\n <>Press {exitState.keyName} again to exit</>\n ) : (\n <>Enter to confirm \u00B7 Esc to exit</>\n )}\n </Text>\n </Box>\n </>\n )\n}\n"],
5
- "mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,eAAe;AACxB,SAAS,cAAc;AAEvB,SAAS,uBAAuB;AAMzB,SAAS,YAAY,EAAE,OAAO,GAA2B;AAC9D,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAU,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAE5B,WAAS,SAAS,OAAqB;AACrC,UAAM,SAAS,wBAAwB;AACvC,YAAQ,OAAO;AAAA,MACb,KAAK,OAAO;AACV,cAAM,YAAY,QAAQ,MAAM,OAAO;AAEvC,YAAI,CAAC,WAAW;AACd,mCAAyB;AAAA,YACvB,GAAG;AAAA,YACH,wBAAwB;AAAA,UAC1B,CAAC;AAAA,QACH;AACA,eAAO;AACP;AAAA,MACF;AAAA,MACA,KAAK,MAAM;AACT,gBAAQ,KAAK,CAAC;AACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,gBAAgB,MAAM,QAAQ,KAAK,CAAC,CAAC;AAEvD,WAAS,CAAC,QAAQ,QAAQ;AACxB,QAAI,IAAI,QAAQ;AACd,cAAQ,KAAK,CAAC;AACd;AAAA,IACF;AAAA,EACF,CAAC;AAED,SACE,0DACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,KAAK;AAAA,MACL,SAAS;AAAA,MACT,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA;AAAA,IAEnB,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,WAAS,wCAEjC;AAAA,IACA,oCAAC,QAAK,MAAI,QAAE,QAAQ,IAAI,CAAE;AAAA,IAE1B,oCAAC,OAAI,eAAc,UAAS,KAAK,KAC/B,oCAAC,YACE,cAAa,wEACK,cAAa,mCAClC,GACA,oCAAC,YAAK,yBACkB,cAAa,wEAErC,CACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,UACP,EAAE,OAAO,gBAAgB,OAAO,MAAM;AAAA,UACtC,EAAE,OAAO,YAAY,OAAO,KAAK;AAAA,QACnC;AAAA,QACA,UAAU,WAAS,SAAS,KAAqB;AAAA;AAAA,IACnD;AAAA,EACF,GACA,oCAAC,OAAI,YAAY,KACf,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,UAAU,UACT,0DAAE,UAAO,UAAU,SAAQ,gBAAc,IAEzC,0DAAE,mCAA8B,CAEpC,CACF,CACF;AAEJ;",
4
+ "sourcesContent": ["import React from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { Select } from './CustomSelect/select'\nimport {\n saveCurrentProjectConfig,\n getCurrentProjectConfig,\n} from '@utils/config'\nimport { PRODUCT_NAME } from '@constants/product'\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\nimport { homedir } from 'os'\nimport { getCwd } from '@utils/state'\nimport Link from './Link'\nimport { SEMANTIC_COLORS } from '@constants/colors'\nimport { t } from '@i18n'\n\ntype Props = {\n onDone(): void\n}\n\nexport function TrustDialog({ onDone }: Props): React.ReactNode {\n const theme = getTheme()\n React.useEffect(() => {}, [])\n\n function onChange(value: 'yes' | 'no') {\n const config = getCurrentProjectConfig()\n switch (value) {\n case 'yes': {\n const isHomeDir = homedir() === getCwd()\n\n if (!isHomeDir) {\n saveCurrentProjectConfig({\n ...config,\n hasTrustDialogAccepted: true,\n })\n }\n onDone()\n break\n }\n case 'no': {\n process.exit(1)\n break\n }\n }\n }\n\n const exitState = useExitOnCtrlCD(() => process.exit(0))\n\n useInput((_input, key) => {\n if (key.escape) {\n process.exit(0)\n return\n }\n })\n\n return (\n <>\n <Box\n flexDirection=\"column\"\n gap={1}\n padding={1}\n borderStyle=\"round\"\n borderColor={theme.warning}\n >\n <Text bold color={theme.warning}>\n {t('dialog.trustTitle')}\n </Text>\n <Text bold>{process.cwd()}</Text>\n\n <Box flexDirection=\"column\" gap={1}>\n <Text>{t('dialog.trustWarning1', { product: PRODUCT_NAME })}</Text>\n <Text>{t('dialog.trustWarning2', { product: PRODUCT_NAME })}</Text>\n </Box>\n\n <Select\n options={[\n { label: t('dialog.yesProceed'), value: 'yes' },\n { label: t('dialog.noExit'), value: 'no' },\n ]}\n onChange={value => onChange(value as 'yes' | 'no')}\n />\n </Box>\n <Box marginLeft={3}>\n <Text color={SEMANTIC_COLORS.dim}>\n {exitState.pending ? (\n <>{t('prompts.pressCtrlDAgain')}</>\n ) : (\n <>{t('dialog.confirmExitPrompt')}</>\n )}\n </Text>\n </Box>\n </>\n )\n}\n"],
5
+ "mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,eAAe;AACxB,SAAS,cAAc;AAEvB,SAAS,uBAAuB;AAChC,SAAS,SAAS;AAMX,SAAS,YAAY,EAAE,OAAO,GAA2B;AAC9D,QAAM,QAAQ,SAAS;AACvB,QAAM,UAAU,MAAM;AAAA,EAAC,GAAG,CAAC,CAAC;AAE5B,WAAS,SAAS,OAAqB;AACrC,UAAM,SAAS,wBAAwB;AACvC,YAAQ,OAAO;AAAA,MACb,KAAK,OAAO;AACV,cAAM,YAAY,QAAQ,MAAM,OAAO;AAEvC,YAAI,CAAC,WAAW;AACd,mCAAyB;AAAA,YACvB,GAAG;AAAA,YACH,wBAAwB;AAAA,UAC1B,CAAC;AAAA,QACH;AACA,eAAO;AACP;AAAA,MACF;AAAA,MACA,KAAK,MAAM;AACT,gBAAQ,KAAK,CAAC;AACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,gBAAgB,MAAM,QAAQ,KAAK,CAAC,CAAC;AAEvD,WAAS,CAAC,QAAQ,QAAQ;AACxB,QAAI,IAAI,QAAQ;AACd,cAAQ,KAAK,CAAC;AACd;AAAA,IACF;AAAA,EACF,CAAC;AAED,SACE,0DACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,KAAK;AAAA,MACL,SAAS;AAAA,MACT,aAAY;AAAA,MACZ,aAAa,MAAM;AAAA;AAAA,IAEnB,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,WACrB,EAAE,mBAAmB,CACxB;AAAA,IACA,oCAAC,QAAK,MAAI,QAAE,QAAQ,IAAI,CAAE;AAAA,IAE1B,oCAAC,OAAI,eAAc,UAAS,KAAK,KAC/B,oCAAC,YAAM,EAAE,wBAAwB,EAAE,SAAS,aAAa,CAAC,CAAE,GAC5D,oCAAC,YAAM,EAAE,wBAAwB,EAAE,SAAS,aAAa,CAAC,CAAE,CAC9D;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,UACP,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,MAAM;AAAA,UAC9C,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,KAAK;AAAA,QAC3C;AAAA,QACA,UAAU,WAAS,SAAS,KAAqB;AAAA;AAAA,IACnD;AAAA,EACF,GACA,oCAAC,OAAI,YAAY,KACf,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,UAAU,UACT,0DAAG,EAAE,yBAAyB,CAAE,IAEhC,0DAAG,EAAE,0BAA0B,CAAE,CAErC,CACF,CACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,9 @@
1
1
  import { Text } from "ink";
2
2
  import * as React from "react";
3
3
  import { getTheme } from "../../../utils/theme.js";
4
+ import { t } from "../../../i18n/index.js";
4
5
  function UserToolCanceledMessage() {
5
- return /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0", /* @__PURE__ */ React.createElement(Text, { color: getTheme().error }, "Interrupted by user"));
6
+ return /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0", /* @__PURE__ */ React.createElement(Text, { color: getTheme().error }, t("prompts.interruptedByUser")));
6
7
  }
7
8
  export {
8
9
  UserToolCanceledMessage
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx"],
4
- "sourcesContent": ["import { Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\n\nexport function UserToolCanceledMessage(): React.ReactNode {\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={getTheme().error}>Interrupted by user</Text>\n </Text>\n )\n}\n"],
5
- "mappings": "AAAA,SAAS,YAAY;AACrB,YAAY,WAAW;AACvB,SAAS,gBAAgB;AAElB,SAAS,0BAA2C;AACzD,SACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,SAAS,EAAE,SAAO,qBAAmB,CACpD;AAEJ;",
4
+ "sourcesContent": ["import { Text } from 'ink'\nimport * as React from 'react'\nimport { getTheme } from '@utils/theme'\nimport { t } from '@i18n'\n\nexport function UserToolCanceledMessage(): React.ReactNode {\n return (\n <Text>\n &nbsp;&nbsp;\u23BF &nbsp;\n <Text color={getTheme().error}>{t('prompts.interruptedByUser')}</Text>\n </Text>\n )\n}\n"],
5
+ "mappings": "AAAA,SAAS,YAAY;AACrB,YAAY,WAAW;AACvB,SAAS,gBAAgB;AACzB,SAAS,SAAS;AAEX,SAAS,0BAA2C;AACzD,SACE,oCAAC,YAAK,uBAEJ,oCAAC,QAAK,OAAO,SAAS,EAAE,SAAQ,EAAE,2BAA2B,CAAE,CACjE;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { VERSION } from "../version.js";
2
2
  const MACRO = {
3
3
  VERSION,
4
- README_URL: "https://within-7.com/minto#readme",
4
+ README_URL: "https://minto.within-7.com/",
5
5
  PACKAGE_URL: "@within-7/minto",
6
6
  ISSUES_EXPLAINER: "report the issue to within-7 team"
7
7
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/constants/macros.ts"],
4
- "sourcesContent": ["import { VERSION } from '../version.js'\n\nexport const MACRO = {\n VERSION: VERSION,\n README_URL: 'https://within-7.com/minto#readme',\n PACKAGE_URL: '@within-7/minto',\n ISSUES_EXPLAINER: 'report the issue to within-7 team',\n}\n"],
4
+ "sourcesContent": ["import { VERSION } from '../version.js'\n\nexport const MACRO = {\n VERSION: VERSION,\n README_URL: 'https://minto.within-7.com/',\n PACKAGE_URL: '@within-7/minto',\n ISSUES_EXPLAINER: 'report the issue to within-7 team',\n}\n"],
5
5
  "mappings": "AAAA,SAAS,eAAe;AAEjB,MAAM,QAAQ;AAAA,EACnB;AAAA,EACA,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,kBAAkB;AACpB;",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,10 @@
1
1
  const PRODUCT_NAME = "Minto";
2
- const PRODUCT_URL = "https://within-7.com/minto";
2
+ const PRODUCT_URL = "https://minto.within-7.com/";
3
3
  const PROJECT_FILE = "MINTO.md";
4
4
  const PRODUCT_COMMAND = "minto";
5
5
  const CONFIG_BASE_DIR = ".minto";
6
6
  const CONFIG_FILE = ".minto.json";
7
- const GITHUB_ISSUES_REPO_URL = "https://within-7.com/minto/issues";
7
+ const GITHUB_ISSUES_REPO_URL = "https://github.com/within-7/minto/issues";
8
8
  const ASCII_LOGO = `
9
9
  \u2588\u2588\u2588\u2557\u2591\u2591\u2591\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557\u2591\u2591\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2588\u2588\u2588\u2557\u2591
10
10
  \u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/constants/product.ts"],
4
- "sourcesContent": ["export const PRODUCT_NAME = 'Minto'\nexport const PRODUCT_URL = 'https://within-7.com/minto'\nexport const PROJECT_FILE = 'MINTO.md'\nexport const PRODUCT_COMMAND = 'minto'\nexport const CONFIG_BASE_DIR = '.minto'\nexport const CONFIG_FILE = '.minto.json'\nexport const GITHUB_ISSUES_REPO_URL = 'https://within-7.com/minto/issues'\n\nexport const ASCII_LOGO = `\n\u2588\u2588\u2588\u2557\u2591\u2591\u2591\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557\u2591\u2591\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2588\u2588\u2588\u2557\u2591\n\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\n\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2588\u2588\u2551\n\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2588\u2588\u2551\n\u2588\u2588\u2551\u2591\u255A\u2550\u255D\u2591\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u2591\u255A\u2588\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2591\u255A\u2588\u2588\u2588\u2588\u2588\u2554\u255D\n\u255A\u2550\u255D\u2591\u2591\u2591\u2591\u2591\u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D\u2591\u2591\u255A\u2550\u2550\u255D\u2591\u2591\u2591\u255A\u2550\u255D\u2591\u2591\u2591\u2591\u255A\u2550\u2550\u2550\u2550\u255D\u2591\n`\n"],
4
+ "sourcesContent": ["export const PRODUCT_NAME = 'Minto'\nexport const PRODUCT_URL = 'https://minto.within-7.com/'\nexport const PROJECT_FILE = 'MINTO.md'\nexport const PRODUCT_COMMAND = 'minto'\nexport const CONFIG_BASE_DIR = '.minto'\nexport const CONFIG_FILE = '.minto.json'\nexport const GITHUB_ISSUES_REPO_URL = 'https://github.com/within-7/minto/issues'\n\nexport const ASCII_LOGO = `\n\u2588\u2588\u2588\u2557\u2591\u2591\u2591\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2557\u2591\u2591\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2588\u2588\u2588\u2557\u2591\n\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557\u2591\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\n\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2588\u2588\u2551\n\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2588\u2588\u2551\n\u2588\u2588\u2551\u2591\u255A\u2550\u255D\u2591\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551\u2591\u255A\u2588\u2588\u2588\u2551\u2591\u2591\u2591\u2588\u2588\u2551\u2591\u2591\u2591\u255A\u2588\u2588\u2588\u2588\u2588\u2554\u255D\n\u255A\u2550\u255D\u2591\u2591\u2591\u2591\u2591\u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D\u2591\u2591\u255A\u2550\u2550\u255D\u2591\u2591\u2591\u255A\u2550\u255D\u2591\u2591\u2591\u2591\u255A\u2550\u2550\u2550\u2550\u255D\u2591\n`\n"],
5
5
  "mappings": "AAAO,MAAM,eAAe;AACrB,MAAM,cAAc;AACpB,MAAM,eAAe;AACrB,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,cAAc;AACpB,MAAM,yBAAyB;AAE/B,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }