@xiaozhi-client/cli 1.9.4-beta.5
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/LICENSE +21 -0
- package/README.md +98 -0
- package/fix-imports.js +32 -0
- package/package.json +26 -0
- package/project.json +75 -0
- package/src/Constants.ts +105 -0
- package/src/Container.ts +212 -0
- package/src/Types.ts +79 -0
- package/src/commands/CommandHandlerFactory.ts +98 -0
- package/src/commands/ConfigCommandHandler.ts +279 -0
- package/src/commands/EndpointCommandHandler.ts +158 -0
- package/src/commands/McpCommandHandler.ts +778 -0
- package/src/commands/ProjectCommandHandler.ts +254 -0
- package/src/commands/ServiceCommandHandler.ts +182 -0
- package/src/commands/__tests__/CommandHandlerFactory.test.ts +323 -0
- package/src/commands/__tests__/CommandRegistry.test.ts +287 -0
- package/src/commands/__tests__/ConfigCommandHandler.test.ts +844 -0
- package/src/commands/__tests__/EndpointCommandHandler.test.ts +426 -0
- package/src/commands/__tests__/McpCommandHandler.test.ts +753 -0
- package/src/commands/__tests__/ProjectCommandHandler.test.ts +230 -0
- package/src/commands/__tests__/ServiceCommands.integration.test.ts +408 -0
- package/src/commands/index.ts +351 -0
- package/src/errors/ErrorHandlers.ts +141 -0
- package/src/errors/ErrorMessages.ts +121 -0
- package/src/errors/__tests__/index.test.ts +186 -0
- package/src/errors/index.ts +163 -0
- package/src/global.d.ts +19 -0
- package/src/index.ts +53 -0
- package/src/interfaces/Command.ts +128 -0
- package/src/interfaces/CommandTypes.ts +95 -0
- package/src/interfaces/Config.ts +25 -0
- package/src/interfaces/Service.ts +99 -0
- package/src/services/DaemonManager.ts +318 -0
- package/src/services/ProcessManager.ts +235 -0
- package/src/services/ServiceManager.ts +319 -0
- package/src/services/TemplateManager.ts +382 -0
- package/src/services/__tests__/DaemonManager.test.ts +378 -0
- package/src/services/__tests__/DaemonMode.integration.test.ts +321 -0
- package/src/services/__tests__/ProcessManager.test.ts +296 -0
- package/src/services/__tests__/ServiceManager.test.ts +774 -0
- package/src/services/__tests__/TemplateManager.test.ts +337 -0
- package/src/types/backend.d.ts +48 -0
- package/src/utils/FileUtils.ts +320 -0
- package/src/utils/FormatUtils.ts +198 -0
- package/src/utils/PathUtils.ts +255 -0
- package/src/utils/PlatformUtils.ts +217 -0
- package/src/utils/Validation.ts +274 -0
- package/src/utils/VersionUtils.ts +141 -0
- package/src/utils/__tests__/FileUtils.test.ts +728 -0
- package/src/utils/__tests__/FormatUtils.test.ts +243 -0
- package/src/utils/__tests__/PathUtils.test.ts +1165 -0
- package/src/utils/__tests__/PlatformUtils.test.ts +723 -0
- package/src/utils/__tests__/Validation.test.ts +560 -0
- package/src/utils/__tests__/VersionUtils.test.ts +410 -0
- package/tsconfig.json +32 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsup.config.ts +107 -0
- package/vitest.config.ts +97 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 格式化工具单元测试
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { FormatUtils } from "../FormatUtils";
|
|
7
|
+
|
|
8
|
+
describe("FormatUtils", () => {
|
|
9
|
+
describe("formatUptime", () => {
|
|
10
|
+
it("should format seconds", () => {
|
|
11
|
+
expect(FormatUtils.formatUptime(30000)).toBe("30秒");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should format minutes and seconds", () => {
|
|
15
|
+
expect(FormatUtils.formatUptime(90000)).toBe("1分钟 30秒");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should format hours and minutes", () => {
|
|
19
|
+
expect(FormatUtils.formatUptime(3690000)).toBe("1小时 1分钟");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should format days, hours and minutes", () => {
|
|
23
|
+
expect(FormatUtils.formatUptime(90090000)).toBe("1天 1小时 1分钟");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("formatFileSize", () => {
|
|
28
|
+
it("should format bytes", () => {
|
|
29
|
+
expect(FormatUtils.formatFileSize(512)).toBe("512 B");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should format kilobytes", () => {
|
|
33
|
+
expect(FormatUtils.formatFileSize(1536)).toBe("1.5 KB");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should format megabytes", () => {
|
|
37
|
+
expect(FormatUtils.formatFileSize(1572864)).toBe("1.5 MB");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should format gigabytes", () => {
|
|
41
|
+
expect(FormatUtils.formatFileSize(1610612736)).toBe("1.5 GB");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe("formatTimestamp", () => {
|
|
46
|
+
const timestamp = new Date("2024-01-01T12:30:45").getTime();
|
|
47
|
+
|
|
48
|
+
it("should format full timestamp", () => {
|
|
49
|
+
const result = FormatUtils.formatTimestamp(timestamp, "full");
|
|
50
|
+
expect(result).toContain("2024");
|
|
51
|
+
expect(result).toContain("12:30:45");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should format date only", () => {
|
|
55
|
+
const result = FormatUtils.formatTimestamp(timestamp, "date");
|
|
56
|
+
expect(result).toContain("2024");
|
|
57
|
+
expect(result).not.toContain("12:30:45");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should format time only", () => {
|
|
61
|
+
const result = FormatUtils.formatTimestamp(timestamp, "time");
|
|
62
|
+
expect(result).toContain("12:30:45");
|
|
63
|
+
expect(result).not.toContain("2024");
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("formatPid", () => {
|
|
68
|
+
it("should format process ID", () => {
|
|
69
|
+
expect(FormatUtils.formatPid(1234)).toBe("PID: 1234");
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("formatPort", () => {
|
|
74
|
+
it("should format port number", () => {
|
|
75
|
+
expect(FormatUtils.formatPort(3000)).toBe("端口: 3000");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("formatUrl", () => {
|
|
80
|
+
it("should format URL without path", () => {
|
|
81
|
+
const result = FormatUtils.formatUrl("http", "localhost", 3000);
|
|
82
|
+
expect(result).toBe("http://localhost:3000");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should format URL with path", () => {
|
|
86
|
+
const result = FormatUtils.formatUrl(
|
|
87
|
+
"https",
|
|
88
|
+
"example.com",
|
|
89
|
+
443,
|
|
90
|
+
"/api/v1"
|
|
91
|
+
);
|
|
92
|
+
expect(result).toBe("https://example.com:443/api/v1");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("formatConfigPair", () => {
|
|
97
|
+
it("should format string value", () => {
|
|
98
|
+
const result = FormatUtils.formatConfigPair("name", "xiaozhi");
|
|
99
|
+
expect(result).toBe("name: xiaozhi");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should format object value", () => {
|
|
103
|
+
const result = FormatUtils.formatConfigPair("config", { port: 3000 });
|
|
104
|
+
expect(result).toContain("config:");
|
|
105
|
+
expect(result).toContain('"port": 3000');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("formatError", () => {
|
|
110
|
+
it("should format error without stack", () => {
|
|
111
|
+
const error = new Error("Test error");
|
|
112
|
+
const result = FormatUtils.formatError(error);
|
|
113
|
+
expect(result).toBe("错误: Test error");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should format error with stack", () => {
|
|
117
|
+
const error = new Error("Test error");
|
|
118
|
+
const result = FormatUtils.formatError(error, true);
|
|
119
|
+
expect(result).toContain("错误: Test error");
|
|
120
|
+
expect(result).toContain("堆栈信息:");
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe("formatList", () => {
|
|
125
|
+
it("should format list with default bullet", () => {
|
|
126
|
+
const items = ["item1", "item2", "item3"];
|
|
127
|
+
const result = FormatUtils.formatList(items);
|
|
128
|
+
expect(result).toBe("• item1\n• item2\n• item3");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("should format list with custom bullet", () => {
|
|
132
|
+
const items = ["item1", "item2"];
|
|
133
|
+
const result = FormatUtils.formatList(items, "-");
|
|
134
|
+
expect(result).toBe("- item1\n- item2");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("formatTable", () => {
|
|
139
|
+
it("should format empty table", () => {
|
|
140
|
+
const result = FormatUtils.formatTable([]);
|
|
141
|
+
expect(result).toBe("");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should format table with data", () => {
|
|
145
|
+
const data = [
|
|
146
|
+
{ name: "Alice", age: 30 },
|
|
147
|
+
{ name: "Bob", age: 25 },
|
|
148
|
+
];
|
|
149
|
+
const result = FormatUtils.formatTable(data);
|
|
150
|
+
expect(result).toContain("name");
|
|
151
|
+
expect(result).toContain("age");
|
|
152
|
+
expect(result).toContain("Alice");
|
|
153
|
+
expect(result).toContain("Bob");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("formatProgressBar", () => {
|
|
158
|
+
it("should format progress bar at 0%", () => {
|
|
159
|
+
const result = FormatUtils.formatProgressBar(0, 100);
|
|
160
|
+
expect(result).toContain("[░░░░░░░░░░░░░░░░░░░░] 0% (0/100)");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should format progress bar at 50%", () => {
|
|
164
|
+
const result = FormatUtils.formatProgressBar(50, 100);
|
|
165
|
+
expect(result).toContain("50% (50/100)");
|
|
166
|
+
expect(result).toContain("█");
|
|
167
|
+
expect(result).toContain("░");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should format progress bar at 100%", () => {
|
|
171
|
+
const result = FormatUtils.formatProgressBar(100, 100);
|
|
172
|
+
expect(result).toContain("[████████████████████] 100% (100/100)");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("formatCommandArgs", () => {
|
|
177
|
+
it("should format command without spaces", () => {
|
|
178
|
+
const result = FormatUtils.formatCommandArgs("node", [
|
|
179
|
+
"script.js",
|
|
180
|
+
"--port",
|
|
181
|
+
"3000",
|
|
182
|
+
]);
|
|
183
|
+
expect(result).toBe("node script.js --port 3000");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("should quote arguments with spaces", () => {
|
|
187
|
+
const result = FormatUtils.formatCommandArgs("node", [
|
|
188
|
+
"my script.js",
|
|
189
|
+
"--name",
|
|
190
|
+
"My App",
|
|
191
|
+
]);
|
|
192
|
+
expect(result).toBe('node "my script.js" --name "My App"');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("truncateText", () => {
|
|
197
|
+
it("should not truncate short text", () => {
|
|
198
|
+
const result = FormatUtils.truncateText("short", 10);
|
|
199
|
+
expect(result).toBe("short");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should truncate long text", () => {
|
|
203
|
+
const result = FormatUtils.truncateText("this is a very long text", 10);
|
|
204
|
+
expect(result).toBe("this is...");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should use custom suffix", () => {
|
|
208
|
+
const result = FormatUtils.truncateText("long text", 5, "---");
|
|
209
|
+
expect(result).toBe("lo---");
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("formatJson", () => {
|
|
214
|
+
it("should format valid object", () => {
|
|
215
|
+
const obj = { name: "test", value: 123 };
|
|
216
|
+
const result = FormatUtils.formatJson(obj);
|
|
217
|
+
expect(result).toContain('"name": "test"');
|
|
218
|
+
expect(result).toContain('"value": 123');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("should handle invalid object", () => {
|
|
222
|
+
const circular: any = {};
|
|
223
|
+
circular.self = circular;
|
|
224
|
+
const result = FormatUtils.formatJson(circular);
|
|
225
|
+
expect(result).toBe("[object Object]");
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("formatBoolean", () => {
|
|
230
|
+
it("should format true with default text", () => {
|
|
231
|
+
expect(FormatUtils.formatBoolean(true)).toBe("是");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("should format false with default text", () => {
|
|
235
|
+
expect(FormatUtils.formatBoolean(false)).toBe("否");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("should format with custom text", () => {
|
|
239
|
+
expect(FormatUtils.formatBoolean(true, "Yes", "No")).toBe("Yes");
|
|
240
|
+
expect(FormatUtils.formatBoolean(false, "Yes", "No")).toBe("No");
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
});
|