@moxt-ai/cli 0.3.2 → 0.3.3-beta.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 +51 -0
- package/dist/index.js +719 -15
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command } from "commander";
|
|
5
4
|
import updateNotifier from "update-notifier";
|
|
6
5
|
|
|
6
|
+
// src/program.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
|
|
7
9
|
// src/commands/file.ts
|
|
8
10
|
import * as fs from "fs";
|
|
9
11
|
|
|
@@ -147,7 +149,7 @@ function getApiKeyOrUndefined() {
|
|
|
147
149
|
|
|
148
150
|
// src/utils/http.ts
|
|
149
151
|
function getUserAgent() {
|
|
150
|
-
return `moxt-cli/${"0.3.
|
|
152
|
+
return `moxt-cli/${"0.3.3-beta.0"} (${platform()}/${arch()}) node/${process.versions.node}`;
|
|
151
153
|
}
|
|
152
154
|
async function fetchApi(method, path2, body) {
|
|
153
155
|
const apiKey = getApiKey();
|
|
@@ -187,6 +189,9 @@ async function httpPut(path2, body) {
|
|
|
187
189
|
async function httpPost(path2, body) {
|
|
188
190
|
return request("POST", path2, body);
|
|
189
191
|
}
|
|
192
|
+
async function httpPatch(path2, body) {
|
|
193
|
+
return request("PATCH", path2, body);
|
|
194
|
+
}
|
|
190
195
|
async function httpDelete(path2, body) {
|
|
191
196
|
return request("DELETE", path2, body);
|
|
192
197
|
}
|
|
@@ -939,6 +944,714 @@ function registerWorkspaceCommand(program2) {
|
|
|
939
944
|
});
|
|
940
945
|
}
|
|
941
946
|
|
|
947
|
+
// src/commands/workflow.ts
|
|
948
|
+
import * as fs3 from "fs";
|
|
949
|
+
var MAX_DESC_LENGTH = 5e3;
|
|
950
|
+
var WorkflowOptionsError = class extends Error {
|
|
951
|
+
constructor(message) {
|
|
952
|
+
super(message);
|
|
953
|
+
this.name = "WorkflowOptionsError";
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
function runOrExit3(fn) {
|
|
957
|
+
try {
|
|
958
|
+
return fn();
|
|
959
|
+
} catch (err) {
|
|
960
|
+
if (err instanceof WorkflowOptionsError || err instanceof SpaceOptionsError || err instanceof SearchOptionsError) {
|
|
961
|
+
printError(err.message);
|
|
962
|
+
process.exit(1);
|
|
963
|
+
}
|
|
964
|
+
throw err;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
function addWorkspaceOption(command) {
|
|
968
|
+
return command.requiredOption("-w, --workspace <workspaceId>", "Workspace ID");
|
|
969
|
+
}
|
|
970
|
+
function addSpaceOptions2(command) {
|
|
971
|
+
return addWorkspaceOption(command).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)");
|
|
972
|
+
}
|
|
973
|
+
function addAssigneeOptions(command) {
|
|
974
|
+
return command.option("--human-id <humanId>", "Human assignee ID").option("--assistant-id <assistantId>", "AI assistant assignee ID").option("--teammate-id <teammateId>", "AI teammate assignee ID");
|
|
975
|
+
}
|
|
976
|
+
function addPreferredAssigneeOptions(command) {
|
|
977
|
+
return command.option("--preferred-human-id <humanId>", "Preferred human assignee ID").option("--preferred-assistant-id <assistantId>", "Preferred AI assistant assignee ID").option("--preferred-teammate-id <teammateId>", "Preferred AI teammate assignee ID");
|
|
978
|
+
}
|
|
979
|
+
function parsePositiveInteger(raw, label) {
|
|
980
|
+
const parsed = Number.parseInt(raw, 10);
|
|
981
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || String(parsed) !== raw) {
|
|
982
|
+
throw new WorkflowOptionsError(`Error: ${label} must be a positive integer, got "${raw}".`);
|
|
983
|
+
}
|
|
984
|
+
return parsed;
|
|
985
|
+
}
|
|
986
|
+
function parseOptionalPositiveInteger(raw, label) {
|
|
987
|
+
if (raw == null || raw === "") return void 0;
|
|
988
|
+
return parsePositiveInteger(raw, label);
|
|
989
|
+
}
|
|
990
|
+
function parseStatusType(raw) {
|
|
991
|
+
if (raw == null || raw === "") return void 0;
|
|
992
|
+
const parsed = Number.parseInt(raw, 10);
|
|
993
|
+
if ((parsed === 1 || parsed === 2 || parsed === 3) && String(parsed) === raw) return parsed;
|
|
994
|
+
throw new WorkflowOptionsError("Error: --type must be one of 1 (todo), 2 (in-progress), or 3 (done).");
|
|
995
|
+
}
|
|
996
|
+
function parseRequiredStatusType(raw) {
|
|
997
|
+
const value = parseStatusType(raw);
|
|
998
|
+
if (value === void 0) {
|
|
999
|
+
throw new WorkflowOptionsError("Error: --type is required.");
|
|
1000
|
+
}
|
|
1001
|
+
return value;
|
|
1002
|
+
}
|
|
1003
|
+
function parsePriority(raw) {
|
|
1004
|
+
if (raw == null || raw === "") return void 0;
|
|
1005
|
+
if (raw === "urgent") return 0;
|
|
1006
|
+
if (raw === "high") return 1;
|
|
1007
|
+
if (raw === "medium") return 2;
|
|
1008
|
+
if (raw === "low") return 3;
|
|
1009
|
+
throw new WorkflowOptionsError('Error: --priority must be "urgent", "high", "medium", or "low".');
|
|
1010
|
+
}
|
|
1011
|
+
function parseRequiredPriority(raw) {
|
|
1012
|
+
return parsePriority(raw ?? "medium") ?? 2;
|
|
1013
|
+
}
|
|
1014
|
+
function parseWorkflowScope(raw) {
|
|
1015
|
+
if (raw == null || raw === "") return "all";
|
|
1016
|
+
if (raw === "all" || raw === "owner_is_me") return raw;
|
|
1017
|
+
throw new WorkflowOptionsError('Error: --scope must be "all" or "owner_is_me".');
|
|
1018
|
+
}
|
|
1019
|
+
function parseTaskScope(raw) {
|
|
1020
|
+
if (raw == null || raw === "") return "all";
|
|
1021
|
+
if (raw === "all" || raw === "assigned_to_me" || raw === "subscribed_by_me" || raw === "owner_is_me") {
|
|
1022
|
+
return raw;
|
|
1023
|
+
}
|
|
1024
|
+
throw new WorkflowOptionsError(
|
|
1025
|
+
'Error: --scope must be "all", "assigned_to_me", "subscribed_by_me", or "owner_is_me".'
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
function parseFileIds(raw, label = "--file-ids") {
|
|
1029
|
+
if (raw == null || raw === "") return void 0;
|
|
1030
|
+
const ids = raw.split(",").map((item) => item.trim()).filter(Boolean);
|
|
1031
|
+
if (ids.length === 0) {
|
|
1032
|
+
throw new WorkflowOptionsError(`Error: ${label} must include at least one file ID.`);
|
|
1033
|
+
}
|
|
1034
|
+
return ids;
|
|
1035
|
+
}
|
|
1036
|
+
function readDescFile(path2) {
|
|
1037
|
+
if (path2 == null || path2 === "") return void 0;
|
|
1038
|
+
if (!fs3.existsSync(path2)) {
|
|
1039
|
+
throw new WorkflowOptionsError(`Error: desc file not found: ${path2}`);
|
|
1040
|
+
}
|
|
1041
|
+
const stat = fs3.statSync(path2);
|
|
1042
|
+
if (!stat.isFile()) {
|
|
1043
|
+
throw new WorkflowOptionsError(`Error: desc file is not a file: ${path2}`);
|
|
1044
|
+
}
|
|
1045
|
+
const buffer2 = fs3.readFileSync(path2);
|
|
1046
|
+
if (isBinaryContent(buffer2)) {
|
|
1047
|
+
throw new WorkflowOptionsError("Error: desc file must be UTF-8 text, not binary content.");
|
|
1048
|
+
}
|
|
1049
|
+
const content = buffer2.toString("utf8");
|
|
1050
|
+
if (content.length > MAX_DESC_LENGTH) {
|
|
1051
|
+
throw new WorkflowOptionsError(`Error: desc file must be at most ${MAX_DESC_LENGTH} characters.`);
|
|
1052
|
+
}
|
|
1053
|
+
return content;
|
|
1054
|
+
}
|
|
1055
|
+
function parseAssigneeBody(options, allowClear) {
|
|
1056
|
+
const hasClear = options.clear === true;
|
|
1057
|
+
const humanId = parseOptionalPositiveInteger(options.humanId, "--human-id");
|
|
1058
|
+
const assistantId = parseOptionalPositiveInteger(options.assistantId, "--assistant-id");
|
|
1059
|
+
const teammateId = parseOptionalPositiveInteger(options.teammateId, "--teammate-id");
|
|
1060
|
+
const count = (humanId !== void 0 ? 1 : 0) + (assistantId !== void 0 ? 1 : 0) + (teammateId !== void 0 ? 1 : 0);
|
|
1061
|
+
if (hasClear && !allowClear) {
|
|
1062
|
+
throw new WorkflowOptionsError("Error: --clear is not supported here.");
|
|
1063
|
+
}
|
|
1064
|
+
if (hasClear && count > 0) {
|
|
1065
|
+
throw new WorkflowOptionsError("Error: --clear cannot be used with assignee ID options.");
|
|
1066
|
+
}
|
|
1067
|
+
if (count > 1) {
|
|
1068
|
+
throw new WorkflowOptionsError("Error: assignee ID options are mutually exclusive.");
|
|
1069
|
+
}
|
|
1070
|
+
if (hasClear) return {};
|
|
1071
|
+
if (humanId !== void 0) return { assigneeHumanId: humanId };
|
|
1072
|
+
if (assistantId !== void 0) return { assigneeAiAssistantId: assistantId };
|
|
1073
|
+
if (teammateId !== void 0) return { assigneeAiTeammateId: teammateId };
|
|
1074
|
+
return {};
|
|
1075
|
+
}
|
|
1076
|
+
function parsePreferredAssigneeBody(options) {
|
|
1077
|
+
const hasClear = options.clearPreferredAssignee === true;
|
|
1078
|
+
const humanId = parseOptionalPositiveInteger(options.preferredHumanId, "--preferred-human-id");
|
|
1079
|
+
const assistantId = parseOptionalPositiveInteger(options.preferredAssistantId, "--preferred-assistant-id");
|
|
1080
|
+
const teammateId = parseOptionalPositiveInteger(options.preferredTeammateId, "--preferred-teammate-id");
|
|
1081
|
+
const count = (humanId !== void 0 ? 1 : 0) + (assistantId !== void 0 ? 1 : 0) + (teammateId !== void 0 ? 1 : 0);
|
|
1082
|
+
if (hasClear && count > 0) {
|
|
1083
|
+
throw new WorkflowOptionsError("Error: --clear-preferred-assignee cannot be used with preferred assignee ID options.");
|
|
1084
|
+
}
|
|
1085
|
+
if (count > 1) {
|
|
1086
|
+
throw new WorkflowOptionsError("Error: preferred assignee ID options are mutually exclusive.");
|
|
1087
|
+
}
|
|
1088
|
+
if (hasClear) return { preferredAssigneeHumanId: null };
|
|
1089
|
+
if (humanId !== void 0) return { preferredAssigneeHumanId: humanId };
|
|
1090
|
+
if (assistantId !== void 0) return { preferredAssigneeAiAssistantId: assistantId };
|
|
1091
|
+
if (teammateId !== void 0) return { preferredAssigneeAiTeammateId: teammateId };
|
|
1092
|
+
return {};
|
|
1093
|
+
}
|
|
1094
|
+
function assertNonEmptyBody(body) {
|
|
1095
|
+
if (Object.keys(body).length === 0) {
|
|
1096
|
+
throw new WorkflowOptionsError("Error: at least one update option must be provided.");
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
function buildQuery(params) {
|
|
1100
|
+
const query = new URLSearchParams();
|
|
1101
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1102
|
+
if (value !== void 0) {
|
|
1103
|
+
query.set(key, String(value));
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
const text = query.toString();
|
|
1107
|
+
return text ? `?${text}` : "";
|
|
1108
|
+
}
|
|
1109
|
+
function failResponse(response) {
|
|
1110
|
+
printError(`Error [${response.status}]: ${JSON.stringify(response.data)}`);
|
|
1111
|
+
process.exit(1);
|
|
1112
|
+
}
|
|
1113
|
+
function priorityLabel(value) {
|
|
1114
|
+
if (value === 0) return "urgent";
|
|
1115
|
+
if (value === 1) return "high";
|
|
1116
|
+
if (value === 2) return "medium";
|
|
1117
|
+
return "low";
|
|
1118
|
+
}
|
|
1119
|
+
function formatAssignee(assignee) {
|
|
1120
|
+
if (!assignee) return "-";
|
|
1121
|
+
if (assignee.type === "human") return assignee.displayName ?? `human:${assignee.humanId}`;
|
|
1122
|
+
if (assignee.type === "assistant") return assignee.displayName ?? `assistant:${assignee.aiAssistantId}`;
|
|
1123
|
+
if (assignee.type === "teammate") return assignee.displayName ?? `teammate:${assignee.aiTeammateId}`;
|
|
1124
|
+
return "unknown";
|
|
1125
|
+
}
|
|
1126
|
+
function printWorkflow(item) {
|
|
1127
|
+
print(`${colors.bold}${item.fileId}${colors.reset} owner=${item.ownerHumanId ?? "-"} desc=${item.desc ?? "-"}`);
|
|
1128
|
+
}
|
|
1129
|
+
function printStatus(item) {
|
|
1130
|
+
print(
|
|
1131
|
+
`${colors.bold}${item.scopedId}${colors.reset} ${item.name} type=${item.type} preferred=${formatAssignee(item.preferredAssignee)}`
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
function printTask(item) {
|
|
1135
|
+
const runIds = item.agentRuns.map((run) => run.pipelineTriggerId).join(",") || "-";
|
|
1136
|
+
print(
|
|
1137
|
+
`${colors.bold}#${item.scopedId}${colors.reset} ${item.title} status=${item.statusScopedId} priority=${priorityLabel(item.priority)} assignee=${formatAssignee(item.assignee)} runs=${runIds}`
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
function registerWorkflowCommand(program2) {
|
|
1141
|
+
const workflow = program2.command("workflow").description("Workflow operations");
|
|
1142
|
+
addWorkspaceOption(
|
|
1143
|
+
workflow.command("list").description("List accessible workflows").option("--scope <scope>", "Workflow scope: all or owner_is_me", "all")
|
|
1144
|
+
).action(async (options) => {
|
|
1145
|
+
const scope = runOrExit3(() => parseWorkflowScope(options.scope));
|
|
1146
|
+
startSpinner("Fetching workflows...");
|
|
1147
|
+
const response = await httpGet(
|
|
1148
|
+
`/workspaces/${options.workspace}/workflows${buildQuery({ scope })}`
|
|
1149
|
+
);
|
|
1150
|
+
if (!response.ok) {
|
|
1151
|
+
stopSpinner(false, "Failed");
|
|
1152
|
+
failResponse(response);
|
|
1153
|
+
}
|
|
1154
|
+
if (response.data.workflows.length === 0) {
|
|
1155
|
+
stopSpinner(true, "No workflows found.");
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
stopSpinner(true, `Found ${response.data.workflows.length} workflow(s)`);
|
|
1159
|
+
for (const item of response.data.workflows) printWorkflow(item);
|
|
1160
|
+
});
|
|
1161
|
+
addSpaceOptions2(
|
|
1162
|
+
workflow.command("create").description("Create a blank workflow").requiredOption("-p, --path <path>", "Target .workflow path").option("--desc-file <localPath>", "Local UTF-8 text file for workflow description").option("--owner-human-id <humanId>", "Workflow owner human ID")
|
|
1163
|
+
).action(async (options) => {
|
|
1164
|
+
const body = runOrExit3(() => {
|
|
1165
|
+
const next = {
|
|
1166
|
+
path: options.path,
|
|
1167
|
+
...resolveSpaceSelector(options)
|
|
1168
|
+
};
|
|
1169
|
+
const desc = readDescFile(options.descFile);
|
|
1170
|
+
if (desc !== void 0) next.desc = desc;
|
|
1171
|
+
const ownerHumanId = parseOptionalPositiveInteger(options.ownerHumanId, "--owner-human-id");
|
|
1172
|
+
if (ownerHumanId !== void 0) next.ownerHumanId = ownerHumanId;
|
|
1173
|
+
return next;
|
|
1174
|
+
});
|
|
1175
|
+
startSpinner("Creating workflow...");
|
|
1176
|
+
const response = await httpPost(`/workspaces/${options.workspace}/workflows`, body);
|
|
1177
|
+
if (!response.ok) {
|
|
1178
|
+
stopSpinner(false, "Failed");
|
|
1179
|
+
failResponse(response);
|
|
1180
|
+
}
|
|
1181
|
+
stopSpinner(true, "Workflow created");
|
|
1182
|
+
printWorkflow(response.data);
|
|
1183
|
+
});
|
|
1184
|
+
addWorkspaceOption(workflow.command("get").description("Get a workflow").argument("<workflowFileId>")).action(
|
|
1185
|
+
async (workflowFileId, options) => {
|
|
1186
|
+
startSpinner("Fetching workflow...");
|
|
1187
|
+
const response = await httpGet(
|
|
1188
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}`
|
|
1189
|
+
);
|
|
1190
|
+
if (!response.ok) {
|
|
1191
|
+
stopSpinner(false, "Failed");
|
|
1192
|
+
failResponse(response);
|
|
1193
|
+
}
|
|
1194
|
+
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
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
);
|
|
1204
|
+
addWorkspaceOption(
|
|
1205
|
+
workflow.command("update").description("Update workflow metadata").argument("<workflowFileId>").option("--desc-file <localPath>", "Local UTF-8 text file for workflow description").option("--owner-human-id <humanId>", "Workflow owner human ID")
|
|
1206
|
+
).action(async (workflowFileId, options) => {
|
|
1207
|
+
const body = runOrExit3(() => {
|
|
1208
|
+
const next = {};
|
|
1209
|
+
const desc = readDescFile(options.descFile);
|
|
1210
|
+
if (desc !== void 0) next.desc = desc;
|
|
1211
|
+
const ownerHumanId = parseOptionalPositiveInteger(options.ownerHumanId, "--owner-human-id");
|
|
1212
|
+
if (ownerHumanId !== void 0) next.ownerHumanId = ownerHumanId;
|
|
1213
|
+
assertNonEmptyBody(next);
|
|
1214
|
+
return next;
|
|
1215
|
+
});
|
|
1216
|
+
startSpinner("Updating workflow...");
|
|
1217
|
+
const response = await httpPatch(`/workspaces/${options.workspace}/workflows/${workflowFileId}`, body);
|
|
1218
|
+
if (!response.ok) {
|
|
1219
|
+
stopSpinner(false, "Failed");
|
|
1220
|
+
failResponse(response);
|
|
1221
|
+
}
|
|
1222
|
+
stopSpinner(true, "Workflow updated");
|
|
1223
|
+
printWorkflow(response.data);
|
|
1224
|
+
});
|
|
1225
|
+
addWorkspaceOption(
|
|
1226
|
+
workflow.command("delete").description("Delete a workflow").argument("<workflowFileId>").option("--message <message>", "Commit message")
|
|
1227
|
+
).action(async (workflowFileId, options) => {
|
|
1228
|
+
startSpinner("Deleting workflow...");
|
|
1229
|
+
const response = await httpDelete(
|
|
1230
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}`,
|
|
1231
|
+
options.message ? { message: options.message } : {}
|
|
1232
|
+
);
|
|
1233
|
+
if (!response.ok) {
|
|
1234
|
+
stopSpinner(false, "Failed");
|
|
1235
|
+
failResponse(response);
|
|
1236
|
+
}
|
|
1237
|
+
stopSpinner(true, `Deleted: ${response.data.fileId}`);
|
|
1238
|
+
});
|
|
1239
|
+
addWorkspaceOption(workflow.command("duplicate").description("Duplicate a workflow").argument("<workflowFileId>")).action(
|
|
1240
|
+
async (workflowFileId, options) => {
|
|
1241
|
+
startSpinner("Duplicating workflow...");
|
|
1242
|
+
const response = await httpPost(
|
|
1243
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/duplicate`,
|
|
1244
|
+
{}
|
|
1245
|
+
);
|
|
1246
|
+
if (!response.ok) {
|
|
1247
|
+
stopSpinner(false, "Failed");
|
|
1248
|
+
failResponse(response);
|
|
1249
|
+
}
|
|
1250
|
+
stopSpinner(true, "Workflow duplicated");
|
|
1251
|
+
printWorkflow(response.data);
|
|
1252
|
+
}
|
|
1253
|
+
);
|
|
1254
|
+
registerStatusCommands(workflow);
|
|
1255
|
+
registerTransitionCommands(workflow);
|
|
1256
|
+
registerTaskCommands(workflow);
|
|
1257
|
+
registerRunCommands(workflow);
|
|
1258
|
+
}
|
|
1259
|
+
function registerStatusCommands(workflow) {
|
|
1260
|
+
const status = workflow.command("status").description("Workflow status operations");
|
|
1261
|
+
addPreferredAssigneeOptions(
|
|
1262
|
+
addWorkspaceOption(
|
|
1263
|
+
status.command("create").description("Create a workflow status").argument("<workflowFileId>").requiredOption("--name <name>", "Status name").requiredOption("--type <type>", "Status type value: 1=todo, 2=in-progress, 3=done").option("--desc-file <localPath>", "Local UTF-8 text file for status description")
|
|
1264
|
+
)
|
|
1265
|
+
).action(
|
|
1266
|
+
async (workflowFileId, options) => {
|
|
1267
|
+
const body = runOrExit3(() => {
|
|
1268
|
+
const next = {
|
|
1269
|
+
name: options.name,
|
|
1270
|
+
type: parseRequiredStatusType(options.type)
|
|
1271
|
+
};
|
|
1272
|
+
const desc = readDescFile(options.descFile);
|
|
1273
|
+
if (desc !== void 0) next.desc = desc;
|
|
1274
|
+
Object.assign(next, parsePreferredAssigneeBody(options));
|
|
1275
|
+
return next;
|
|
1276
|
+
});
|
|
1277
|
+
startSpinner("Creating status...");
|
|
1278
|
+
const response = await httpPost(
|
|
1279
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/statuses`,
|
|
1280
|
+
body
|
|
1281
|
+
);
|
|
1282
|
+
if (!response.ok) {
|
|
1283
|
+
stopSpinner(false, "Failed");
|
|
1284
|
+
failResponse(response);
|
|
1285
|
+
}
|
|
1286
|
+
stopSpinner(true, "Status created");
|
|
1287
|
+
printStatus(response.data);
|
|
1288
|
+
}
|
|
1289
|
+
);
|
|
1290
|
+
addPreferredAssigneeOptions(
|
|
1291
|
+
addWorkspaceOption(
|
|
1292
|
+
status.command("update").description("Update a workflow status").argument("<workflowFileId>").argument("<statusScopedId>").option("--name <name>", "Status name").option("--type <type>", "Status type value: 1=todo, 2=in-progress, 3=done").option("--desc-file <localPath>", "Local UTF-8 text file for status description").option("--clear-desc", "Clear status description").option("--clear-preferred-assignee", "Clear preferred assignee")
|
|
1293
|
+
)
|
|
1294
|
+
).action(
|
|
1295
|
+
async (workflowFileId, statusScopedId, options) => {
|
|
1296
|
+
const body = runOrExit3(() => {
|
|
1297
|
+
if (options.descFile && options.clearDesc) {
|
|
1298
|
+
throw new WorkflowOptionsError("Error: --desc-file cannot be used with --clear-desc.");
|
|
1299
|
+
}
|
|
1300
|
+
const next = {};
|
|
1301
|
+
if (options.name) next.name = options.name;
|
|
1302
|
+
const type = parseStatusType(options.type);
|
|
1303
|
+
if (type !== void 0) next.type = type;
|
|
1304
|
+
const desc = readDescFile(options.descFile);
|
|
1305
|
+
if (desc !== void 0) next.desc = desc;
|
|
1306
|
+
if (options.clearDesc) next.desc = null;
|
|
1307
|
+
Object.assign(next, parsePreferredAssigneeBody(options));
|
|
1308
|
+
assertNonEmptyBody(next);
|
|
1309
|
+
return next;
|
|
1310
|
+
});
|
|
1311
|
+
const id = runOrExit3(() => parsePositiveInteger(statusScopedId, "statusScopedId"));
|
|
1312
|
+
startSpinner("Updating status...");
|
|
1313
|
+
const response = await httpPatch(
|
|
1314
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/statuses/${id}`,
|
|
1315
|
+
body
|
|
1316
|
+
);
|
|
1317
|
+
if (!response.ok) {
|
|
1318
|
+
stopSpinner(false, "Failed");
|
|
1319
|
+
failResponse(response);
|
|
1320
|
+
}
|
|
1321
|
+
stopSpinner(true, "Status updated");
|
|
1322
|
+
printStatus(response.data);
|
|
1323
|
+
}
|
|
1324
|
+
);
|
|
1325
|
+
addWorkspaceOption(
|
|
1326
|
+
status.command("move-after").description("Move a workflow status after another status").argument("<workflowFileId>").argument("<statusScopedId>").option("--after <statusScopedId>", "Anchor status scoped ID").option("--first", "Move to first position")
|
|
1327
|
+
).action(
|
|
1328
|
+
async (workflowFileId, statusScopedId, options) => {
|
|
1329
|
+
const { id, anchoredStatusScopedId } = runOrExit3(() => {
|
|
1330
|
+
if (options.after && options.first) {
|
|
1331
|
+
throw new WorkflowOptionsError("Error: --after cannot be used with --first.");
|
|
1332
|
+
}
|
|
1333
|
+
if (!options.after && !options.first) {
|
|
1334
|
+
throw new WorkflowOptionsError("Error: either --after or --first is required.");
|
|
1335
|
+
}
|
|
1336
|
+
return {
|
|
1337
|
+
id: parsePositiveInteger(statusScopedId, "statusScopedId"),
|
|
1338
|
+
anchoredStatusScopedId: options.first ? null : parsePositiveInteger(options.after, "--after")
|
|
1339
|
+
};
|
|
1340
|
+
});
|
|
1341
|
+
startSpinner("Moving status...");
|
|
1342
|
+
const response = await httpPost(
|
|
1343
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/statuses/${id}/move-after`,
|
|
1344
|
+
{ anchoredStatusScopedId }
|
|
1345
|
+
);
|
|
1346
|
+
if (!response.ok) {
|
|
1347
|
+
stopSpinner(false, "Failed");
|
|
1348
|
+
failResponse(response);
|
|
1349
|
+
}
|
|
1350
|
+
stopSpinner(true, "Status moved");
|
|
1351
|
+
}
|
|
1352
|
+
);
|
|
1353
|
+
addWorkspaceOption(
|
|
1354
|
+
status.command("delete").description("Delete a workflow status").argument("<workflowFileId>").argument("<statusScopedId>")
|
|
1355
|
+
).action(async (workflowFileId, statusScopedId, options) => {
|
|
1356
|
+
const id = runOrExit3(() => parsePositiveInteger(statusScopedId, "statusScopedId"));
|
|
1357
|
+
startSpinner("Deleting status...");
|
|
1358
|
+
const response = await httpDelete(
|
|
1359
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/statuses/${id}`
|
|
1360
|
+
);
|
|
1361
|
+
if (!response.ok) {
|
|
1362
|
+
stopSpinner(false, "Failed");
|
|
1363
|
+
failResponse(response);
|
|
1364
|
+
}
|
|
1365
|
+
stopSpinner(true, `Deleted: ${response.data.scopedId}`);
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
function registerTransitionCommands(workflow) {
|
|
1369
|
+
const transition = workflow.command("transition").description("Workflow transition operations");
|
|
1370
|
+
for (const action of ["create", "delete"]) {
|
|
1371
|
+
addWorkspaceOption(
|
|
1372
|
+
transition.command(action).description(`${action === "create" ? "Create" : "Delete"} a workflow transition`).argument("<workflowFileId>").requiredOption("--from <statusScopedId>", "Source status scoped ID").requiredOption("--to <statusScopedId>", "Target status scoped ID")
|
|
1373
|
+
).action(async (workflowFileId, options) => {
|
|
1374
|
+
const body = runOrExit3(() => ({
|
|
1375
|
+
statusFromScopedId: parsePositiveInteger(options.from, "--from"),
|
|
1376
|
+
statusToScopedId: parsePositiveInteger(options.to, "--to")
|
|
1377
|
+
}));
|
|
1378
|
+
startSpinner(`${action === "create" ? "Creating" : "Deleting"} transition...`);
|
|
1379
|
+
const response = action === "create" ? await httpPost(
|
|
1380
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/transitions`,
|
|
1381
|
+
body
|
|
1382
|
+
) : await httpDelete(
|
|
1383
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/transitions`,
|
|
1384
|
+
body
|
|
1385
|
+
);
|
|
1386
|
+
if (!response.ok) {
|
|
1387
|
+
stopSpinner(false, "Failed");
|
|
1388
|
+
failResponse(response);
|
|
1389
|
+
}
|
|
1390
|
+
stopSpinner(true, action === "create" ? "Transition created" : "Transition deleted");
|
|
1391
|
+
print(`${response.data.statusFromScopedId} -> ${response.data.statusToScopedId}`);
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
function registerTaskCommands(workflow) {
|
|
1396
|
+
const task = workflow.command("task").description("Workflow task operations");
|
|
1397
|
+
addWorkspaceOption(
|
|
1398
|
+
task.command("list").description("List workflow tasks").option("--workflow-file-id <workflowFileId>", "Filter by workflow file ID").option("--scope <scope>", "Task scope", "all").option("-l, --limit <limit>", "Maximum number of tasks to return", "20").option("--cursor <cursor>", "Pagination cursor")
|
|
1399
|
+
).action(
|
|
1400
|
+
async (options) => {
|
|
1401
|
+
const query = runOrExit3(() => buildQuery({
|
|
1402
|
+
scope: parseTaskScope(options.scope),
|
|
1403
|
+
limit: parseSearchLimit(options.limit, 20, 100),
|
|
1404
|
+
cursor: options.cursor,
|
|
1405
|
+
workflowFileId: options.workflowFileId
|
|
1406
|
+
}));
|
|
1407
|
+
startSpinner("Fetching workflow tasks...");
|
|
1408
|
+
const response = await httpGet(`/workspaces/${options.workspace}/workflow-tasks${query}`);
|
|
1409
|
+
if (!response.ok) {
|
|
1410
|
+
stopSpinner(false, "Failed");
|
|
1411
|
+
failResponse(response);
|
|
1412
|
+
}
|
|
1413
|
+
if (response.data.tasks.length === 0) {
|
|
1414
|
+
stopSpinner(true, "No workflow tasks found.");
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
stopSpinner(true, `Found ${response.data.tasks.length} task(s)`);
|
|
1418
|
+
for (const item of response.data.tasks) printTask(item);
|
|
1419
|
+
if (response.data.nextCursor) print(`${colors.dim}nextCursor=${response.data.nextCursor}${colors.reset}`);
|
|
1420
|
+
}
|
|
1421
|
+
);
|
|
1422
|
+
addWorkspaceOption(
|
|
1423
|
+
task.command("get").description("Get a workflow task").argument("<workflowFileId>").argument("<taskScopedId>")
|
|
1424
|
+
).action(async (workflowFileId, taskScopedId, options) => {
|
|
1425
|
+
const id = runOrExit3(() => parsePositiveInteger(taskScopedId, "taskScopedId"));
|
|
1426
|
+
startSpinner("Fetching task...");
|
|
1427
|
+
const response = await httpGet(
|
|
1428
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks/${id}`
|
|
1429
|
+
);
|
|
1430
|
+
if (!response.ok) {
|
|
1431
|
+
stopSpinner(false, "Failed");
|
|
1432
|
+
failResponse(response);
|
|
1433
|
+
}
|
|
1434
|
+
stopSpinner(true, "Task fetched");
|
|
1435
|
+
printTask(response.data);
|
|
1436
|
+
});
|
|
1437
|
+
addAssigneeOptions(
|
|
1438
|
+
addWorkspaceOption(
|
|
1439
|
+
task.command("create").description("Create a workflow task").argument("<workflowFileId>").requiredOption("--title <title>", "Task title").requiredOption("--status <statusScopedId>", "Status scoped ID").option("--priority <priority>", "Priority: urgent, high, medium, or low", "medium").option("--desc-file <localPath>", "Local UTF-8 text file for task description").option("--owner-human-id <humanId>", "Task owner human ID")
|
|
1440
|
+
)
|
|
1441
|
+
).action(
|
|
1442
|
+
async (workflowFileId, options) => {
|
|
1443
|
+
const body = runOrExit3(() => {
|
|
1444
|
+
const next = {
|
|
1445
|
+
title: options.title,
|
|
1446
|
+
statusScopedId: parsePositiveInteger(options.status, "--status"),
|
|
1447
|
+
priority: parseRequiredPriority(options.priority)
|
|
1448
|
+
};
|
|
1449
|
+
const desc = readDescFile(options.descFile);
|
|
1450
|
+
if (desc !== void 0) next.desc = desc;
|
|
1451
|
+
const ownerHumanId = parseOptionalPositiveInteger(options.ownerHumanId, "--owner-human-id");
|
|
1452
|
+
if (ownerHumanId !== void 0) next.ownerHumanId = ownerHumanId;
|
|
1453
|
+
Object.assign(next, parseAssigneeBody(options, false));
|
|
1454
|
+
return next;
|
|
1455
|
+
});
|
|
1456
|
+
startSpinner("Creating task...");
|
|
1457
|
+
const response = await httpPost(
|
|
1458
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks`,
|
|
1459
|
+
body
|
|
1460
|
+
);
|
|
1461
|
+
if (!response.ok) {
|
|
1462
|
+
stopSpinner(false, "Failed");
|
|
1463
|
+
failResponse(response);
|
|
1464
|
+
}
|
|
1465
|
+
stopSpinner(true, "Task created");
|
|
1466
|
+
printTask(response.data);
|
|
1467
|
+
}
|
|
1468
|
+
);
|
|
1469
|
+
addWorkspaceOption(
|
|
1470
|
+
task.command("update").description("Update workflow task metadata").argument("<workflowFileId>").argument("<taskScopedId>").option("--title <title>", "Task title").option("--priority <priority>", "Priority: urgent, high, medium, or low").option("--desc-file <localPath>", "Local UTF-8 text file for task description").option("--clear-desc", "Clear task description").option("--owner-human-id <humanId>", "Task owner human ID")
|
|
1471
|
+
).action(
|
|
1472
|
+
async (workflowFileId, taskScopedId, options) => {
|
|
1473
|
+
const body = runOrExit3(() => {
|
|
1474
|
+
if (options.descFile && options.clearDesc) {
|
|
1475
|
+
throw new WorkflowOptionsError("Error: --desc-file cannot be used with --clear-desc.");
|
|
1476
|
+
}
|
|
1477
|
+
const next = {};
|
|
1478
|
+
if (options.title) next.title = options.title;
|
|
1479
|
+
const priority = parsePriority(options.priority);
|
|
1480
|
+
if (priority !== void 0) next.priority = priority;
|
|
1481
|
+
const desc = readDescFile(options.descFile);
|
|
1482
|
+
if (desc !== void 0) next.desc = desc;
|
|
1483
|
+
if (options.clearDesc) next.desc = null;
|
|
1484
|
+
const ownerHumanId = parseOptionalPositiveInteger(options.ownerHumanId, "--owner-human-id");
|
|
1485
|
+
if (ownerHumanId !== void 0) next.ownerHumanId = ownerHumanId;
|
|
1486
|
+
assertNonEmptyBody(next);
|
|
1487
|
+
return next;
|
|
1488
|
+
});
|
|
1489
|
+
const id = runOrExit3(() => parsePositiveInteger(taskScopedId, "taskScopedId"));
|
|
1490
|
+
startSpinner("Updating task...");
|
|
1491
|
+
const response = await httpPatch(
|
|
1492
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks/${id}/metadata`,
|
|
1493
|
+
body
|
|
1494
|
+
);
|
|
1495
|
+
if (!response.ok) {
|
|
1496
|
+
stopSpinner(false, "Failed");
|
|
1497
|
+
failResponse(response);
|
|
1498
|
+
}
|
|
1499
|
+
stopSpinner(true, "Task updated");
|
|
1500
|
+
printTask(response.data);
|
|
1501
|
+
}
|
|
1502
|
+
);
|
|
1503
|
+
for (const action of ["add-linked-files", "remove-linked-files"]) {
|
|
1504
|
+
addWorkspaceOption(
|
|
1505
|
+
task.command(action).description(`${action === "add-linked-files" ? "Add" : "Remove"} linked files on a workflow task`).argument("<workflowFileId>").argument("<taskScopedId>").requiredOption("--file-ids <ids>", "Comma-separated file IDs")
|
|
1506
|
+
).action(
|
|
1507
|
+
async (workflowFileId, taskScopedId, options) => {
|
|
1508
|
+
const { id, fileIds } = runOrExit3(() => ({
|
|
1509
|
+
id: parsePositiveInteger(taskScopedId, "taskScopedId"),
|
|
1510
|
+
fileIds: parseFileIds(options.fileIds, "--file-ids")
|
|
1511
|
+
}));
|
|
1512
|
+
startSpinner(action === "add-linked-files" ? "Adding linked files..." : "Removing linked files...");
|
|
1513
|
+
const path2 = `/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks/${id}/linked-files`;
|
|
1514
|
+
const response = action === "add-linked-files" ? await httpPost(path2, { fileIds }) : await httpDelete(path2, { fileIds });
|
|
1515
|
+
if (!response.ok) {
|
|
1516
|
+
stopSpinner(false, "Failed");
|
|
1517
|
+
failResponse(response);
|
|
1518
|
+
}
|
|
1519
|
+
stopSpinner(true, action === "add-linked-files" ? "Linked files added" : "Linked files removed");
|
|
1520
|
+
printTask(response.data);
|
|
1521
|
+
}
|
|
1522
|
+
);
|
|
1523
|
+
}
|
|
1524
|
+
addWorkspaceOption(
|
|
1525
|
+
task.command("move").description("Move a workflow task to another status").argument("<workflowFileId>").argument("<taskScopedId>").requiredOption("--status <statusScopedId>", "Target status scoped ID")
|
|
1526
|
+
).action(
|
|
1527
|
+
async (workflowFileId, taskScopedId, options) => {
|
|
1528
|
+
const { id, statusScopedId } = runOrExit3(() => ({
|
|
1529
|
+
id: parsePositiveInteger(taskScopedId, "taskScopedId"),
|
|
1530
|
+
statusScopedId: parsePositiveInteger(options.status, "--status")
|
|
1531
|
+
}));
|
|
1532
|
+
startSpinner("Moving task...");
|
|
1533
|
+
const response = await httpPatch(
|
|
1534
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks/${id}/status`,
|
|
1535
|
+
{ statusScopedId }
|
|
1536
|
+
);
|
|
1537
|
+
if (!response.ok) {
|
|
1538
|
+
stopSpinner(false, "Failed");
|
|
1539
|
+
failResponse(response);
|
|
1540
|
+
}
|
|
1541
|
+
stopSpinner(true, "Task moved");
|
|
1542
|
+
printTask(response.data);
|
|
1543
|
+
}
|
|
1544
|
+
);
|
|
1545
|
+
addAssigneeOptions(
|
|
1546
|
+
addWorkspaceOption(
|
|
1547
|
+
task.command("assign").description("Update workflow task assignee").argument("<workflowFileId>").argument("<taskScopedId>").option("--clear", "Clear assignee")
|
|
1548
|
+
)
|
|
1549
|
+
).action(
|
|
1550
|
+
async (workflowFileId, taskScopedId, options) => {
|
|
1551
|
+
const body = runOrExit3(() => {
|
|
1552
|
+
const next = parseAssigneeBody(options, true);
|
|
1553
|
+
if (Object.keys(next).length === 0 && options.clear !== true) assertNonEmptyBody(next);
|
|
1554
|
+
return next;
|
|
1555
|
+
});
|
|
1556
|
+
const id = runOrExit3(() => parsePositiveInteger(taskScopedId, "taskScopedId"));
|
|
1557
|
+
startSpinner("Updating task assignee...");
|
|
1558
|
+
const response = await httpPatch(
|
|
1559
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks/${id}/assignee`,
|
|
1560
|
+
body
|
|
1561
|
+
);
|
|
1562
|
+
if (!response.ok) {
|
|
1563
|
+
stopSpinner(false, "Failed");
|
|
1564
|
+
failResponse(response);
|
|
1565
|
+
}
|
|
1566
|
+
stopSpinner(true, "Task assignee updated");
|
|
1567
|
+
printTask(response.data);
|
|
1568
|
+
}
|
|
1569
|
+
);
|
|
1570
|
+
addWorkspaceOption(
|
|
1571
|
+
task.command("delete").description("Delete a workflow task").argument("<workflowFileId>").argument("<taskScopedId>")
|
|
1572
|
+
).action(async (workflowFileId, taskScopedId, options) => {
|
|
1573
|
+
const id = runOrExit3(() => parsePositiveInteger(taskScopedId, "taskScopedId"));
|
|
1574
|
+
startSpinner("Deleting task...");
|
|
1575
|
+
const response = await httpDelete(
|
|
1576
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/tasks/${id}`
|
|
1577
|
+
);
|
|
1578
|
+
if (!response.ok) {
|
|
1579
|
+
stopSpinner(false, "Failed");
|
|
1580
|
+
failResponse(response);
|
|
1581
|
+
}
|
|
1582
|
+
stopSpinner(true, `Deleted: ${response.data.scopedId}`);
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
function registerRunCommands(workflow) {
|
|
1586
|
+
const run = workflow.command("run").description("Workflow agent run operations");
|
|
1587
|
+
addWorkspaceOption(
|
|
1588
|
+
run.command("status").description("Get workflow agent run statuses").argument("<workflowFileId>").argument("<triggerIds...>")
|
|
1589
|
+
).action(async (workflowFileId, triggerIds, options) => {
|
|
1590
|
+
const workflowPipelineTriggerIds = runOrExit3(
|
|
1591
|
+
() => triggerIds.map((triggerId) => parsePositiveInteger(triggerId, "workflowPipelineTriggerId"))
|
|
1592
|
+
);
|
|
1593
|
+
startSpinner("Fetching run statuses...");
|
|
1594
|
+
const response = await httpPost(
|
|
1595
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/pipeline/triggers/statuses`,
|
|
1596
|
+
{ workflowPipelineTriggerIds }
|
|
1597
|
+
);
|
|
1598
|
+
if (!response.ok) {
|
|
1599
|
+
stopSpinner(false, "Failed");
|
|
1600
|
+
failResponse(response);
|
|
1601
|
+
}
|
|
1602
|
+
stopSpinner(true, `Found ${response.data.length} run status item(s)`);
|
|
1603
|
+
for (const item of response.data) {
|
|
1604
|
+
print(`${colors.bold}${item.workflowPipelineTriggerId}${colors.reset} ${item.pipelineStatus}`);
|
|
1605
|
+
}
|
|
1606
|
+
});
|
|
1607
|
+
addWorkspaceOption(
|
|
1608
|
+
run.command("output").description("Get workflow agent run output events").argument("<workflowFileId>").argument("<triggerId>")
|
|
1609
|
+
).action(async (workflowFileId, triggerId, options) => {
|
|
1610
|
+
const id = runOrExit3(() => parsePositiveInteger(triggerId, "workflowPipelineTriggerId"));
|
|
1611
|
+
startSpinner("Fetching run output...");
|
|
1612
|
+
const response = await httpGet(
|
|
1613
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/pipeline/trigger/${id}/output`
|
|
1614
|
+
);
|
|
1615
|
+
if (!response.ok) {
|
|
1616
|
+
stopSpinner(false, "Failed");
|
|
1617
|
+
failResponse(response);
|
|
1618
|
+
}
|
|
1619
|
+
stopSpinner(true, `Run ${response.data.workflowPipelineTriggerId}`);
|
|
1620
|
+
for (const event of response.data.pipelineEvents) print(event);
|
|
1621
|
+
});
|
|
1622
|
+
addWorkspaceOption(
|
|
1623
|
+
run.command("abort").description("Abort a workflow agent run").argument("<workflowFileId>").argument("<triggerId>")
|
|
1624
|
+
).action(async (workflowFileId, triggerId, options) => {
|
|
1625
|
+
const id = runOrExit3(() => parsePositiveInteger(triggerId, "workflowPipelineTriggerId"));
|
|
1626
|
+
startSpinner("Aborting run...");
|
|
1627
|
+
const response = await httpPost(
|
|
1628
|
+
`/workspaces/${options.workspace}/workflows/${workflowFileId}/pipeline/trigger/${id}/abort`,
|
|
1629
|
+
{}
|
|
1630
|
+
);
|
|
1631
|
+
if (!response.ok) {
|
|
1632
|
+
stopSpinner(false, "Failed");
|
|
1633
|
+
failResponse(response);
|
|
1634
|
+
}
|
|
1635
|
+
stopSpinner(true, `Abort accepted: ${id}`);
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// src/program.ts
|
|
1640
|
+
function createProgram(version) {
|
|
1641
|
+
const program2 = new Command();
|
|
1642
|
+
program2.name("moxt").description("Moxt CLI - AI Workspace").version(version).action(() => {
|
|
1643
|
+
program2.help();
|
|
1644
|
+
});
|
|
1645
|
+
registerWhoamiCommand(program2);
|
|
1646
|
+
registerWorkspaceCommand(program2);
|
|
1647
|
+
registerFileCommand(program2);
|
|
1648
|
+
registerMemoryCommand(program2);
|
|
1649
|
+
registerWorkflowCommand(program2);
|
|
1650
|
+
registerMiniappCommand(program2);
|
|
1651
|
+
registerTelemetryCommand(program2);
|
|
1652
|
+
return program2;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
942
1655
|
// src/telemetry/client.ts
|
|
943
1656
|
import { arch as arch2, platform as platform2 } from "os";
|
|
944
1657
|
var buffer = [];
|
|
@@ -946,7 +1659,7 @@ var FLUSH_TIMEOUT_MS = 3e3;
|
|
|
946
1659
|
var MAX_BATCH_SIZE = 100;
|
|
947
1660
|
function commonLabels() {
|
|
948
1661
|
return {
|
|
949
|
-
cli_version: "0.3.
|
|
1662
|
+
cli_version: "0.3.3-beta.0",
|
|
950
1663
|
node_version: process.versions.node,
|
|
951
1664
|
os: platform2(),
|
|
952
1665
|
arch: arch2(),
|
|
@@ -992,7 +1705,7 @@ async function flush() {
|
|
|
992
1705
|
}
|
|
993
1706
|
const batch = buffer.splice(0, MAX_BATCH_SIZE);
|
|
994
1707
|
const payload = {
|
|
995
|
-
release_id: "0.3.
|
|
1708
|
+
release_id: "0.3.3-beta.0",
|
|
996
1709
|
client_type: "cli",
|
|
997
1710
|
metric_data_list: batch.map((m) => ({
|
|
998
1711
|
profile: "cli",
|
|
@@ -1133,20 +1846,11 @@ function installExitHandler() {
|
|
|
1133
1846
|
|
|
1134
1847
|
// src/index.ts
|
|
1135
1848
|
updateNotifier({
|
|
1136
|
-
pkg: { name: "@moxt-ai/cli", version: "0.3.
|
|
1849
|
+
pkg: { name: "@moxt-ai/cli", version: "0.3.3-beta.0" }
|
|
1137
1850
|
}).notify();
|
|
1138
|
-
var program =
|
|
1139
|
-
program.name("moxt").description("Moxt CLI - AI Workspace").version("0.3.2").action(() => {
|
|
1140
|
-
program.help();
|
|
1141
|
-
});
|
|
1851
|
+
var program = createProgram("0.3.3-beta.0");
|
|
1142
1852
|
instrumentProgram(program);
|
|
1143
1853
|
installExitHandler();
|
|
1144
|
-
registerWhoamiCommand(program);
|
|
1145
|
-
registerWorkspaceCommand(program);
|
|
1146
|
-
registerFileCommand(program);
|
|
1147
|
-
registerMemoryCommand(program);
|
|
1148
|
-
registerMiniappCommand(program);
|
|
1149
|
-
registerTelemetryCommand(program);
|
|
1150
1854
|
program.parseAsync(process.argv).then(async () => {
|
|
1151
1855
|
await flush();
|
|
1152
1856
|
}).catch(async (err) => {
|