@moxt-ai/cli 0.2.0 → 0.3.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/README.md +67 -6
- package/dist/index.js +621 -118
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/dist/index.js
CHANGED
|
@@ -7,6 +7,118 @@ import updateNotifier from "update-notifier";
|
|
|
7
7
|
// src/commands/file.ts
|
|
8
8
|
import * as fs from "fs";
|
|
9
9
|
|
|
10
|
+
// src/utils/file-selector.ts
|
|
11
|
+
var SpaceOptionsError = class extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "SpaceOptionsError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function resolveSpaceSelector(options) {
|
|
18
|
+
const { space, teamSpaceId, teammateId } = options;
|
|
19
|
+
const personalIsSet = options.personal === true;
|
|
20
|
+
const spaceIsSet = space != null && space !== "";
|
|
21
|
+
const teamSpaceIdIsSet = teamSpaceId != null && teamSpaceId !== "";
|
|
22
|
+
const teammateIdIsSet = teammateId != null && teammateId !== "";
|
|
23
|
+
const selectorCount = (spaceIsSet ? 1 : 0) + (personalIsSet ? 1 : 0) + (teamSpaceIdIsSet ? 1 : 0) + (teammateIdIsSet ? 1 : 0);
|
|
24
|
+
if (selectorCount > 1) {
|
|
25
|
+
throw new SpaceOptionsError(
|
|
26
|
+
"Error: -s, --personal, --team-space-id, and --teammate-id are mutually exclusive."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
if (teamSpaceId != null && teamSpaceId !== "") {
|
|
30
|
+
return { teamSpaceId };
|
|
31
|
+
}
|
|
32
|
+
if (teammateId != null && teammateId !== "") {
|
|
33
|
+
const parsed = Number.parseInt(teammateId, 10);
|
|
34
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || String(parsed) !== teammateId) {
|
|
35
|
+
throw new SpaceOptionsError(
|
|
36
|
+
`Error: --teammate-id must be a positive integer, got "${teammateId}".`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return { agentId: parsed };
|
|
40
|
+
}
|
|
41
|
+
if (personalIsSet) {
|
|
42
|
+
return { space: "personal" };
|
|
43
|
+
}
|
|
44
|
+
if (space != null && space !== "") {
|
|
45
|
+
return { space };
|
|
46
|
+
}
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
function buildFileQueryString(path2, spaceParams) {
|
|
50
|
+
const params = new URLSearchParams();
|
|
51
|
+
if (path2 != null && path2 !== "") {
|
|
52
|
+
params.set("path", path2);
|
|
53
|
+
}
|
|
54
|
+
if (spaceParams.space) {
|
|
55
|
+
params.set("space", spaceParams.space);
|
|
56
|
+
}
|
|
57
|
+
if (spaceParams.teamSpaceId) {
|
|
58
|
+
params.set("teamSpaceId", spaceParams.teamSpaceId);
|
|
59
|
+
}
|
|
60
|
+
if (spaceParams.agentId != null) {
|
|
61
|
+
params.set("agentId", String(spaceParams.agentId));
|
|
62
|
+
}
|
|
63
|
+
const qs = params.toString();
|
|
64
|
+
return qs ? `?${qs}` : "";
|
|
65
|
+
}
|
|
66
|
+
function isBinaryContent(buffer2) {
|
|
67
|
+
const sampleSize = Math.min(buffer2.length, 8192);
|
|
68
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
69
|
+
const byte = buffer2[i];
|
|
70
|
+
if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
function resolveReadMode(options) {
|
|
77
|
+
if (options.url && options.workspace) {
|
|
78
|
+
throw new SpaceOptionsError("Error: --url cannot be used with --workspace");
|
|
79
|
+
}
|
|
80
|
+
if (options.url && options.path) {
|
|
81
|
+
throw new SpaceOptionsError("Error: --url cannot be used with --path");
|
|
82
|
+
}
|
|
83
|
+
if (!options.url && !options.workspace) {
|
|
84
|
+
throw new SpaceOptionsError("Error: Either --url or --workspace is required");
|
|
85
|
+
}
|
|
86
|
+
if (!options.url && !options.path) {
|
|
87
|
+
throw new SpaceOptionsError("Error: --path is required when not using --url");
|
|
88
|
+
}
|
|
89
|
+
if (options.url) {
|
|
90
|
+
return { kind: "by-url", url: options.url };
|
|
91
|
+
}
|
|
92
|
+
if (!options.workspace) {
|
|
93
|
+
throw new SpaceOptionsError("Error: Either --url or --workspace is required");
|
|
94
|
+
}
|
|
95
|
+
if (!options.path) {
|
|
96
|
+
throw new SpaceOptionsError("Error: --path is required when not using --url");
|
|
97
|
+
}
|
|
98
|
+
return { kind: "by-path", workspace: options.workspace, path: options.path };
|
|
99
|
+
}
|
|
100
|
+
function resolveWriteMode(options) {
|
|
101
|
+
if (options.url && options.workspace) {
|
|
102
|
+
throw new SpaceOptionsError("Error: --url cannot be used with --workspace");
|
|
103
|
+
}
|
|
104
|
+
if (options.url && options.path) {
|
|
105
|
+
throw new SpaceOptionsError("Error: --url cannot be used with --path");
|
|
106
|
+
}
|
|
107
|
+
if (options.url && options.recursive) {
|
|
108
|
+
throw new SpaceOptionsError("Error: --recursive cannot be used with --url (the file must already exist)");
|
|
109
|
+
}
|
|
110
|
+
if (!options.url && !options.workspace) {
|
|
111
|
+
throw new SpaceOptionsError("Error: Either --url or --workspace is required");
|
|
112
|
+
}
|
|
113
|
+
if (!options.url && !options.path) {
|
|
114
|
+
throw new SpaceOptionsError("Error: --path is required when not using --url");
|
|
115
|
+
}
|
|
116
|
+
if (options.url) {
|
|
117
|
+
return { kind: "by-url", url: options.url };
|
|
118
|
+
}
|
|
119
|
+
return { kind: "by-path", workspace: options.workspace, path: options.path };
|
|
120
|
+
}
|
|
121
|
+
|
|
10
122
|
// src/utils/http.ts
|
|
11
123
|
import { arch, platform } from "os";
|
|
12
124
|
|
|
@@ -29,14 +141,17 @@ function getApiKey() {
|
|
|
29
141
|
}
|
|
30
142
|
return apiKey;
|
|
31
143
|
}
|
|
144
|
+
function getApiKeyOrUndefined() {
|
|
145
|
+
return process.env.MOXT_API_KEY;
|
|
146
|
+
}
|
|
32
147
|
|
|
33
148
|
// src/utils/http.ts
|
|
34
149
|
function getUserAgent() {
|
|
35
|
-
return `moxt-cli/${"0.
|
|
150
|
+
return `moxt-cli/${"0.3.1"} (${platform()}/${arch()}) node/${process.versions.node}`;
|
|
36
151
|
}
|
|
37
|
-
async function
|
|
152
|
+
async function fetchApi(method, path2, body) {
|
|
38
153
|
const apiKey = getApiKey();
|
|
39
|
-
const url = `${getApiBaseUrl()}${
|
|
154
|
+
const url = `${getApiBaseUrl()}${path2}`;
|
|
40
155
|
const response = await fetch(url, {
|
|
41
156
|
method,
|
|
42
157
|
headers: {
|
|
@@ -46,35 +161,43 @@ async function request(method, path, body) {
|
|
|
46
161
|
},
|
|
47
162
|
body: body ? JSON.stringify(body) : void 0
|
|
48
163
|
});
|
|
49
|
-
let data;
|
|
50
|
-
const contentType = response.headers.get("content-type");
|
|
51
|
-
if (contentType?.includes("application/json")) {
|
|
52
|
-
data = await response.json();
|
|
53
|
-
} else {
|
|
54
|
-
data = await response.text();
|
|
55
|
-
}
|
|
56
164
|
if (response.status === 401) {
|
|
57
165
|
console.error("Authentication failed. Check your MOXT_API_KEY.");
|
|
58
166
|
console.error("Get a new key at: https://moxt.ai");
|
|
59
167
|
process.exit(1);
|
|
60
168
|
}
|
|
169
|
+
return response;
|
|
170
|
+
}
|
|
171
|
+
async function request(method, path2, body) {
|
|
172
|
+
const response = await fetchApi(method, path2, body);
|
|
173
|
+
const contentType = response.headers.get("content-type");
|
|
174
|
+
const data = contentType?.includes("application/json") ? await response.json() : await response.text();
|
|
61
175
|
return {
|
|
62
176
|
ok: response.ok,
|
|
63
177
|
status: response.status,
|
|
64
178
|
data
|
|
65
179
|
};
|
|
66
180
|
}
|
|
67
|
-
async function httpGet(
|
|
68
|
-
return request("GET",
|
|
181
|
+
async function httpGet(path2) {
|
|
182
|
+
return request("GET", path2);
|
|
69
183
|
}
|
|
70
|
-
async function httpPut(
|
|
71
|
-
return request("PUT",
|
|
184
|
+
async function httpPut(path2, body) {
|
|
185
|
+
return request("PUT", path2, body);
|
|
72
186
|
}
|
|
73
|
-
async function httpPost(
|
|
74
|
-
return request("POST",
|
|
187
|
+
async function httpPost(path2, body) {
|
|
188
|
+
return request("POST", path2, body);
|
|
75
189
|
}
|
|
76
|
-
async function httpDelete(
|
|
77
|
-
return request("DELETE",
|
|
190
|
+
async function httpDelete(path2, body) {
|
|
191
|
+
return request("DELETE", path2, body);
|
|
192
|
+
}
|
|
193
|
+
async function httpRaw(method, path2, body) {
|
|
194
|
+
const response = await fetchApi(method, path2, body);
|
|
195
|
+
return {
|
|
196
|
+
ok: response.ok,
|
|
197
|
+
status: response.status,
|
|
198
|
+
text: await response.text(),
|
|
199
|
+
contentType: response.headers.get("content-type")
|
|
200
|
+
};
|
|
78
201
|
}
|
|
79
202
|
|
|
80
203
|
// src/utils/output.ts
|
|
@@ -117,59 +240,16 @@ function stopSpinner(success, message) {
|
|
|
117
240
|
}
|
|
118
241
|
|
|
119
242
|
// src/commands/file.ts
|
|
120
|
-
function
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return false;
|
|
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}".`);
|
|
243
|
+
function runOrExit(fn) {
|
|
244
|
+
try {
|
|
245
|
+
return fn();
|
|
246
|
+
} catch (err) {
|
|
247
|
+
if (err instanceof SpaceOptionsError) {
|
|
248
|
+
printError(err.message);
|
|
145
249
|
process.exit(1);
|
|
146
250
|
}
|
|
147
|
-
|
|
251
|
+
throw err;
|
|
148
252
|
}
|
|
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
253
|
}
|
|
174
254
|
function addSpaceOptions(cmd) {
|
|
175
255
|
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)");
|
|
@@ -179,7 +259,7 @@ function registerFileCommand(program2) {
|
|
|
179
259
|
addSpaceOptions(
|
|
180
260
|
file.command("get-url").description("Resolve the shareable browser URL for a file").requiredOption("-p, --path <path>", "File path")
|
|
181
261
|
).action(async (options) => {
|
|
182
|
-
const spaceParams =
|
|
262
|
+
const spaceParams = runOrExit(() => resolveSpaceSelector(options));
|
|
183
263
|
const qs = buildFileQueryString(options.path, spaceParams);
|
|
184
264
|
startSpinner("Resolving URL...");
|
|
185
265
|
const response = await httpGet(
|
|
@@ -202,7 +282,7 @@ function registerFileCommand(program2) {
|
|
|
202
282
|
addSpaceOptions(
|
|
203
283
|
file.command("list").description("List directory contents").option("-p, --path <path>", "Directory path", "/")
|
|
204
284
|
).action(async (options) => {
|
|
205
|
-
const spaceParams =
|
|
285
|
+
const spaceParams = runOrExit(() => resolveSpaceSelector(options));
|
|
206
286
|
const qs = buildFileQueryString(options.path, spaceParams);
|
|
207
287
|
startSpinner("Listing files...");
|
|
208
288
|
const response = await httpGet(
|
|
@@ -217,12 +297,12 @@ function registerFileCommand(program2) {
|
|
|
217
297
|
}
|
|
218
298
|
process.exit(1);
|
|
219
299
|
}
|
|
220
|
-
const { path, entries } = response.data;
|
|
300
|
+
const { path: path2, entries } = response.data;
|
|
221
301
|
if (!entries || entries.length === 0) {
|
|
222
|
-
stopSpinner(true, `${
|
|
302
|
+
stopSpinner(true, `${path2}: empty directory`);
|
|
223
303
|
return;
|
|
224
304
|
}
|
|
225
|
-
stopSpinner(true,
|
|
305
|
+
stopSpinner(true, path2);
|
|
226
306
|
for (const entry of entries) {
|
|
227
307
|
if (entry.type === "directory") {
|
|
228
308
|
print(`${colors.blue}${entry.name}/${colors.reset}`);
|
|
@@ -232,36 +312,21 @@ function registerFileCommand(program2) {
|
|
|
232
312
|
}
|
|
233
313
|
});
|
|
234
314
|
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
|
-
|
|
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");
|
|
245
|
-
process.exit(1);
|
|
246
|
-
}
|
|
247
|
-
if (!options.url && !options.path) {
|
|
248
|
-
printError("Error: --path is required when not using --url");
|
|
249
|
-
process.exit(1);
|
|
250
|
-
}
|
|
315
|
+
const mode = runOrExit(() => resolveReadMode(options));
|
|
251
316
|
startSpinner("Reading file...");
|
|
252
317
|
let response;
|
|
253
318
|
let displayPath;
|
|
254
|
-
if (
|
|
255
|
-
displayPath =
|
|
319
|
+
if (mode.kind === "by-url") {
|
|
320
|
+
displayPath = mode.url;
|
|
256
321
|
response = await httpGet(
|
|
257
|
-
`/files/read-by-url?url=${encodeURIComponent(
|
|
322
|
+
`/files/read-by-url?url=${encodeURIComponent(mode.url)}`
|
|
258
323
|
);
|
|
259
324
|
} else {
|
|
260
|
-
displayPath =
|
|
261
|
-
const spaceParams =
|
|
262
|
-
const qs = buildFileQueryString(
|
|
325
|
+
displayPath = mode.path;
|
|
326
|
+
const spaceParams = runOrExit(() => resolveSpaceSelector(options));
|
|
327
|
+
const qs = buildFileQueryString(mode.path, spaceParams);
|
|
263
328
|
response = await httpGet(
|
|
264
|
-
`/workspaces/${
|
|
329
|
+
`/workspaces/${mode.workspace}/files/read${qs}`
|
|
265
330
|
);
|
|
266
331
|
}
|
|
267
332
|
if (!response.ok) {
|
|
@@ -282,11 +347,9 @@ function registerFileCommand(program2) {
|
|
|
282
347
|
stopSpinner(true, "Done");
|
|
283
348
|
print(content ?? "");
|
|
284
349
|
});
|
|
285
|
-
|
|
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(
|
|
350
|
+
file.command("put").description("Upload a file").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>", "Remote file path").option("-u, --url <url>", "Moxt file URL (e.g., https://moxt.ai/w/{workspaceId}/{fileId})").requiredOption("-l, --local-path <localPath>", "Local file path").option("-r, --recursive", "Create parent directories if needed").action(
|
|
288
351
|
async (options) => {
|
|
289
|
-
const
|
|
352
|
+
const mode = runOrExit(() => resolveWriteMode(options));
|
|
290
353
|
if (!fs.existsSync(options.localPath)) {
|
|
291
354
|
print(`${colors.red}\u2620 Local file not found: ${options.localPath}${colors.reset}`);
|
|
292
355
|
process.exit(1);
|
|
@@ -301,26 +364,42 @@ function registerFileCommand(program2) {
|
|
|
301
364
|
print(`${colors.red}\u2620 File too large (max 10MB): ${options.localPath}${colors.reset}`);
|
|
302
365
|
process.exit(1);
|
|
303
366
|
}
|
|
304
|
-
const
|
|
305
|
-
if (isBinaryContent(
|
|
367
|
+
const buffer2 = fs.readFileSync(options.localPath);
|
|
368
|
+
if (isBinaryContent(buffer2)) {
|
|
306
369
|
print(`${colors.red}\u2620 Binary files are not allowed. Only text files can be uploaded.${colors.reset}`);
|
|
307
370
|
process.exit(1);
|
|
308
371
|
}
|
|
309
|
-
const content =
|
|
372
|
+
const content = buffer2.toString("utf8");
|
|
310
373
|
startSpinner("Uploading...");
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
|
|
374
|
+
let response;
|
|
375
|
+
let displayPath;
|
|
376
|
+
if (mode.kind === "by-url") {
|
|
377
|
+
displayPath = mode.url;
|
|
378
|
+
response = await httpPut("/files/write-by-url", {
|
|
379
|
+
url: mode.url,
|
|
380
|
+
content
|
|
381
|
+
});
|
|
382
|
+
} else {
|
|
383
|
+
displayPath = mode.path;
|
|
384
|
+
const spaceParams = runOrExit(() => resolveSpaceSelector(options));
|
|
385
|
+
response = await httpPut(
|
|
386
|
+
`/workspaces/${mode.workspace}/files/write`,
|
|
387
|
+
{
|
|
388
|
+
path: mode.path,
|
|
389
|
+
content,
|
|
390
|
+
recursive: options.recursive ?? false,
|
|
391
|
+
...spaceParams
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
}
|
|
320
395
|
if (!response.ok) {
|
|
321
396
|
stopSpinner(false, "Failed");
|
|
322
397
|
if (response.status === 404) {
|
|
323
|
-
|
|
398
|
+
if (mode.kind === "by-url") {
|
|
399
|
+
print(`${colors.red}\u2620 ${displayPath} does not exist${colors.reset}`);
|
|
400
|
+
} else {
|
|
401
|
+
print(`${colors.red}\u2620 Parent directory does not exist${colors.reset}`);
|
|
402
|
+
}
|
|
324
403
|
} else if (response.status === 400) {
|
|
325
404
|
printError(`Error: ${JSON.stringify(response.data)}`);
|
|
326
405
|
} else {
|
|
@@ -336,7 +415,7 @@ function registerFileCommand(program2) {
|
|
|
336
415
|
file.command("mkdir").description("Create a directory").requiredOption("-p, --path <path>", "Directory path").option("-r, --recursive", "Create parent directories if needed")
|
|
337
416
|
).action(
|
|
338
417
|
async (options) => {
|
|
339
|
-
const spaceParams =
|
|
418
|
+
const spaceParams = runOrExit(() => resolveSpaceSelector(options));
|
|
340
419
|
startSpinner("Creating directory...");
|
|
341
420
|
const response = await httpPost(
|
|
342
421
|
`/workspaces/${options.workspace}/files/mkdir`,
|
|
@@ -365,7 +444,7 @@ function registerFileCommand(program2) {
|
|
|
365
444
|
file.command("del").description("Delete a file or empty directory").requiredOption("-p, --path <path>", "File or directory path")
|
|
366
445
|
).action(
|
|
367
446
|
async (options) => {
|
|
368
|
-
const spaceParams =
|
|
447
|
+
const spaceParams = runOrExit(() => resolveSpaceSelector(options));
|
|
369
448
|
startSpinner("Deleting...");
|
|
370
449
|
const response = await httpDelete(
|
|
371
450
|
`/workspaces/${options.workspace}/files/delete`,
|
|
@@ -390,6 +469,231 @@ function registerFileCommand(program2) {
|
|
|
390
469
|
);
|
|
391
470
|
}
|
|
392
471
|
|
|
472
|
+
// src/utils/miniapp-db.ts
|
|
473
|
+
var MiniappDbOptionsError = class extends Error {
|
|
474
|
+
constructor(message) {
|
|
475
|
+
super(message);
|
|
476
|
+
this.name = "MiniappDbOptionsError";
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
var NON_FILTER_QUERY_PARAMS = /* @__PURE__ */ new Set([
|
|
480
|
+
"select",
|
|
481
|
+
"order",
|
|
482
|
+
"limit",
|
|
483
|
+
"offset",
|
|
484
|
+
"range",
|
|
485
|
+
"range-unit"
|
|
486
|
+
]);
|
|
487
|
+
var ALLOWED_MINIAPP_DB_EMAIL_DOMAINS = ["@paraflow.com", "@moxt.ai", "@kanyun.com"];
|
|
488
|
+
function normalizePostgrestPath(path2) {
|
|
489
|
+
const trimmed = path2.trim();
|
|
490
|
+
if (!trimmed) {
|
|
491
|
+
throw new MiniappDbOptionsError("Error: PostgREST path is required.");
|
|
492
|
+
}
|
|
493
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
494
|
+
}
|
|
495
|
+
function buildMiniappDbDataPath(workspaceId, appId, postgrestPath) {
|
|
496
|
+
return `/workspaces/${encodeURIComponent(workspaceId)}/miniapps/${encodeURIComponent(appId)}/db/data${normalizePostgrestPath(postgrestPath)}`;
|
|
497
|
+
}
|
|
498
|
+
function buildMiniappDbSchemaPath(workspaceId, appId) {
|
|
499
|
+
return `/workspaces/${encodeURIComponent(workspaceId)}/miniapps/${encodeURIComponent(appId)}/db/schema`;
|
|
500
|
+
}
|
|
501
|
+
function parseJsonBody(raw) {
|
|
502
|
+
let parsed;
|
|
503
|
+
try {
|
|
504
|
+
parsed = JSON.parse(raw);
|
|
505
|
+
} catch (error) {
|
|
506
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
507
|
+
throw new MiniappDbOptionsError(`Error: --body must be valid JSON. ${detail}`);
|
|
508
|
+
}
|
|
509
|
+
if (parsed === null || typeof parsed !== "object" && !Array.isArray(parsed)) {
|
|
510
|
+
throw new MiniappDbOptionsError("Error: --body must be a JSON object or array.");
|
|
511
|
+
}
|
|
512
|
+
return parsed;
|
|
513
|
+
}
|
|
514
|
+
function hasPostgrestFilter(postgrestPath) {
|
|
515
|
+
const normalizedPath = normalizePostgrestPath(postgrestPath);
|
|
516
|
+
const parsed = new URL(normalizedPath, "https://postgrest.local");
|
|
517
|
+
for (const [name] of parsed.searchParams.entries()) {
|
|
518
|
+
if (!NON_FILTER_QUERY_PARAMS.has(name.toLowerCase())) {
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
function assertPostgrestFilter(postgrestPath, method) {
|
|
525
|
+
if (!hasPostgrestFilter(postgrestPath)) {
|
|
526
|
+
throw new MiniappDbOptionsError(
|
|
527
|
+
`Error: ${method.toLowerCase()} requires at least one PostgREST filter query parameter.`
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function formatRawResponse(text, pretty) {
|
|
532
|
+
if (!pretty || !text) {
|
|
533
|
+
return text;
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
return JSON.stringify(JSON.parse(text), null, 2);
|
|
537
|
+
} catch {
|
|
538
|
+
return text;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
function isAllowedMiniappDbUserEmail(email) {
|
|
542
|
+
const normalized = email.trim().toLowerCase();
|
|
543
|
+
return ALLOWED_MINIAPP_DB_EMAIL_DOMAINS.some((domain) => normalized.endsWith(domain));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/commands/miniapp.ts
|
|
547
|
+
function runOrExit2(fn) {
|
|
548
|
+
try {
|
|
549
|
+
return fn();
|
|
550
|
+
} catch (err) {
|
|
551
|
+
if (err instanceof MiniappDbOptionsError) {
|
|
552
|
+
printError(err.message);
|
|
553
|
+
process.exit(1);
|
|
554
|
+
}
|
|
555
|
+
throw err;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function addMiniappDbTargetOptions(command) {
|
|
559
|
+
return command.requiredOption("-w, --workspace <workspaceId>", "Workspace ID").requiredOption("--app-id <appId>", "Miniapp app ID");
|
|
560
|
+
}
|
|
561
|
+
function handleRawResponse(response, pretty) {
|
|
562
|
+
if (!response.ok) {
|
|
563
|
+
printError(`Error [${response.status}]: ${response.text}`);
|
|
564
|
+
process.exit(1);
|
|
565
|
+
}
|
|
566
|
+
print(formatRawResponse(response.text, pretty));
|
|
567
|
+
}
|
|
568
|
+
async function ensureAllowedMiniappDbUser() {
|
|
569
|
+
const response = await httpGet("/users/whoami");
|
|
570
|
+
if (!response.ok) {
|
|
571
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
if (!isAllowedMiniappDbUserEmail(response.data.email)) {
|
|
575
|
+
printError("Error: miniapp db commands are only available to @paraflow.com, @moxt.ai, or @kanyun.com users.");
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
async function requestDataApi(method, postgrestPath, options, body) {
|
|
580
|
+
await ensureAllowedMiniappDbUser();
|
|
581
|
+
const path2 = buildMiniappDbDataPath(options.workspace, options.appId, postgrestPath);
|
|
582
|
+
const response = await httpRaw(method, path2, body);
|
|
583
|
+
handleRawResponse(response, options.pretty);
|
|
584
|
+
}
|
|
585
|
+
function registerMiniappCommand(program2) {
|
|
586
|
+
const miniapp = program2.command("miniapp", { hidden: true }).description("Miniapp operations");
|
|
587
|
+
const db = miniapp.command("db").description("Miniapp database operations");
|
|
588
|
+
addMiniappDbTargetOptions(
|
|
589
|
+
db.command("schema").description("Print the miniapp database schema SQL")
|
|
590
|
+
).action(async (options) => {
|
|
591
|
+
await ensureAllowedMiniappDbUser();
|
|
592
|
+
const response = await httpGet(buildMiniappDbSchemaPath(options.workspace, options.appId));
|
|
593
|
+
if (!response.ok) {
|
|
594
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
print(response.data.sql);
|
|
598
|
+
});
|
|
599
|
+
addMiniappDbTargetOptions(
|
|
600
|
+
db.command("get").description("Read miniapp data through PostgREST").argument("<path>", "PostgREST path, for example /todos?select=*").option("--pretty", "Pretty-print JSON responses")
|
|
601
|
+
).action(async (postgrestPath, options) => {
|
|
602
|
+
await requestDataApi("GET", postgrestPath, options);
|
|
603
|
+
});
|
|
604
|
+
addMiniappDbTargetOptions(
|
|
605
|
+
db.command("post").description("Create miniapp data through PostgREST").argument("<path>", "PostgREST path, for example /todos").requiredOption("--body <json>", "JSON object or array request body").option("--pretty", "Pretty-print JSON responses")
|
|
606
|
+
).action(async (postgrestPath, options) => {
|
|
607
|
+
const body = runOrExit2(() => parseJsonBody(options.body ?? ""));
|
|
608
|
+
await requestDataApi("POST", postgrestPath, options, body);
|
|
609
|
+
});
|
|
610
|
+
addMiniappDbTargetOptions(
|
|
611
|
+
db.command("patch").description("Update miniapp data through PostgREST").argument("<path>", "PostgREST path with a filter, for example /todos?id=eq.1").requiredOption("--body <json>", "JSON object or array request body").option("--pretty", "Pretty-print JSON responses")
|
|
612
|
+
).action(async (postgrestPath, options) => {
|
|
613
|
+
runOrExit2(() => assertPostgrestFilter(postgrestPath, "PATCH"));
|
|
614
|
+
const body = runOrExit2(() => parseJsonBody(options.body ?? ""));
|
|
615
|
+
await requestDataApi("PATCH", postgrestPath, options, body);
|
|
616
|
+
});
|
|
617
|
+
addMiniappDbTargetOptions(
|
|
618
|
+
db.command("delete").description("Delete miniapp data through PostgREST").argument("<path>", "PostgREST path with a filter, for example /todos?id=eq.1").option("--yes", "Confirm the delete operation").option("--pretty", "Pretty-print JSON responses")
|
|
619
|
+
).action(async (postgrestPath, options) => {
|
|
620
|
+
if (options.yes !== true) {
|
|
621
|
+
printError("Error: delete requires --yes.");
|
|
622
|
+
process.exit(1);
|
|
623
|
+
}
|
|
624
|
+
runOrExit2(() => assertPostgrestFilter(postgrestPath, "DELETE"));
|
|
625
|
+
await requestDataApi("DELETE", postgrestPath, options);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// src/telemetry/config.ts
|
|
630
|
+
import * as fs2 from "fs";
|
|
631
|
+
import * as os from "os";
|
|
632
|
+
import * as path from "path";
|
|
633
|
+
function getConfigPath() {
|
|
634
|
+
return path.join(os.homedir(), ".moxt", "config.json");
|
|
635
|
+
}
|
|
636
|
+
function readTelemetryConfig() {
|
|
637
|
+
try {
|
|
638
|
+
const raw = fs2.readFileSync(getConfigPath(), "utf8");
|
|
639
|
+
const parsed = JSON.parse(raw);
|
|
640
|
+
return parsed.telemetry ?? {};
|
|
641
|
+
} catch {
|
|
642
|
+
return {};
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function writeTelemetryConfig(update) {
|
|
646
|
+
const configPath = getConfigPath();
|
|
647
|
+
let existing = {};
|
|
648
|
+
try {
|
|
649
|
+
existing = JSON.parse(fs2.readFileSync(configPath, "utf8"));
|
|
650
|
+
} catch {
|
|
651
|
+
existing = {};
|
|
652
|
+
}
|
|
653
|
+
const currentTelemetry = existing.telemetry ?? {};
|
|
654
|
+
const next = { ...existing, telemetry: { ...currentTelemetry, ...update } };
|
|
655
|
+
fs2.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
656
|
+
fs2.writeFileSync(configPath, JSON.stringify(next, null, 2));
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// src/telemetry/opt-out.ts
|
|
660
|
+
function isCiEnvironment() {
|
|
661
|
+
return process.env.CI === "true" || process.env.CI === "1";
|
|
662
|
+
}
|
|
663
|
+
function isTelemetryDisabled() {
|
|
664
|
+
if (process.env.MOXT_TELEMETRY_DISABLED === "1" || process.env.MOXT_TELEMETRY_DISABLED === "true") {
|
|
665
|
+
return true;
|
|
666
|
+
}
|
|
667
|
+
if (process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true") {
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
return readTelemetryConfig().disabled === true;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// src/commands/telemetry.ts
|
|
674
|
+
function registerTelemetryCommand(program2) {
|
|
675
|
+
const telemetry = program2.command("telemetry").description("Manage Moxt CLI telemetry");
|
|
676
|
+
telemetry.command("status").description("Show telemetry status").action(() => {
|
|
677
|
+
const cfg = readTelemetryConfig();
|
|
678
|
+
const envOverride = process.env.MOXT_TELEMETRY_DISABLED === "1" || process.env.MOXT_TELEMETRY_DISABLED === "true" || process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true";
|
|
679
|
+
const state = isTelemetryDisabled() ? "disabled" : "enabled";
|
|
680
|
+
print(`telemetry: ${state}`);
|
|
681
|
+
if (envOverride) {
|
|
682
|
+
print("(disabled via environment variable)");
|
|
683
|
+
} else if (cfg.disabled) {
|
|
684
|
+
print("(disabled via config file)");
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
telemetry.command("enable").description("Enable telemetry").action(() => {
|
|
688
|
+
writeTelemetryConfig({ disabled: false });
|
|
689
|
+
print("telemetry: enabled");
|
|
690
|
+
});
|
|
691
|
+
telemetry.command("disable").description("Disable telemetry").action(() => {
|
|
692
|
+
writeTelemetryConfig({ disabled: true });
|
|
693
|
+
print("telemetry: disabled");
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
|
|
393
697
|
// src/commands/whoami.ts
|
|
394
698
|
function registerWhoamiCommand(program2) {
|
|
395
699
|
program2.command("whoami").description("Show current user information").action(async () => {
|
|
@@ -519,19 +823,218 @@ function registerWorkspaceCommand(program2) {
|
|
|
519
823
|
});
|
|
520
824
|
}
|
|
521
825
|
|
|
826
|
+
// src/telemetry/client.ts
|
|
827
|
+
import { arch as arch2, platform as platform2 } from "os";
|
|
828
|
+
var buffer = [];
|
|
829
|
+
var FLUSH_TIMEOUT_MS = 3e3;
|
|
830
|
+
var MAX_BATCH_SIZE = 100;
|
|
831
|
+
function commonLabels() {
|
|
832
|
+
return {
|
|
833
|
+
cli_version: "0.3.1",
|
|
834
|
+
node_version: process.versions.node,
|
|
835
|
+
os: platform2(),
|
|
836
|
+
arch: arch2(),
|
|
837
|
+
is_ci: isCiEnvironment() ? "true" : "false"
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
function record(metric) {
|
|
841
|
+
if (isTelemetryDisabled()) {
|
|
842
|
+
debugLog(`record: disabled, dropping ${metric.metric_id}`);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (!getApiKeyOrUndefined()) {
|
|
846
|
+
debugLog(`record: no API key, dropping ${metric.metric_id}`);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
buffer.push({
|
|
850
|
+
...metric,
|
|
851
|
+
extra_label_name_2_value: {
|
|
852
|
+
...commonLabels(),
|
|
853
|
+
...metric.extra_label_name_2_value ?? {}
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
debugLog(`record: buffered ${metric.metric_id} (buffer=${buffer.length})`);
|
|
857
|
+
}
|
|
858
|
+
function isDebug() {
|
|
859
|
+
return process.env.MOXT_TELEMETRY_DEBUG === "1" || process.env.MOXT_TELEMETRY_DEBUG === "true";
|
|
860
|
+
}
|
|
861
|
+
function debugLog(msg, detail) {
|
|
862
|
+
if (!isDebug()) return;
|
|
863
|
+
process.stderr.write(`[telemetry] ${msg}${detail !== void 0 ? ` ${JSON.stringify(detail)}` : ""}
|
|
864
|
+
`);
|
|
865
|
+
}
|
|
866
|
+
async function flush() {
|
|
867
|
+
if (buffer.length === 0) {
|
|
868
|
+
debugLog("flush: buffer empty, skipping");
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const apiKey = getApiKeyOrUndefined();
|
|
872
|
+
if (!apiKey) {
|
|
873
|
+
debugLog("flush: no API key, dropping buffer");
|
|
874
|
+
buffer.length = 0;
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
const batch = buffer.splice(0, MAX_BATCH_SIZE);
|
|
878
|
+
const payload = {
|
|
879
|
+
release_id: "0.3.1",
|
|
880
|
+
client_type: "cli",
|
|
881
|
+
metric_data_list: batch.map((m) => ({
|
|
882
|
+
profile: "cli",
|
|
883
|
+
metric_id: m.metric_id,
|
|
884
|
+
metric_type: m.metric_type,
|
|
885
|
+
value: m.value,
|
|
886
|
+
extra_label_name_2_value: m.extra_label_name_2_value
|
|
887
|
+
}))
|
|
888
|
+
};
|
|
889
|
+
const url = `${getApiBaseUrl()}/cli-metrics`;
|
|
890
|
+
debugLog(`flush: POST ${url} with ${batch.length} metrics`, payload);
|
|
891
|
+
try {
|
|
892
|
+
const controller = new AbortController();
|
|
893
|
+
const timeout = setTimeout(() => {
|
|
894
|
+
controller.abort();
|
|
895
|
+
}, FLUSH_TIMEOUT_MS);
|
|
896
|
+
try {
|
|
897
|
+
const res = await fetch(url, {
|
|
898
|
+
method: "POST",
|
|
899
|
+
headers: {
|
|
900
|
+
"Content-Type": "application/json",
|
|
901
|
+
Authorization: `Bearer ${apiKey}`
|
|
902
|
+
},
|
|
903
|
+
body: JSON.stringify(payload),
|
|
904
|
+
signal: controller.signal
|
|
905
|
+
});
|
|
906
|
+
debugLog(`flush: response status=${res.status}`);
|
|
907
|
+
} finally {
|
|
908
|
+
clearTimeout(timeout);
|
|
909
|
+
}
|
|
910
|
+
} catch (err) {
|
|
911
|
+
debugLog("flush: failed", err instanceof Error ? err.message : String(err));
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// src/telemetry/notice.ts
|
|
916
|
+
var NOTICE = [
|
|
917
|
+
"",
|
|
918
|
+
"Attention: Moxt CLI now collects anonymous telemetry regarding usage.",
|
|
919
|
+
"This information is used to shape Moxt CLI's roadmap and prioritize features.",
|
|
920
|
+
"",
|
|
921
|
+
"You may opt out by setting MOXT_TELEMETRY_DISABLED=1 in your env",
|
|
922
|
+
"or by running `moxt telemetry disable`.",
|
|
923
|
+
"Details: https://www.npmjs.com/package/@moxt-ai/cli#telemetry",
|
|
924
|
+
""
|
|
925
|
+
];
|
|
926
|
+
function maybeShowTelemetryNotice() {
|
|
927
|
+
if (isTelemetryDisabled()) return;
|
|
928
|
+
if (isCiEnvironment()) return;
|
|
929
|
+
if (readTelemetryConfig().noticeShown) return;
|
|
930
|
+
for (const line of NOTICE) {
|
|
931
|
+
process.stderr.write(`${line}
|
|
932
|
+
`);
|
|
933
|
+
}
|
|
934
|
+
try {
|
|
935
|
+
writeTelemetryConfig({ noticeShown: true });
|
|
936
|
+
} catch {
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// src/telemetry/instrument.ts
|
|
941
|
+
var current = null;
|
|
942
|
+
function commandPath(cmd) {
|
|
943
|
+
const names = [];
|
|
944
|
+
let node = cmd;
|
|
945
|
+
while (node && node.parent) {
|
|
946
|
+
names.unshift(node.name());
|
|
947
|
+
node = node.parent;
|
|
948
|
+
}
|
|
949
|
+
if (names.length === 0) return { command: "unknown" };
|
|
950
|
+
if (names.length === 1) return { command: names[0] };
|
|
951
|
+
return { command: names[0], subcommand: names.slice(1).join(" ") };
|
|
952
|
+
}
|
|
953
|
+
function instrumentProgram(program2) {
|
|
954
|
+
program2.hook("preAction", (_thisCommand, actionCommand) => {
|
|
955
|
+
const { command, subcommand } = commandPath(actionCommand);
|
|
956
|
+
if (command !== "telemetry") {
|
|
957
|
+
maybeShowTelemetryNotice();
|
|
958
|
+
}
|
|
959
|
+
current = { name: command, subcommand, startedAt: Date.now() };
|
|
960
|
+
record({
|
|
961
|
+
metric_id: "client.cli.command_invocation.count",
|
|
962
|
+
metric_type: "counter",
|
|
963
|
+
value: 1,
|
|
964
|
+
extra_label_name_2_value: {
|
|
965
|
+
command,
|
|
966
|
+
...subcommand ? { subcommand } : {},
|
|
967
|
+
status: "started"
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
});
|
|
971
|
+
program2.hook("postAction", async () => {
|
|
972
|
+
await reportOutcome("success");
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
async function reportOutcome(status, errorCode) {
|
|
976
|
+
if (!current) return;
|
|
977
|
+
const { name, subcommand, startedAt } = current;
|
|
978
|
+
const durationSeconds = (Date.now() - startedAt) / 1e3;
|
|
979
|
+
record({
|
|
980
|
+
metric_id: "client.cli.command_duration_seconds",
|
|
981
|
+
metric_type: "histogram",
|
|
982
|
+
value: durationSeconds,
|
|
983
|
+
extra_label_name_2_value: {
|
|
984
|
+
command: name,
|
|
985
|
+
...subcommand ? { subcommand } : {},
|
|
986
|
+
status
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
if (status === "error") {
|
|
990
|
+
record({
|
|
991
|
+
metric_id: "client.cli.command_error.count",
|
|
992
|
+
metric_type: "counter",
|
|
993
|
+
value: 1,
|
|
994
|
+
extra_label_name_2_value: {
|
|
995
|
+
command: name,
|
|
996
|
+
...subcommand ? { subcommand } : {},
|
|
997
|
+
...errorCode ? { error_code: errorCode } : {}
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
current = null;
|
|
1002
|
+
await flush();
|
|
1003
|
+
}
|
|
1004
|
+
function installExitHandler() {
|
|
1005
|
+
const handleError = (errorCode) => {
|
|
1006
|
+
void reportOutcome("error", errorCode);
|
|
1007
|
+
};
|
|
1008
|
+
process.on("uncaughtException", () => {
|
|
1009
|
+
handleError("uncaught_exception");
|
|
1010
|
+
process.exit(1);
|
|
1011
|
+
});
|
|
1012
|
+
process.on("unhandledRejection", () => {
|
|
1013
|
+
handleError("unhandled_rejection");
|
|
1014
|
+
process.exit(1);
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
|
|
522
1018
|
// src/index.ts
|
|
523
1019
|
updateNotifier({
|
|
524
|
-
pkg: { name: "@moxt-ai/cli", version: "0.
|
|
1020
|
+
pkg: { name: "@moxt-ai/cli", version: "0.3.1" }
|
|
525
1021
|
}).notify();
|
|
526
1022
|
var program = new Command();
|
|
527
|
-
program.name("moxt").description("Moxt CLI - AI Workspace").version("0.
|
|
1023
|
+
program.name("moxt").description("Moxt CLI - AI Workspace").version("0.3.1").action(() => {
|
|
528
1024
|
program.help();
|
|
529
1025
|
});
|
|
1026
|
+
instrumentProgram(program);
|
|
1027
|
+
installExitHandler();
|
|
530
1028
|
registerWhoamiCommand(program);
|
|
531
1029
|
registerWorkspaceCommand(program);
|
|
532
1030
|
registerFileCommand(program);
|
|
533
|
-
program
|
|
1031
|
+
registerMiniappCommand(program);
|
|
1032
|
+
registerTelemetryCommand(program);
|
|
1033
|
+
program.parseAsync(process.argv).then(async () => {
|
|
1034
|
+
await flush();
|
|
1035
|
+
}).catch(async (err) => {
|
|
534
1036
|
console.error("CLI Error:", err);
|
|
1037
|
+
await flush();
|
|
535
1038
|
process.exit(1);
|
|
536
1039
|
});
|
|
537
1040
|
//# sourceMappingURL=index.js.map
|