@moxt-ai/cli 0.3.3-beta.0 → 0.3.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,6 +6,157 @@ import updateNotifier from "update-notifier";
6
6
  // src/program.ts
7
7
  import { Command } from "commander";
8
8
 
9
+ // src/utils/output.ts
10
+ var colors = {
11
+ bold: "\x1B[1m",
12
+ blue: "\x1B[1;34m",
13
+ green: "\x1B[32m",
14
+ red: "\x1B[31m",
15
+ cyan: "\x1B[36m",
16
+ dim: "\x1B[2m",
17
+ reset: "\x1B[0m"
18
+ };
19
+ function print(message) {
20
+ console.log(message);
21
+ }
22
+ function printError(message) {
23
+ console.error(`${colors.red}${message}${colors.reset}`);
24
+ }
25
+
26
+ // src/utils/runtime-context.ts
27
+ var DEFAULT_USER_HOST = "api.moxt.ai";
28
+ var SANDBOX_ENV_KEYS = ["BASE_API_HOST", "SANDBOX_TOOL_API_TOKEN", "MOXT_REPO_PAYLOAD", "MOXT_WORKSPACE_ID"];
29
+ var RuntimeContextError = class extends Error {
30
+ constructor(message) {
31
+ super(message);
32
+ this.name = "RuntimeContextError";
33
+ }
34
+ };
35
+ function resolveRuntimeContext(env = process.env) {
36
+ if (hasAnySandboxEnv(env)) {
37
+ return resolveSandboxRuntimeContext(env);
38
+ }
39
+ const apiKey = readNonEmptyEnv(env, "MOXT_API_KEY");
40
+ if (apiKey) {
41
+ return {
42
+ mode: "user",
43
+ host: readNonEmptyEnv(env, "MOXT_HOST") ?? DEFAULT_USER_HOST,
44
+ apiKey
45
+ };
46
+ }
47
+ throw new RuntimeContextError("Missing auth. Set sandbox environment variables or MOXT_API_KEY.");
48
+ }
49
+ function resolveSandboxRuntimeContext(env = process.env) {
50
+ const missingKeys = SANDBOX_ENV_KEYS.filter((key) => !readNonEmptyEnv(env, key));
51
+ if (missingKeys.length > 0) {
52
+ throw new RuntimeContextError(`Incomplete sandbox environment. Missing: ${missingKeys.join(", ")}.`);
53
+ }
54
+ return {
55
+ mode: "sandbox",
56
+ baseApiHost: normalizeBaseApiHost(readRequiredEnv(env, "BASE_API_HOST")),
57
+ sandboxToolApiToken: readRequiredEnv(env, "SANDBOX_TOOL_API_TOKEN"),
58
+ workspaceId: readRequiredEnv(env, "MOXT_WORKSPACE_ID"),
59
+ repoPayload: parseRepoPayload(readRequiredEnv(env, "MOXT_REPO_PAYLOAD"))
60
+ };
61
+ }
62
+ function parseRepoPayload(raw) {
63
+ let parsed;
64
+ try {
65
+ parsed = JSON.parse(raw);
66
+ } catch (error) {
67
+ throw new RuntimeContextError(`MOXT_REPO_PAYLOAD must be valid JSON: ${error instanceof Error ? error.message : String(error)}`);
68
+ }
69
+ if (!isRecord(parsed)) {
70
+ throw new RuntimeContextError("MOXT_REPO_PAYLOAD must be a JSON object.");
71
+ }
72
+ const personal = parseRepoEntry(parsed.personal, "personal");
73
+ const teamsValue = parsed.teams;
74
+ if (!Array.isArray(teamsValue)) {
75
+ throw new RuntimeContextError("MOXT_REPO_PAYLOAD.teams must be an array.");
76
+ }
77
+ const teams = teamsValue.map((entry, index) => parseRepoEntry(entry, `teams[${index}]`));
78
+ const workspace = parsed.workspace == null ? null : parseRepoEntry(parsed.workspace, "workspace");
79
+ return { personal, teams, workspace };
80
+ }
81
+ function normalizeBaseApiHost(value) {
82
+ const trimmed = value.trim();
83
+ if (!trimmed) {
84
+ throw new RuntimeContextError("BASE_API_HOST must not be empty.");
85
+ }
86
+ return trimmed.replace(/\/+$/, "");
87
+ }
88
+ function hasAnySandboxEnv(env) {
89
+ return SANDBOX_ENV_KEYS.some((key) => readNonEmptyEnv(env, key) !== void 0);
90
+ }
91
+ function readRequiredEnv(env, key) {
92
+ const value = readNonEmptyEnv(env, key);
93
+ if (!value) {
94
+ throw new RuntimeContextError(`${key} is required.`);
95
+ }
96
+ return value;
97
+ }
98
+ function readNonEmptyEnv(env, key) {
99
+ const value = env[key];
100
+ if (typeof value !== "string") return void 0;
101
+ const trimmed = value.trim();
102
+ return trimmed.length > 0 ? trimmed : void 0;
103
+ }
104
+ function parseRepoEntry(value, path2) {
105
+ if (!isRecord(value)) {
106
+ throw new RuntimeContextError(`MOXT_REPO_PAYLOAD.${path2} must be an object.`);
107
+ }
108
+ const repoId = readStringField(value, "repoId", path2);
109
+ const name = readStringField(value, "name", path2);
110
+ return { repoId, name };
111
+ }
112
+ function readStringField(record2, field, path2) {
113
+ const value = record2[field];
114
+ if (typeof value !== "string" || value.trim().length === 0) {
115
+ throw new RuntimeContextError(`MOXT_REPO_PAYLOAD.${path2}.${field} must be a non-empty string.`);
116
+ }
117
+ return value;
118
+ }
119
+ function isRecord(value) {
120
+ return typeof value === "object" && value !== null && !Array.isArray(value);
121
+ }
122
+
123
+ // src/utils/sandbox-path.ts
124
+ function listRepoEntries(repoPayload) {
125
+ return [
126
+ repoPayload.personal,
127
+ ...repoPayload.teams,
128
+ ...repoPayload.workspace ? [repoPayload.workspace] : []
129
+ ];
130
+ }
131
+
132
+ // src/commands/auth.ts
133
+ function registerAuthCommand(program2) {
134
+ const auth = program2.command("auth").description("Authentication utilities");
135
+ auth.command("status").description("Show CLI authentication mode").action(() => {
136
+ try {
137
+ const context = resolveRuntimeContext();
138
+ if (context.mode === "sandbox") {
139
+ print(`${colors.bold}Mode${colors.reset}: sandbox`);
140
+ print(`${colors.bold}Workspace${colors.reset}: ${context.workspaceId}`);
141
+ print(`${colors.bold}Base API${colors.reset}: ${context.baseApiHost}`);
142
+ print(`${colors.bold}Repos${colors.reset}:`);
143
+ for (const repo of listRepoEntries(context.repoPayload)) {
144
+ print(` ${repo.name} ${repo.repoId}`);
145
+ }
146
+ return;
147
+ }
148
+ print(`${colors.bold}Mode${colors.reset}: user`);
149
+ print(`${colors.bold}Host${colors.reset}: ${context.host}`);
150
+ } catch (error) {
151
+ if (error instanceof RuntimeContextError) {
152
+ printError(error.message);
153
+ process.exit(1);
154
+ }
155
+ throw error;
156
+ }
157
+ });
158
+ }
159
+
9
160
  // src/commands/file.ts
10
161
  import * as fs from "fs";
11
162
 
@@ -149,7 +300,7 @@ function getApiKeyOrUndefined() {
149
300
 
150
301
  // src/utils/http.ts
151
302
  function getUserAgent() {
152
- return `moxt-cli/${"0.3.3-beta.0"} (${platform()}/${arch()}) node/${process.versions.node}`;
303
+ return `moxt-cli/${"0.3.3-beta.1"} (${platform()}/${arch()}) node/${process.versions.node}`;
153
304
  }
154
305
  async function fetchApi(method, path2, body) {
155
306
  const apiKey = getApiKey();
@@ -205,23 +356,6 @@ async function httpRaw(method, path2, body) {
205
356
  };
206
357
  }
207
358
 
208
- // src/utils/output.ts
209
- var colors = {
210
- bold: "\x1B[1m",
211
- blue: "\x1B[1;34m",
212
- green: "\x1B[32m",
213
- red: "\x1B[31m",
214
- cyan: "\x1B[36m",
215
- dim: "\x1B[2m",
216
- reset: "\x1B[0m"
217
- };
218
- function print(message) {
219
- console.log(message);
220
- }
221
- function printError(message) {
222
- console.error(`${colors.red}${message}${colors.reset}`);
223
- }
224
-
225
359
  // src/utils/search-options.ts
226
360
  var SearchOptionsError = class extends Error {
227
361
  constructor(message) {
@@ -1111,10 +1245,34 @@ function failResponse(response) {
1111
1245
  process.exit(1);
1112
1246
  }
1113
1247
  function priorityLabel(value) {
1114
- if (value === 0) return "urgent";
1115
- if (value === 1) return "high";
1116
- if (value === 2) return "medium";
1117
- return "low";
1248
+ switch (value) {
1249
+ case 0:
1250
+ return "urgent";
1251
+ case 1:
1252
+ return "high";
1253
+ case 2:
1254
+ return "medium";
1255
+ case 3:
1256
+ return "low";
1257
+ default: {
1258
+ const unsupportedValue = value;
1259
+ throw new Error(`Unsupported workflow task priority: ${String(unsupportedValue)}`);
1260
+ }
1261
+ }
1262
+ }
1263
+ function statusTypeLabel(value) {
1264
+ switch (value) {
1265
+ case 1:
1266
+ return "todo";
1267
+ case 2:
1268
+ return "in-progress";
1269
+ case 3:
1270
+ return "done";
1271
+ default: {
1272
+ const unsupportedValue = value;
1273
+ throw new Error(`Unsupported workflow status type: ${String(unsupportedValue)}`);
1274
+ }
1275
+ }
1118
1276
  }
1119
1277
  function formatAssignee(assignee) {
1120
1278
  if (!assignee) return "-";
@@ -1126,17 +1284,128 @@ function formatAssignee(assignee) {
1126
1284
  function printWorkflow(item) {
1127
1285
  print(`${colors.bold}${item.fileId}${colors.reset} owner=${item.ownerHumanId ?? "-"} desc=${item.desc ?? "-"}`);
1128
1286
  }
1129
- function printStatus(item) {
1130
- print(
1131
- `${colors.bold}${item.scopedId}${colors.reset} ${item.name} type=${item.type} preferred=${formatAssignee(item.preferredAssignee)}`
1132
- );
1287
+ function indentation(size) {
1288
+ return " ".repeat(size);
1289
+ }
1290
+ function formatDetailScalar(value) {
1291
+ if (value === null) return "null";
1292
+ if (value === "") return '""';
1293
+ if (typeof value === "string" && /[\r\n]/.test(value)) return JSON.stringify(value);
1294
+ return String(value);
1133
1295
  }
1134
- function printTask(item) {
1296
+ function printDetailField(name, value, indent = 0) {
1297
+ print(`${indentation(indent)}${name}: ${formatDetailScalar(value)}`);
1298
+ }
1299
+ function printDetailTextField(name, value, indent = 0) {
1300
+ if (value === null || value === "") {
1301
+ printDetailField(name, value, indent);
1302
+ return;
1303
+ }
1304
+ print(`${indentation(indent)}${name}:`);
1305
+ for (const line of value.split(/\r?\n/)) {
1306
+ print(`${indentation(indent + 2)}${line}`);
1307
+ }
1308
+ }
1309
+ function printAssigneeDetail(name, assignee, indent = 0) {
1310
+ if (assignee === null) {
1311
+ printDetailField(name, null, indent);
1312
+ return;
1313
+ }
1314
+ print(`${indentation(indent)}${name}:`);
1315
+ printDetailField("type", assignee.type, indent + 2);
1316
+ switch (assignee.type) {
1317
+ case "human":
1318
+ printDetailField("humanId", assignee.humanId, indent + 2);
1319
+ printDetailField("displayName", assignee.displayName, indent + 2);
1320
+ printDetailField("avatarUrl", assignee.avatarUrl, indent + 2);
1321
+ return;
1322
+ case "assistant":
1323
+ printDetailField("aiAssistantId", assignee.aiAssistantId, indent + 2);
1324
+ printDetailField("displayName", assignee.displayName, indent + 2);
1325
+ printDetailField("avatarUrl", assignee.avatarUrl, indent + 2);
1326
+ return;
1327
+ case "teammate":
1328
+ printDetailField("aiTeammateId", assignee.aiTeammateId, indent + 2);
1329
+ printDetailField("displayName", assignee.displayName, indent + 2);
1330
+ printDetailField("avatarUrl", assignee.avatarUrl, indent + 2);
1331
+ return;
1332
+ case "unknown":
1333
+ printDetailField("humanId", assignee.humanId, indent + 2);
1334
+ printDetailField("aiAssistantId", assignee.aiAssistantId, indent + 2);
1335
+ printDetailField("aiTeammateId", assignee.aiTeammateId, indent + 2);
1336
+ }
1337
+ }
1338
+ function printStatusRemainingFields(item, indent) {
1339
+ printDetailField("name", item.name, indent);
1340
+ printDetailTextField("desc", item.desc, indent);
1341
+ printDetailField("type", `${item.type} (${statusTypeLabel(item.type)})`, indent);
1342
+ printAssigneeDetail("preferredAssignee", item.preferredAssignee, indent);
1343
+ printDetailField("order", item.order, indent);
1344
+ }
1345
+ function printStatusDetail(item) {
1346
+ print(`${colors.bold}Status${colors.reset}`);
1347
+ printDetailField("scopedId", item.scopedId);
1348
+ printStatusRemainingFields(item, 0);
1349
+ }
1350
+ function printWorkflowDetail(item) {
1351
+ print(`${colors.bold}Workflow${colors.reset}`);
1352
+ printDetailField("fileId", item.fileId);
1353
+ printDetailField("ownerHumanId", item.ownerHumanId);
1354
+ printDetailTextField("desc", item.desc);
1355
+ if (item.statusList.length === 0) {
1356
+ print("statusList: []");
1357
+ } else {
1358
+ print("statusList:");
1359
+ for (const status of item.statusList) {
1360
+ print(` - scopedId: ${status.scopedId}`);
1361
+ printStatusRemainingFields(status, 4);
1362
+ }
1363
+ }
1364
+ if (item.transitions.length === 0) {
1365
+ print("transitions: []");
1366
+ } else {
1367
+ print("transitions:");
1368
+ for (const transition of item.transitions) {
1369
+ print(` - statusFromScopedId: ${transition.statusFromScopedId}`);
1370
+ printDetailField("statusToScopedId", transition.statusToScopedId, 4);
1371
+ }
1372
+ }
1373
+ }
1374
+ function printTaskSummary(item) {
1135
1375
  const runIds = item.agentRuns.map((run) => run.pipelineTriggerId).join(",") || "-";
1136
1376
  print(
1137
1377
  `${colors.bold}#${item.scopedId}${colors.reset} ${item.title} status=${item.statusScopedId} priority=${priorityLabel(item.priority)} assignee=${formatAssignee(item.assignee)} runs=${runIds}`
1138
1378
  );
1139
1379
  }
1380
+ function printTaskDetail(item) {
1381
+ print(`${colors.bold}Task${colors.reset}`);
1382
+ printDetailField("scopedId", item.scopedId);
1383
+ printDetailField("workflowFileId", item.workflowFileId);
1384
+ printDetailField("ownerHumanId", item.ownerHumanId);
1385
+ printDetailField("title", item.title);
1386
+ printDetailTextField("desc", item.desc);
1387
+ printDetailField("statusScopedId", item.statusScopedId);
1388
+ printDetailField("priority", `${item.priority} (${priorityLabel(item.priority)})`);
1389
+ printAssigneeDetail("assignee", item.assignee);
1390
+ if (item.linkedFileIds.length === 0) {
1391
+ print("linkedFileIds: []");
1392
+ } else {
1393
+ print("linkedFileIds:");
1394
+ for (const fileId of item.linkedFileIds) print(` - ${fileId}`);
1395
+ }
1396
+ printDetailField("subscribed", item.subscribed);
1397
+ if (item.agentRuns.length === 0) {
1398
+ print("agentRuns: []");
1399
+ } else {
1400
+ print("agentRuns:");
1401
+ for (const run of item.agentRuns) {
1402
+ print(` - pipelineTriggerId: ${run.pipelineTriggerId}`);
1403
+ printAssigneeDetail("executor", run.executor, 4);
1404
+ }
1405
+ }
1406
+ printDetailField("createdAt", item.createdAt);
1407
+ printDetailField("latestActAt", item.latestActAt);
1408
+ }
1140
1409
  function registerWorkflowCommand(program2) {
1141
1410
  const workflow = program2.command("workflow").description("Workflow operations");
1142
1411
  addWorkspaceOption(
@@ -1192,13 +1461,7 @@ function registerWorkflowCommand(program2) {
1192
1461
  failResponse(response);
1193
1462
  }
1194
1463
  stopSpinner(true, "Workflow fetched");
1195
- printWorkflow(response.data);
1196
- print(`${colors.bold}Statuses${colors.reset}`);
1197
- for (const status of response.data.statusList) printStatus(status);
1198
- print(`${colors.bold}Transitions${colors.reset}`);
1199
- for (const transition of response.data.transitions) {
1200
- print(`${transition.statusFromScopedId} -> ${transition.statusToScopedId}`);
1201
- }
1464
+ printWorkflowDetail(response.data);
1202
1465
  }
1203
1466
  );
1204
1467
  addWorkspaceOption(
@@ -1284,7 +1547,7 @@ function registerStatusCommands(workflow) {
1284
1547
  failResponse(response);
1285
1548
  }
1286
1549
  stopSpinner(true, "Status created");
1287
- printStatus(response.data);
1550
+ printStatusDetail(response.data);
1288
1551
  }
1289
1552
  );
1290
1553
  addPreferredAssigneeOptions(
@@ -1319,7 +1582,7 @@ function registerStatusCommands(workflow) {
1319
1582
  failResponse(response);
1320
1583
  }
1321
1584
  stopSpinner(true, "Status updated");
1322
- printStatus(response.data);
1585
+ printStatusDetail(response.data);
1323
1586
  }
1324
1587
  );
1325
1588
  addWorkspaceOption(
@@ -1415,7 +1678,7 @@ function registerTaskCommands(workflow) {
1415
1678
  return;
1416
1679
  }
1417
1680
  stopSpinner(true, `Found ${response.data.tasks.length} task(s)`);
1418
- for (const item of response.data.tasks) printTask(item);
1681
+ for (const item of response.data.tasks) printTaskSummary(item);
1419
1682
  if (response.data.nextCursor) print(`${colors.dim}nextCursor=${response.data.nextCursor}${colors.reset}`);
1420
1683
  }
1421
1684
  );
@@ -1432,7 +1695,7 @@ function registerTaskCommands(workflow) {
1432
1695
  failResponse(response);
1433
1696
  }
1434
1697
  stopSpinner(true, "Task fetched");
1435
- printTask(response.data);
1698
+ printTaskDetail(response.data);
1436
1699
  });
1437
1700
  addAssigneeOptions(
1438
1701
  addWorkspaceOption(
@@ -1463,7 +1726,7 @@ function registerTaskCommands(workflow) {
1463
1726
  failResponse(response);
1464
1727
  }
1465
1728
  stopSpinner(true, "Task created");
1466
- printTask(response.data);
1729
+ printTaskDetail(response.data);
1467
1730
  }
1468
1731
  );
1469
1732
  addWorkspaceOption(
@@ -1497,7 +1760,7 @@ function registerTaskCommands(workflow) {
1497
1760
  failResponse(response);
1498
1761
  }
1499
1762
  stopSpinner(true, "Task updated");
1500
- printTask(response.data);
1763
+ printTaskDetail(response.data);
1501
1764
  }
1502
1765
  );
1503
1766
  for (const action of ["add-linked-files", "remove-linked-files"]) {
@@ -1517,7 +1780,7 @@ function registerTaskCommands(workflow) {
1517
1780
  failResponse(response);
1518
1781
  }
1519
1782
  stopSpinner(true, action === "add-linked-files" ? "Linked files added" : "Linked files removed");
1520
- printTask(response.data);
1783
+ printTaskDetail(response.data);
1521
1784
  }
1522
1785
  );
1523
1786
  }
@@ -1539,7 +1802,7 @@ function registerTaskCommands(workflow) {
1539
1802
  failResponse(response);
1540
1803
  }
1541
1804
  stopSpinner(true, "Task moved");
1542
- printTask(response.data);
1805
+ printTaskDetail(response.data);
1543
1806
  }
1544
1807
  );
1545
1808
  addAssigneeOptions(
@@ -1564,7 +1827,7 @@ function registerTaskCommands(workflow) {
1564
1827
  failResponse(response);
1565
1828
  }
1566
1829
  stopSpinner(true, "Task assignee updated");
1567
- printTask(response.data);
1830
+ printTaskDetail(response.data);
1568
1831
  }
1569
1832
  );
1570
1833
  addWorkspaceOption(
@@ -1642,6 +1905,7 @@ function createProgram(version) {
1642
1905
  program2.name("moxt").description("Moxt CLI - AI Workspace").version(version).action(() => {
1643
1906
  program2.help();
1644
1907
  });
1908
+ registerAuthCommand(program2);
1645
1909
  registerWhoamiCommand(program2);
1646
1910
  registerWorkspaceCommand(program2);
1647
1911
  registerFileCommand(program2);
@@ -1659,7 +1923,7 @@ var FLUSH_TIMEOUT_MS = 3e3;
1659
1923
  var MAX_BATCH_SIZE = 100;
1660
1924
  function commonLabels() {
1661
1925
  return {
1662
- cli_version: "0.3.3-beta.0",
1926
+ cli_version: "0.3.3-beta.1",
1663
1927
  node_version: process.versions.node,
1664
1928
  os: platform2(),
1665
1929
  arch: arch2(),
@@ -1705,7 +1969,7 @@ async function flush() {
1705
1969
  }
1706
1970
  const batch = buffer.splice(0, MAX_BATCH_SIZE);
1707
1971
  const payload = {
1708
- release_id: "0.3.3-beta.0",
1972
+ release_id: "0.3.3-beta.1",
1709
1973
  client_type: "cli",
1710
1974
  metric_data_list: batch.map((m) => ({
1711
1975
  profile: "cli",
@@ -1846,9 +2110,9 @@ function installExitHandler() {
1846
2110
 
1847
2111
  // src/index.ts
1848
2112
  updateNotifier({
1849
- pkg: { name: "@moxt-ai/cli", version: "0.3.3-beta.0" }
2113
+ pkg: { name: "@moxt-ai/cli", version: "0.3.3-beta.1" }
1850
2114
  }).notify();
1851
- var program = createProgram("0.3.3-beta.0");
2115
+ var program = createProgram("0.3.3-beta.1");
1852
2116
  instrumentProgram(program);
1853
2117
  installExitHandler();
1854
2118
  program.parseAsync(process.argv).then(async () => {