@moxt-ai/cli 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -2
- package/dist/index.js +90 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,6 +33,18 @@ Workspace management.
|
|
|
33
33
|
moxt workspace list
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
### members
|
|
37
|
+
|
|
38
|
+
Manage workspace members.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# List all members in a workspace
|
|
42
|
+
moxt members list -w <workspace-id>
|
|
43
|
+
|
|
44
|
+
# Remove members by email (comma-separated)
|
|
45
|
+
moxt members remove -w <workspace-id> <email1>,<email2>
|
|
46
|
+
```
|
|
47
|
+
|
|
36
48
|
### file
|
|
37
49
|
|
|
38
50
|
File operations in workspace.
|
|
@@ -41,9 +53,12 @@ File operations in workspace.
|
|
|
41
53
|
# List directory contents
|
|
42
54
|
moxt file list -w <workspace-id> [-p <path>] [-s <personal|team>]
|
|
43
55
|
|
|
44
|
-
# Read file content
|
|
56
|
+
# Read file content by path
|
|
45
57
|
moxt file read -w <workspace-id> -p <path> [-s <personal|team>]
|
|
46
58
|
|
|
59
|
+
# Read file content by URL
|
|
60
|
+
moxt file read --url <moxt-url>
|
|
61
|
+
|
|
47
62
|
# Upload a file
|
|
48
63
|
moxt file put -w <workspace-id> -p <path> -l <local-path> [-s <personal|team>] [-r]
|
|
49
64
|
|
|
@@ -58,12 +73,15 @@ moxt file del -w <workspace-id> -p <path> [-s <personal|team>]
|
|
|
58
73
|
|
|
59
74
|
| Option | Description |
|
|
60
75
|
|--------|-------------|
|
|
61
|
-
| `-w, --workspace <id>` | Workspace ID
|
|
76
|
+
| `-w, --workspace <id>` | Workspace ID |
|
|
62
77
|
| `-p, --path <path>` | File or directory path |
|
|
78
|
+
| `-u, --url <url>` | Moxt file URL (e.g., `https://moxt.ai/w/{workspaceId}/{fileId}`) |
|
|
63
79
|
| `-l, --local-path <path>` | Local file path (for upload) |
|
|
64
80
|
| `-s, --space <type>` | Space type: `personal` or `team` (default: `team`) |
|
|
65
81
|
| `-r, --recursive` | Create parent directories if needed |
|
|
66
82
|
|
|
83
|
+
> **Note**: For `file read`, use either `--url` or both `--workspace` and `--path`. They are mutually exclusive.
|
|
84
|
+
|
|
67
85
|
## Configuration
|
|
68
86
|
|
|
69
87
|
Set the following environment variables:
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ function getApiKey() {
|
|
|
32
32
|
|
|
33
33
|
// src/utils/http.ts
|
|
34
34
|
function getUserAgent() {
|
|
35
|
-
return `moxt-cli/${"0.1.
|
|
35
|
+
return `moxt-cli/${"0.1.9"} (${platform()}/${arch()}) node/${process.versions.node}`;
|
|
36
36
|
}
|
|
37
37
|
async function request(method, path, body) {
|
|
38
38
|
const apiKey = getApiKey();
|
|
@@ -157,16 +157,33 @@ function registerFileCommand(program2) {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
|
-
file.command("read").description("Read file content").
|
|
161
|
-
|
|
160
|
+
file.command("read").description("Read file content").option("-w, --workspace <id>", "Workspace ID").option("-p, --path <path>", "File path").option("-s, --space <type>", "Space type: personal or team", "team").option("-u, --url <url>", "Moxt file URL (e.g., https://moxt.ai/w/{workspaceId}/{fileId})").action(async (options) => {
|
|
161
|
+
if (options.url && (options.workspace || options.path)) {
|
|
162
|
+
printError("Error: --url cannot be used with --workspace or --path");
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
if (!options.url && (!options.workspace || !options.path)) {
|
|
166
|
+
printError("Error: Either --url or both --workspace and --path are required");
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
162
169
|
startSpinner("Reading file...");
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
)
|
|
170
|
+
let response;
|
|
171
|
+
let displayPath;
|
|
172
|
+
if (options.url) {
|
|
173
|
+
displayPath = options.url;
|
|
174
|
+
response = await httpGet(
|
|
175
|
+
`/files/read-by-url?url=${encodeURIComponent(options.url)}`
|
|
176
|
+
);
|
|
177
|
+
} else {
|
|
178
|
+
displayPath = options.path;
|
|
179
|
+
response = await httpGet(
|
|
180
|
+
`/workspaces/${options.workspace}/files/read?path=${encodeURIComponent(options.path)}&space=${options.space}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
166
183
|
if (!response.ok) {
|
|
167
184
|
stopSpinner(false, "Failed");
|
|
168
185
|
if (response.status === 404) {
|
|
169
|
-
print(`${colors.red}\u2620 ${
|
|
186
|
+
print(`${colors.red}\u2620 ${displayPath} does not exist${colors.reset}`);
|
|
170
187
|
} else {
|
|
171
188
|
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
172
189
|
}
|
|
@@ -175,7 +192,7 @@ function registerFileCommand(program2) {
|
|
|
175
192
|
const { type, content } = response.data;
|
|
176
193
|
if (type === "directory") {
|
|
177
194
|
stopSpinner(false, "Failed");
|
|
178
|
-
print(`${colors.red}\u2620 ${
|
|
195
|
+
print(`${colors.red}\u2620 ${displayPath} is a directory${colors.reset}`);
|
|
179
196
|
process.exit(1);
|
|
180
197
|
}
|
|
181
198
|
stopSpinner(true, "Done");
|
|
@@ -301,6 +318,10 @@ function registerWhoamiCommand(program2) {
|
|
|
301
318
|
}
|
|
302
319
|
|
|
303
320
|
// src/commands/workspace.ts
|
|
321
|
+
var emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
322
|
+
function isValidEmail(email) {
|
|
323
|
+
return emailRegex.test(email);
|
|
324
|
+
}
|
|
304
325
|
function registerWorkspaceCommand(program2) {
|
|
305
326
|
const workspace = program2.command("workspace").description("Workspace management");
|
|
306
327
|
workspace.command("list").description("List all workspaces you belong to").action(async () => {
|
|
@@ -322,14 +343,73 @@ function registerWorkspaceCommand(program2) {
|
|
|
322
343
|
process.exit(1);
|
|
323
344
|
}
|
|
324
345
|
});
|
|
346
|
+
const members = program2.command("members").description("Manage workspace members");
|
|
347
|
+
members.command("list").description("List all members in a workspace").requiredOption("-w, --workspace <workspaceId>", "Workspace ID").action(async (options) => {
|
|
348
|
+
const { workspace: workspaceId } = options;
|
|
349
|
+
startSpinner("Fetching workspace members...");
|
|
350
|
+
const response = await httpGet(`/workspaces/${workspaceId}/members`);
|
|
351
|
+
if (!response.ok) {
|
|
352
|
+
stopSpinner(false, "Failed to fetch members");
|
|
353
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
354
|
+
process.exit(1);
|
|
355
|
+
}
|
|
356
|
+
const { members: members2 } = response.data;
|
|
357
|
+
if (members2.length === 0) {
|
|
358
|
+
stopSpinner(true, "No members found.");
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
stopSpinner(true, `Found ${members2.length} member(s)`);
|
|
362
|
+
for (const member of members2) {
|
|
363
|
+
const name = member.displayName || "-";
|
|
364
|
+
print(`${colors.bold}${member.email}${colors.reset} ${name} ${member.role}`);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
members.command("remove").description("Remove members from a workspace").requiredOption("-w, --workspace <workspaceId>", "Workspace ID").argument("<emails>", "Emails to remove (comma-separated)").action(async (emailsArg, options) => {
|
|
368
|
+
const { workspace: workspaceId } = options;
|
|
369
|
+
const emails = emailsArg.split(",").map((e) => e.trim()).filter(Boolean);
|
|
370
|
+
if (emails.length === 0) {
|
|
371
|
+
printError("No valid emails provided");
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
const invalidEmails = emails.filter((e) => !isValidEmail(e));
|
|
375
|
+
if (invalidEmails.length > 0) {
|
|
376
|
+
for (const email of invalidEmails) {
|
|
377
|
+
printError(`Invalid email format: ${email}`);
|
|
378
|
+
}
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
startSpinner("Fetching workspace members...");
|
|
382
|
+
const membersResponse = await httpGet(`/workspaces/${workspaceId}/members`);
|
|
383
|
+
if (!membersResponse.ok) {
|
|
384
|
+
stopSpinner(false, "Failed to fetch members");
|
|
385
|
+
printError(`Error [${membersResponse.status}]: ${JSON.stringify(membersResponse.data)}`);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
stopSpinner(true, "Members fetched");
|
|
389
|
+
const { members: members2 } = membersResponse.data;
|
|
390
|
+
const emailToMember = new Map(members2.map((m) => [m.email.toLowerCase(), m]));
|
|
391
|
+
for (const email of emails) {
|
|
392
|
+
const member = emailToMember.get(email.toLowerCase());
|
|
393
|
+
if (!member) {
|
|
394
|
+
print(`${colors.red}\u2717${colors.reset} ${email} - not found in workspace`);
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
const deleteResponse = await httpDelete(`/workspaces/${workspaceId}/members/${member.userId}`);
|
|
398
|
+
if (deleteResponse.ok) {
|
|
399
|
+
print(`${colors.green}\u2713${colors.reset} ${email} - removed`);
|
|
400
|
+
} else {
|
|
401
|
+
print(`${colors.red}\u2717${colors.reset} ${email} - failed: ${JSON.stringify(deleteResponse.data)}`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
});
|
|
325
405
|
}
|
|
326
406
|
|
|
327
407
|
// src/index.ts
|
|
328
408
|
updateNotifier({
|
|
329
|
-
pkg: { name: "@moxt-ai/cli", version: "0.1.
|
|
409
|
+
pkg: { name: "@moxt-ai/cli", version: "0.1.9" }
|
|
330
410
|
}).notify();
|
|
331
411
|
var program = new Command();
|
|
332
|
-
program.name("moxt").description("Moxt CLI - AI Workspace").version("0.1.
|
|
412
|
+
program.name("moxt").description("Moxt CLI - AI Workspace").version("0.1.9").action(() => {
|
|
333
413
|
program.help();
|
|
334
414
|
});
|
|
335
415
|
registerWhoamiCommand(program);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/file.ts","../src/utils/http.ts","../src/utils/config.ts","../src/utils/output.ts","../src/utils/spinner.ts","../src/commands/whoami.ts","../src/commands/workspace.ts"],"sourcesContent":["import { Command } from 'commander'\nimport updateNotifier from 'update-notifier'\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\nupdateNotifier({\n pkg: { name: '@moxt-ai/cli', version: __CLI_VERSION__ },\n}).notify()\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .action(async (options: { workspace: string; path: string; space: string }) => {\n const space = options.space\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .action(async (options: { workspace: string; path: string; space: string }) => {\n const space = options.space\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .option('-r, --recursive', 'Create parent directories if needed')\n .action(\n async (options: {\n workspace: string\n path: string\n localPath: string\n space: string\n recursive?: boolean\n }) => {\n const space = options.space\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .option('-r, --recursive', 'Create parent directories if needed')\n .action(\n async (options: {\n workspace: string\n path: string\n space: string\n recursive?: boolean\n }) => {\n const space = options.space\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .action(\n async (options: {\n workspace: string\n path: string\n space: string\n }) => {\n const space = options.space\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","import { arch, platform } from 'os'\nimport { getApiBaseUrl, getApiKey } from './config.js'\n\ndeclare const __CLI_VERSION__: string\n\nexport interface ApiResponse<T> {\n ok: boolean\n status: number\n data: T\n}\n\nfunction getUserAgent(): string {\n return `moxt-cli/${__CLI_VERSION__} (${platform()}/${arch()}) node/${process.versions.node}`\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 'User-Agent': getUserAgent(),\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')\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","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')\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","// 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/file.ts","../src/utils/http.ts","../src/utils/config.ts","../src/utils/output.ts","../src/utils/spinner.ts","../src/commands/whoami.ts","../src/commands/workspace.ts"],"sourcesContent":["import { Command } from 'commander'\nimport updateNotifier from 'update-notifier'\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\nupdateNotifier({\n pkg: { name: '@moxt-ai/cli', version: __CLI_VERSION__ },\n}).notify()\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 * Detect if a Buffer contains binary content.\n * Text files must not contain control characters (except tab, newline, carriage return).\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 // control chars except 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('-s, --space <type>', 'Space type: personal or team', 'team')\n .action(async (options: { workspace: string; path: string; space: string }) => {\n const space = options.space\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 .option('-w, --workspace <id>', 'Workspace ID')\n .option('-p, --path <path>', 'File path')\n .option('-s, --space <type>', 'Space type: personal or team', 'team')\n .option('-u, --url <url>', 'Moxt file URL (e.g., https://moxt.ai/w/{workspaceId}/{fileId})')\n .action(async (options: { workspace?: string; path?: string; space: string; url?: string }) => {\n // Validate mutually exclusive options\n if (options.url && (options.workspace || options.path)) {\n printError('Error: --url cannot be used with --workspace or --path')\n process.exit(1)\n }\n if (!options.url && (!options.workspace || !options.path)) {\n printError('Error: Either --url or both --workspace and --path are required')\n process.exit(1)\n }\n\n startSpinner('Reading file...')\n\n let response: { ok: boolean; status: number; data: FileReadResponse }\n let displayPath: string\n\n if (options.url) {\n displayPath = options.url\n response = await httpGet<FileReadResponse>(\n `/files/read-by-url?url=${encodeURIComponent(options.url)}`,\n )\n } else {\n displayPath = options.path!\n response = await httpGet<FileReadResponse>(\n `/workspaces/${options.workspace}/files/read?path=${encodeURIComponent(options.path!)}&space=${options.space}`,\n )\n }\n\n if (!response.ok) {\n stopSpinner(false, 'Failed')\n if (response.status === 404) {\n print(`${colors.red}☠ ${displayPath} 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}☠ ${displayPath} 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('-s, --space <type>', 'Space type: personal or team', 'team')\n .option('-r, --recursive', 'Create parent directories if needed')\n .action(\n async (options: {\n workspace: string\n path: string\n localPath: string\n space: string\n recursive?: boolean\n }) => {\n const space = options.space\n\n // check local file exists\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 // check it is a file, not a directory\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 // check file size (10MB limit)\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 // read file and check for binary content\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .option('-r, --recursive', 'Create parent directories if needed')\n .action(\n async (options: {\n workspace: string\n path: string\n space: string\n recursive?: boolean\n }) => {\n const space = options.space\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('-s, --space <type>', 'Space type: personal or team', 'team')\n .action(\n async (options: {\n workspace: string\n path: string\n space: string\n }) => {\n const space = options.space\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","import { arch, platform } from 'os'\nimport { getApiBaseUrl, getApiKey } from './config.js'\n\ndeclare const __CLI_VERSION__: string\n\nexport interface ApiResponse<T> {\n ok: boolean\n status: number\n data: T\n}\n\nfunction getUserAgent(): string {\n return `moxt-cli/${__CLI_VERSION__} (${platform()}/${arch()}) node/${process.versions.node}`\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 'User-Agent': getUserAgent(),\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')\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","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')\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","// ANSI colors\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 { httpDelete, 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\ninterface MemberItem {\n userId: number\n email: string\n displayName: string | null\n role: string\n}\n\ninterface MembersResponse {\n members: MemberItem[]\n}\n\n// Email regex (same as web/src/utils/email.ts)\nconst emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/\n\nfunction isValidEmail(email: string): boolean {\n return emailRegex.test(email)\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 const members = program.command('members').description('Manage workspace members')\n\n members\n .command('list')\n .description('List all members in a workspace')\n .requiredOption('-w, --workspace <workspaceId>', 'Workspace ID')\n .action(async (options: { workspace: string }) => {\n const { workspace: workspaceId } = options\n\n startSpinner('Fetching workspace members...')\n const response = await httpGet<MembersResponse>(`/workspaces/${workspaceId}/members`)\n\n if (!response.ok) {\n stopSpinner(false, 'Failed to fetch members')\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n process.exit(1)\n }\n\n const { members } = response.data\n if (members.length === 0) {\n stopSpinner(true, 'No members found.')\n return\n }\n\n stopSpinner(true, `Found ${members.length} member(s)`)\n\n for (const member of members) {\n const name = member.displayName || '-'\n print(`${colors.bold}${member.email}${colors.reset}\\t${name}\\t${member.role}`)\n }\n })\n\n members\n .command('remove')\n .description('Remove members from a workspace')\n .requiredOption('-w, --workspace <workspaceId>', 'Workspace ID')\n .argument('<emails>', 'Emails to remove (comma-separated)')\n .action(async (emailsArg: string, options: { workspace: string }) => {\n const { workspace: workspaceId } = options\n\n const emails = emailsArg.split(',').map((e) => e.trim()).filter(Boolean)\n if (emails.length === 0) {\n printError('No valid emails provided')\n process.exit(1)\n }\n\n // Validate email format\n const invalidEmails = emails.filter((e) => !isValidEmail(e))\n if (invalidEmails.length > 0) {\n for (const email of invalidEmails) {\n printError(`Invalid email format: ${email}`)\n }\n process.exit(1)\n }\n\n // Fetch members to get userId by email\n startSpinner('Fetching workspace members...')\n const membersResponse = await httpGet<MembersResponse>(`/workspaces/${workspaceId}/members`)\n\n if (!membersResponse.ok) {\n stopSpinner(false, 'Failed to fetch members')\n printError(`Error [${membersResponse.status}]: ${JSON.stringify(membersResponse.data)}`)\n process.exit(1)\n }\n\n stopSpinner(true, 'Members fetched')\n\n const { members } = membersResponse.data\n const emailToMember = new Map(members.map((m) => [m.email.toLowerCase(), m]))\n\n // Remove each member\n for (const email of emails) {\n const member = emailToMember.get(email.toLowerCase())\n if (!member) {\n print(`${colors.red}✗${colors.reset} ${email} - not found in workspace`)\n continue\n }\n\n const deleteResponse = await httpDelete(`/workspaces/${workspaceId}/members/${member.userId}`)\n\n if (deleteResponse.ok) {\n print(`${colors.green}✓${colors.reset} ${email} - removed`)\n } else {\n print(`${colors.red}✗${colors.reset} ${email} - failed: ${JSON.stringify(deleteResponse.data)}`)\n }\n }\n })\n}\n"],"mappings":"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","names":["program","program","program","members"]}
|