@moxt-ai/cli 0.1.9 → 0.2.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/README.md CHANGED
@@ -45,42 +45,100 @@ moxt members list -w <workspace-id>
45
45
  moxt members remove -w <workspace-id> <email1>,<email2>
46
46
  ```
47
47
 
48
+ ### space
49
+
50
+ List accessible spaces in a workspace.
51
+
52
+ ```bash
53
+ # List all accessible spaces (personal, team, teammate)
54
+ moxt space list -w <workspace-id>
55
+ ```
56
+
57
+ Output columns: TYPE, TEAM_SPACE_ID, TEAMMATE_ID, NAME
58
+
59
+ - `personal` — Your personal space (Momo). Both IDs are empty; this is the default.
60
+ - `team` — Teamspace. Only `TEAM_SPACE_ID` is populated.
61
+ - `teammate` — AI teammate. Only `TEAMMATE_ID` is populated.
62
+
48
63
  ### file
49
64
 
50
- File operations in workspace.
65
+ File operations on a space. Use `moxt space list` to find available spaces.
51
66
 
52
67
  ```bash
53
- # List directory contents
54
- moxt file list -w <workspace-id> [-p <path>] [-s <personal|team>]
68
+ # List directory contents (defaults to personal space)
69
+ moxt file list -w <workspace-id> [-p <path>]
70
+
71
+ # List directory in personal space (explicit)
72
+ moxt file list -w <workspace-id> --personal [-p <path>]
73
+
74
+ # List directory in a teamspace (by name)
75
+ moxt file list -w <workspace-id> -s <teamspace-name> [-p <path>]
76
+
77
+ # List directory in a teamspace (by ID)
78
+ moxt file list -w <workspace-id> --team-space-id <teamSpaceId> [-p <path>]
79
+
80
+ # List directory in a teammate space (by teammate ID)
81
+ moxt file list -w <workspace-id> --teammate-id <teammateId> [-p <path>]
55
82
 
56
83
  # Read file content by path
57
- moxt file read -w <workspace-id> -p <path> [-s <personal|team>]
84
+ moxt file read -w <workspace-id> -p <path>
85
+
86
+ # Read file content from a teamspace (by name or ID)
87
+ moxt file read -w <workspace-id> -s <teamspace-name> -p <path>
88
+ moxt file read -w <workspace-id> --team-space-id <teamSpaceId> -p <path>
89
+
90
+ # Read file content from a teammate space (by teammate ID)
91
+ moxt file read -w <workspace-id> --teammate-id <teammateId> -p <path>
58
92
 
59
93
  # Read file content by URL
60
94
  moxt file read --url <moxt-url>
61
95
 
96
+ # Resolve the shareable browser URL for a file by path
97
+ moxt file get-url -w <workspace-id> -p <path>
98
+
99
+ # Resolve URL in a teamspace (by name or ID)
100
+ moxt file get-url -w <workspace-id> -s <teamspace-name> -p <path>
101
+ moxt file get-url -w <workspace-id> --team-space-id <teamSpaceId> -p <path>
102
+
103
+ # Resolve URL in a teammate space (by teammate ID)
104
+ moxt file get-url -w <workspace-id> --teammate-id <teammateId> -p <path>
105
+
62
106
  # Upload a file
63
- moxt file put -w <workspace-id> -p <path> -l <local-path> [-s <personal|team>] [-r]
107
+ moxt file put -w <workspace-id> -p <path> -l <local-path> [-r]
108
+
109
+ # Upload a file to a teamspace (by name or ID)
110
+ moxt file put -w <workspace-id> -s <teamspace-name> -p <path> -l <local-path> [-r]
111
+ moxt file put -w <workspace-id> --team-space-id <teamSpaceId> -p <path> -l <local-path> [-r]
112
+
113
+ # Upload a file to a teammate space (by teammate ID)
114
+ moxt file put -w <workspace-id> --teammate-id <teammateId> -p <path> -l <local-path> [-r]
64
115
 
65
116
  # Create a directory
66
- moxt file mkdir -w <workspace-id> -p <path> [-s <personal|team>] [-r]
117
+ moxt file mkdir -w <workspace-id> -p <path> [-r]
118
+ moxt file mkdir -w <workspace-id> -s <teamspace-name> -p <path> [-r]
67
119
 
68
120
  # Delete a file or empty directory
69
- moxt file del -w <workspace-id> -p <path> [-s <personal|team>]
121
+ moxt file del -w <workspace-id> -p <path>
122
+ moxt file del -w <workspace-id> -s <teamspace-name> -p <path>
70
123
  ```
71
124
 
72
125
  #### File command options
73
126
 
74
127
  | Option | Description |
75
128
  |--------|-------------|
76
- | `-w, --workspace <id>` | Workspace ID |
129
+ | `-w, --workspace <id>` | Workspace ID (required for all except URL mode) |
130
+ | `-s, --space <name>` | Space name (`personal` or teamspace name) |
131
+ | `--personal` | Use personal space (default when no space specified) |
132
+ | `--team-space-id <id>` | Team space ID |
133
+ | `--teammate-id <id>` | Teammate ID (teammate space) |
77
134
  | `-p, --path <path>` | File or directory path |
78
135
  | `-u, --url <url>` | Moxt file URL (e.g., `https://moxt.ai/w/{workspaceId}/{fileId}`) |
79
136
  | `-l, --local-path <path>` | Local file path (for upload) |
80
- | `-s, --space <type>` | Space type: `personal` or `team` (default: `team`) |
81
137
  | `-r, --recursive` | Create parent directories if needed |
82
138
 
83
- > **Note**: For `file read`, use either `--url` or both `--workspace` and `--path`. They are mutually exclusive.
139
+ > **Note**: `-s`, `--personal`, `--team-space-id`, and `--teammate-id` are mutually exclusive.
140
+ > For `file read`, use either `--url` or `--workspace` with `--path`. They are mutually exclusive.
141
+ > `file get-url` returns a stable Moxt URL (e.g., `https://moxt.ai/w/{workspaceId}/{fileId}`) for the given path; the URL is unchanged across writes to the same path and can be fed back into `file read --url`.
84
142
 
85
143
  ## Configuration
86
144
 
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.9"} (${platform()}/${arch()}) node/${process.versions.node}`;
35
+ return `moxt-cli/${"0.2.0"} (${platform()}/${arch()}) node/${process.versions.node}`;
36
36
  }
37
37
  async function request(method, path, body) {
38
38
  const apiKey = getApiKey();
@@ -83,6 +83,7 @@ var colors = {
83
83
  blue: "\x1B[1;34m",
84
84
  green: "\x1B[32m",
85
85
  red: "\x1B[31m",
86
+ cyan: "\x1B[36m",
86
87
  dim: "\x1B[2m",
87
88
  reset: "\x1B[0m"
88
89
  };
@@ -126,13 +127,86 @@ function isBinaryContent(buffer) {
126
127
  }
127
128
  return false;
128
129
  }
130
+ function validateSpaceOptions(options) {
131
+ const mutuallyExclusive = [options.space, options.personal, options.teamSpaceId, options.teammateId].filter(
132
+ Boolean
133
+ ).length;
134
+ if (mutuallyExclusive > 1) {
135
+ printError("Error: -s, --personal, --team-space-id, and --teammate-id are mutually exclusive.");
136
+ process.exit(1);
137
+ }
138
+ if (options.teamSpaceId) {
139
+ return { teamSpaceId: options.teamSpaceId };
140
+ }
141
+ if (options.teammateId) {
142
+ const parsed = Number.parseInt(options.teammateId, 10);
143
+ if (!Number.isInteger(parsed) || parsed <= 0) {
144
+ printError(`Error: --teammate-id must be a positive integer, got "${options.teammateId}".`);
145
+ process.exit(1);
146
+ }
147
+ return { agentId: parsed };
148
+ }
149
+ if (options.personal) {
150
+ return { space: "personal" };
151
+ }
152
+ if (options.space) {
153
+ return { space: options.space };
154
+ }
155
+ return {};
156
+ }
157
+ function buildFileQueryString(path, spaceParams) {
158
+ const params = new URLSearchParams();
159
+ if (path) {
160
+ params.set("path", path);
161
+ }
162
+ if (spaceParams.space) {
163
+ params.set("space", spaceParams.space);
164
+ }
165
+ if (spaceParams.teamSpaceId) {
166
+ params.set("teamSpaceId", spaceParams.teamSpaceId);
167
+ }
168
+ if (spaceParams.agentId != null) {
169
+ params.set("agentId", String(spaceParams.agentId));
170
+ }
171
+ const qs = params.toString();
172
+ return qs ? `?${qs}` : "";
173
+ }
174
+ function addSpaceOptions(cmd) {
175
+ return cmd.requiredOption("-w, --workspace <workspaceId>", "Workspace ID").option("-s, --space <name>", "Space name (personal or teamspace name)").option("--personal", "Use personal space (default)").option("--team-space-id <teamSpaceId>", "Team space ID").option("--teammate-id <teammateId>", "Teammate ID (teammate space)");
176
+ }
129
177
  function registerFileCommand(program2) {
130
178
  const file = program2.command("file").description("File operations");
131
- file.command("list").description("List directory contents").requiredOption("-w, --workspace <id>", "Workspace ID").option("-p, --path <path>", "Directory path", "/").option("-s, --space <type>", "Space type: personal or team", "team").action(async (options) => {
132
- const space = options.space;
179
+ addSpaceOptions(
180
+ file.command("get-url").description("Resolve the shareable browser URL for a file").requiredOption("-p, --path <path>", "File path")
181
+ ).action(async (options) => {
182
+ const spaceParams = validateSpaceOptions(options);
183
+ const qs = buildFileQueryString(options.path, spaceParams);
184
+ startSpinner("Resolving URL...");
185
+ const response = await httpGet(
186
+ `/workspaces/${options.workspace}/files/url${qs}`
187
+ );
188
+ if (!response.ok) {
189
+ stopSpinner(false, "Failed");
190
+ if (response.status === 404) {
191
+ print(`${colors.red}\u2620 ${options.path} does not exist${colors.reset}`);
192
+ } else if (response.status === 400) {
193
+ printError(`Error: ${JSON.stringify(response.data)}`);
194
+ } else {
195
+ printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
196
+ }
197
+ process.exit(1);
198
+ }
199
+ stopSpinner(true, response.data.path);
200
+ print(`${colors.cyan}${response.data.url}${colors.reset}`);
201
+ });
202
+ addSpaceOptions(
203
+ file.command("list").description("List directory contents").option("-p, --path <path>", "Directory path", "/")
204
+ ).action(async (options) => {
205
+ const spaceParams = validateSpaceOptions(options);
206
+ const qs = buildFileQueryString(options.path, spaceParams);
133
207
  startSpinner("Listing files...");
134
208
  const response = await httpGet(
135
- `/workspaces/${options.workspace}/files/list?path=${encodeURIComponent(options.path)}&space=${space}`
209
+ `/workspaces/${options.workspace}/files/list${qs}`
136
210
  );
137
211
  if (!response.ok) {
138
212
  stopSpinner(false, "Failed");
@@ -157,13 +231,21 @@ function registerFileCommand(program2) {
157
231
  }
158
232
  }
159
233
  });
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");
234
+ file.command("read").description("Read file content").option("-w, --workspace <workspaceId>", "Workspace ID").option("-s, --space <name>", "Space name (personal or teamspace name)").option("--personal", "Use personal space (default)").option("--team-space-id <teamSpaceId>", "Team space ID").option("--teammate-id <teammateId>", "Teammate ID (teammate space)").option("-p, --path <path>", "File path").option("-u, --url <url>", "Moxt file URL (e.g., https://moxt.ai/w/{workspaceId}/{fileId})").action(async (options) => {
235
+ if (options.url && options.workspace) {
236
+ printError("Error: --url cannot be used with --workspace");
237
+ process.exit(1);
238
+ }
239
+ if (options.url && options.path) {
240
+ printError("Error: --url cannot be used with --path");
241
+ process.exit(1);
242
+ }
243
+ if (!options.url && !options.workspace) {
244
+ printError("Error: Either --url or --workspace is required");
163
245
  process.exit(1);
164
246
  }
165
- if (!options.url && (!options.workspace || !options.path)) {
166
- printError("Error: Either --url or both --workspace and --path are required");
247
+ if (!options.url && !options.path) {
248
+ printError("Error: --path is required when not using --url");
167
249
  process.exit(1);
168
250
  }
169
251
  startSpinner("Reading file...");
@@ -176,8 +258,10 @@ function registerFileCommand(program2) {
176
258
  );
177
259
  } else {
178
260
  displayPath = options.path;
261
+ const spaceParams = validateSpaceOptions(options);
262
+ const qs = buildFileQueryString(options.path, spaceParams);
179
263
  response = await httpGet(
180
- `/workspaces/${options.workspace}/files/read?path=${encodeURIComponent(options.path)}&space=${options.space}`
264
+ `/workspaces/${options.workspace}/files/read${qs}`
181
265
  );
182
266
  }
183
267
  if (!response.ok) {
@@ -198,9 +282,11 @@ function registerFileCommand(program2) {
198
282
  stopSpinner(true, "Done");
199
283
  print(content ?? "");
200
284
  });
201
- 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("-s, --space <type>", "Space type: personal or team", "team").option("-r, --recursive", "Create parent directories if needed").action(
285
+ addSpaceOptions(
286
+ file.command("put").description("Upload a file").requiredOption("-p, --path <path>", "Remote file path").requiredOption("-l, --local-path <localPath>", "Local file path").option("-r, --recursive", "Create parent directories if needed")
287
+ ).action(
202
288
  async (options) => {
203
- const space = options.space;
289
+ const spaceParams = validateSpaceOptions(options);
204
290
  if (!fs.existsSync(options.localPath)) {
205
291
  print(`${colors.red}\u2620 Local file not found: ${options.localPath}${colors.reset}`);
206
292
  process.exit(1);
@@ -227,8 +313,8 @@ function registerFileCommand(program2) {
227
313
  {
228
314
  path: options.path,
229
315
  content,
230
- space,
231
- recursive: options.recursive ?? false
316
+ recursive: options.recursive ?? false,
317
+ ...spaceParams
232
318
  }
233
319
  );
234
320
  if (!response.ok) {
@@ -246,16 +332,18 @@ function registerFileCommand(program2) {
246
332
  stopSpinner(true, `${action}: ${response.data.path}`);
247
333
  }
248
334
  );
249
- file.command("mkdir").description("Create a directory").requiredOption("-w, --workspace <id>", "Workspace ID").requiredOption("-p, --path <path>", "Directory path").option("-s, --space <type>", "Space type: personal or team", "team").option("-r, --recursive", "Create parent directories if needed").action(
335
+ addSpaceOptions(
336
+ file.command("mkdir").description("Create a directory").requiredOption("-p, --path <path>", "Directory path").option("-r, --recursive", "Create parent directories if needed")
337
+ ).action(
250
338
  async (options) => {
251
- const space = options.space;
339
+ const spaceParams = validateSpaceOptions(options);
252
340
  startSpinner("Creating directory...");
253
341
  const response = await httpPost(
254
342
  `/workspaces/${options.workspace}/files/mkdir`,
255
343
  {
256
344
  path: options.path,
257
- space,
258
- recursive: options.recursive ?? false
345
+ recursive: options.recursive ?? false,
346
+ ...spaceParams
259
347
  }
260
348
  );
261
349
  if (!response.ok) {
@@ -273,15 +361,17 @@ function registerFileCommand(program2) {
273
361
  stopSpinner(true, `${action}: ${response.data.path}`);
274
362
  }
275
363
  );
276
- 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("-s, --space <type>", "Space type: personal or team", "team").action(
364
+ addSpaceOptions(
365
+ file.command("del").description("Delete a file or empty directory").requiredOption("-p, --path <path>", "File or directory path")
366
+ ).action(
277
367
  async (options) => {
278
- const space = options.space;
368
+ const spaceParams = validateSpaceOptions(options);
279
369
  startSpinner("Deleting...");
280
370
  const response = await httpDelete(
281
371
  `/workspaces/${options.workspace}/files/delete`,
282
372
  {
283
373
  path: options.path,
284
- space
374
+ ...spaceParams
285
375
  }
286
376
  );
287
377
  if (!response.ok) {
@@ -402,14 +492,39 @@ function registerWorkspaceCommand(program2) {
402
492
  }
403
493
  }
404
494
  });
495
+ const space = program2.command("space").description("Manage spaces");
496
+ space.command("list").description("List accessible spaces in a workspace").requiredOption("-w, --workspace <workspaceId>", "Workspace ID").action(async (options) => {
497
+ const { workspace: workspaceId } = options;
498
+ startSpinner("Fetching spaces...");
499
+ const response = await httpGet(`/workspaces/${workspaceId}/spaces`);
500
+ if (!response.ok) {
501
+ stopSpinner(false, "Failed to fetch spaces");
502
+ printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
503
+ process.exit(1);
504
+ }
505
+ const { spaces } = response.data;
506
+ if (spaces.length === 0) {
507
+ stopSpinner(true, "No spaces found.");
508
+ return;
509
+ }
510
+ stopSpinner(true, `Found ${spaces.length} space(s)`);
511
+ print(
512
+ `${colors.bold}TYPE${colors.reset} ${colors.bold}TEAM_SPACE_ID${colors.reset} ${colors.bold}TEAMMATE_ID${colors.reset} ${colors.bold}NAME${colors.reset}`
513
+ );
514
+ for (const s of spaces) {
515
+ const teamSpaceId = s.teamSpaceId ?? "";
516
+ const teammateId = s.agentId != null ? String(s.agentId) : "";
517
+ print(`${s.type} ${teamSpaceId} ${teammateId} ${s.name}`);
518
+ }
519
+ });
405
520
  }
406
521
 
407
522
  // src/index.ts
408
523
  updateNotifier({
409
- pkg: { name: "@moxt-ai/cli", version: "0.1.9" }
524
+ pkg: { name: "@moxt-ai/cli", version: "0.2.0" }
410
525
  }).notify();
411
526
  var program = new Command();
412
- program.name("moxt").description("Moxt CLI - AI Workspace").version("0.1.9").action(() => {
527
+ program.name("moxt").description("Moxt CLI - AI Workspace").version("0.2.0").action(() => {
413
528
  program.help();
414
529
  });
415
530
  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 * 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"]}
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\ninterface FileUrlResponse {\n path: string\n url: 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\ninterface SpaceOptions {\n workspace: string\n space?: string\n personal?: boolean\n teamSpaceId?: string\n teammateId?: string\n}\n\ninterface SpaceParams {\n space?: string\n teamSpaceId?: string\n agentId?: number\n}\n\nfunction validateSpaceOptions(options: SpaceOptions): SpaceParams {\n const mutuallyExclusive = [options.space, options.personal, options.teamSpaceId, options.teammateId].filter(\n Boolean,\n ).length\n if (mutuallyExclusive > 1) {\n printError('Error: -s, --personal, --team-space-id, and --teammate-id are mutually exclusive.')\n process.exit(1)\n }\n\n if (options.teamSpaceId) {\n return { teamSpaceId: options.teamSpaceId }\n }\n if (options.teammateId) {\n const parsed = Number.parseInt(options.teammateId, 10)\n if (!Number.isInteger(parsed) || parsed <= 0) {\n printError(`Error: --teammate-id must be a positive integer, got \"${options.teammateId}\".`)\n process.exit(1)\n }\n return { agentId: parsed }\n }\n if (options.personal) {\n return { space: 'personal' }\n }\n if (options.space) {\n return { space: options.space }\n }\n // Default: personal space\n return {}\n}\n\nfunction buildFileQueryString(path: string | undefined, spaceParams: SpaceParams): string {\n const params = new URLSearchParams()\n if (path) {\n params.set('path', path)\n }\n if (spaceParams.space) {\n params.set('space', spaceParams.space)\n }\n if (spaceParams.teamSpaceId) {\n params.set('teamSpaceId', spaceParams.teamSpaceId)\n }\n if (spaceParams.agentId != null) {\n params.set('agentId', String(spaceParams.agentId))\n }\n const qs = params.toString()\n return qs ? `?${qs}` : ''\n}\n\nfunction addSpaceOptions(cmd: Command): Command {\n return cmd\n .requiredOption('-w, --workspace <workspaceId>', 'Workspace ID')\n .option('-s, --space <name>', 'Space name (personal or teamspace name)')\n .option('--personal', 'Use personal space (default)')\n .option('--team-space-id <teamSpaceId>', 'Team space ID')\n .option('--teammate-id <teammateId>', 'Teammate ID (teammate space)')\n}\n\nexport function registerFileCommand(program: Command): void {\n const file = program.command('file').description('File operations')\n\n addSpaceOptions(\n file.command('get-url')\n .description('Resolve the shareable browser URL for a file')\n .requiredOption('-p, --path <path>', 'File path'),\n ).action(async (options: SpaceOptions & { path: string }) => {\n const spaceParams = validateSpaceOptions(options)\n const qs = buildFileQueryString(options.path, spaceParams)\n\n startSpinner('Resolving URL...')\n const response = await httpGet<FileUrlResponse>(\n `/workspaces/${options.workspace}/files/url${qs}`,\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 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 stopSpinner(true, response.data.path)\n print(`${colors.cyan}${response.data.url}${colors.reset}`)\n })\n\n addSpaceOptions(\n file.command('list')\n .description('List directory contents')\n .option('-p, --path <path>', 'Directory path', '/'),\n ).action(async (options: SpaceOptions & { path: string }) => {\n const spaceParams = validateSpaceOptions(options)\n const qs = buildFileQueryString(options.path, spaceParams)\n\n startSpinner('Listing files...')\n const response = await httpGet<FileReadResponse>(\n `/workspaces/${options.workspace}/files/list${qs}`,\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 <workspaceId>', 'Workspace ID')\n .option('-s, --space <name>', 'Space name (personal or teamspace name)')\n .option('--personal', 'Use personal space (default)')\n .option('--team-space-id <teamSpaceId>', 'Team space ID')\n .option('--teammate-id <teammateId>', 'Teammate ID (teammate space)')\n .option('-p, --path <path>', 'File path')\n .option('-u, --url <url>', 'Moxt file URL (e.g., https://moxt.ai/w/{workspaceId}/{fileId})')\n .action(async (options: Partial<SpaceOptions> & { path?: string; url?: string }) => {\n // Validate mutually exclusive options: -u vs -w\n if (options.url && options.workspace) {\n printError('Error: --url cannot be used with --workspace')\n process.exit(1)\n }\n if (options.url && options.path) {\n printError('Error: --url cannot be used with --path')\n process.exit(1)\n }\n if (!options.url && !options.workspace) {\n printError('Error: Either --url or --workspace is required')\n process.exit(1)\n }\n if (!options.url && !options.path) {\n printError('Error: --path is required when not using --url')\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 const spaceParams = validateSpaceOptions(options as SpaceOptions)\n const qs = buildFileQueryString(options.path, spaceParams)\n response = await httpGet<FileReadResponse>(\n `/workspaces/${options.workspace}/files/read${qs}`,\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 addSpaceOptions(\n file.command('put')\n .description('Upload a file')\n .requiredOption('-p, --path <path>', 'Remote file path')\n .requiredOption('-l, --local-path <localPath>', 'Local file path')\n .option('-r, --recursive', 'Create parent directories if needed'),\n ).action(\n async (options: SpaceOptions & {\n path: string\n localPath: string\n recursive?: boolean\n }) => {\n const spaceParams = validateSpaceOptions(options)\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 recursive: options.recursive ?? false,\n ...spaceParams,\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 addSpaceOptions(\n file.command('mkdir')\n .description('Create a directory')\n .requiredOption('-p, --path <path>', 'Directory path')\n .option('-r, --recursive', 'Create parent directories if needed'),\n ).action(\n async (options: SpaceOptions & {\n path: string\n recursive?: boolean\n }) => {\n const spaceParams = validateSpaceOptions(options)\n\n startSpinner('Creating directory...')\n const response = await httpPost<MkdirResponse>(\n `/workspaces/${options.workspace}/files/mkdir`,\n {\n path: options.path,\n recursive: options.recursive ?? false,\n ...spaceParams,\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 addSpaceOptions(\n file.command('del')\n .description('Delete a file or empty directory')\n .requiredOption('-p, --path <path>', 'File or directory path'),\n ).action(\n async (options: SpaceOptions & {\n path: string\n }) => {\n const spaceParams = validateSpaceOptions(options)\n\n startSpinner('Deleting...')\n const response = await httpDelete<DeleteResponse>(\n `/workspaces/${options.workspace}/files/delete`,\n {\n path: options.path,\n ...spaceParams,\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 cyan: '\\x1b[36m',\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, httpDelete } 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\ninterface SpaceItem {\n type: 'personal' | 'team' | 'teammate'\n name: string\n teamSpaceId: string | null\n agentId: number | null\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 const space = program.command('space').description('Manage spaces')\n\n space\n .command('list')\n .description('List accessible spaces 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 spaces...')\n const response = await httpGet<{ spaces: SpaceItem[] }>(`/workspaces/${workspaceId}/spaces`)\n\n if (!response.ok) {\n stopSpinner(false, 'Failed to fetch spaces')\n printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`)\n process.exit(1)\n }\n\n const { spaces } = response.data\n if (spaces.length === 0) {\n stopSpinner(true, 'No spaces found.')\n return\n }\n\n stopSpinner(true, `Found ${spaces.length} space(s)`)\n\n print(\n `${colors.bold}TYPE${colors.reset}\\t${colors.bold}TEAM_SPACE_ID${colors.reset}\\t${colors.bold}TEAMMATE_ID${colors.reset}\\t${colors.bold}NAME${colors.reset}`,\n )\n for (const s of spaces) {\n const teamSpaceId = s.teamSpaceId ?? ''\n const teammateId = s.agentId != null ? String(s.agentId) : ''\n print(`${s.type}\\t${teamSpaceId}\\t${teammateId}\\t${s.name}`)\n }\n })\n\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;AACxB,OAAO,oBAAoB;;;ACD3B,YAAY,QAAQ;;;ACApB,SAAS,MAAM,gBAAgB;;;ACA/B,IAAM,eAAe;AAEd,SAAS,gBAAwB;AACpC,QAAM,OAAO,QAAQ,IAAI,aAAa;AACtC,SAAO,WAAW,IAAI;AAC1B;AAEO,SAAS,YAAoB;AAChC,QAAM,SAAS,QAAQ,IAAI;AAE3B,MAAI,CAAC,QAAQ;AACT,YAAQ,MAAM,+CAA+C;AAC7D,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,sCAAsC;AACpD,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,cAAc;AAC5B,YAAQ,MAAM,gCAAgC;AAC9C,YAAQ,KAAK,CAAC;AAAA,EAClB;AAEA,SAAO;AACX;;;ADVA,SAAS,eAAuB;AAC5B,SAAO,YAAY,OAAe,KAAK,SAAS,CAAC,IAAI,KAAK,CAAC,UAAU,QAAQ,SAAS,IAAI;AAC9F;AAEA,eAAe,QAAW,QAAgB,MAAc,MAAyC;AAC7F,QAAM,SAAS,UAAU;AACzB,QAAM,MAAM,GAAG,cAAc,CAAC,GAAG,IAAI;AAErC,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAC9B;AAAA,IACA,SAAS;AAAA,MACL,gBAAgB;AAAA,MAChB,eAAe,UAAU,MAAM;AAAA,MAC/B,cAAc,aAAa;AAAA,IAC/B;AAAA,IACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,EACxC,CAAC;AAED,MAAI;AACJ,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,MAAI,aAAa,SAAS,kBAAkB,GAAG;AAC3C,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC,OAAO;AACH,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC;AAEA,MAAI,SAAS,WAAW,KAAK;AACzB,YAAQ,MAAM,iDAAiD;AAC/D,YAAQ,MAAM,mCAAmC;AACjD,YAAQ,KAAK,CAAC;AAAA,EAClB;AAEA,SAAO;AAAA,IACH,IAAI,SAAS;AAAA,IACb,QAAQ,SAAS;AAAA,IACjB;AAAA,EACJ;AACJ;AAEA,eAAsB,QAAW,MAAuC;AACpE,SAAO,QAAW,OAAO,IAAI;AACjC;AAEA,eAAsB,QAAW,MAAc,MAAwC;AACnF,SAAO,QAAW,OAAO,MAAM,IAAI;AACvC;AAEA,eAAsB,SAAY,MAAc,MAAwC;AACpF,SAAO,QAAW,QAAQ,MAAM,IAAI;AACxC;AAEA,eAAsB,WAAc,MAAc,MAAyC;AACvF,SAAO,QAAW,UAAU,MAAM,IAAI;AAC1C;;;AE/DO,IAAM,SAAS;AAAA,EAClB,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AACX;AAEO,SAAS,MAAM,SAAuB;AACzC,UAAQ,IAAI,OAAO;AACvB;AAEO,SAAS,WAAW,SAAuB;AAC9C,UAAQ,MAAM,GAAG,OAAO,GAAG,GAAG,OAAO,GAAG,OAAO,KAAK,EAAE;AAC1D;;;ACjBA,IAAM,SAAS,CAAC,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,QAAG;AAEhE,IAAI,aAAoD;AACxD,IAAI,aAAa;AAEV,SAAS,aAAa,SAAuB;AAChD,eAAa;AACb,UAAQ,OAAO,MAAM,GAAG,OAAO,UAAU,CAAC,IAAI,OAAO,EAAE;AAEvD,eAAa,YAAY,MAAM;AAC3B,kBAAc,aAAa,KAAK,OAAO;AACvC,YAAQ,OAAO,MAAM,KAAK,OAAO,UAAU,CAAC,IAAI,OAAO,EAAE;AAAA,EAC7D,GAAG,EAAE;AACT;AAEO,SAAS,YAAY,SAAkB,SAAwB;AAClE,MAAI,YAAY;AACZ,kBAAc,UAAU;AACxB,iBAAa;AAAA,EACjB;AAEA,QAAM,SAAS,UAAU,0BAAqB;AAE9C,UAAQ,OAAO,MAAM,YAAY,MAAM,IAAI,WAAW,EAAE;AAAA,CAAI;AAChE;;;AJkBA,SAAS,gBAAgB,QAAyB;AAC9C,QAAM,aAAa,KAAK,IAAI,OAAO,QAAQ,IAAI;AAE/C,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACjC,UAAM,OAAO,OAAO,CAAC;AAErB,QAAI,OAAO,MAAM,SAAS,KAAK,SAAS,MAAM,SAAS,IAAI;AACvD,aAAO;AAAA,IACX;AAAA,EACJ;AAEA,SAAO;AACX;AAgBA,SAAS,qBAAqB,SAAoC;AAC9D,QAAM,oBAAoB,CAAC,QAAQ,OAAO,QAAQ,UAAU,QAAQ,aAAa,QAAQ,UAAU,EAAE;AAAA,IACjG;AAAA,EACJ,EAAE;AACF,MAAI,oBAAoB,GAAG;AACvB,eAAW,mFAAmF;AAC9F,YAAQ,KAAK,CAAC;AAAA,EAClB;AAEA,MAAI,QAAQ,aAAa;AACrB,WAAO,EAAE,aAAa,QAAQ,YAAY;AAAA,EAC9C;AACA,MAAI,QAAQ,YAAY;AACpB,UAAM,SAAS,OAAO,SAAS,QAAQ,YAAY,EAAE;AACrD,QAAI,CAAC,OAAO,UAAU,MAAM,KAAK,UAAU,GAAG;AAC1C,iBAAW,yDAAyD,QAAQ,UAAU,IAAI;AAC1F,cAAQ,KAAK,CAAC;AAAA,IAClB;AACA,WAAO,EAAE,SAAS,OAAO;AAAA,EAC7B;AACA,MAAI,QAAQ,UAAU;AAClB,WAAO,EAAE,OAAO,WAAW;AAAA,EAC/B;AACA,MAAI,QAAQ,OAAO;AACf,WAAO,EAAE,OAAO,QAAQ,MAAM;AAAA,EAClC;AAEA,SAAO,CAAC;AACZ;AAEA,SAAS,qBAAqB,MAA0B,aAAkC;AACtF,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,MAAM;AACN,WAAO,IAAI,QAAQ,IAAI;AAAA,EAC3B;AACA,MAAI,YAAY,OAAO;AACnB,WAAO,IAAI,SAAS,YAAY,KAAK;AAAA,EACzC;AACA,MAAI,YAAY,aAAa;AACzB,WAAO,IAAI,eAAe,YAAY,WAAW;AAAA,EACrD;AACA,MAAI,YAAY,WAAW,MAAM;AAC7B,WAAO,IAAI,WAAW,OAAO,YAAY,OAAO,CAAC;AAAA,EACrD;AACA,QAAM,KAAK,OAAO,SAAS;AAC3B,SAAO,KAAK,IAAI,EAAE,KAAK;AAC3B;AAEA,SAAS,gBAAgB,KAAuB;AAC5C,SAAO,IACF,eAAe,iCAAiC,cAAc,EAC9D,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,cAAc,8BAA8B,EACnD,OAAO,iCAAiC,eAAe,EACvD,OAAO,8BAA8B,8BAA8B;AAC5E;AAEO,SAAS,oBAAoBA,UAAwB;AACxD,QAAM,OAAOA,SAAQ,QAAQ,MAAM,EAAE,YAAY,iBAAiB;AAElE;AAAA,IACI,KAAK,QAAQ,SAAS,EACjB,YAAY,8CAA8C,EAC1D,eAAe,qBAAqB,WAAW;AAAA,EACxD,EAAE,OAAO,OAAO,YAA6C;AACzD,UAAM,cAAc,qBAAqB,OAAO;AAChD,UAAM,KAAK,qBAAqB,QAAQ,MAAM,WAAW;AAEzD,iBAAa,kBAAkB;AAC/B,UAAM,WAAW,MAAM;AAAA,MACnB,eAAe,QAAQ,SAAS,aAAa,EAAE;AAAA,IACnD;AAEA,QAAI,CAAC,SAAS,IAAI;AACd,kBAAY,OAAO,QAAQ;AAC3B,UAAI,SAAS,WAAW,KAAK;AACzB,cAAM,GAAG,OAAO,GAAG,UAAK,QAAQ,IAAI,kBAAkB,OAAO,KAAK,EAAE;AAAA,MACxE,WAAW,SAAS,WAAW,KAAK;AAChC,mBAAW,UAAU,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,MACxD,OAAO;AACH,mBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,MAC7E;AACA,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,gBAAY,MAAM,SAAS,KAAK,IAAI;AACpC,UAAM,GAAG,OAAO,IAAI,GAAG,SAAS,KAAK,GAAG,GAAG,OAAO,KAAK,EAAE;AAAA,EAC7D,CAAC;AAED;AAAA,IACI,KAAK,QAAQ,MAAM,EACd,YAAY,yBAAyB,EACrC,OAAO,qBAAqB,kBAAkB,GAAG;AAAA,EAC1D,EAAE,OAAO,OAAO,YAA6C;AACzD,UAAM,cAAc,qBAAqB,OAAO;AAChD,UAAM,KAAK,qBAAqB,QAAQ,MAAM,WAAW;AAEzD,iBAAa,kBAAkB;AAC/B,UAAM,WAAW,MAAM;AAAA,MACnB,eAAe,QAAQ,SAAS,cAAc,EAAE;AAAA,IACpD;AAEA,QAAI,CAAC,SAAS,IAAI;AACd,kBAAY,OAAO,QAAQ;AAC3B,UAAI,SAAS,WAAW,KAAK;AACzB,cAAM,GAAG,OAAO,GAAG,UAAK,QAAQ,IAAI,kBAAkB,OAAO,KAAK,EAAE;AAAA,MACxE,OAAO;AACH,mBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,MAC7E;AACA,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,UAAM,EAAE,MAAM,QAAQ,IAAI,SAAS;AAEnC,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AAClC,kBAAY,MAAM,GAAG,IAAI,mBAAmB;AAC5C;AAAA,IACJ;AAEA,gBAAY,MAAM,IAAI;AACtB,eAAW,SAAS,SAAS;AACzB,UAAI,MAAM,SAAS,aAAa;AAC5B,cAAM,GAAG,OAAO,IAAI,GAAG,MAAM,IAAI,IAAI,OAAO,KAAK,EAAE;AAAA,MACvD,OAAO;AACH,cAAM,MAAM,IAAI;AAAA,MACpB;AAAA,IACJ;AAAA,EACJ,CAAC;AAED,OAAK,QAAQ,MAAM,EACd,YAAY,mBAAmB,EAC/B,OAAO,iCAAiC,cAAc,EACtD,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,cAAc,8BAA8B,EACnD,OAAO,iCAAiC,eAAe,EACvD,OAAO,8BAA8B,8BAA8B,EACnE,OAAO,qBAAqB,WAAW,EACvC,OAAO,mBAAmB,gEAAgE,EAC1F,OAAO,OAAO,YAAqE;AAEhF,QAAI,QAAQ,OAAO,QAAQ,WAAW;AAClC,iBAAW,8CAA8C;AACzD,cAAQ,KAAK,CAAC;AAAA,IAClB;AACA,QAAI,QAAQ,OAAO,QAAQ,MAAM;AAC7B,iBAAW,yCAAyC;AACpD,cAAQ,KAAK,CAAC;AAAA,IAClB;AACA,QAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,WAAW;AACpC,iBAAW,gDAAgD;AAC3D,cAAQ,KAAK,CAAC;AAAA,IAClB;AACA,QAAI,CAAC,QAAQ,OAAO,CAAC,QAAQ,MAAM;AAC/B,iBAAW,gDAAgD;AAC3D,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,iBAAa,iBAAiB;AAE9B,QAAI;AACJ,QAAI;AAEJ,QAAI,QAAQ,KAAK;AACb,oBAAc,QAAQ;AACtB,iBAAW,MAAM;AAAA,QACb,0BAA0B,mBAAmB,QAAQ,GAAG,CAAC;AAAA,MAC7D;AAAA,IACJ,OAAO;AACH,oBAAc,QAAQ;AACtB,YAAM,cAAc,qBAAqB,OAAuB;AAChE,YAAM,KAAK,qBAAqB,QAAQ,MAAM,WAAW;AACzD,iBAAW,MAAM;AAAA,QACb,eAAe,QAAQ,SAAS,cAAc,EAAE;AAAA,MACpD;AAAA,IACJ;AAEA,QAAI,CAAC,SAAS,IAAI;AACd,kBAAY,OAAO,QAAQ;AAC3B,UAAI,SAAS,WAAW,KAAK;AACzB,cAAM,GAAG,OAAO,GAAG,UAAK,WAAW,kBAAkB,OAAO,KAAK,EAAE;AAAA,MACvE,OAAO;AACH,mBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,MAC7E;AACA,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,UAAM,EAAE,MAAM,QAAQ,IAAI,SAAS;AAEnC,QAAI,SAAS,aAAa;AACtB,kBAAY,OAAO,QAAQ;AAC3B,YAAM,GAAG,OAAO,GAAG,UAAK,WAAW,kBAAkB,OAAO,KAAK,EAAE;AACnE,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,gBAAY,MAAM,MAAM;AACxB,UAAM,WAAW,EAAE;AAAA,EACvB,CAAC;AAEL;AAAA,IACI,KAAK,QAAQ,KAAK,EACb,YAAY,eAAe,EAC3B,eAAe,qBAAqB,kBAAkB,EACtD,eAAe,gCAAgC,iBAAiB,EAChE,OAAO,mBAAmB,qCAAqC;AAAA,EACxE,EAAE;AAAA,IACE,OAAO,YAID;AACF,YAAM,cAAc,qBAAqB,OAAO;AAGhD,UAAI,CAAI,cAAW,QAAQ,SAAS,GAAG;AACnC,cAAM,GAAG,OAAO,GAAG,gCAA2B,QAAQ,SAAS,GAAG,OAAO,KAAK,EAAE;AAChF,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAGA,YAAM,QAAW,YAAS,QAAQ,SAAS;AAC3C,UAAI,CAAC,MAAM,OAAO,GAAG;AACjB,cAAM,GAAG,OAAO,GAAG,sBAAiB,QAAQ,SAAS,GAAG,OAAO,KAAK,EAAE;AACtE,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAGA,YAAM,UAAU,KAAK,OAAO;AAC5B,UAAI,MAAM,OAAO,SAAS;AACtB,cAAM,GAAG,OAAO,GAAG,qCAAgC,QAAQ,SAAS,GAAG,OAAO,KAAK,EAAE;AACrF,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAGA,YAAM,SAAY,gBAAa,QAAQ,SAAS;AAChD,UAAI,gBAAgB,MAAM,GAAG;AACzB,cAAM,GAAG,OAAO,GAAG,wEAAmE,OAAO,KAAK,EAAE;AACpG,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAEA,YAAM,UAAU,OAAO,SAAS,MAAM;AAEtC,mBAAa,cAAc;AAC3B,YAAM,WAAW,MAAM;AAAA,QACnB,eAAe,QAAQ,SAAS;AAAA,QAChC;AAAA,UACI,MAAM,QAAQ;AAAA,UACd;AAAA,UACA,WAAW,QAAQ,aAAa;AAAA,UAChC,GAAG;AAAA,QACP;AAAA,MACJ;AAEA,UAAI,CAAC,SAAS,IAAI;AACd,oBAAY,OAAO,QAAQ;AAC3B,YAAI,SAAS,WAAW,KAAK;AACzB,gBAAM,GAAG,OAAO,GAAG,yCAAoC,OAAO,KAAK,EAAE;AAAA,QACzE,WAAW,SAAS,WAAW,KAAK;AAChC,qBAAW,UAAU,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,QACxD,OAAO;AACH,qBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,QAC7E;AACA,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAEA,YAAM,SAAS,SAAS,KAAK,UAAU,YAAY;AACnD,kBAAY,MAAM,GAAG,MAAM,KAAK,SAAS,KAAK,IAAI,EAAE;AAAA,IACxD;AAAA,EACJ;AAEA;AAAA,IACI,KAAK,QAAQ,OAAO,EACf,YAAY,oBAAoB,EAChC,eAAe,qBAAqB,gBAAgB,EACpD,OAAO,mBAAmB,qCAAqC;AAAA,EACxE,EAAE;AAAA,IACE,OAAO,YAGD;AACF,YAAM,cAAc,qBAAqB,OAAO;AAEhD,mBAAa,uBAAuB;AACpC,YAAM,WAAW,MAAM;AAAA,QACnB,eAAe,QAAQ,SAAS;AAAA,QAChC;AAAA,UACI,MAAM,QAAQ;AAAA,UACd,WAAW,QAAQ,aAAa;AAAA,UAChC,GAAG;AAAA,QACP;AAAA,MACJ;AAEA,UAAI,CAAC,SAAS,IAAI;AACd,oBAAY,OAAO,QAAQ;AAC3B,YAAI,SAAS,WAAW,KAAK;AACzB,gBAAM,GAAG,OAAO,GAAG,yCAAoC,OAAO,KAAK,EAAE;AAAA,QACzE,WAAW,SAAS,WAAW,KAAK;AAChC,qBAAW,UAAU,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,QACxD,OAAO;AACH,qBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,QAC7E;AACA,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAEA,YAAM,SAAS,SAAS,KAAK,UAAU,YAAY;AACnD,kBAAY,MAAM,GAAG,MAAM,KAAK,SAAS,KAAK,IAAI,EAAE;AAAA,IACxD;AAAA,EACJ;AAEA;AAAA,IACI,KAAK,QAAQ,KAAK,EACb,YAAY,kCAAkC,EAC9C,eAAe,qBAAqB,wBAAwB;AAAA,EACrE,EAAE;AAAA,IACE,OAAO,YAED;AACF,YAAM,cAAc,qBAAqB,OAAO;AAEhD,mBAAa,aAAa;AAC1B,YAAM,WAAW,MAAM;AAAA,QACnB,eAAe,QAAQ,SAAS;AAAA,QAChC;AAAA,UACI,MAAM,QAAQ;AAAA,UACd,GAAG;AAAA,QACP;AAAA,MACJ;AAEA,UAAI,CAAC,SAAS,IAAI;AACd,oBAAY,OAAO,QAAQ;AAC3B,YAAI,SAAS,WAAW,KAAK;AACzB,gBAAM,GAAG,OAAO,GAAG,0BAAqB,QAAQ,IAAI,GAAG,OAAO,KAAK,EAAE;AAAA,QACzE,WAAW,SAAS,WAAW,KAAK;AAChC,gBAAM,GAAG,OAAO,GAAG,2CAAsC,OAAO,KAAK,EAAE;AAAA,QAC3E,OAAO;AACH,qBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AAAA,QAC7E;AACA,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAEA,kBAAY,MAAM,YAAY,SAAS,KAAK,IAAI,EAAE;AAAA,IACtD;AAAA,EACJ;AACJ;;;AKlZO,SAAS,sBAAsBC,UAAwB;AAC1D,EAAAA,SACK,QAAQ,QAAQ,EAChB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAChB,iBAAa,uBAAuB;AACpC,UAAM,WAAW,MAAM,QAAwB,eAAe;AAE9D,QAAI,SAAS,IAAI;AACb,kBAAY,MAAM,MAAM;AACxB,YAAM,GAAG,OAAO,IAAI,WAAW,OAAO,KAAK,KAAK,SAAS,KAAK,QAAQ,EAAE;AACxE,YAAM,GAAG,OAAO,IAAI,QAAQ,OAAO,KAAK,KAAK,SAAS,KAAK,KAAK,EAAE;AAAA,IACtE,OAAO;AACH,kBAAY,OAAO,QAAQ;AAC3B,iBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AACzE,cAAQ,KAAK,CAAC;AAAA,IAClB;AAAA,EACJ,CAAC;AACT;;;ACKA,IAAM,aAAa;AAEnB,SAAS,aAAa,OAAwB;AAC1C,SAAO,WAAW,KAAK,KAAK;AAChC;AAEO,SAAS,yBAAyBC,UAAwB;AAC7D,QAAM,YAAYA,SAAQ,QAAQ,WAAW,EAAE,YAAY,sBAAsB;AAEjF,YACK,QAAQ,MAAM,EACd,YAAY,mCAAmC,EAC/C,OAAO,YAAY;AAChB,iBAAa,wBAAwB;AACrC,UAAM,WAAW,MAAM,QAA+B,aAAa;AAEnE,QAAI,SAAS,IAAI;AACb,YAAM,EAAE,WAAW,IAAI,SAAS;AAChC,UAAI,WAAW,WAAW,GAAG;AACzB,oBAAY,MAAM,sBAAsB;AACxC;AAAA,MACJ;AAEA,kBAAY,MAAM,SAAS,WAAW,MAAM,eAAe;AAE3D,iBAAW,MAAM,YAAY;AACzB,cAAM,GAAG,OAAO,IAAI,GAAG,GAAG,WAAW,GAAG,OAAO,KAAK,IAAK,GAAG,IAAI,EAAE;AAAA,MACtE;AAAA,IACJ,OAAO;AACH,kBAAY,OAAO,QAAQ;AAC3B,iBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AACzE,cAAQ,KAAK,CAAC;AAAA,IAClB;AAAA,EACJ,CAAC;AAEL,QAAM,UAAUA,SAAQ,QAAQ,SAAS,EAAE,YAAY,0BAA0B;AAEjF,UACK,QAAQ,MAAM,EACd,YAAY,iCAAiC,EAC7C,eAAe,iCAAiC,cAAc,EAC9D,OAAO,OAAO,YAAmC;AAC9C,UAAM,EAAE,WAAW,YAAY,IAAI;AAEnC,iBAAa,+BAA+B;AAC5C,UAAM,WAAW,MAAM,QAAyB,eAAe,WAAW,UAAU;AAEpF,QAAI,CAAC,SAAS,IAAI;AACd,kBAAY,OAAO,yBAAyB;AAC5C,iBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AACzE,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,UAAM,EAAE,SAAAC,SAAQ,IAAI,SAAS;AAC7B,QAAIA,SAAQ,WAAW,GAAG;AACtB,kBAAY,MAAM,mBAAmB;AACrC;AAAA,IACJ;AAEA,gBAAY,MAAM,SAASA,SAAQ,MAAM,YAAY;AAErD,eAAW,UAAUA,UAAS;AAC1B,YAAM,OAAO,OAAO,eAAe;AACnC,YAAM,GAAG,OAAO,IAAI,GAAG,OAAO,KAAK,GAAG,OAAO,KAAK,IAAK,IAAI,IAAK,OAAO,IAAI,EAAE;AAAA,IACjF;AAAA,EACJ,CAAC;AAEL,UACK,QAAQ,QAAQ,EAChB,YAAY,iCAAiC,EAC7C,eAAe,iCAAiC,cAAc,EAC9D,SAAS,YAAY,oCAAoC,EACzD,OAAO,OAAO,WAAmB,YAAmC;AACjE,UAAM,EAAE,WAAW,YAAY,IAAI;AAEnC,UAAM,SAAS,UAAU,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AACvE,QAAI,OAAO,WAAW,GAAG;AACrB,iBAAW,0BAA0B;AACrC,cAAQ,KAAK,CAAC;AAAA,IAClB;AAGA,UAAM,gBAAgB,OAAO,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;AAC3D,QAAI,cAAc,SAAS,GAAG;AAC1B,iBAAW,SAAS,eAAe;AAC/B,mBAAW,yBAAyB,KAAK,EAAE;AAAA,MAC/C;AACA,cAAQ,KAAK,CAAC;AAAA,IAClB;AAGA,iBAAa,+BAA+B;AAC5C,UAAM,kBAAkB,MAAM,QAAyB,eAAe,WAAW,UAAU;AAE3F,QAAI,CAAC,gBAAgB,IAAI;AACrB,kBAAY,OAAO,yBAAyB;AAC5C,iBAAW,UAAU,gBAAgB,MAAM,MAAM,KAAK,UAAU,gBAAgB,IAAI,CAAC,EAAE;AACvF,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,gBAAY,MAAM,iBAAiB;AAEnC,UAAM,EAAE,SAAAA,SAAQ,IAAI,gBAAgB;AACpC,UAAM,gBAAgB,IAAI,IAAIA,SAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC;AAG5E,eAAW,SAAS,QAAQ;AACxB,YAAM,SAAS,cAAc,IAAI,MAAM,YAAY,CAAC;AACpD,UAAI,CAAC,QAAQ;AACT,cAAM,GAAG,OAAO,GAAG,SAAI,OAAO,KAAK,IAAI,KAAK,2BAA2B;AACvE;AAAA,MACJ;AAEA,YAAM,iBAAiB,MAAM,WAAW,eAAe,WAAW,YAAY,OAAO,MAAM,EAAE;AAE7F,UAAI,eAAe,IAAI;AACnB,cAAM,GAAG,OAAO,KAAK,SAAI,OAAO,KAAK,IAAI,KAAK,YAAY;AAAA,MAC9D,OAAO;AACH,cAAM,GAAG,OAAO,GAAG,SAAI,OAAO,KAAK,IAAI,KAAK,cAAc,KAAK,UAAU,eAAe,IAAI,CAAC,EAAE;AAAA,MACnG;AAAA,IACJ;AAAA,EACJ,CAAC;AAEL,QAAM,QAAQD,SAAQ,QAAQ,OAAO,EAAE,YAAY,eAAe;AAElE,QACK,QAAQ,MAAM,EACd,YAAY,uCAAuC,EACnD,eAAe,iCAAiC,cAAc,EAC9D,OAAO,OAAO,YAAmC;AAC9C,UAAM,EAAE,WAAW,YAAY,IAAI;AAEnC,iBAAa,oBAAoB;AACjC,UAAM,WAAW,MAAM,QAAiC,eAAe,WAAW,SAAS;AAE3F,QAAI,CAAC,SAAS,IAAI;AACd,kBAAY,OAAO,wBAAwB;AAC3C,iBAAW,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,SAAS,IAAI,CAAC,EAAE;AACzE,cAAQ,KAAK,CAAC;AAAA,IAClB;AAEA,UAAM,EAAE,OAAO,IAAI,SAAS;AAC5B,QAAI,OAAO,WAAW,GAAG;AACrB,kBAAY,MAAM,kBAAkB;AACpC;AAAA,IACJ;AAEA,gBAAY,MAAM,SAAS,OAAO,MAAM,WAAW;AAEnD;AAAA,MACI,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,IAAK,OAAO,IAAI,gBAAgB,OAAO,KAAK,IAAK,OAAO,IAAI,cAAc,OAAO,KAAK,IAAK,OAAO,IAAI,OAAO,OAAO,KAAK;AAAA,IAC9J;AACA,eAAW,KAAK,QAAQ;AACpB,YAAM,cAAc,EAAE,eAAe;AACrC,YAAM,aAAa,EAAE,WAAW,OAAO,OAAO,EAAE,OAAO,IAAI;AAC3D,YAAM,GAAG,EAAE,IAAI,IAAK,WAAW,IAAK,UAAU,IAAK,EAAE,IAAI,EAAE;AAAA,IAC/D;AAAA,EACJ,CAAC;AAET;;;APxLA,eAAe;AAAA,EACX,KAAK,EAAE,MAAM,gBAAgB,SAAS,QAAgB;AAC1D,CAAC,EAAE,OAAO;AAEV,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACK,KAAK,MAAM,EACX,YAAY,yBAAyB,EACrC,QAAQ,OAAe,EACvB,OAAO,MAAM;AACV,UAAQ,KAAK;AACjB,CAAC;AAEL,sBAAsB,OAAO;AAC7B,yBAAyB,OAAO;AAChC,oBAAoB,OAAO;AAE3B,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAiB;AACrD,UAAQ,MAAM,cAAc,GAAG;AAC/B,UAAQ,KAAK,CAAC;AAClB,CAAC;","names":["program","program","program","members"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxt-ai/cli",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "Moxt - The Agent-Native Workspace",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",