@within-7/minto 0.3.9 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agents/AgentsCommand.js +459 -655
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/types.js +1 -0
- package/dist/commands/agents/types.js.map +2 -2
- package/dist/commands/agents/utils/fileOperations.js +96 -36
- package/dist/commands/agents/utils/fileOperations.js.map +3 -3
- package/dist/commands/agents/utils/index.js +3 -1
- package/dist/commands/agents/utils/index.js.map +2 -2
- package/dist/commands/context.js +54 -23
- package/dist/commands/context.js.map +2 -2
- package/dist/commands/export.js +673 -93
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/language.js +19 -46
- package/dist/commands/language.js.map +2 -2
- package/dist/commands/mcp-interactive.js +419 -217
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +415 -66
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/permissions.js +75 -49
- package/dist/commands/permissions.js.map +2 -2
- package/dist/commands/plugin.js +882 -185
- package/dist/commands/plugin.js.map +3 -3
- package/dist/commands/resume.js +1 -1
- package/dist/commands/resume.js.map +1 -1
- package/dist/commands/sandbox.js +168 -70
- package/dist/commands/sandbox.js.map +2 -2
- package/dist/commands/setup.js +593 -107
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/stats.js +188 -131
- package/dist/commands/stats.js.map +2 -2
- package/dist/commands/status.js +75 -13
- package/dist/commands/status.js.map +2 -2
- package/dist/commands/undo.js +138 -174
- package/dist/commands/undo.js.map +2 -2
- package/dist/commands.js.map +1 -1
- package/dist/components/Help.js +165 -32
- package/dist/components/Help.js.map +2 -2
- package/dist/components/InfoPanel/InfoPanel.js +123 -0
- package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
- package/dist/components/InfoPanel/index.js +5 -0
- package/dist/components/InfoPanel/index.js.map +7 -0
- package/dist/components/InfoPanel/types.js +1 -0
- package/dist/components/InfoPanel/types.js.map +7 -0
- package/dist/components/ModelSelector/BrandTextInput.js +43 -0
- package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
- package/dist/components/ModelSelector/ModelSelector.js +419 -501
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/ModelSelector/WizardContainer.js +45 -0
- package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
- package/dist/components/ModelSelector/index.js +1 -3
- package/dist/components/ModelSelector/index.js.map +2 -2
- package/dist/components/PromptInput.js +5 -5
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/SimpleSelector/SimpleSelector.js +154 -0
- package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
- package/dist/components/SimpleSelector/index.js +5 -0
- package/dist/components/SimpleSelector/index.js.map +7 -0
- package/dist/components/SimpleSelector/types.js +1 -0
- package/dist/components/SimpleSelector/types.js.map +7 -0
- package/dist/components/StatusOverlayContent.js +21 -0
- package/dist/components/StatusOverlayContent.js.map +7 -0
- package/dist/components/TabbedListView/ScrollableList.js +31 -5
- package/dist/components/TabbedListView/ScrollableList.js.map +2 -2
- package/dist/components/TabbedListView/TabbedListView.js +122 -47
- package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
- package/dist/core/backupHook.js +29 -0
- package/dist/core/backupHook.js.map +7 -0
- package/dist/core/config/defaults.js +8 -2
- package/dist/core/config/defaults.js.map +2 -2
- package/dist/core/config/schema.js +14 -2
- package/dist/core/config/schema.js.map +2 -2
- package/dist/core/costTracker.js +0 -16
- package/dist/core/costTracker.js.map +2 -2
- package/dist/cost-tracker.js +0 -16
- package/dist/cost-tracker.js.map +2 -2
- package/dist/entrypoints/bootstrap.js +3 -1
- package/dist/entrypoints/bootstrap.js.map +2 -2
- package/dist/entrypoints/cli.js +32 -0
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/i18n/locales/en.js +300 -1
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +301 -2
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/services/customCommands.js +30 -8
- package/dist/services/customCommands.js.map +2 -2
- package/dist/services/plugins/lspServers.js +1 -1
- package/dist/services/plugins/lspServers.js.map +2 -2
- package/dist/services/plugins/pluginRuntime.js +2 -1
- package/dist/services/plugins/pluginRuntime.js.map +2 -2
- package/dist/services/plugins/pluginValidation.js +10 -3
- package/dist/services/plugins/pluginValidation.js.map +2 -2
- package/dist/services/plugins/skillMarketplace.js +16 -8
- package/dist/services/plugins/skillMarketplace.js.map +2 -2
- package/dist/services/systemReminder.js +17 -6
- package/dist/services/systemReminder.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +7 -0
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +7 -0
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js +7 -0
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/TaskTool/TaskTool.js +9 -6
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/types/PermissionMode.js.map +1 -1
- package/dist/types/plugin.js +2 -4
- package/dist/types/plugin.js.map +2 -2
- package/dist/utils/agentHookExecutor.js +1 -4
- package/dist/utils/agentHookExecutor.js.map +2 -2
- package/dist/utils/agentLoader.js +67 -13
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/agentMemory.js.map +2 -2
- package/dist/utils/claudeCodeSync.js +439 -0
- package/dist/utils/claudeCodeSync.js.map +7 -0
- package/dist/utils/config.js +1 -23
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/execFileNoThrow.js +2 -1
- package/dist/utils/execFileNoThrow.js.map +2 -2
- package/dist/utils/marketplaceManager.js +80 -43
- package/dist/utils/marketplaceManager.js.map +2 -2
- package/dist/utils/messages.js +2 -2
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/pluginInstaller.js +34 -24
- package/dist/utils/pluginInstaller.js.map +2 -2
- package/dist/utils/pluginLoader.js +48 -25
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/repoFetcher.js +110 -0
- package/dist/utils/repoFetcher.js.map +7 -0
- package/dist/utils/skillLoader.js +18 -6
- package/dist/utils/skillLoader.js.map +2 -2
- package/dist/utils/stringSubstitution.js +4 -5
- package/dist/utils/stringSubstitution.js.map +2 -2
- package/dist/utils/teamConfig.js +153 -13
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/terminal.js +1 -1
- package/dist/utils/terminal.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +6 -6
package/dist/commands/undo.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import React, { useState, useEffect } from "react";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
import { SEMANTIC_COLORS } from "../constants/colors.js";
|
|
1
|
+
import React, { useState, useEffect, useCallback, useMemo } from "react";
|
|
4
2
|
import { getCwd } from "../utils/state.js";
|
|
5
3
|
import {
|
|
6
4
|
listBackedUpFiles,
|
|
7
5
|
getBackupVersions,
|
|
8
6
|
restoreBackup
|
|
9
7
|
} from "../core/backupManager.js";
|
|
8
|
+
import { TabbedListView } from "../components/TabbedListView/TabbedListView.js";
|
|
10
9
|
import { t } from "../i18n/index.js";
|
|
11
10
|
function formatTimestamp(timestamp) {
|
|
12
11
|
const date = new Date(timestamp);
|
|
@@ -42,198 +41,162 @@ function getRelativePath(filePath) {
|
|
|
42
41
|
}
|
|
43
42
|
return filePath;
|
|
44
43
|
}
|
|
45
|
-
const FileListView = ({ files, selectedIndex, onSelect, onClose }) => {
|
|
46
|
-
useInput((input, key) => {
|
|
47
|
-
if (key.escape || input === "q") {
|
|
48
|
-
onClose();
|
|
49
|
-
} else if (key.return) {
|
|
50
|
-
if (files.length > 0 && files[selectedIndex]) {
|
|
51
|
-
onSelect(files[selectedIndex]);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
if (files.length === 0) {
|
|
56
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.brand }, t("commands.undo.title"))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.undo.noBackups")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.undo.smartModeHint").replace("--smart", ""), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.info }, "--smart")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, t("commands.undo.smartModeCommand"))), /* @__PURE__ */ React.createElement(Box, { marginTop: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, t("commands.undo.pressQOrEsc"))));
|
|
57
|
-
}
|
|
58
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.brand }, t("commands.undo.title")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "- ", t("commands.undo.selectFile"))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, files.map((file, index) => {
|
|
59
|
-
const isSelected = index === selectedIndex;
|
|
60
|
-
const relativePath = getRelativePath(file.filePath);
|
|
61
|
-
return /* @__PURE__ */ React.createElement(Box, { key: file.filePath, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? SEMANTIC_COLORS.info : void 0 }, isSelected ? "\u25B6 " : " ", /* @__PURE__ */ React.createElement(
|
|
62
|
-
Text,
|
|
63
|
-
{
|
|
64
|
-
color: isSelected ? SEMANTIC_COLORS.primary : SEMANTIC_COLORS.secondary
|
|
65
|
-
},
|
|
66
|
-
relativePath
|
|
67
|
-
), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", "(", t("commands.undo.versions", { count: file.versionCount }), ")")));
|
|
68
|
-
})), /* @__PURE__ */ React.createElement(Box, { marginTop: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, t("commands.undo.navHintsFile"))));
|
|
69
|
-
};
|
|
70
|
-
const VersionListView = ({ file, versions, selectedIndex, onSelect, onBack }) => {
|
|
71
|
-
useInput((input, key) => {
|
|
72
|
-
if (key.escape || input === "q") {
|
|
73
|
-
onBack();
|
|
74
|
-
} else if (key.return) {
|
|
75
|
-
if (versions.length > 0 && versions[selectedIndex]) {
|
|
76
|
-
onSelect(versions[selectedIndex]);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
const relativePath = getRelativePath(file.filePath);
|
|
81
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.brand }, t("commands.undo.selectVersion"))), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.undo.file"), ": "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, relativePath)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, versions.map((version, index) => {
|
|
82
|
-
const isSelected = index === selectedIndex;
|
|
83
|
-
return /* @__PURE__ */ React.createElement(Box, { key: version.version, paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: isSelected ? SEMANTIC_COLORS.info : void 0 }, isSelected ? "\u25B6 " : " ", /* @__PURE__ */ React.createElement(
|
|
84
|
-
Text,
|
|
85
|
-
{
|
|
86
|
-
color: isSelected ? SEMANTIC_COLORS.primary : SEMANTIC_COLORS.secondary
|
|
87
|
-
},
|
|
88
|
-
"v",
|
|
89
|
-
version.version
|
|
90
|
-
), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, ": ", version.operation, " - ", formatTimestamp(version.timestamp))));
|
|
91
|
-
})), /* @__PURE__ */ React.createElement(Box, { marginTop: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, t("commands.undo.navHintsVersion"))));
|
|
92
|
-
};
|
|
93
|
-
const SuccessView = ({ file, version, onClose }) => {
|
|
94
|
-
useInput((input, key) => {
|
|
95
|
-
if (key.escape || input === "q" || key.return) {
|
|
96
|
-
onClose();
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
const relativePath = getRelativePath(file.filePath);
|
|
100
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.success }, "\u2713 ", t("commands.undo.fileRestored"))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.undo.file"), ": "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, relativePath)), /* @__PURE__ */ React.createElement(Box, { paddingLeft: 1, marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("commands.undo.restoredTo"), ": ", version.operation, " (", formatTimestamp(version.timestamp), ")")), /* @__PURE__ */ React.createElement(Box, { marginTop: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, t("commands.undo.pressAnyKey"))));
|
|
101
|
-
};
|
|
102
44
|
const UndoCommand = ({ onClose }) => {
|
|
103
|
-
const [
|
|
45
|
+
const [phase, setPhase] = useState({ type: "file-list" });
|
|
104
46
|
const [files, setFiles] = useState([]);
|
|
105
|
-
const [selectedFileIndex, setSelectedFileIndex] = useState(0);
|
|
106
|
-
const [selectedFile, setSelectedFile] = useState(
|
|
107
|
-
null
|
|
108
|
-
);
|
|
109
47
|
const [versions, setVersions] = useState([]);
|
|
110
|
-
const [
|
|
111
|
-
const [
|
|
112
|
-
null
|
|
113
|
-
);
|
|
114
|
-
const [error, setError] = useState(null);
|
|
115
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
48
|
+
const [loading, setLoading] = useState(true);
|
|
49
|
+
const [statusOverlay, setStatusOverlay] = useState(null);
|
|
116
50
|
useEffect(() => {
|
|
117
51
|
const loadFiles = async () => {
|
|
118
52
|
try {
|
|
119
53
|
const backupFiles = await listBackedUpFiles();
|
|
120
54
|
setFiles(backupFiles);
|
|
121
|
-
} catch
|
|
122
|
-
|
|
55
|
+
} catch {
|
|
56
|
+
setFiles([]);
|
|
123
57
|
} finally {
|
|
124
|
-
|
|
58
|
+
setLoading(false);
|
|
125
59
|
}
|
|
126
60
|
};
|
|
127
61
|
loadFiles();
|
|
128
62
|
}, []);
|
|
129
|
-
|
|
130
|
-
(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (phase.type === "version-list") {
|
|
65
|
+
const loadVersions = async () => {
|
|
66
|
+
setLoading(true);
|
|
67
|
+
try {
|
|
68
|
+
const fileVersions = await getBackupVersions(phase.file.filePath);
|
|
69
|
+
setVersions(fileVersions);
|
|
70
|
+
} catch {
|
|
71
|
+
setVersions([]);
|
|
72
|
+
} finally {
|
|
73
|
+
setLoading(false);
|
|
136
74
|
}
|
|
75
|
+
};
|
|
76
|
+
loadVersions();
|
|
77
|
+
}
|
|
78
|
+
}, [phase]);
|
|
79
|
+
const { tabs, items, title, footerHint, emptyText } = useMemo(() => {
|
|
80
|
+
switch (phase.type) {
|
|
81
|
+
case "file-list": {
|
|
82
|
+
const fileTabs = [
|
|
83
|
+
{ id: "files", label: t("commands.undo.tabFiles") }
|
|
84
|
+
];
|
|
85
|
+
const fileItems = files.map((file) => ({
|
|
86
|
+
id: file.filePath,
|
|
87
|
+
label: getRelativePath(file.filePath),
|
|
88
|
+
description: t("commands.undo.versions", {
|
|
89
|
+
count: file.versionCount
|
|
90
|
+
}),
|
|
91
|
+
data: { file }
|
|
92
|
+
}));
|
|
93
|
+
return {
|
|
94
|
+
tabs: fileTabs,
|
|
95
|
+
items: fileItems,
|
|
96
|
+
title: t("commands.undo.title"),
|
|
97
|
+
footerHint: "\u2191\u2193 Navigate \xB7 Enter Select \xB7 Esc Close",
|
|
98
|
+
emptyText: t("commands.undo.noBackups")
|
|
99
|
+
};
|
|
137
100
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
101
|
+
case "version-list": {
|
|
102
|
+
const versionTabs = [
|
|
103
|
+
{ id: "versions", label: t("commands.undo.tabVersions") }
|
|
104
|
+
];
|
|
105
|
+
const versionItems = versions.map((version) => ({
|
|
106
|
+
id: String(version.version),
|
|
107
|
+
label: `v${version.version}: ${version.operation}`,
|
|
108
|
+
description: formatTimestamp(version.timestamp),
|
|
109
|
+
data: { version }
|
|
110
|
+
}));
|
|
111
|
+
return {
|
|
112
|
+
tabs: versionTabs,
|
|
113
|
+
items: versionItems,
|
|
114
|
+
title: getRelativePath(phase.file.filePath),
|
|
115
|
+
footerHint: "\u2191\u2193 Navigate \xB7 Enter Restore \xB7 Esc Back",
|
|
116
|
+
emptyText: "No versions found"
|
|
117
|
+
};
|
|
151
118
|
}
|
|
152
|
-
},
|
|
153
|
-
{ isActive: view === "version-list" }
|
|
154
|
-
);
|
|
155
|
-
const handleFileSelect = async (file) => {
|
|
156
|
-
setSelectedFile(file);
|
|
157
|
-
try {
|
|
158
|
-
const fileVersions = await getBackupVersions(file.filePath);
|
|
159
|
-
setVersions(fileVersions);
|
|
160
|
-
setSelectedVersionIndex(0);
|
|
161
|
-
setView("version-list");
|
|
162
|
-
} catch (err) {
|
|
163
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
164
119
|
}
|
|
165
|
-
};
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
setRestoredVersion(version);
|
|
175
|
-
setView("success");
|
|
176
|
-
} else {
|
|
177
|
-
setError(t("commands.undo.restoreFailed"));
|
|
178
|
-
}
|
|
179
|
-
} catch (err) {
|
|
180
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
120
|
+
}, [phase, files, versions]);
|
|
121
|
+
const handleStatusDismiss = useCallback(() => {
|
|
122
|
+
setStatusOverlay(null);
|
|
123
|
+
onClose();
|
|
124
|
+
}, [onClose]);
|
|
125
|
+
const handleBack = useCallback(() => {
|
|
126
|
+
if (statusOverlay && statusOverlay.type !== "loading") {
|
|
127
|
+
handleStatusDismiss();
|
|
128
|
+
return;
|
|
181
129
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
FileListView,
|
|
199
|
-
{
|
|
200
|
-
files,
|
|
201
|
-
selectedIndex: selectedFileIndex,
|
|
202
|
-
onSelect: handleFileSelect,
|
|
203
|
-
onClose
|
|
130
|
+
if (phase.type === "file-list") {
|
|
131
|
+
onClose();
|
|
132
|
+
} else {
|
|
133
|
+
setPhase({ type: "file-list" });
|
|
134
|
+
}
|
|
135
|
+
}, [phase, statusOverlay, onClose, handleStatusDismiss]);
|
|
136
|
+
const handleClose = handleBack;
|
|
137
|
+
const handleTabChange = useCallback(() => {
|
|
138
|
+
}, []);
|
|
139
|
+
const handleSelect = useCallback(
|
|
140
|
+
async (item) => {
|
|
141
|
+
switch (phase.type) {
|
|
142
|
+
case "file-list": {
|
|
143
|
+
const data = item.data;
|
|
144
|
+
setPhase({ type: "version-list", file: data.file });
|
|
145
|
+
break;
|
|
204
146
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
147
|
+
case "version-list": {
|
|
148
|
+
const data = item.data;
|
|
149
|
+
setStatusOverlay({
|
|
150
|
+
type: "loading",
|
|
151
|
+
message: "Restoring file..."
|
|
152
|
+
});
|
|
153
|
+
try {
|
|
154
|
+
const success = await restoreBackup(
|
|
155
|
+
phase.file.filePath,
|
|
156
|
+
data.version.version
|
|
157
|
+
);
|
|
158
|
+
if (success) {
|
|
159
|
+
setStatusOverlay({
|
|
160
|
+
type: "success",
|
|
161
|
+
message: `${t("commands.undo.fileRestored")}: v${data.version.version}`
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
164
|
+
setStatusOverlay({
|
|
165
|
+
type: "error",
|
|
166
|
+
message: t("commands.undo.restoreFailed")
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
} catch (err) {
|
|
170
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
171
|
+
setStatusOverlay({ type: "error", message: msg });
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
219
174
|
}
|
|
220
|
-
);
|
|
221
|
-
case "success":
|
|
222
|
-
if (!selectedFile || !restoredVersion) {
|
|
223
|
-
onClose();
|
|
224
|
-
return null;
|
|
225
175
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
176
|
+
},
|
|
177
|
+
[phase]
|
|
178
|
+
);
|
|
179
|
+
const currentTab = phase.type === "file-list" ? "files" : "versions";
|
|
180
|
+
return /* @__PURE__ */ React.createElement(
|
|
181
|
+
TabbedListView,
|
|
182
|
+
{
|
|
183
|
+
title,
|
|
184
|
+
tabs,
|
|
185
|
+
activeTab: currentTab,
|
|
186
|
+
onTabChange: handleTabChange,
|
|
187
|
+
items,
|
|
188
|
+
searchEnabled: false,
|
|
189
|
+
onSelect: handleSelect,
|
|
190
|
+
onClose: handleClose,
|
|
191
|
+
onBack: handleBack,
|
|
192
|
+
statusOverlay,
|
|
193
|
+
footerHint,
|
|
194
|
+
isLoading: loading,
|
|
195
|
+
loadingText: t("commands.undo.loading"),
|
|
196
|
+
emptyText,
|
|
197
|
+
statusDismissHint: "Enter Close"
|
|
198
|
+
}
|
|
199
|
+
);
|
|
237
200
|
};
|
|
238
201
|
const command = {
|
|
239
202
|
name: "undo",
|
|
@@ -241,6 +204,7 @@ const command = {
|
|
|
241
204
|
type: "local-jsx",
|
|
242
205
|
isEnabled: true,
|
|
243
206
|
isHidden: false,
|
|
207
|
+
hidePromptInput: true,
|
|
244
208
|
userFacingName() {
|
|
245
209
|
return "undo";
|
|
246
210
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/undo.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Undo Command\n *\n * Interactive command to restore file versions from backups.\n * Requires --smart mode to have backups available.\n */\n\nimport React, { useState, useEffect } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport type { Command } from '@commands'\nimport { SEMANTIC_COLORS } from '@constants/colors'\nimport { getCwd } from '@utils/state'\nimport {\n listBackedUpFiles,\n getBackupVersions,\n restoreBackup,\n type BackupFileSummary,\n type BackupMetadata,\n} from '../core/backupManager'\nimport { t } from '@i18n'\n\ntype ViewState = 'file-list' | 'version-list' | 'success'\n\ninterface UndoCommandProps {\n onClose: () => void\n}\n\n/**\n * Format a timestamp as a human-readable string\n */\nfunction formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp)\n const now = new Date()\n const diff = now.getTime() - timestamp\n const timeStr = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`\n\n // Within last hour - show minutes\n if (diff < 60 * 60 * 1000) {\n const minutes = Math.floor(diff / (60 * 1000))\n return minutes <= 1\n ? t('commands.undo.justNow')\n : t('commands.undo.minutesAgo', { count: minutes })\n }\n\n // Within today - show time\n if (\n date.getDate() === now.getDate() &&\n date.getMonth() === now.getMonth() &&\n date.getFullYear() === now.getFullYear()\n ) {\n return `${t('commands.undo.today')} ${timeStr}`\n }\n\n // Within this week - show day and time\n if (diff < 7 * 24 * 60 * 60 * 1000) {\n const weekdayKeys = [\n 'commands.undo.weekday.sun',\n 'commands.undo.weekday.mon',\n 'commands.undo.weekday.tue',\n 'commands.undo.weekday.wed',\n 'commands.undo.weekday.thu',\n 'commands.undo.weekday.fri',\n 'commands.undo.weekday.sat',\n ] as const\n return `${t(weekdayKeys[date.getDay()])} ${timeStr}`\n }\n\n // Otherwise - show date\n return `${date.getMonth() + 1}/${date.getDate()} ${timeStr}`\n}\n\n/**\n * Get relative path from cwd\n */\nfunction getRelativePath(filePath: string): string {\n const cwd = getCwd()\n if (filePath.startsWith(cwd)) {\n const relative = filePath.slice(cwd.length)\n return relative.startsWith('/') ? relative.slice(1) : relative\n }\n return filePath\n}\n\n/**\n * File List View - shows all files with backups\n */\nconst FileListView: React.FC<{\n files: BackupFileSummary[]\n selectedIndex: number\n onSelect: (file: BackupFileSummary) => void\n onClose: () => void\n}> = ({ files, selectedIndex, onSelect, onClose }) => {\n useInput((input, key) => {\n if (key.escape || input === 'q') {\n onClose()\n } else if (key.return) {\n if (files.length > 0 && files[selectedIndex]) {\n onSelect(files[selectedIndex])\n }\n }\n })\n\n if (files.length === 0) {\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color={SEMANTIC_COLORS.brand}>\n {t('commands.undo.title')}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" paddingLeft={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('commands.undo.noBackups')}\n </Text>\n <Text color={SEMANTIC_COLORS.muted}> </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('commands.undo.smartModeHint').replace('--smart', '')}\n <Text color={SEMANTIC_COLORS.info}>--smart</Text>\n </Text>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.undo.smartModeCommand')}\n </Text>\n </Box>\n\n <Box marginTop={2}>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.undo.pressQOrEsc')}\n </Text>\n </Box>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color={SEMANTIC_COLORS.brand}>\n {t('commands.undo.title')}\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n - {t('commands.undo.selectFile')}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\">\n {files.map((file, index) => {\n const isSelected = index === selectedIndex\n const relativePath = getRelativePath(file.filePath)\n\n return (\n <Box key={file.filePath} paddingLeft={1}>\n <Text color={isSelected ? SEMANTIC_COLORS.info : undefined}>\n {isSelected ? '\u25B6 ' : ' '}\n <Text\n color={\n isSelected\n ? SEMANTIC_COLORS.primary\n : SEMANTIC_COLORS.secondary\n }\n >\n {relativePath}\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n ({t('commands.undo.versions', { count: file.versionCount })})\n </Text>\n </Text>\n </Box>\n )\n })}\n </Box>\n\n <Box marginTop={2}>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.undo.navHintsFile')}\n </Text>\n </Box>\n </Box>\n )\n}\n\n/**\n * Version List View - shows all versions for a selected file\n */\nconst VersionListView: React.FC<{\n file: BackupFileSummary\n versions: BackupMetadata[]\n selectedIndex: number\n onSelect: (version: BackupMetadata) => void\n onBack: () => void\n}> = ({ file, versions, selectedIndex, onSelect, onBack }) => {\n useInput((input, key) => {\n if (key.escape || input === 'q') {\n onBack()\n } else if (key.return) {\n if (versions.length > 0 && versions[selectedIndex]) {\n onSelect(versions[selectedIndex])\n }\n }\n })\n\n const relativePath = getRelativePath(file.filePath)\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color={SEMANTIC_COLORS.brand}>\n {t('commands.undo.selectVersion')}\n </Text>\n </Box>\n\n <Box marginBottom={1} paddingLeft={1}>\n <Text color={SEMANTIC_COLORS.dim}>{t('commands.undo.file')}: </Text>\n <Text color={SEMANTIC_COLORS.secondary}>{relativePath}</Text>\n </Box>\n\n <Box flexDirection=\"column\">\n {versions.map((version, index) => {\n const isSelected = index === selectedIndex\n\n return (\n <Box key={version.version} paddingLeft={1}>\n <Text color={isSelected ? SEMANTIC_COLORS.info : undefined}>\n {isSelected ? '\u25B6 ' : ' '}\n <Text\n color={\n isSelected\n ? SEMANTIC_COLORS.primary\n : SEMANTIC_COLORS.secondary\n }\n >\n v{version.version}\n </Text>\n <Text color={SEMANTIC_COLORS.dim}>\n : {version.operation} - {formatTimestamp(version.timestamp)}\n </Text>\n </Text>\n </Box>\n )\n })}\n </Box>\n\n <Box marginTop={2}>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.undo.navHintsVersion')}\n </Text>\n </Box>\n </Box>\n )\n}\n\n/**\n * Success View - shows restoration confirmation\n */\nconst SuccessView: React.FC<{\n file: BackupFileSummary\n version: BackupMetadata\n onClose: () => void\n}> = ({ file, version, onClose }) => {\n useInput((input, key) => {\n if (key.escape || input === 'q' || key.return) {\n onClose()\n }\n })\n\n const relativePath = getRelativePath(file.filePath)\n\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color={SEMANTIC_COLORS.success}>\n \u2713 {t('commands.undo.fileRestored')}\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" paddingLeft={1}>\n <Text color={SEMANTIC_COLORS.dim}>{t('commands.undo.file')}: </Text>\n <Text color={SEMANTIC_COLORS.secondary}>{relativePath}</Text>\n </Box>\n\n <Box paddingLeft={1} marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('commands.undo.restoredTo')}: {version.operation} (\n {formatTimestamp(version.timestamp)})\n </Text>\n </Box>\n\n <Box marginTop={2}>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.undo.pressAnyKey')}\n </Text>\n </Box>\n </Box>\n )\n}\n\n/**\n * Main Undo Command Component\n */\nconst UndoCommand: React.FC<UndoCommandProps> = ({ onClose }) => {\n const [view, setView] = useState<ViewState>('file-list')\n const [files, setFiles] = useState<BackupFileSummary[]>([])\n const [selectedFileIndex, setSelectedFileIndex] = useState(0)\n const [selectedFile, setSelectedFile] = useState<BackupFileSummary | null>(\n null,\n )\n const [versions, setVersions] = useState<BackupMetadata[]>([])\n const [selectedVersionIndex, setSelectedVersionIndex] = useState(0)\n const [restoredVersion, setRestoredVersion] = useState<BackupMetadata | null>(\n null,\n )\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n\n // Load files with backups on mount\n useEffect(() => {\n const loadFiles = async () => {\n try {\n const backupFiles = await listBackedUpFiles()\n // Already sorted by most recent in listBackedUpFiles\n setFiles(backupFiles)\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setIsLoading(false)\n }\n }\n loadFiles()\n }, [])\n\n // Handle keyboard navigation for file list\n useInput(\n (input, key) => {\n if (view === 'file-list' && files.length > 0) {\n if (key.upArrow) {\n setSelectedFileIndex(prev => Math.max(0, prev - 1))\n } else if (key.downArrow) {\n setSelectedFileIndex(prev => Math.min(files.length - 1, prev + 1))\n }\n }\n },\n { isActive: view === 'file-list' },\n )\n\n // Handle keyboard navigation for version list\n useInput(\n (input, key) => {\n if (view === 'version-list' && versions.length > 0) {\n if (key.upArrow) {\n setSelectedVersionIndex(prev => Math.max(0, prev - 1))\n } else if (key.downArrow) {\n setSelectedVersionIndex(prev =>\n Math.min(versions.length - 1, prev + 1),\n )\n }\n }\n },\n { isActive: view === 'version-list' },\n )\n\n // Handle file selection\n const handleFileSelect = async (file: BackupFileSummary) => {\n setSelectedFile(file)\n try {\n const fileVersions = await getBackupVersions(file.filePath)\n // Already sorted by newest first in getBackupVersions\n setVersions(fileVersions)\n setSelectedVersionIndex(0)\n setView('version-list')\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n }\n\n // Handle version selection and restore\n const handleVersionSelect = async (version: BackupMetadata) => {\n if (!selectedFile) return\n\n try {\n const success = await restoreBackup(\n selectedFile.filePath,\n version.version,\n )\n if (success) {\n setRestoredVersion(version)\n setView('success')\n } else {\n setError(t('commands.undo.restoreFailed'))\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n }\n }\n\n // Handle back navigation\n const handleBack = () => {\n setView('file-list')\n setSelectedFile(null)\n setVersions([])\n setSelectedVersionIndex(0)\n }\n\n // Loading state\n if (isLoading) {\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Text color={SEMANTIC_COLORS.dim}>{t('commands.undo.loading')}</Text>\n </Box>\n )\n }\n\n // Error display\n if (error) {\n return (\n <Box flexDirection=\"column\" marginY={1}>\n <Box marginBottom={1}>\n <Text bold color={SEMANTIC_COLORS.error}>\n {t('commands.undo.error')}\n </Text>\n </Box>\n <Box paddingLeft={1}>\n <Text color={SEMANTIC_COLORS.dim}>{error}</Text>\n </Box>\n <Box marginTop={2}>\n <Text color={SEMANTIC_COLORS.muted}>\n {t('commands.undo.pressAnyKey')}\n </Text>\n </Box>\n </Box>\n )\n }\n\n // Render current view\n switch (view) {\n case 'file-list':\n return (\n <FileListView\n files={files}\n selectedIndex={selectedFileIndex}\n onSelect={handleFileSelect}\n onClose={onClose}\n />\n )\n\n case 'version-list':\n if (!selectedFile) {\n handleBack()\n return null\n }\n return (\n <VersionListView\n file={selectedFile}\n versions={versions}\n selectedIndex={selectedVersionIndex}\n onSelect={handleVersionSelect}\n onBack={handleBack}\n />\n )\n\n case 'success':\n if (!selectedFile || !restoredVersion) {\n onClose()\n return null\n }\n return (\n <SuccessView\n file={selectedFile}\n version={restoredVersion}\n onClose={onClose}\n />\n )\n\n default:\n return null\n }\n}\n\n/**\n * Undo Command Export\n */\nconst command: Command = {\n name: 'undo',\n description: t('commands.undo.description'),\n type: 'local-jsx' as const,\n isEnabled: true,\n isHidden: false,\n\n userFacingName() {\n return 'undo'\n },\n\n async call(onDone: (result?: string) => void) {\n return <UndoCommand onClose={onDone} />\n },\n}\n\nexport default command\n"],
|
|
5
|
-
"mappings": "AAOA,OAAO,SAAS,UAAU,
|
|
4
|
+
"sourcesContent": ["/**\n * Undo Command\n *\n * Interactive command to restore file versions from backups.\n * Uses TabbedListView with a phase state machine for consistent UI.\n */\n\nimport React, { useState, useEffect, useCallback, useMemo } from 'react'\nimport type { Command } from '@commands'\nimport { getCwd } from '@utils/state'\nimport {\n listBackedUpFiles,\n getBackupVersions,\n restoreBackup,\n type BackupFileSummary,\n type BackupMetadata,\n} from '../core/backupManager'\nimport { TabbedListView } from '@components/TabbedListView/TabbedListView'\nimport type {\n ListItem,\n TabDefinition,\n StatusOverlay,\n} from '@components/TabbedListView/types'\nimport { t } from '@i18n'\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nfunction formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp)\n const now = new Date()\n const diff = now.getTime() - timestamp\n const timeStr = `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`\n\n if (diff < 60 * 60 * 1000) {\n const minutes = Math.floor(diff / (60 * 1000))\n return minutes <= 1\n ? t('commands.undo.justNow')\n : t('commands.undo.minutesAgo', { count: minutes })\n }\n\n if (\n date.getDate() === now.getDate() &&\n date.getMonth() === now.getMonth() &&\n date.getFullYear() === now.getFullYear()\n ) {\n return `${t('commands.undo.today')} ${timeStr}`\n }\n\n if (diff < 7 * 24 * 60 * 60 * 1000) {\n const weekdayKeys = [\n 'commands.undo.weekday.sun',\n 'commands.undo.weekday.mon',\n 'commands.undo.weekday.tue',\n 'commands.undo.weekday.wed',\n 'commands.undo.weekday.thu',\n 'commands.undo.weekday.fri',\n 'commands.undo.weekday.sat',\n ] as const\n return `${t(weekdayKeys[date.getDay()])} ${timeStr}`\n }\n\n return `${date.getMonth() + 1}/${date.getDate()} ${timeStr}`\n}\n\nfunction getRelativePath(filePath: string): string {\n const cwd = getCwd()\n if (filePath.startsWith(cwd)) {\n const relative = filePath.slice(cwd.length)\n return relative.startsWith('/') ? relative.slice(1) : relative\n }\n return filePath\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype UndoPhase =\n | { type: 'file-list' }\n | { type: 'version-list'; file: BackupFileSummary }\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nconst UndoCommand: React.FC<{ onClose: () => void }> = ({ onClose }) => {\n const [phase, setPhase] = useState<UndoPhase>({ type: 'file-list' })\n const [files, setFiles] = useState<BackupFileSummary[]>([])\n const [versions, setVersions] = useState<BackupMetadata[]>([])\n const [loading, setLoading] = useState(true)\n const [statusOverlay, setStatusOverlay] = useState<StatusOverlay | null>(null)\n\n // Load files on mount\n useEffect(() => {\n const loadFiles = async () => {\n try {\n const backupFiles = await listBackedUpFiles()\n setFiles(backupFiles)\n } catch {\n setFiles([])\n } finally {\n setLoading(false)\n }\n }\n loadFiles()\n }, [])\n\n // Load versions when entering version-list phase\n useEffect(() => {\n if (phase.type === 'version-list') {\n const loadVersions = async () => {\n setLoading(true)\n try {\n const fileVersions = await getBackupVersions(phase.file.filePath)\n setVersions(fileVersions)\n } catch {\n setVersions([])\n } finally {\n setLoading(false)\n }\n }\n loadVersions()\n }\n }, [phase])\n\n // Build tabs, items, title based on phase\n const { tabs, items, title, footerHint, emptyText } = useMemo(() => {\n switch (phase.type) {\n case 'file-list': {\n const fileTabs: TabDefinition[] = [\n { id: 'files', label: t('commands.undo.tabFiles') },\n ]\n\n const fileItems: ListItem[] = files.map(file => ({\n id: file.filePath,\n label: getRelativePath(file.filePath),\n description: t('commands.undo.versions', {\n count: file.versionCount,\n }),\n data: { file },\n }))\n\n return {\n tabs: fileTabs,\n items: fileItems,\n title: t('commands.undo.title'),\n footerHint: '\u2191\u2193 Navigate \u00B7 Enter Select \u00B7 Esc Close',\n emptyText: t('commands.undo.noBackups'),\n }\n }\n\n case 'version-list': {\n const versionTabs: TabDefinition[] = [\n { id: 'versions', label: t('commands.undo.tabVersions') },\n ]\n\n const versionItems: ListItem[] = versions.map(version => ({\n id: String(version.version),\n label: `v${version.version}: ${version.operation}`,\n description: formatTimestamp(version.timestamp),\n data: { version },\n }))\n\n return {\n tabs: versionTabs,\n items: versionItems,\n title: getRelativePath(phase.file.filePath),\n footerHint: '\u2191\u2193 Navigate \u00B7 Enter Restore \u00B7 Esc Back',\n emptyText: 'No versions found',\n }\n }\n }\n }, [phase, files, versions])\n\n // Handle status overlay dismiss\n const handleStatusDismiss = useCallback(() => {\n setStatusOverlay(null)\n onClose()\n }, [onClose])\n\n // Handle back / close\n const handleBack = useCallback(() => {\n if (statusOverlay && statusOverlay.type !== 'loading') {\n handleStatusDismiss()\n return\n }\n if (phase.type === 'file-list') {\n onClose()\n } else {\n setPhase({ type: 'file-list' })\n }\n }, [phase, statusOverlay, onClose, handleStatusDismiss])\n\n const handleClose = handleBack\n\n // Handle tab change (no-op, single tab per phase)\n const handleTabChange = useCallback(() => {}, [])\n\n // Handle item selection\n const handleSelect = useCallback(\n async (item: ListItem) => {\n switch (phase.type) {\n case 'file-list': {\n const data = item.data as { file: BackupFileSummary }\n setPhase({ type: 'version-list', file: data.file })\n break\n }\n\n case 'version-list': {\n const data = item.data as { version: BackupMetadata }\n setStatusOverlay({\n type: 'loading',\n message: 'Restoring file...',\n })\n\n try {\n const success = await restoreBackup(\n phase.file.filePath,\n data.version.version,\n )\n if (success) {\n setStatusOverlay({\n type: 'success',\n message: `${t('commands.undo.fileRestored')}: v${data.version.version}`,\n })\n } else {\n setStatusOverlay({\n type: 'error',\n message: t('commands.undo.restoreFailed'),\n })\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n setStatusOverlay({ type: 'error', message: msg })\n }\n break\n }\n }\n },\n [phase],\n )\n\n const currentTab = phase.type === 'file-list' ? 'files' : 'versions'\n\n return (\n <TabbedListView\n title={title}\n tabs={tabs}\n activeTab={currentTab}\n onTabChange={handleTabChange}\n items={items}\n searchEnabled={false}\n onSelect={handleSelect}\n onClose={handleClose}\n onBack={handleBack}\n statusOverlay={statusOverlay}\n footerHint={footerHint}\n isLoading={loading}\n loadingText={t('commands.undo.loading')}\n emptyText={emptyText}\n statusDismissHint=\"Enter Close\"\n />\n )\n}\n\n// =============================================================================\n// Command Export\n// =============================================================================\n\nconst command: Command = {\n name: 'undo',\n description: t('commands.undo.description'),\n type: 'local-jsx' as const,\n isEnabled: true,\n isHidden: false,\n hidePromptInput: true,\n\n userFacingName() {\n return 'undo'\n },\n\n async call(onDone: (result?: string) => void) {\n return <UndoCommand onClose={onDone} />\n },\n}\n\nexport default command\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/commands.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/commands.ts"],
|
|
4
|
-
"sourcesContent": ["import React from 'react'\nimport clear from './commands/clear'\nimport compact from './commands/compact'\nimport config from './commands/config'\nimport context from './commands/context'\nimport cost from './commands/cost'\nimport ctx_viz from './commands/ctx_viz'\nimport exportCmd from './commands/export'\nimport help from './commands/help'\nimport init from './commands/init'\nimport mcp from './commands/mcp-interactive'\nimport model from './commands/model'\nimport permissions from './commands/permissions'\nimport refreshCommands from './commands/refreshCommands'\nimport sandbox from './commands/sandbox'\nimport setup from './commands/setup'\nimport status from './commands/status'\nimport terminalSetup from './commands/terminalSetup'\nimport { Tool, ToolUseContext } from './Tool'\nimport resume from './commands/resume'\nimport newCmd from './commands/new'\nimport agents from './commands/agents'\nimport plugin from './commands/plugin'\nimport undo from './commands/undo'\nimport language from './commands/language'\nimport { quit } from './commands/quit'\nimport stats from './commands/stats'\n// Phase 4: Diagnostic and task management commands\nimport doctor from './commands/doctor'\nimport bug from './commands/bug'\nimport tasks from './commands/tasks'\nimport todos from './commands/todos'\nimport { getMCPCommands } from './services/mcpClient'\nimport {\n loadCustomCommands,\n loadPluginCommands,\n} from './services/customCommands'\nimport type { MessageParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport { memoize } from 'lodash-es'\nimport type { Message } from './query'\n\ntype PromptCommand = {\n type: 'prompt'\n progressMessage: string\n argNames?: string[]\n getPromptForCommand(args: string): Promise<MessageParam[]>\n}\n\ntype LocalCommand = {\n type: 'local'\n call(\n args: string,\n context: {\n options: {\n commands: Command[]\n tools: Tool[]\n slowAndCapableModel: string\n }\n abortController: AbortController\n setForkConvoWithMessagesOnTheNextRender: (\n forkConvoWithMessages: Message[],\n ) => void\n },\n ): Promise<string>\n}\n\ntype LocalJSXCommand = {\n type: 'local-jsx'\n
|
|
4
|
+
"sourcesContent": ["import React from 'react'\nimport clear from './commands/clear'\nimport compact from './commands/compact'\nimport config from './commands/config'\nimport context from './commands/context'\nimport cost from './commands/cost'\nimport ctx_viz from './commands/ctx_viz'\nimport exportCmd from './commands/export'\nimport help from './commands/help'\nimport init from './commands/init'\nimport mcp from './commands/mcp-interactive'\nimport model from './commands/model'\nimport permissions from './commands/permissions'\nimport refreshCommands from './commands/refreshCommands'\nimport sandbox from './commands/sandbox'\nimport setup from './commands/setup'\nimport status from './commands/status'\nimport terminalSetup from './commands/terminalSetup'\nimport { Tool, ToolUseContext } from './Tool'\nimport resume from './commands/resume'\nimport newCmd from './commands/new'\nimport agents from './commands/agents'\nimport plugin from './commands/plugin'\nimport undo from './commands/undo'\nimport language from './commands/language'\nimport { quit } from './commands/quit'\nimport stats from './commands/stats'\n// Phase 4: Diagnostic and task management commands\nimport doctor from './commands/doctor'\nimport bug from './commands/bug'\nimport tasks from './commands/tasks'\nimport todos from './commands/todos'\nimport { getMCPCommands } from './services/mcpClient'\nimport {\n loadCustomCommands,\n loadPluginCommands,\n} from './services/customCommands'\nimport type { MessageParam } from '@anthropic-ai/sdk/resources/index.mjs'\nimport { memoize } from 'lodash-es'\nimport type { Message } from './query'\n\ntype PromptCommand = {\n type: 'prompt'\n progressMessage: string\n argNames?: string[]\n getPromptForCommand(args: string): Promise<MessageParam[]>\n}\n\ntype LocalCommand = {\n type: 'local'\n call(\n args: string,\n context: {\n options: {\n commands: Command[]\n tools: Tool[]\n slowAndCapableModel: string\n }\n abortController: AbortController\n setForkConvoWithMessagesOnTheNextRender: (\n forkConvoWithMessages: Message[],\n ) => void\n },\n ): Promise<string>\n}\n\ntype LocalJSXCommand = {\n type: 'local-jsx'\n call(\n onDone: (result?: string) => void,\n context: ToolUseContext & {\n setForkConvoWithMessagesOnTheNextRender: (\n forkConvoWithMessages: Message[],\n ) => void\n /** Unmount current REPL (for commands that need to replace the entire UI) */\n unmount?: () => void\n },\n args?: string,\n ): Promise<React.ReactNode>\n}\n\nexport type Command = {\n description: string\n isEnabled: boolean\n isHidden: boolean\n name: string\n aliases?: string[]\n /** When true, the command's JSX replaces the PromptInput instead of rendering below it */\n hidePromptInput?: boolean\n userFacingName(): string\n} & (PromptCommand | LocalCommand | LocalJSXCommand)\n\n// Hidden developer commands (not shown in /help but still accessible)\nconst HIDDEN_COMMANDS = [ctx_viz, refreshCommands, terminalSetup]\n\n// Declared as a function so that we don't run this until getCommands is called,\n// since underlying functions read from config, which can't be read at module initialization time\nconst COMMANDS = memoize((): Command[] => [\n agents,\n bug,\n clear,\n compact,\n config,\n context,\n cost,\n doctor,\n exportCmd,\n help,\n init,\n language,\n mcp,\n model,\n newCmd,\n permissions,\n plugin,\n quit,\n resume,\n sandbox,\n setup,\n stats,\n status,\n tasks,\n todos,\n undo,\n ...HIDDEN_COMMANDS,\n])\n\nexport const getCommands = memoize(async (): Promise<Command[]> => {\n const [mcpCommands, customCommands, pluginCommands] = await Promise.all([\n getMCPCommands(),\n loadCustomCommands(),\n loadPluginCommands(),\n ])\n\n // Get built-in commands\n const builtInCommands = COMMANDS()\n\n // Sort built-in commands alphabetically by name\n const sortedBuiltIn = [...builtInCommands].sort((a, b) =>\n a.userFacingName().localeCompare(b.userFacingName()),\n )\n\n // Sort MCP commands alphabetically by name\n const sortedMCP = [...mcpCommands].sort((a, b) =>\n a.userFacingName().localeCompare(b.userFacingName()),\n )\n\n // Sort plugin commands alphabetically by name\n const sortedPlugin = [...pluginCommands].sort((a, b) =>\n a.userFacingName().localeCompare(b.userFacingName()),\n )\n\n // Sort custom commands alphabetically by name\n const sortedCustom = [...customCommands].sort((a, b) =>\n a.userFacingName().localeCompare(b.userFacingName()),\n )\n\n // Command priority (later overrides earlier):\n // 1. MCP commands (lowest priority) - sorted alphabetically\n // 2. Plugin commands - sorted alphabetically\n // 3. Custom commands (user/project) - sorted alphabetically\n // 4. Built-in commands (highest priority) - sorted alphabetically\n // Display order: Built-in first, then custom/plugin/MCP\n return [\n ...sortedBuiltIn,\n ...sortedCustom,\n ...sortedPlugin,\n ...sortedMCP,\n ].filter(_ => _.isEnabled)\n})\n\nexport function hasCommand(commandName: string, commands: Command[]): boolean {\n return commands.some(\n _ => _.userFacingName() === commandName || _.aliases?.includes(commandName),\n )\n}\n\nexport function getCommand(commandName: string, commands: Command[]): Command {\n const command = commands.find(\n _ => _.userFacingName() === commandName || _.aliases?.includes(commandName),\n ) as Command | undefined\n if (!command) {\n throw ReferenceError(\n `Command ${commandName} not found. Available commands: ${commands\n .map(_ => {\n const name = _.userFacingName()\n return _.aliases ? `${name} (aliases: ${_.aliases.join(', ')})` : name\n })\n .join(', ')}`,\n )\n }\n\n return command\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|