@moxt-ai/moxt-cli 0.1.0
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/index.js +331 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/file.ts
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
|
|
9
|
+
// src/utils/config.ts
|
|
10
|
+
var DEFAULT_HOST = "api.moxt.ai";
|
|
11
|
+
function getApiBaseUrl() {
|
|
12
|
+
const host = process.env.MOXT_HOST ?? DEFAULT_HOST;
|
|
13
|
+
return `https://${host}/openapi/v1`;
|
|
14
|
+
}
|
|
15
|
+
function getApiKey() {
|
|
16
|
+
const apiKey = process.env.MOXT_API_KEY;
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
console.error("MOXT_API_KEY environment variable is not set.");
|
|
19
|
+
console.error("");
|
|
20
|
+
console.error("Get your API key at: https://moxt.ai/settings/api-keys");
|
|
21
|
+
console.error("");
|
|
22
|
+
console.error("Then set it:");
|
|
23
|
+
console.error(" export MOXT_API_KEY=moxt_...");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
return apiKey;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/utils/http.ts
|
|
30
|
+
async function request(method, path, body) {
|
|
31
|
+
const apiKey = getApiKey();
|
|
32
|
+
const url = `${getApiBaseUrl()}${path}`;
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
method,
|
|
35
|
+
headers: {
|
|
36
|
+
"Content-Type": "application/json",
|
|
37
|
+
Authorization: `Bearer ${apiKey}`
|
|
38
|
+
},
|
|
39
|
+
body: body ? JSON.stringify(body) : void 0
|
|
40
|
+
});
|
|
41
|
+
let data;
|
|
42
|
+
const contentType = response.headers.get("content-type");
|
|
43
|
+
if (contentType?.includes("application/json")) {
|
|
44
|
+
data = await response.json();
|
|
45
|
+
} else {
|
|
46
|
+
data = await response.text();
|
|
47
|
+
}
|
|
48
|
+
if (response.status === 401) {
|
|
49
|
+
console.error("Authentication failed. Check your MOXT_API_KEY.");
|
|
50
|
+
console.error("Get a new key at: https://moxt.ai/settings/api-keys");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
ok: response.ok,
|
|
55
|
+
status: response.status,
|
|
56
|
+
data
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function httpGet(path) {
|
|
60
|
+
return request("GET", path);
|
|
61
|
+
}
|
|
62
|
+
async function httpPut(path, body) {
|
|
63
|
+
return request("PUT", path, body);
|
|
64
|
+
}
|
|
65
|
+
async function httpPost(path, body) {
|
|
66
|
+
return request("POST", path, body);
|
|
67
|
+
}
|
|
68
|
+
async function httpDelete(path, body) {
|
|
69
|
+
return request("DELETE", path, body);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/utils/output.ts
|
|
73
|
+
var colors = {
|
|
74
|
+
bold: "\x1B[1m",
|
|
75
|
+
blue: "\x1B[1;34m",
|
|
76
|
+
green: "\x1B[32m",
|
|
77
|
+
red: "\x1B[31m",
|
|
78
|
+
dim: "\x1B[2m",
|
|
79
|
+
reset: "\x1B[0m"
|
|
80
|
+
};
|
|
81
|
+
function print(message) {
|
|
82
|
+
console.log(message);
|
|
83
|
+
}
|
|
84
|
+
function printError(message) {
|
|
85
|
+
console.error(`${colors.red}${message}${colors.reset}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/utils/spinner.ts
|
|
89
|
+
var frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
90
|
+
var intervalId = null;
|
|
91
|
+
var frameIndex = 0;
|
|
92
|
+
function startSpinner(message) {
|
|
93
|
+
frameIndex = 0;
|
|
94
|
+
process.stdout.write(`${frames[frameIndex]} ${message}`);
|
|
95
|
+
intervalId = setInterval(() => {
|
|
96
|
+
frameIndex = (frameIndex + 1) % frames.length;
|
|
97
|
+
process.stdout.write(`\r${frames[frameIndex]} ${message}`);
|
|
98
|
+
}, 80);
|
|
99
|
+
}
|
|
100
|
+
function stopSpinner(success, message) {
|
|
101
|
+
if (intervalId) {
|
|
102
|
+
clearInterval(intervalId);
|
|
103
|
+
intervalId = null;
|
|
104
|
+
}
|
|
105
|
+
const symbol = success ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
|
|
106
|
+
process.stdout.write(`\x1B[2K\r${symbol} ${message ?? ""}
|
|
107
|
+
`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/commands/file.ts
|
|
111
|
+
function isBinaryContent(buffer) {
|
|
112
|
+
const sampleSize = Math.min(buffer.length, 8192);
|
|
113
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
114
|
+
const byte = buffer[i];
|
|
115
|
+
if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
function registerFileCommand(program2) {
|
|
122
|
+
const file = program2.command("file").description("File operations");
|
|
123
|
+
file.command("list").description("List directory contents").requiredOption("-w, --workspace <id>", "Workspace ID").option("-p, --path <path>", "Directory path", "/").option("-t, --team", "Access team space (default)").option("-P, --personal", "Access personal space").action(async (options) => {
|
|
124
|
+
const space = options.personal ? "personal" : "team";
|
|
125
|
+
startSpinner("Listing files...");
|
|
126
|
+
const response = await httpGet(
|
|
127
|
+
`/workspaces/${options.workspace}/files/list?path=${encodeURIComponent(options.path)}&space=${space}`
|
|
128
|
+
);
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
stopSpinner(false, "Failed");
|
|
131
|
+
if (response.status === 404) {
|
|
132
|
+
print(`${colors.red}\u2620 ${options.path} does not exist${colors.reset}`);
|
|
133
|
+
} else {
|
|
134
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
135
|
+
}
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const { path, entries } = response.data;
|
|
139
|
+
if (!entries || entries.length === 0) {
|
|
140
|
+
stopSpinner(true, `${path}: empty directory`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
stopSpinner(true, path);
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
if (entry.type === "directory") {
|
|
146
|
+
print(`${colors.blue}${entry.name}/${colors.reset}`);
|
|
147
|
+
} else {
|
|
148
|
+
print(entry.name);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
file.command("read").description("Read file content").requiredOption("-w, --workspace <id>", "Workspace ID").requiredOption("-p, --path <path>", "File path").option("-t, --team", "Access team space (default)").option("-P, --personal", "Access personal space").action(async (options) => {
|
|
153
|
+
const space = options.personal ? "personal" : "team";
|
|
154
|
+
startSpinner("Reading file...");
|
|
155
|
+
const response = await httpGet(
|
|
156
|
+
`/workspaces/${options.workspace}/files/read?path=${encodeURIComponent(options.path)}&space=${space}`
|
|
157
|
+
);
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
stopSpinner(false, "Failed");
|
|
160
|
+
if (response.status === 404) {
|
|
161
|
+
print(`${colors.red}\u2620 ${options.path} does not exist${colors.reset}`);
|
|
162
|
+
} else {
|
|
163
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
164
|
+
}
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
const { type, content } = response.data;
|
|
168
|
+
if (type === "directory") {
|
|
169
|
+
stopSpinner(false, "Failed");
|
|
170
|
+
print(`${colors.red}\u2620 ${options.path} is a directory${colors.reset}`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
stopSpinner(true, "Done");
|
|
174
|
+
print(content ?? "");
|
|
175
|
+
});
|
|
176
|
+
file.command("put").description("Upload a file").requiredOption("-w, --workspace <id>", "Workspace ID").requiredOption("-p, --path <path>", "Remote file path").requiredOption("-l, --local-path <localPath>", "Local file path").option("-t, --team", "Access team space (default)").option("-P, --personal", "Access personal space").option("-r, --recursive", "Create parent directories if needed").action(
|
|
177
|
+
async (options) => {
|
|
178
|
+
const space = options.personal ? "personal" : "team";
|
|
179
|
+
if (!fs.existsSync(options.localPath)) {
|
|
180
|
+
print(`${colors.red}\u2620 Local file not found: ${options.localPath}${colors.reset}`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
const stats = fs.statSync(options.localPath);
|
|
184
|
+
if (!stats.isFile()) {
|
|
185
|
+
print(`${colors.red}\u2620 Not a file: ${options.localPath}${colors.reset}`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
const maxSize = 10 * 1024 * 1024;
|
|
189
|
+
if (stats.size > maxSize) {
|
|
190
|
+
print(`${colors.red}\u2620 File too large (max 10MB): ${options.localPath}${colors.reset}`);
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
const buffer = fs.readFileSync(options.localPath);
|
|
194
|
+
if (isBinaryContent(buffer)) {
|
|
195
|
+
print(`${colors.red}\u2620 Binary files are not allowed. Only text files can be uploaded.${colors.reset}`);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
const content = buffer.toString("utf8");
|
|
199
|
+
startSpinner("Uploading...");
|
|
200
|
+
const response = await httpPut(
|
|
201
|
+
`/workspaces/${options.workspace}/files/write`,
|
|
202
|
+
{
|
|
203
|
+
path: options.path,
|
|
204
|
+
content,
|
|
205
|
+
space,
|
|
206
|
+
recursive: options.recursive ?? false
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
stopSpinner(false, "Failed");
|
|
211
|
+
if (response.status === 404) {
|
|
212
|
+
print(`${colors.red}\u2620 Parent directory does not exist${colors.reset}`);
|
|
213
|
+
} else if (response.status === 400) {
|
|
214
|
+
printError(`Error: ${JSON.stringify(response.data)}`);
|
|
215
|
+
} else {
|
|
216
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
217
|
+
}
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const action = response.data.created ? "Created" : "Updated";
|
|
221
|
+
stopSpinner(true, `${action}: ${response.data.path}`);
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
file.command("mkdir").description("Create a directory").requiredOption("-w, --workspace <id>", "Workspace ID").requiredOption("-p, --path <path>", "Directory path").option("-t, --team", "Access team space (default)").option("-P, --personal", "Access personal space").option("-r, --recursive", "Create parent directories if needed").action(
|
|
225
|
+
async (options) => {
|
|
226
|
+
const space = options.personal ? "personal" : "team";
|
|
227
|
+
startSpinner("Creating directory...");
|
|
228
|
+
const response = await httpPost(
|
|
229
|
+
`/workspaces/${options.workspace}/files/mkdir`,
|
|
230
|
+
{
|
|
231
|
+
path: options.path,
|
|
232
|
+
space,
|
|
233
|
+
recursive: options.recursive ?? false
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
if (!response.ok) {
|
|
237
|
+
stopSpinner(false, "Failed");
|
|
238
|
+
if (response.status === 404) {
|
|
239
|
+
print(`${colors.red}\u2620 Parent directory does not exist${colors.reset}`);
|
|
240
|
+
} else if (response.status === 400) {
|
|
241
|
+
printError(`Error: ${JSON.stringify(response.data)}`);
|
|
242
|
+
} else {
|
|
243
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
244
|
+
}
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
const action = response.data.created ? "Created" : "Already exists";
|
|
248
|
+
stopSpinner(true, `${action}: ${response.data.path}`);
|
|
249
|
+
}
|
|
250
|
+
);
|
|
251
|
+
file.command("del").description("Delete a file or empty directory").requiredOption("-w, --workspace <id>", "Workspace ID").requiredOption("-p, --path <path>", "File or directory path").option("-t, --team", "Access team space (default)").option("-P, --personal", "Access personal space").action(
|
|
252
|
+
async (options) => {
|
|
253
|
+
const space = options.personal ? "personal" : "team";
|
|
254
|
+
startSpinner("Deleting...");
|
|
255
|
+
const response = await httpDelete(
|
|
256
|
+
`/workspaces/${options.workspace}/files/delete`,
|
|
257
|
+
{
|
|
258
|
+
path: options.path,
|
|
259
|
+
space
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
if (!response.ok) {
|
|
263
|
+
stopSpinner(false, "Failed");
|
|
264
|
+
if (response.status === 404) {
|
|
265
|
+
print(`${colors.red}\u2620 Path not found: ${options.path}${colors.reset}`);
|
|
266
|
+
} else if (response.status === 400) {
|
|
267
|
+
print(`${colors.red}\u2620 Cannot delete non-empty directory${colors.reset}`);
|
|
268
|
+
} else {
|
|
269
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
270
|
+
}
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
stopSpinner(true, `Deleted: ${response.data.path}`);
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/commands/whoami.ts
|
|
279
|
+
function registerWhoamiCommand(program2) {
|
|
280
|
+
program2.command("whoami").description("Show current user information").action(async () => {
|
|
281
|
+
startSpinner("Fetching user info...");
|
|
282
|
+
const response = await httpGet("/users/whoami");
|
|
283
|
+
if (response.ok) {
|
|
284
|
+
stopSpinner(true, "Done");
|
|
285
|
+
print(`${colors.bold}Nickname${colors.reset}: ${response.data.nickname}`);
|
|
286
|
+
print(`${colors.bold}Email${colors.reset}: ${response.data.email}`);
|
|
287
|
+
} else {
|
|
288
|
+
stopSpinner(false, "Failed");
|
|
289
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/commands/workspace.ts
|
|
296
|
+
function registerWorkspaceCommand(program2) {
|
|
297
|
+
const workspace = program2.command("workspace").description("Workspace management");
|
|
298
|
+
workspace.command("list").description("List all workspaces you belong to").action(async () => {
|
|
299
|
+
startSpinner("Fetching workspaces...");
|
|
300
|
+
const response = await httpGet("/workspaces");
|
|
301
|
+
if (response.ok) {
|
|
302
|
+
const { workspaces } = response.data;
|
|
303
|
+
if (workspaces.length === 0) {
|
|
304
|
+
stopSpinner(true, "No workspaces found.");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
stopSpinner(true, `Found ${workspaces.length} workspace(s)`);
|
|
308
|
+
for (const ws of workspaces) {
|
|
309
|
+
print(`${colors.bold}${ws.workspaceId}${colors.reset} ${ws.name}`);
|
|
310
|
+
}
|
|
311
|
+
} else {
|
|
312
|
+
stopSpinner(false, "Failed");
|
|
313
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/index.ts
|
|
320
|
+
var program = new Command();
|
|
321
|
+
program.name("moxt").description("Moxt CLI - AI Workspace").version("0.1.0").action(() => {
|
|
322
|
+
program.help();
|
|
323
|
+
});
|
|
324
|
+
registerWhoamiCommand(program);
|
|
325
|
+
registerWorkspaceCommand(program);
|
|
326
|
+
registerFileCommand(program);
|
|
327
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
328
|
+
console.error("CLI Error:", err);
|
|
329
|
+
process.exit(1);
|
|
330
|
+
});
|
|
331
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/file.ts","../src/utils/config.ts","../src/utils/http.ts","../src/utils/output.ts","../src/utils/spinner.ts","../src/commands/whoami.ts","../src/commands/workspace.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { registerFileCommand } from './commands/file.js'\nimport { registerWhoamiCommand } from './commands/whoami.js'\nimport { registerWorkspaceCommand } from './commands/workspace.js'\n\ndeclare const __CLI_VERSION__: string\n\nconst program = new Command()\n\nprogram\n .name('moxt')\n .description('Moxt CLI - AI Workspace')\n .version(__CLI_VERSION__)\n .action(() => {\n program.help()\n })\n\nregisterWhoamiCommand(program)\nregisterWorkspaceCommand(program)\nregisterFileCommand(program)\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error('CLI Error:', err)\n process.exit(1)\n})\n","import * as fs from 'node:fs'\nimport { Command } from 'commander'\nimport { httpDelete, httpGet, httpPost, httpPut } from '../utils/http.js'\nimport { colors, print, printError } from '../utils/output.js'\nimport { startSpinner, stopSpinner } from '../utils/spinner.js'\n\ninterface FileEntry {\n name: string\n type: 'file' | 'directory'\n size: number | null\n}\n\ninterface FileReadResponse {\n path: string\n type: 'file' | 'directory'\n entries: FileEntry[] | null\n content: string | null\n}\n\ninterface FileWriteResponse {\n path: string\n created: boolean\n}\n\ninterface MkdirResponse {\n path: string\n created: boolean\n}\n\ninterface DeleteResponse {\n path: string\n}\n\n/**\n * 检测 Buffer 是否为二进制内容\n * 文本文件不应包含控制字符(除了 tab、换行、回车)\n */\nfunction isBinaryContent(buffer: Buffer): boolean {\n const sampleSize = Math.min(buffer.length, 8192)\n\n for (let i = 0; i < sampleSize; i++) {\n const byte = buffer[i]\n // 控制字符(除了 tab=9, newline=10, carriage return=13)\n if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {\n return true\n }\n }\n\n return false\n}\n\nexport function registerFileCommand(program: Command): void {\n const file = program.command('file').description('File operations')\n\n file.command('list')\n .description('List directory contents')\n .requiredOption('-w, --workspace <id>', 'Workspace ID')\n .option('-p, --path <path>', 'Directory path', '/')\n .option('-t, --team', 'Access team space (default)')\n .option('-P, --personal', 'Access personal space')\n .action(async (options: { workspace: string; path: string; team?: boolean; personal?: boolean }) => {\n const space = options.personal ? 'personal' : 'team'\n startSpinner('Listing files...')\n const response = await httpGet<FileReadResponse>(\n `/workspaces/${options.workspace}/files/list?path=${encodeURIComponent(options.path)}&space=${space}`,\n )\n\n if (!response.ok) {\n stopSpinner(false, 'Failed')\n if (response.status === 404) {\n print(`${colors.red}☠ ${options.path} does not exist${colors.reset}`)\n } else {\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n }\n process.exit(1)\n }\n\n const { path, entries } = response.data\n\n if (!entries || entries.length === 0) {\n stopSpinner(true, `${path}: empty directory`)\n return\n }\n\n stopSpinner(true, path)\n for (const entry of entries) {\n if (entry.type === 'directory') {\n print(`${colors.blue}${entry.name}/${colors.reset}`)\n } else {\n print(entry.name)\n }\n }\n })\n\n file.command('read')\n .description('Read file content')\n .requiredOption('-w, --workspace <id>', 'Workspace ID')\n .requiredOption('-p, --path <path>', 'File path')\n .option('-t, --team', 'Access team space (default)')\n .option('-P, --personal', 'Access personal space')\n .action(async (options: { workspace: string; path: string; team?: boolean; personal?: boolean }) => {\n const space = options.personal ? 'personal' : 'team'\n startSpinner('Reading file...')\n const response = await httpGet<FileReadResponse>(\n `/workspaces/${options.workspace}/files/read?path=${encodeURIComponent(options.path)}&space=${space}`,\n )\n\n if (!response.ok) {\n stopSpinner(false, 'Failed')\n if (response.status === 404) {\n print(`${colors.red}☠ ${options.path} does not exist${colors.reset}`)\n } else {\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n }\n process.exit(1)\n }\n\n const { type, content } = response.data\n\n if (type === 'directory') {\n stopSpinner(false, 'Failed')\n print(`${colors.red}☠ ${options.path} is a directory${colors.reset}`)\n process.exit(1)\n }\n\n stopSpinner(true, 'Done')\n print(content ?? '')\n })\n\n file.command('put')\n .description('Upload a file')\n .requiredOption('-w, --workspace <id>', 'Workspace ID')\n .requiredOption('-p, --path <path>', 'Remote file path')\n .requiredOption('-l, --local-path <localPath>', 'Local file path')\n .option('-t, --team', 'Access team space (default)')\n .option('-P, --personal', 'Access personal space')\n .option('-r, --recursive', 'Create parent directories if needed')\n .action(\n async (options: {\n workspace: string\n path: string\n localPath: string\n team?: boolean\n personal?: boolean\n recursive?: boolean\n }) => {\n const space = options.personal ? 'personal' : 'team'\n\n // 检查本地文件是否存在\n if (!fs.existsSync(options.localPath)) {\n print(`${colors.red}☠ Local file not found: ${options.localPath}${colors.reset}`)\n process.exit(1)\n }\n\n // 检查是否为文件\n const stats = fs.statSync(options.localPath)\n if (!stats.isFile()) {\n print(`${colors.red}☠ Not a file: ${options.localPath}${colors.reset}`)\n process.exit(1)\n }\n\n // 检查文件大小 (10MB)\n const maxSize = 10 * 1024 * 1024\n if (stats.size > maxSize) {\n print(`${colors.red}☠ File too large (max 10MB): ${options.localPath}${colors.reset}`)\n process.exit(1)\n }\n\n // 读取文件内容并检查是否为二进制\n const buffer = fs.readFileSync(options.localPath)\n if (isBinaryContent(buffer)) {\n print(`${colors.red}☠ Binary files are not allowed. Only text files can be uploaded.${colors.reset}`)\n process.exit(1)\n }\n\n const content = buffer.toString('utf8')\n\n startSpinner('Uploading...')\n const response = await httpPut<FileWriteResponse>(\n `/workspaces/${options.workspace}/files/write`,\n {\n path: options.path,\n content,\n space,\n recursive: options.recursive ?? false,\n },\n )\n\n if (!response.ok) {\n stopSpinner(false, 'Failed')\n if (response.status === 404) {\n print(`${colors.red}☠ Parent directory does not exist${colors.reset}`)\n } else if (response.status === 400) {\n printError(`Error: ${JSON.stringify(response.data)}`)\n } else {\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n }\n process.exit(1)\n }\n\n const action = response.data.created ? 'Created' : 'Updated'\n stopSpinner(true, `${action}: ${response.data.path}`)\n },\n )\n\n file.command('mkdir')\n .description('Create a directory')\n .requiredOption('-w, --workspace <id>', 'Workspace ID')\n .requiredOption('-p, --path <path>', 'Directory path')\n .option('-t, --team', 'Access team space (default)')\n .option('-P, --personal', 'Access personal space')\n .option('-r, --recursive', 'Create parent directories if needed')\n .action(\n async (options: {\n workspace: string\n path: string\n team?: boolean\n personal?: boolean\n recursive?: boolean\n }) => {\n const space = options.personal ? 'personal' : 'team'\n\n startSpinner('Creating directory...')\n const response = await httpPost<MkdirResponse>(\n `/workspaces/${options.workspace}/files/mkdir`,\n {\n path: options.path,\n space,\n recursive: options.recursive ?? false,\n },\n )\n\n if (!response.ok) {\n stopSpinner(false, 'Failed')\n if (response.status === 404) {\n print(`${colors.red}☠ Parent directory does not exist${colors.reset}`)\n } else if (response.status === 400) {\n printError(`Error: ${JSON.stringify(response.data)}`)\n } else {\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n }\n process.exit(1)\n }\n\n const action = response.data.created ? 'Created' : 'Already exists'\n stopSpinner(true, `${action}: ${response.data.path}`)\n },\n )\n\n file.command('del')\n .description('Delete a file or empty directory')\n .requiredOption('-w, --workspace <id>', 'Workspace ID')\n .requiredOption('-p, --path <path>', 'File or directory path')\n .option('-t, --team', 'Access team space (default)')\n .option('-P, --personal', 'Access personal space')\n .action(\n async (options: {\n workspace: string\n path: string\n team?: boolean\n personal?: boolean\n }) => {\n const space = options.personal ? 'personal' : 'team'\n\n startSpinner('Deleting...')\n const response = await httpDelete<DeleteResponse>(\n `/workspaces/${options.workspace}/files/delete`,\n {\n path: options.path,\n space,\n },\n )\n\n if (!response.ok) {\n stopSpinner(false, 'Failed')\n if (response.status === 404) {\n print(`${colors.red}☠ Path not found: ${options.path}${colors.reset}`)\n } else if (response.status === 400) {\n print(`${colors.red}☠ Cannot delete non-empty directory${colors.reset}`)\n } else {\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n }\n process.exit(1)\n }\n\n stopSpinner(true, `Deleted: ${response.data.path}`)\n },\n )\n}\n","const DEFAULT_HOST = 'api.moxt.ai'\n\nexport function getApiBaseUrl(): string {\n const host = process.env.MOXT_HOST ?? DEFAULT_HOST\n return `https://${host}/openapi/v1`\n}\n\nexport function getApiKey(): string {\n const apiKey = process.env.MOXT_API_KEY\n\n if (!apiKey) {\n console.error('MOXT_API_KEY environment variable is not set.')\n console.error('')\n console.error('Get your API key at: https://moxt.ai/settings/api-keys')\n console.error('')\n console.error('Then set it:')\n console.error(' export MOXT_API_KEY=moxt_...')\n process.exit(1)\n }\n\n return apiKey\n}\n","import { getApiBaseUrl, getApiKey } from './config.js'\n\nexport interface ApiResponse<T> {\n ok: boolean\n status: number\n data: T\n}\n\nasync function request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {\n const apiKey = getApiKey()\n const url = `${getApiBaseUrl()}${path}`\n\n const response = await fetch(url, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: body ? JSON.stringify(body) : undefined,\n })\n\n let data: T\n const contentType = response.headers.get('content-type')\n if (contentType?.includes('application/json')) {\n data = (await response.json()) as T\n } else {\n data = (await response.text()) as T\n }\n\n if (response.status === 401) {\n console.error('Authentication failed. Check your MOXT_API_KEY.')\n console.error('Get a new key at: https://moxt.ai/settings/api-keys')\n process.exit(1)\n }\n\n return {\n ok: response.ok,\n status: response.status,\n data,\n }\n}\n\nexport async function httpGet<T>(path: string): Promise<ApiResponse<T>> {\n return request<T>('GET', path)\n}\n\nexport async function httpPut<T>(path: string, body: unknown): Promise<ApiResponse<T>> {\n return request<T>('PUT', path, body)\n}\n\nexport async function httpPost<T>(path: string, body: unknown): Promise<ApiResponse<T>> {\n return request<T>('POST', path, body)\n}\n\nexport async function httpDelete<T>(path: string, body: unknown): Promise<ApiResponse<T>> {\n return request<T>('DELETE', path, body)\n}\n","// ANSI 颜色\nexport const colors = {\n bold: '\\x1b[1m',\n blue: '\\x1b[1;34m',\n green: '\\x1b[32m',\n red: '\\x1b[31m',\n dim: '\\x1b[2m',\n reset: '\\x1b[0m',\n}\n\nexport function print(message: string): void {\n console.log(message)\n}\n\nexport function printError(message: string): void {\n console.error(`${colors.red}${message}${colors.reset}`)\n}\n","const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']\n\nlet intervalId: ReturnType<typeof setInterval> | null = null\nlet frameIndex = 0\n\nexport function startSpinner(message: string): void {\n frameIndex = 0\n process.stdout.write(`${frames[frameIndex]} ${message}`)\n\n intervalId = setInterval(() => {\n frameIndex = (frameIndex + 1) % frames.length\n process.stdout.write(`\\r${frames[frameIndex]} ${message}`)\n }, 80)\n}\n\nexport function stopSpinner(success: boolean, message?: string): void {\n if (intervalId) {\n clearInterval(intervalId)\n intervalId = null\n }\n\n const symbol = success ? '\\x1b[32m✓\\x1b[0m' : '\\x1b[31m✗\\x1b[0m'\n // \\x1b[2K 清除整行,\\r 回到行首\n process.stdout.write(`\\x1b[2K\\r${symbol} ${message ?? ''}\\n`)\n}\n","import { Command } from 'commander'\nimport { httpGet } from '../utils/http.js'\nimport { colors, print, printError } from '../utils/output.js'\nimport { startSpinner, stopSpinner } from '../utils/spinner.js'\n\ninterface WhoamiResponse {\n nickname: string\n email: string\n}\n\nexport function registerWhoamiCommand(program: Command): void {\n program\n .command('whoami')\n .description('Show current user information')\n .action(async () => {\n startSpinner('Fetching user info...')\n const response = await httpGet<WhoamiResponse>('/users/whoami')\n\n if (response.ok) {\n stopSpinner(true, 'Done')\n print(`${colors.bold}Nickname${colors.reset}: ${response.data.nickname}`)\n print(`${colors.bold}Email${colors.reset}: ${response.data.email}`)\n } else {\n stopSpinner(false, 'Failed')\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n process.exit(1)\n }\n })\n}\n","import { Command } from 'commander'\nimport { httpGet } from '../utils/http.js'\nimport { colors, print, printError } from '../utils/output.js'\nimport { startSpinner, stopSpinner } from '../utils/spinner.js'\n\ninterface WorkspaceItem {\n workspaceId: string\n name: string\n}\n\ninterface WorkspaceListResponse {\n workspaces: WorkspaceItem[]\n}\n\nexport function registerWorkspaceCommand(program: Command): void {\n const workspace = program.command('workspace').description('Workspace management')\n\n workspace\n .command('list')\n .description('List all workspaces you belong to')\n .action(async () => {\n startSpinner('Fetching workspaces...')\n const response = await httpGet<WorkspaceListResponse>('/workspaces')\n\n if (response.ok) {\n const { workspaces } = response.data\n if (workspaces.length === 0) {\n stopSpinner(true, 'No workspaces found.')\n return\n }\n\n stopSpinner(true, `Found ${workspaces.length} workspace(s)`)\n\n for (const ws of workspaces) {\n print(`${colors.bold}${ws.workspaceId}${colors.reset}\\t${ws.name}`)\n }\n } else {\n stopSpinner(false, 'Failed')\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n process.exit(1)\n }\n })\n}\n"],"mappings":"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","names":["program","program","program"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@moxt-ai/moxt-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Moxt CLI - AI Workspace command line tool",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"moxt": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"prepublishOnly": "pnpm build",
|
|
18
|
+
"release": "pnpm build && npm publish --access public"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"moxt",
|
|
22
|
+
"cli",
|
|
23
|
+
"ai",
|
|
24
|
+
"workspace"
|
|
25
|
+
],
|
|
26
|
+
"author": "Moxt",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/anthropics/moxt"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://moxt.ai",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"commander": "^14.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.17.0",
|
|
41
|
+
"tsup": "^8.5.0",
|
|
42
|
+
"tsx": "^4.0.0",
|
|
43
|
+
"typescript": "^5.8.0",
|
|
44
|
+
"vitest": "^3.2.0"
|
|
45
|
+
}
|
|
46
|
+
}
|