@hardfin/cli 0.0.2-dev.3 → 0.0.2-dev.6
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 +65 -1
- package/dist/cli.js +1552 -0
- package/package.json +23 -3
- package/bin/hardfin.js +0 -27
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1552 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { Command, Option } from "commander";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
//#region src/command/registry.ts
|
|
7
|
+
/** ExitCode is what the process returns, and what an agent branches on. */
|
|
8
|
+
const ExitCode = {
|
|
9
|
+
OK: 0,
|
|
10
|
+
ERROR: 1,
|
|
11
|
+
USAGE: 2,
|
|
12
|
+
NOT_AUTHENTICATED: 4
|
|
13
|
+
};
|
|
14
|
+
/** defineCommand records one command so every surface reads the same declaration. */
|
|
15
|
+
function defineCommand(command) {
|
|
16
|
+
return command;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/config/settings.ts
|
|
20
|
+
/** The API version this build was written against, sent on every request. */
|
|
21
|
+
const API_VERSION = "2026-09-17";
|
|
22
|
+
const DEFAULT_API_URL = "https://api.hardfin.com/v2";
|
|
23
|
+
/** toApiUrl picks the API this invocation talks to. */
|
|
24
|
+
function toApiUrl(override) {
|
|
25
|
+
return (override ?? process.env["HARDFIN_API_URL"] ?? DEFAULT_API_URL).replace(/\/+$/, "");
|
|
26
|
+
}
|
|
27
|
+
/** toApiKey reads the API key an unattended caller set. */
|
|
28
|
+
function toApiKey() {
|
|
29
|
+
return process.env["HARDFIN_API_KEY"] || void 0;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/output/writer.ts
|
|
33
|
+
/** writeData prints a command's result on stdout. */
|
|
34
|
+
function writeData(value) {
|
|
35
|
+
if (typeof value === "string") {
|
|
36
|
+
process.stdout.write(value.endsWith("\n") ? value : `${value}\n`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
40
|
+
}
|
|
41
|
+
/** writeFailure prints why a command failed on stderr, as text or as JSON. */
|
|
42
|
+
function writeFailure(message, isJSON, errors, requestId) {
|
|
43
|
+
if (!isJSON) {
|
|
44
|
+
process.stderr.write(`error: ${message}\n`);
|
|
45
|
+
for (const entry of errors?.slice(1) ?? []) process.stderr.write(` ${entry.error} (${entry.statusCode})\n`);
|
|
46
|
+
if (requestId) process.stderr.write(` request ${requestId}\n`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const payload = {
|
|
50
|
+
errors: errors ?? [{
|
|
51
|
+
error: message,
|
|
52
|
+
statusCode: 0
|
|
53
|
+
}],
|
|
54
|
+
requestId: requestId ?? null
|
|
55
|
+
};
|
|
56
|
+
process.stderr.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
57
|
+
}
|
|
58
|
+
/** isJSONOutput decides whether this invocation prints machine-readable output. */
|
|
59
|
+
function isJSONOutput(flags) {
|
|
60
|
+
if (flags["json"] === true) return true;
|
|
61
|
+
return !process.stdout.isTTY;
|
|
62
|
+
}
|
|
63
|
+
/** version is what this build reports, read from the published package manifest. */
|
|
64
|
+
const version = createRequire(import.meta.url)("../package.json").version;
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/command/agent-guide.ts
|
|
67
|
+
const agentGuideCommand = defineCommand({
|
|
68
|
+
name: "agent-guide",
|
|
69
|
+
summary: "Print instructions an agent can follow to use this CLI",
|
|
70
|
+
description: "Writes Markdown describing every command, its flags, and its exit codes. Save it as a skill file, an AGENTS.md section, or paste it into a system prompt.",
|
|
71
|
+
arguments: [],
|
|
72
|
+
flags: [{
|
|
73
|
+
name: "json",
|
|
74
|
+
description: "Print the command registry as JSON instead of Markdown",
|
|
75
|
+
schema: z.boolean().optional()
|
|
76
|
+
}],
|
|
77
|
+
examples: [{
|
|
78
|
+
description: "Write a skill file",
|
|
79
|
+
command: "hardfin agent-guide > SKILL.md"
|
|
80
|
+
}, {
|
|
81
|
+
description: "Inspect the registry",
|
|
82
|
+
command: "hardfin agent-guide --json"
|
|
83
|
+
}],
|
|
84
|
+
run: runAgentGuide
|
|
85
|
+
});
|
|
86
|
+
/** toGuide renders the registry as the Markdown an agent reads. */
|
|
87
|
+
function toGuide(commands, version) {
|
|
88
|
+
const lines = [
|
|
89
|
+
"# Hardfin CLI",
|
|
90
|
+
"",
|
|
91
|
+
`The \`hardfin\` command calls the Hardfin API. This guide describes version ${version} of the CLI, which speaks API version ${API_VERSION}.`,
|
|
92
|
+
"",
|
|
93
|
+
"## Before calling",
|
|
94
|
+
"",
|
|
95
|
+
"- Authenticate by setting `HARDFIN_API_KEY`, or by running `hardfin login`",
|
|
96
|
+
"- Every command prints JSON on stdout and diagnostics on stderr",
|
|
97
|
+
"- Output is JSON whenever stdout is not a terminal, so no flag is needed when calling from code",
|
|
98
|
+
"",
|
|
99
|
+
"## Exit codes",
|
|
100
|
+
"",
|
|
101
|
+
"| Code | Means |",
|
|
102
|
+
"| --- | --- |",
|
|
103
|
+
"| 0 | The command succeeded |",
|
|
104
|
+
"| 1 | The command failed |",
|
|
105
|
+
"| 2 | The command was called wrongly |",
|
|
106
|
+
"| 4 | No usable credential |",
|
|
107
|
+
"",
|
|
108
|
+
"## Commands",
|
|
109
|
+
""
|
|
110
|
+
];
|
|
111
|
+
for (const command of commands) {
|
|
112
|
+
lines.push(`### \`hardfin ${command.name}\``, "", command.description ?? command.summary, "");
|
|
113
|
+
if (command.arguments.length > 0) {
|
|
114
|
+
lines.push("| Argument | Required | Holds |", "| --- | --- | --- |");
|
|
115
|
+
for (const argument of command.arguments) lines.push(`| \`${argument.name}\` | ${argument.required ? "yes" : "no"} | ${argument.description} |`);
|
|
116
|
+
lines.push("");
|
|
117
|
+
}
|
|
118
|
+
if (command.flags.length > 0) {
|
|
119
|
+
lines.push("| Flag | Takes | Does |", "| --- | --- | --- |");
|
|
120
|
+
for (const flag of command.flags) {
|
|
121
|
+
const name = flag.short ? `-${flag.short}, --${flag.name}` : `--${flag.name}`;
|
|
122
|
+
lines.push(`| \`${name}\` | ${flag.valueName ?? "nothing"} | ${flag.description} |`);
|
|
123
|
+
}
|
|
124
|
+
lines.push("");
|
|
125
|
+
}
|
|
126
|
+
for (const example of command.examples) lines.push(`${example.description}:`, "", "```sh", example.command, "```", "");
|
|
127
|
+
}
|
|
128
|
+
return lines.join("\n");
|
|
129
|
+
}
|
|
130
|
+
async function runAgentGuide(input) {
|
|
131
|
+
if (input.flags["json"] === true) {
|
|
132
|
+
writeData(input.commands.map(toSummary));
|
|
133
|
+
return ExitCode.OK;
|
|
134
|
+
}
|
|
135
|
+
writeData(toGuide(input.commands, version));
|
|
136
|
+
return ExitCode.OK;
|
|
137
|
+
}
|
|
138
|
+
function toSummary(command) {
|
|
139
|
+
return {
|
|
140
|
+
name: command.name,
|
|
141
|
+
summary: command.summary,
|
|
142
|
+
description: command.description ?? command.summary,
|
|
143
|
+
arguments: command.arguments,
|
|
144
|
+
flags: command.flags.map((flag) => ({
|
|
145
|
+
name: flag.name,
|
|
146
|
+
short: flag.short ?? null,
|
|
147
|
+
description: flag.description,
|
|
148
|
+
valueName: flag.valueName ?? null,
|
|
149
|
+
repeatable: flag.repeatable ?? false
|
|
150
|
+
})),
|
|
151
|
+
examples: command.examples
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/http/client.ts
|
|
156
|
+
/** RequestFailure is a call the API refused, carrying what the envelope said. */
|
|
157
|
+
var RequestFailure = class extends Error {
|
|
158
|
+
status;
|
|
159
|
+
errors;
|
|
160
|
+
requestId;
|
|
161
|
+
constructor(status, errors, requestId) {
|
|
162
|
+
super(errors[0]?.error ?? `the request failed with status ${status}`);
|
|
163
|
+
this.name = "RequestFailure";
|
|
164
|
+
this.status = status;
|
|
165
|
+
this.errors = errors;
|
|
166
|
+
this.requestId = requestId;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
/** request calls one /v2 endpoint and returns the envelope it answered with. */
|
|
170
|
+
async function request(options) {
|
|
171
|
+
const url = new URL(`${options.apiUrl}${toLeadingSlash(options.path)}`);
|
|
172
|
+
if (options.query) url.search = options.query.toString();
|
|
173
|
+
const headers = {
|
|
174
|
+
"X-API-Key": options.apiKey,
|
|
175
|
+
"X-API-Version": API_VERSION,
|
|
176
|
+
Accept: "application/json"
|
|
177
|
+
};
|
|
178
|
+
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
179
|
+
const response = await fetch(url, {
|
|
180
|
+
method: options.method,
|
|
181
|
+
headers,
|
|
182
|
+
body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
|
|
183
|
+
});
|
|
184
|
+
const envelope = toEnvelope(await response.text());
|
|
185
|
+
if (!response.ok && envelope === void 0) throw new RequestFailure(response.status, [{
|
|
186
|
+
error: toStatusMessage(response.status),
|
|
187
|
+
statusCode: response.status
|
|
188
|
+
}]);
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
const errors = envelope?.metadata?.errors ?? [];
|
|
191
|
+
throw new RequestFailure(response.status, errors.length > 0 ? errors : [{
|
|
192
|
+
error: toStatusMessage(response.status),
|
|
193
|
+
statusCode: response.status
|
|
194
|
+
}], envelope?.metadata?.requestId);
|
|
195
|
+
}
|
|
196
|
+
return envelope ?? { data: null };
|
|
197
|
+
}
|
|
198
|
+
function toLeadingSlash(path) {
|
|
199
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
200
|
+
}
|
|
201
|
+
function toEnvelope(text) {
|
|
202
|
+
if (text.trim() === "") return;
|
|
203
|
+
try {
|
|
204
|
+
return JSON.parse(text);
|
|
205
|
+
} catch {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function toStatusMessage(status) {
|
|
210
|
+
if (status === 401) return "the credential is missing or is not valid";
|
|
211
|
+
if (status === 403) return "the organization is deactivated, or its access has ended";
|
|
212
|
+
return `the request failed with status ${status}`;
|
|
213
|
+
}
|
|
214
|
+
const apiCommand = defineCommand({
|
|
215
|
+
name: "api",
|
|
216
|
+
summary: "Call a Hardfin API endpoint and print what it answers",
|
|
217
|
+
description: "Reaches every endpoint the API publishes. The path is everything after /v2, and the response envelope is printed as it arrived.",
|
|
218
|
+
arguments: [{
|
|
219
|
+
name: "path",
|
|
220
|
+
description: "The endpoint path, such as /customer or /item/item_V1StGXR8Z5jdHi6B",
|
|
221
|
+
required: true
|
|
222
|
+
}],
|
|
223
|
+
flags: [
|
|
224
|
+
{
|
|
225
|
+
name: "method",
|
|
226
|
+
short: "X",
|
|
227
|
+
description: "The HTTP method to use",
|
|
228
|
+
valueName: "method",
|
|
229
|
+
schema: z.enum([
|
|
230
|
+
"GET",
|
|
231
|
+
"POST",
|
|
232
|
+
"PATCH",
|
|
233
|
+
"PUT",
|
|
234
|
+
"DELETE"
|
|
235
|
+
]),
|
|
236
|
+
defaultValue: "GET"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: "field",
|
|
240
|
+
short: "f",
|
|
241
|
+
description: "A query parameter as key=value, repeatable",
|
|
242
|
+
valueName: "key=value",
|
|
243
|
+
repeatable: true,
|
|
244
|
+
schema: z.array(z.string()).default([])
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
name: "input",
|
|
248
|
+
description: "A file holding the JSON request body, or - for stdin",
|
|
249
|
+
valueName: "file",
|
|
250
|
+
schema: z.string().optional()
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: "json",
|
|
254
|
+
description: "Print machine-readable output, which is the default when stdout is not a terminal",
|
|
255
|
+
schema: z.boolean().optional()
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
examples: [
|
|
259
|
+
{
|
|
260
|
+
description: "List customers",
|
|
261
|
+
command: "hardfin api /customer"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
description: "Take the second page",
|
|
265
|
+
command: "hardfin api /customer -f page=2 -f limit=50"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
description: "Change an item",
|
|
269
|
+
command: "hardfin api -X PATCH /item/item_V1StGXR8Z5jdHi6B --input body.json"
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
run: runApi
|
|
273
|
+
});
|
|
274
|
+
async function runApi(input) {
|
|
275
|
+
const apiKey = toApiKey();
|
|
276
|
+
if (!apiKey) {
|
|
277
|
+
writeFailure("not authenticated. Set HARDFIN_API_KEY to an API key for your organization", input.isJSON);
|
|
278
|
+
return ExitCode.NOT_AUTHENTICATED;
|
|
279
|
+
}
|
|
280
|
+
const path = input.args[0];
|
|
281
|
+
if (!path) {
|
|
282
|
+
writeFailure("a path is required, such as /customer", input.isJSON);
|
|
283
|
+
return ExitCode.USAGE;
|
|
284
|
+
}
|
|
285
|
+
const query = toQuery$1(input.flags["field"]);
|
|
286
|
+
if (query === void 0) {
|
|
287
|
+
writeFailure("each --field is key=value, such as -f limit=50", input.isJSON);
|
|
288
|
+
return ExitCode.USAGE;
|
|
289
|
+
}
|
|
290
|
+
let body;
|
|
291
|
+
if (typeof input.flags["input"] === "string") {
|
|
292
|
+
body = toBody$1(input.flags["input"]);
|
|
293
|
+
if (body === void 0) {
|
|
294
|
+
writeFailure(`${input.flags["input"]} does not hold JSON`, input.isJSON);
|
|
295
|
+
return ExitCode.USAGE;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
writeData((await request({
|
|
300
|
+
apiUrl: toApiUrl(),
|
|
301
|
+
apiKey,
|
|
302
|
+
method: String(input.flags["method"] ?? "GET").toUpperCase(),
|
|
303
|
+
path,
|
|
304
|
+
query,
|
|
305
|
+
body
|
|
306
|
+
})).data);
|
|
307
|
+
return ExitCode.OK;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (error instanceof RequestFailure) {
|
|
310
|
+
writeFailure(error.message, input.isJSON, error.errors, error.requestId);
|
|
311
|
+
return error.status === 401 ? ExitCode.NOT_AUTHENTICATED : ExitCode.ERROR;
|
|
312
|
+
}
|
|
313
|
+
writeFailure(error instanceof Error ? error.message : String(error), input.isJSON);
|
|
314
|
+
return ExitCode.ERROR;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/** toQuery folds the repeated --field flags into query parameters. */
|
|
318
|
+
function toQuery$1(fields) {
|
|
319
|
+
const query = new URLSearchParams();
|
|
320
|
+
for (const field of Array.isArray(fields) ? fields : []) {
|
|
321
|
+
const split = field.indexOf("=");
|
|
322
|
+
if (split < 1) return;
|
|
323
|
+
query.append(field.slice(0, split), field.slice(split + 1));
|
|
324
|
+
}
|
|
325
|
+
return query;
|
|
326
|
+
}
|
|
327
|
+
function toBody$1(source) {
|
|
328
|
+
const text = source === "-" ? readFileSync(0, "utf8") : readFileSync(source, "utf8");
|
|
329
|
+
try {
|
|
330
|
+
return JSON.parse(text);
|
|
331
|
+
} catch {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region src/command/operation.ts
|
|
337
|
+
const INPUT_FLAG = {
|
|
338
|
+
name: "input",
|
|
339
|
+
description: "A file holding the JSON request body, or - for stdin",
|
|
340
|
+
valueName: "file",
|
|
341
|
+
schema: z.string()
|
|
342
|
+
};
|
|
343
|
+
const JSON_FLAG = {
|
|
344
|
+
name: "json",
|
|
345
|
+
description: "Print machine-readable output, which is the default when stdout is not a terminal",
|
|
346
|
+
schema: z.boolean()
|
|
347
|
+
};
|
|
348
|
+
/** defineOperation turns one endpoint into the command that calls it. */
|
|
349
|
+
function defineOperation(operation) {
|
|
350
|
+
const flags = [...operation.queryFlags, JSON_FLAG];
|
|
351
|
+
if (operation.takesBody) flags.splice(flags.length - 1, 0, INPUT_FLAG);
|
|
352
|
+
return {
|
|
353
|
+
name: operation.name,
|
|
354
|
+
summary: operation.summary,
|
|
355
|
+
description: operation.description ?? operation.summary,
|
|
356
|
+
arguments: operation.pathParameters,
|
|
357
|
+
flags,
|
|
358
|
+
examples: [],
|
|
359
|
+
run: (input) => runOperation(operation, input)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
async function runOperation(operation, input) {
|
|
363
|
+
const apiKey = toApiKey();
|
|
364
|
+
if (!apiKey) {
|
|
365
|
+
writeFailure("not authenticated. Set HARDFIN_API_KEY to an API key for your organization", input.isJSON);
|
|
366
|
+
return ExitCode.NOT_AUTHENTICATED;
|
|
367
|
+
}
|
|
368
|
+
const path = toPath(operation, input.args);
|
|
369
|
+
if (path === void 0) {
|
|
370
|
+
writeFailure(`this command takes ${operation.pathParameters.length} argument(s)`, input.isJSON);
|
|
371
|
+
return ExitCode.USAGE;
|
|
372
|
+
}
|
|
373
|
+
let body;
|
|
374
|
+
if (typeof input.flags["input"] === "string") {
|
|
375
|
+
body = toBody(input.flags["input"]);
|
|
376
|
+
if (body === void 0) {
|
|
377
|
+
writeFailure(`${input.flags["input"]} does not hold JSON`, input.isJSON);
|
|
378
|
+
return ExitCode.USAGE;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
writeData((await request({
|
|
383
|
+
apiUrl: toApiUrl(),
|
|
384
|
+
apiKey,
|
|
385
|
+
method: operation.method,
|
|
386
|
+
path,
|
|
387
|
+
query: toQuery(operation, input.flags),
|
|
388
|
+
body
|
|
389
|
+
})).data);
|
|
390
|
+
return ExitCode.OK;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
if (error instanceof RequestFailure) {
|
|
393
|
+
writeFailure(error.message, input.isJSON, error.errors, error.requestId);
|
|
394
|
+
return error.status === 401 ? ExitCode.NOT_AUTHENTICATED : ExitCode.ERROR;
|
|
395
|
+
}
|
|
396
|
+
writeFailure(error instanceof Error ? error.message : String(error), input.isJSON);
|
|
397
|
+
return ExitCode.ERROR;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/** toPath fills the path template from the positional arguments, in order. */
|
|
401
|
+
function toPath(operation, args) {
|
|
402
|
+
if (args.length !== operation.pathParameters.length) return;
|
|
403
|
+
let path = operation.path;
|
|
404
|
+
for (const [index, parameter] of operation.pathParameters.entries()) path = path.replace(`{${parameter.name}}`, encodeURIComponent(args[index] ?? ""));
|
|
405
|
+
return path;
|
|
406
|
+
}
|
|
407
|
+
/** toQuery carries only the flags this invocation actually set. */
|
|
408
|
+
function toQuery(operation, flags) {
|
|
409
|
+
const query = new URLSearchParams();
|
|
410
|
+
for (const flag of operation.queryFlags) {
|
|
411
|
+
const value = flags[toOptionKey(flag.name)];
|
|
412
|
+
if (value === void 0) continue;
|
|
413
|
+
for (const entry of Array.isArray(value) ? value : [value]) query.append(flag.queryName, String(entry));
|
|
414
|
+
}
|
|
415
|
+
return query;
|
|
416
|
+
}
|
|
417
|
+
/** toOptionKey names the parsed flag, which the parser reports in camel case. */
|
|
418
|
+
function toOptionKey(name) {
|
|
419
|
+
return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
420
|
+
}
|
|
421
|
+
function toBody(source) {
|
|
422
|
+
const text = source === "-" ? readFileSync(0, "utf8") : readFileSync(source, "utf8");
|
|
423
|
+
try {
|
|
424
|
+
return JSON.parse(text);
|
|
425
|
+
} catch {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
430
|
+
//#region src/command/commands.ts
|
|
431
|
+
/** commands is every command the CLI offers, and drives help and the agent guide. */
|
|
432
|
+
const commands = [
|
|
433
|
+
...[
|
|
434
|
+
{
|
|
435
|
+
name: "asset",
|
|
436
|
+
summary: "Asset commands",
|
|
437
|
+
arguments: [],
|
|
438
|
+
flags: [],
|
|
439
|
+
examples: [],
|
|
440
|
+
subcommands: [
|
|
441
|
+
defineOperation({
|
|
442
|
+
name: "list",
|
|
443
|
+
summary: "Get asset listing",
|
|
444
|
+
method: "GET",
|
|
445
|
+
path: "/asset",
|
|
446
|
+
pathParameters: [],
|
|
447
|
+
queryFlags: [
|
|
448
|
+
{
|
|
449
|
+
name: "page",
|
|
450
|
+
queryName: "page",
|
|
451
|
+
description: "The page to return, starting at 1",
|
|
452
|
+
valueName: "number",
|
|
453
|
+
schema: z.coerce.number()
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
name: "limit",
|
|
457
|
+
queryName: "limit",
|
|
458
|
+
description: "The number of records per page, from 1 to 100",
|
|
459
|
+
valueName: "number",
|
|
460
|
+
schema: z.coerce.number()
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
name: "sort-by",
|
|
464
|
+
queryName: "sortBy",
|
|
465
|
+
description: "The field to sort by",
|
|
466
|
+
valueName: "value",
|
|
467
|
+
schema: z.enum([
|
|
468
|
+
"serial",
|
|
469
|
+
"project",
|
|
470
|
+
"item",
|
|
471
|
+
"location",
|
|
472
|
+
"owner",
|
|
473
|
+
"activity"
|
|
474
|
+
])
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: "sort-order",
|
|
478
|
+
queryName: "sortOrder",
|
|
479
|
+
description: "The sort direction",
|
|
480
|
+
valueName: "value",
|
|
481
|
+
schema: z.enum(["ASC", "DESC"])
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
name: "archived",
|
|
485
|
+
queryName: "archived",
|
|
486
|
+
description: "Whether to return unarchived records, archived records, or all of them",
|
|
487
|
+
valueName: "value",
|
|
488
|
+
schema: z.enum([
|
|
489
|
+
"all",
|
|
490
|
+
"false",
|
|
491
|
+
"true"
|
|
492
|
+
])
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
name: "search-query",
|
|
496
|
+
queryName: "searchQuery",
|
|
497
|
+
description: "Text to match against the serial, description, item, project, owner, and location, ignored when shorter than three characters",
|
|
498
|
+
valueName: "value",
|
|
499
|
+
schema: z.string()
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "for-asset-id",
|
|
503
|
+
queryName: "forAssetId",
|
|
504
|
+
description: "The IDs of the assets to list",
|
|
505
|
+
valueName: "value",
|
|
506
|
+
repeatable: true,
|
|
507
|
+
schema: z.array(z.string())
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
name: "for-asset-key",
|
|
511
|
+
queryName: "forAssetKey",
|
|
512
|
+
description: "The keys of the assets to list",
|
|
513
|
+
valueName: "value",
|
|
514
|
+
repeatable: true,
|
|
515
|
+
schema: z.array(z.string())
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: "for-customer",
|
|
519
|
+
queryName: "forCustomer",
|
|
520
|
+
description: "The IDs of the customers whose assets to list",
|
|
521
|
+
valueName: "value",
|
|
522
|
+
repeatable: true,
|
|
523
|
+
schema: z.array(z.string())
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
name: "for-item",
|
|
527
|
+
queryName: "forItem",
|
|
528
|
+
description: "The IDs of the items whose assets to list",
|
|
529
|
+
valueName: "value",
|
|
530
|
+
repeatable: true,
|
|
531
|
+
schema: z.array(z.string())
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: "at-site",
|
|
535
|
+
queryName: "atSite",
|
|
536
|
+
description: "The IDs of the locations whose assets to list",
|
|
537
|
+
valueName: "value",
|
|
538
|
+
repeatable: true,
|
|
539
|
+
schema: z.array(z.string())
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
name: "at-customer-sites",
|
|
543
|
+
queryName: "atCustomerSites",
|
|
544
|
+
description: "The IDs of the customers whose sites to list assets at",
|
|
545
|
+
valueName: "value",
|
|
546
|
+
repeatable: true,
|
|
547
|
+
schema: z.array(z.string())
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
name: "with-functional-statuses",
|
|
551
|
+
queryName: "withFunctionalStatuses",
|
|
552
|
+
description: "The functional statuses to list, where SCRAPPED lists scrapped assets",
|
|
553
|
+
valueName: "value",
|
|
554
|
+
repeatable: true,
|
|
555
|
+
schema: z.array(z.enum([
|
|
556
|
+
"FUNCTIONAL",
|
|
557
|
+
"NEEDS_REVIEW",
|
|
558
|
+
"NON-FUNCTIONAL",
|
|
559
|
+
"SCRAPPED"
|
|
560
|
+
]))
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
name: "with-transit-statuses",
|
|
564
|
+
queryName: "withTransitStatuses",
|
|
565
|
+
description: "The transit statuses to list",
|
|
566
|
+
valueName: "value",
|
|
567
|
+
repeatable: true,
|
|
568
|
+
schema: z.array(z.enum([
|
|
569
|
+
"IN_TRANSIT",
|
|
570
|
+
"IN_TRANSIT_TO_FIELD",
|
|
571
|
+
"IN_TRANSIT_TO_INVENTORY",
|
|
572
|
+
"NOT_IN_TRANSIT"
|
|
573
|
+
]))
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
name: "with-inventory-statuses",
|
|
577
|
+
queryName: "withInventoryStatuses",
|
|
578
|
+
description: "In_inventory, not_in_inventory, or both, which filters only when one is sent",
|
|
579
|
+
valueName: "value",
|
|
580
|
+
repeatable: true,
|
|
581
|
+
schema: z.array(z.string())
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
name: "with-location-company-type",
|
|
585
|
+
queryName: "withLocationCompanyType",
|
|
586
|
+
description: "Customer, manufacturer, or both, for assets at customer sites or your own, which filters only when one is sent",
|
|
587
|
+
valueName: "value",
|
|
588
|
+
repeatable: true,
|
|
589
|
+
schema: z.array(z.string())
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
name: "with-project-status",
|
|
593
|
+
queryName: "withProjectStatus",
|
|
594
|
+
description: "The project assignments to list: upcoming, active, past, or none",
|
|
595
|
+
valueName: "value",
|
|
596
|
+
repeatable: true,
|
|
597
|
+
schema: z.array(z.string())
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
name: "with-owner",
|
|
601
|
+
queryName: "withOwner",
|
|
602
|
+
description: "Manufacturer for assets your organization owns, customer for assets customers own, or both",
|
|
603
|
+
valueName: "value",
|
|
604
|
+
repeatable: true,
|
|
605
|
+
schema: z.array(z.string())
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
name: "for-project",
|
|
609
|
+
queryName: "forProject",
|
|
610
|
+
description: "The IDs of the projects whose assets to list",
|
|
611
|
+
valueName: "value",
|
|
612
|
+
repeatable: true,
|
|
613
|
+
schema: z.array(z.string())
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
name: "scrapped",
|
|
617
|
+
queryName: "scrapped",
|
|
618
|
+
description: "Whether to list unscrapped assets, scrapped assets, or all of them",
|
|
619
|
+
valueName: "value",
|
|
620
|
+
schema: z.enum([
|
|
621
|
+
"all",
|
|
622
|
+
"false",
|
|
623
|
+
"true"
|
|
624
|
+
])
|
|
625
|
+
}
|
|
626
|
+
],
|
|
627
|
+
takesBody: false
|
|
628
|
+
}),
|
|
629
|
+
defineOperation({
|
|
630
|
+
name: "create",
|
|
631
|
+
summary: "Create asset",
|
|
632
|
+
method: "POST",
|
|
633
|
+
path: "/asset",
|
|
634
|
+
pathParameters: [],
|
|
635
|
+
queryFlags: [],
|
|
636
|
+
takesBody: true
|
|
637
|
+
}),
|
|
638
|
+
defineOperation({
|
|
639
|
+
name: "get",
|
|
640
|
+
summary: "Get asset",
|
|
641
|
+
method: "GET",
|
|
642
|
+
path: "/asset/{assetKey}",
|
|
643
|
+
pathParameters: [{
|
|
644
|
+
name: "assetKey",
|
|
645
|
+
description: "The asset's key",
|
|
646
|
+
required: true
|
|
647
|
+
}],
|
|
648
|
+
queryFlags: [],
|
|
649
|
+
takesBody: false
|
|
650
|
+
}),
|
|
651
|
+
defineOperation({
|
|
652
|
+
name: "update",
|
|
653
|
+
summary: "Patch asset",
|
|
654
|
+
method: "PATCH",
|
|
655
|
+
path: "/asset/{assetKey}",
|
|
656
|
+
pathParameters: [{
|
|
657
|
+
name: "assetKey",
|
|
658
|
+
description: "The asset's key",
|
|
659
|
+
required: true
|
|
660
|
+
}],
|
|
661
|
+
queryFlags: [],
|
|
662
|
+
takesBody: true
|
|
663
|
+
}),
|
|
664
|
+
{
|
|
665
|
+
name: "accounting",
|
|
666
|
+
summary: "Accounting commands",
|
|
667
|
+
arguments: [],
|
|
668
|
+
flags: [],
|
|
669
|
+
examples: [],
|
|
670
|
+
subcommands: [defineOperation({
|
|
671
|
+
name: "update",
|
|
672
|
+
summary: "Update asset accounting",
|
|
673
|
+
method: "PATCH",
|
|
674
|
+
path: "/asset/{assetKey}/accounting",
|
|
675
|
+
pathParameters: [{
|
|
676
|
+
name: "assetKey",
|
|
677
|
+
description: "The asset's key",
|
|
678
|
+
required: true
|
|
679
|
+
}],
|
|
680
|
+
queryFlags: [],
|
|
681
|
+
takesBody: true
|
|
682
|
+
}), {
|
|
683
|
+
name: "in-service-management",
|
|
684
|
+
summary: "In service management commands",
|
|
685
|
+
arguments: [],
|
|
686
|
+
flags: [],
|
|
687
|
+
examples: [],
|
|
688
|
+
subcommands: [defineOperation({
|
|
689
|
+
name: "update",
|
|
690
|
+
summary: "Toggle in service date management",
|
|
691
|
+
method: "PATCH",
|
|
692
|
+
path: "/asset/{assetKey}/accounting/in-service-management",
|
|
693
|
+
pathParameters: [{
|
|
694
|
+
name: "assetKey",
|
|
695
|
+
description: "The asset's key",
|
|
696
|
+
required: true
|
|
697
|
+
}],
|
|
698
|
+
queryFlags: [],
|
|
699
|
+
takesBody: true
|
|
700
|
+
})]
|
|
701
|
+
}]
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
name: "cost-adjustment",
|
|
705
|
+
summary: "Cost adjustment commands",
|
|
706
|
+
arguments: [],
|
|
707
|
+
flags: [],
|
|
708
|
+
examples: [],
|
|
709
|
+
subcommands: [defineOperation({
|
|
710
|
+
name: "create",
|
|
711
|
+
summary: "Create asset cost adjustment",
|
|
712
|
+
method: "POST",
|
|
713
|
+
path: "/asset/{assetKey}/cost-adjustment",
|
|
714
|
+
pathParameters: [{
|
|
715
|
+
name: "assetKey",
|
|
716
|
+
description: "The asset's key",
|
|
717
|
+
required: true
|
|
718
|
+
}],
|
|
719
|
+
queryFlags: [],
|
|
720
|
+
takesBody: true
|
|
721
|
+
})]
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
name: "file",
|
|
725
|
+
summary: "File commands",
|
|
726
|
+
arguments: [],
|
|
727
|
+
flags: [],
|
|
728
|
+
examples: [],
|
|
729
|
+
subcommands: [defineOperation({
|
|
730
|
+
name: "list",
|
|
731
|
+
summary: "Get asset files",
|
|
732
|
+
method: "GET",
|
|
733
|
+
path: "/asset/{assetKey}/file",
|
|
734
|
+
pathParameters: [{
|
|
735
|
+
name: "assetKey",
|
|
736
|
+
description: "The asset's key",
|
|
737
|
+
required: true
|
|
738
|
+
}],
|
|
739
|
+
queryFlags: [],
|
|
740
|
+
takesBody: false
|
|
741
|
+
}), defineOperation({
|
|
742
|
+
name: "delete",
|
|
743
|
+
summary: "Delete asset file",
|
|
744
|
+
method: "DELETE",
|
|
745
|
+
path: "/asset/{assetKey}/file/{fileKey}",
|
|
746
|
+
pathParameters: [{
|
|
747
|
+
name: "assetKey",
|
|
748
|
+
description: "The asset's key",
|
|
749
|
+
required: true
|
|
750
|
+
}, {
|
|
751
|
+
name: "fileKey",
|
|
752
|
+
description: "The file's key",
|
|
753
|
+
required: true
|
|
754
|
+
}],
|
|
755
|
+
queryFlags: [],
|
|
756
|
+
takesBody: false
|
|
757
|
+
})]
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
name: "ownership",
|
|
761
|
+
summary: "Ownership commands",
|
|
762
|
+
arguments: [],
|
|
763
|
+
flags: [],
|
|
764
|
+
examples: [],
|
|
765
|
+
subcommands: [
|
|
766
|
+
defineOperation({
|
|
767
|
+
name: "list",
|
|
768
|
+
summary: "Get asset ownership history",
|
|
769
|
+
method: "GET",
|
|
770
|
+
path: "/asset/{assetKey}/ownership",
|
|
771
|
+
pathParameters: [{
|
|
772
|
+
name: "assetKey",
|
|
773
|
+
description: "The asset's key",
|
|
774
|
+
required: true
|
|
775
|
+
}],
|
|
776
|
+
queryFlags: [],
|
|
777
|
+
takesBody: false
|
|
778
|
+
}),
|
|
779
|
+
defineOperation({
|
|
780
|
+
name: "create",
|
|
781
|
+
summary: "Create asset ownership",
|
|
782
|
+
method: "POST",
|
|
783
|
+
path: "/asset/{assetKey}/ownership",
|
|
784
|
+
pathParameters: [{
|
|
785
|
+
name: "assetKey",
|
|
786
|
+
description: "The asset's key",
|
|
787
|
+
required: true
|
|
788
|
+
}],
|
|
789
|
+
queryFlags: [],
|
|
790
|
+
takesBody: true
|
|
791
|
+
}),
|
|
792
|
+
defineOperation({
|
|
793
|
+
name: "clear",
|
|
794
|
+
summary: "Clear the ownership an asset holds today",
|
|
795
|
+
method: "DELETE",
|
|
796
|
+
path: "/asset/{assetKey}/ownership",
|
|
797
|
+
pathParameters: [{
|
|
798
|
+
name: "assetKey",
|
|
799
|
+
description: "The asset's key",
|
|
800
|
+
required: true
|
|
801
|
+
}],
|
|
802
|
+
queryFlags: [],
|
|
803
|
+
takesBody: true
|
|
804
|
+
}),
|
|
805
|
+
defineOperation({
|
|
806
|
+
name: "get",
|
|
807
|
+
summary: "Get asset ownership segment",
|
|
808
|
+
method: "GET",
|
|
809
|
+
path: "/asset/{assetKey}/ownership/{segmentKey}",
|
|
810
|
+
pathParameters: [{
|
|
811
|
+
name: "assetKey",
|
|
812
|
+
description: "The asset's key",
|
|
813
|
+
required: true
|
|
814
|
+
}, {
|
|
815
|
+
name: "segmentKey",
|
|
816
|
+
description: "The ownership segment's key",
|
|
817
|
+
required: true
|
|
818
|
+
}],
|
|
819
|
+
queryFlags: [],
|
|
820
|
+
takesBody: false
|
|
821
|
+
}),
|
|
822
|
+
defineOperation({
|
|
823
|
+
name: "update",
|
|
824
|
+
summary: "Patch asset ownership segment",
|
|
825
|
+
method: "PATCH",
|
|
826
|
+
path: "/asset/{assetKey}/ownership/{segmentKey}",
|
|
827
|
+
pathParameters: [{
|
|
828
|
+
name: "assetKey",
|
|
829
|
+
description: "The asset's key",
|
|
830
|
+
required: true
|
|
831
|
+
}, {
|
|
832
|
+
name: "segmentKey",
|
|
833
|
+
description: "The ownership segment's key",
|
|
834
|
+
required: true
|
|
835
|
+
}],
|
|
836
|
+
queryFlags: [],
|
|
837
|
+
takesBody: true
|
|
838
|
+
}),
|
|
839
|
+
defineOperation({
|
|
840
|
+
name: "delete",
|
|
841
|
+
summary: "Delete asset ownership segment",
|
|
842
|
+
method: "DELETE",
|
|
843
|
+
path: "/asset/{assetKey}/ownership/{segmentKey}",
|
|
844
|
+
pathParameters: [{
|
|
845
|
+
name: "assetKey",
|
|
846
|
+
description: "The asset's key",
|
|
847
|
+
required: true
|
|
848
|
+
}, {
|
|
849
|
+
name: "segmentKey",
|
|
850
|
+
description: "The ownership segment's key",
|
|
851
|
+
required: true
|
|
852
|
+
}],
|
|
853
|
+
queryFlags: [],
|
|
854
|
+
takesBody: false
|
|
855
|
+
})
|
|
856
|
+
]
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
name: "url-link",
|
|
860
|
+
summary: "URL link commands",
|
|
861
|
+
arguments: [],
|
|
862
|
+
flags: [],
|
|
863
|
+
examples: [],
|
|
864
|
+
subcommands: [defineOperation({
|
|
865
|
+
name: "list",
|
|
866
|
+
summary: "Get asset URL links",
|
|
867
|
+
method: "GET",
|
|
868
|
+
path: "/asset/{assetKey}/url-link",
|
|
869
|
+
pathParameters: [{
|
|
870
|
+
name: "assetKey",
|
|
871
|
+
description: "The asset's key",
|
|
872
|
+
required: true
|
|
873
|
+
}],
|
|
874
|
+
queryFlags: [],
|
|
875
|
+
takesBody: false
|
|
876
|
+
}), defineOperation({
|
|
877
|
+
name: "create",
|
|
878
|
+
summary: "Create asset URL link",
|
|
879
|
+
method: "POST",
|
|
880
|
+
path: "/asset/{assetKey}/url-link",
|
|
881
|
+
pathParameters: [{
|
|
882
|
+
name: "assetKey",
|
|
883
|
+
description: "The asset's key",
|
|
884
|
+
required: true
|
|
885
|
+
}],
|
|
886
|
+
queryFlags: [],
|
|
887
|
+
takesBody: true
|
|
888
|
+
})]
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
name: "useful-life-revision",
|
|
892
|
+
summary: "Useful life revision commands",
|
|
893
|
+
arguments: [],
|
|
894
|
+
flags: [],
|
|
895
|
+
examples: [],
|
|
896
|
+
subcommands: [defineOperation({
|
|
897
|
+
name: "create",
|
|
898
|
+
summary: "Create asset useful life revision",
|
|
899
|
+
method: "POST",
|
|
900
|
+
path: "/asset/{assetKey}/useful-life-revision",
|
|
901
|
+
pathParameters: [{
|
|
902
|
+
name: "assetKey",
|
|
903
|
+
description: "The asset's key",
|
|
904
|
+
required: true
|
|
905
|
+
}],
|
|
906
|
+
queryFlags: [],
|
|
907
|
+
takesBody: true
|
|
908
|
+
})]
|
|
909
|
+
}
|
|
910
|
+
]
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
name: "customer",
|
|
914
|
+
summary: "Customer commands",
|
|
915
|
+
arguments: [],
|
|
916
|
+
flags: [],
|
|
917
|
+
examples: [],
|
|
918
|
+
subcommands: [
|
|
919
|
+
defineOperation({
|
|
920
|
+
name: "list",
|
|
921
|
+
summary: "Get customers",
|
|
922
|
+
method: "GET",
|
|
923
|
+
path: "/customer",
|
|
924
|
+
pathParameters: [],
|
|
925
|
+
queryFlags: [
|
|
926
|
+
{
|
|
927
|
+
name: "page",
|
|
928
|
+
queryName: "page",
|
|
929
|
+
description: "The page to return, starting at 1",
|
|
930
|
+
valueName: "number",
|
|
931
|
+
schema: z.coerce.number()
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
name: "limit",
|
|
935
|
+
queryName: "limit",
|
|
936
|
+
description: "The number of records per page, from 1 to 100",
|
|
937
|
+
valueName: "number",
|
|
938
|
+
schema: z.coerce.number()
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
name: "sort-by",
|
|
942
|
+
queryName: "sortBy",
|
|
943
|
+
description: "The field to sort by",
|
|
944
|
+
valueName: "value",
|
|
945
|
+
schema: z.string()
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
name: "sort-order",
|
|
949
|
+
queryName: "sortOrder",
|
|
950
|
+
description: "The sort direction",
|
|
951
|
+
valueName: "value",
|
|
952
|
+
schema: z.enum(["ASC", "DESC"])
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
name: "archived",
|
|
956
|
+
queryName: "archived",
|
|
957
|
+
description: "Whether to return unarchived records, archived records, or all of them",
|
|
958
|
+
valueName: "value",
|
|
959
|
+
schema: z.enum([
|
|
960
|
+
"all",
|
|
961
|
+
"false",
|
|
962
|
+
"true"
|
|
963
|
+
])
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
name: "is-customer",
|
|
967
|
+
queryName: "isCustomer",
|
|
968
|
+
description: "True to return only customers, or false to return only non-customers",
|
|
969
|
+
schema: z.boolean()
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
name: "is-supplier",
|
|
973
|
+
queryName: "isSupplier",
|
|
974
|
+
description: "True to return only suppliers, or false to return only non-suppliers",
|
|
975
|
+
schema: z.boolean()
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
name: "sync-statuses",
|
|
979
|
+
queryName: "syncStatuses",
|
|
980
|
+
description: "The CRM sync statuses to return: in-sync, out-of-sync, or not-linked",
|
|
981
|
+
valueName: "value",
|
|
982
|
+
repeatable: true,
|
|
983
|
+
schema: z.array(z.string())
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
name: "search",
|
|
987
|
+
queryName: "search",
|
|
988
|
+
description: "Text to match against customer names",
|
|
989
|
+
valueName: "value",
|
|
990
|
+
schema: z.string()
|
|
991
|
+
}
|
|
992
|
+
],
|
|
993
|
+
takesBody: false
|
|
994
|
+
}),
|
|
995
|
+
defineOperation({
|
|
996
|
+
name: "create",
|
|
997
|
+
summary: "Create customer",
|
|
998
|
+
method: "POST",
|
|
999
|
+
path: "/customer",
|
|
1000
|
+
pathParameters: [],
|
|
1001
|
+
queryFlags: [],
|
|
1002
|
+
takesBody: true
|
|
1003
|
+
}),
|
|
1004
|
+
defineOperation({
|
|
1005
|
+
name: "get",
|
|
1006
|
+
summary: "Get customer",
|
|
1007
|
+
method: "GET",
|
|
1008
|
+
path: "/customer/{customerKey}",
|
|
1009
|
+
pathParameters: [{
|
|
1010
|
+
name: "customerKey",
|
|
1011
|
+
description: "The customer's key",
|
|
1012
|
+
required: true
|
|
1013
|
+
}],
|
|
1014
|
+
queryFlags: [],
|
|
1015
|
+
takesBody: false
|
|
1016
|
+
}),
|
|
1017
|
+
defineOperation({
|
|
1018
|
+
name: "update",
|
|
1019
|
+
summary: "Patch customer",
|
|
1020
|
+
method: "PATCH",
|
|
1021
|
+
path: "/customer/{customerKey}",
|
|
1022
|
+
pathParameters: [{
|
|
1023
|
+
name: "customerKey",
|
|
1024
|
+
description: "The customer's key",
|
|
1025
|
+
required: true
|
|
1026
|
+
}],
|
|
1027
|
+
queryFlags: [],
|
|
1028
|
+
takesBody: true
|
|
1029
|
+
})
|
|
1030
|
+
]
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
name: "file",
|
|
1034
|
+
summary: "File commands",
|
|
1035
|
+
arguments: [],
|
|
1036
|
+
flags: [],
|
|
1037
|
+
examples: [],
|
|
1038
|
+
subcommands: [defineOperation({
|
|
1039
|
+
name: "create",
|
|
1040
|
+
summary: "Upload file",
|
|
1041
|
+
method: "POST",
|
|
1042
|
+
path: "/file",
|
|
1043
|
+
pathParameters: [],
|
|
1044
|
+
queryFlags: [],
|
|
1045
|
+
takesBody: true
|
|
1046
|
+
}), defineOperation({
|
|
1047
|
+
name: "get",
|
|
1048
|
+
summary: "Get file",
|
|
1049
|
+
method: "GET",
|
|
1050
|
+
path: "/file/{fileKey}",
|
|
1051
|
+
pathParameters: [{
|
|
1052
|
+
name: "fileKey",
|
|
1053
|
+
description: "The file's key, and a public file is readable with any organization's API key while any other file is readable only with its own organization's",
|
|
1054
|
+
required: true
|
|
1055
|
+
}],
|
|
1056
|
+
queryFlags: [{
|
|
1057
|
+
name: "attachment",
|
|
1058
|
+
queryName: "attachment",
|
|
1059
|
+
description: "Present, with any value or none, when the file should download as an attachment rather than open inline",
|
|
1060
|
+
valueName: "value",
|
|
1061
|
+
schema: z.string()
|
|
1062
|
+
}],
|
|
1063
|
+
takesBody: false
|
|
1064
|
+
})]
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
name: "item",
|
|
1068
|
+
summary: "Item commands",
|
|
1069
|
+
arguments: [],
|
|
1070
|
+
flags: [],
|
|
1071
|
+
examples: [],
|
|
1072
|
+
subcommands: [
|
|
1073
|
+
defineOperation({
|
|
1074
|
+
name: "list",
|
|
1075
|
+
summary: "Get items",
|
|
1076
|
+
method: "GET",
|
|
1077
|
+
path: "/item",
|
|
1078
|
+
pathParameters: [],
|
|
1079
|
+
queryFlags: [
|
|
1080
|
+
{
|
|
1081
|
+
name: "type",
|
|
1082
|
+
queryName: "type",
|
|
1083
|
+
description: "The item type to list, SERVICE, DEVICE, or BULK, or absent for every type",
|
|
1084
|
+
valueName: "value",
|
|
1085
|
+
schema: z.enum([
|
|
1086
|
+
"BULK",
|
|
1087
|
+
"DEVICE",
|
|
1088
|
+
"SERVICE"
|
|
1089
|
+
])
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
name: "search",
|
|
1093
|
+
queryName: "search",
|
|
1094
|
+
description: "Text to match against item names, SKUs, and descriptions, in any case",
|
|
1095
|
+
valueName: "value",
|
|
1096
|
+
schema: z.string()
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
name: "page",
|
|
1100
|
+
queryName: "page",
|
|
1101
|
+
description: "The page to return, starting at 1",
|
|
1102
|
+
valueName: "number",
|
|
1103
|
+
schema: z.coerce.number()
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
name: "limit",
|
|
1107
|
+
queryName: "limit",
|
|
1108
|
+
description: "The number of records per page, from 1 to 100",
|
|
1109
|
+
valueName: "number",
|
|
1110
|
+
schema: z.coerce.number()
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
name: "sort-by",
|
|
1114
|
+
queryName: "sortBy",
|
|
1115
|
+
description: "The field to sort by",
|
|
1116
|
+
valueName: "value",
|
|
1117
|
+
schema: z.enum([
|
|
1118
|
+
"name",
|
|
1119
|
+
"sku",
|
|
1120
|
+
"type",
|
|
1121
|
+
"lastUpdatedAt"
|
|
1122
|
+
])
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
name: "sort-order",
|
|
1126
|
+
queryName: "sortOrder",
|
|
1127
|
+
description: "The sort direction",
|
|
1128
|
+
valueName: "value",
|
|
1129
|
+
schema: z.enum(["ASC", "DESC"])
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
name: "archived",
|
|
1133
|
+
queryName: "archived",
|
|
1134
|
+
description: "Whether to return unarchived records, archived records, or all of them",
|
|
1135
|
+
valueName: "value",
|
|
1136
|
+
schema: z.enum([
|
|
1137
|
+
"all",
|
|
1138
|
+
"false",
|
|
1139
|
+
"true"
|
|
1140
|
+
])
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
name: "exclude-linked-integration",
|
|
1144
|
+
queryName: "excludeLinkedIntegration",
|
|
1145
|
+
description: "An integration whose already-linked items to leave out",
|
|
1146
|
+
valueName: "value",
|
|
1147
|
+
schema: z.string()
|
|
1148
|
+
}
|
|
1149
|
+
],
|
|
1150
|
+
takesBody: false
|
|
1151
|
+
}),
|
|
1152
|
+
defineOperation({
|
|
1153
|
+
name: "create",
|
|
1154
|
+
summary: "Create item",
|
|
1155
|
+
method: "POST",
|
|
1156
|
+
path: "/item",
|
|
1157
|
+
pathParameters: [],
|
|
1158
|
+
queryFlags: [],
|
|
1159
|
+
takesBody: true
|
|
1160
|
+
}),
|
|
1161
|
+
defineOperation({
|
|
1162
|
+
name: "get",
|
|
1163
|
+
summary: "Get item",
|
|
1164
|
+
method: "GET",
|
|
1165
|
+
path: "/item/{itemKey}",
|
|
1166
|
+
pathParameters: [{
|
|
1167
|
+
name: "itemKey",
|
|
1168
|
+
description: "The item's key",
|
|
1169
|
+
required: true
|
|
1170
|
+
}],
|
|
1171
|
+
queryFlags: [],
|
|
1172
|
+
takesBody: false
|
|
1173
|
+
}),
|
|
1174
|
+
defineOperation({
|
|
1175
|
+
name: "update",
|
|
1176
|
+
summary: "Update item",
|
|
1177
|
+
method: "PATCH",
|
|
1178
|
+
path: "/item/{itemKey}",
|
|
1179
|
+
pathParameters: [{
|
|
1180
|
+
name: "itemKey",
|
|
1181
|
+
description: "The item's key",
|
|
1182
|
+
required: true
|
|
1183
|
+
}],
|
|
1184
|
+
queryFlags: [],
|
|
1185
|
+
takesBody: true
|
|
1186
|
+
}),
|
|
1187
|
+
{
|
|
1188
|
+
name: "accounting",
|
|
1189
|
+
summary: "Accounting commands",
|
|
1190
|
+
arguments: [],
|
|
1191
|
+
flags: [],
|
|
1192
|
+
examples: [],
|
|
1193
|
+
subcommands: [defineOperation({
|
|
1194
|
+
name: "update",
|
|
1195
|
+
summary: "Update item accounting",
|
|
1196
|
+
method: "PATCH",
|
|
1197
|
+
path: "/item/{itemKey}/accounting",
|
|
1198
|
+
pathParameters: [{
|
|
1199
|
+
name: "itemKey",
|
|
1200
|
+
description: "The item's key",
|
|
1201
|
+
required: true
|
|
1202
|
+
}],
|
|
1203
|
+
queryFlags: [],
|
|
1204
|
+
takesBody: true
|
|
1205
|
+
})]
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
name: "field",
|
|
1209
|
+
summary: "Field commands",
|
|
1210
|
+
arguments: [],
|
|
1211
|
+
flags: [],
|
|
1212
|
+
examples: [],
|
|
1213
|
+
subcommands: [
|
|
1214
|
+
defineOperation({
|
|
1215
|
+
name: "create",
|
|
1216
|
+
summary: "Create item field",
|
|
1217
|
+
method: "POST",
|
|
1218
|
+
path: "/item/{itemKey}/field",
|
|
1219
|
+
pathParameters: [{
|
|
1220
|
+
name: "itemKey",
|
|
1221
|
+
description: "The item's key",
|
|
1222
|
+
required: true
|
|
1223
|
+
}],
|
|
1224
|
+
queryFlags: [],
|
|
1225
|
+
takesBody: true
|
|
1226
|
+
}),
|
|
1227
|
+
defineOperation({
|
|
1228
|
+
name: "update",
|
|
1229
|
+
summary: "Update item field",
|
|
1230
|
+
method: "PATCH",
|
|
1231
|
+
path: "/item/{itemKey}/field/{fieldKey}",
|
|
1232
|
+
pathParameters: [{
|
|
1233
|
+
name: "itemKey",
|
|
1234
|
+
description: "The item's key",
|
|
1235
|
+
required: true
|
|
1236
|
+
}, {
|
|
1237
|
+
name: "fieldKey",
|
|
1238
|
+
description: "The field's key",
|
|
1239
|
+
required: true
|
|
1240
|
+
}],
|
|
1241
|
+
queryFlags: [],
|
|
1242
|
+
takesBody: true
|
|
1243
|
+
}),
|
|
1244
|
+
defineOperation({
|
|
1245
|
+
name: "delete",
|
|
1246
|
+
summary: "Delete item field",
|
|
1247
|
+
method: "DELETE",
|
|
1248
|
+
path: "/item/{itemKey}/field/{fieldKey}",
|
|
1249
|
+
pathParameters: [{
|
|
1250
|
+
name: "itemKey",
|
|
1251
|
+
description: "The item's key",
|
|
1252
|
+
required: true
|
|
1253
|
+
}, {
|
|
1254
|
+
name: "fieldKey",
|
|
1255
|
+
description: "The field's key",
|
|
1256
|
+
required: true
|
|
1257
|
+
}],
|
|
1258
|
+
queryFlags: [],
|
|
1259
|
+
takesBody: false
|
|
1260
|
+
})
|
|
1261
|
+
]
|
|
1262
|
+
}
|
|
1263
|
+
]
|
|
1264
|
+
},
|
|
1265
|
+
{
|
|
1266
|
+
name: "location",
|
|
1267
|
+
summary: "Location commands",
|
|
1268
|
+
arguments: [],
|
|
1269
|
+
flags: [],
|
|
1270
|
+
examples: [],
|
|
1271
|
+
subcommands: [
|
|
1272
|
+
defineOperation({
|
|
1273
|
+
name: "list",
|
|
1274
|
+
summary: "Get location listing",
|
|
1275
|
+
method: "GET",
|
|
1276
|
+
path: "/location",
|
|
1277
|
+
pathParameters: [],
|
|
1278
|
+
queryFlags: [
|
|
1279
|
+
{
|
|
1280
|
+
name: "page",
|
|
1281
|
+
queryName: "page",
|
|
1282
|
+
description: "The page to return, starting at 1",
|
|
1283
|
+
valueName: "number",
|
|
1284
|
+
schema: z.coerce.number()
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
name: "limit",
|
|
1288
|
+
queryName: "limit",
|
|
1289
|
+
description: "The number of records per page, from 1 to 100",
|
|
1290
|
+
valueName: "number",
|
|
1291
|
+
schema: z.coerce.number()
|
|
1292
|
+
},
|
|
1293
|
+
{
|
|
1294
|
+
name: "sort-by",
|
|
1295
|
+
queryName: "sortBy",
|
|
1296
|
+
description: "The field to sort by",
|
|
1297
|
+
valueName: "value",
|
|
1298
|
+
schema: z.enum([
|
|
1299
|
+
"name",
|
|
1300
|
+
"company",
|
|
1301
|
+
"assetCount"
|
|
1302
|
+
])
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
name: "sort-order",
|
|
1306
|
+
queryName: "sortOrder",
|
|
1307
|
+
description: "The sort direction",
|
|
1308
|
+
valueName: "value",
|
|
1309
|
+
schema: z.enum(["ASC", "DESC"])
|
|
1310
|
+
},
|
|
1311
|
+
{
|
|
1312
|
+
name: "archived",
|
|
1313
|
+
queryName: "archived",
|
|
1314
|
+
description: "Whether to return unarchived records, archived records, or all of them",
|
|
1315
|
+
valueName: "value",
|
|
1316
|
+
schema: z.enum([
|
|
1317
|
+
"all",
|
|
1318
|
+
"false",
|
|
1319
|
+
"true"
|
|
1320
|
+
])
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
name: "is-transient",
|
|
1324
|
+
queryName: "isTransient",
|
|
1325
|
+
description: "Whether to return permanent locations (false), transient locations (true), or both (all)",
|
|
1326
|
+
valueName: "value",
|
|
1327
|
+
schema: z.enum([
|
|
1328
|
+
"all",
|
|
1329
|
+
"false",
|
|
1330
|
+
"true"
|
|
1331
|
+
])
|
|
1332
|
+
},
|
|
1333
|
+
{
|
|
1334
|
+
name: "search",
|
|
1335
|
+
queryName: "search",
|
|
1336
|
+
description: "Text to match against location and customer names",
|
|
1337
|
+
valueName: "value",
|
|
1338
|
+
schema: z.string()
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
name: "for-customer-ids",
|
|
1342
|
+
queryName: "forCustomerIds",
|
|
1343
|
+
description: "The IDs of the customers whose locations to return",
|
|
1344
|
+
valueName: "value",
|
|
1345
|
+
repeatable: true,
|
|
1346
|
+
schema: z.array(z.string())
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
name: "include-organization",
|
|
1350
|
+
queryName: "includeOrganization",
|
|
1351
|
+
description: "Whether the customer filter also matches your organization's own locations, which on its own returns only those",
|
|
1352
|
+
schema: z.boolean()
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
name: "sync-statuses",
|
|
1356
|
+
queryName: "syncStatuses",
|
|
1357
|
+
description: "The CRM sync statuses to return: in-sync, out-of-sync, or not-linked",
|
|
1358
|
+
valueName: "value",
|
|
1359
|
+
repeatable: true,
|
|
1360
|
+
schema: z.array(z.string())
|
|
1361
|
+
}
|
|
1362
|
+
],
|
|
1363
|
+
takesBody: false
|
|
1364
|
+
}),
|
|
1365
|
+
defineOperation({
|
|
1366
|
+
name: "create",
|
|
1367
|
+
summary: "Create location",
|
|
1368
|
+
method: "POST",
|
|
1369
|
+
path: "/location",
|
|
1370
|
+
pathParameters: [],
|
|
1371
|
+
queryFlags: [],
|
|
1372
|
+
takesBody: true
|
|
1373
|
+
}),
|
|
1374
|
+
defineOperation({
|
|
1375
|
+
name: "get",
|
|
1376
|
+
summary: "Get location",
|
|
1377
|
+
method: "GET",
|
|
1378
|
+
path: "/location/{locationKey}",
|
|
1379
|
+
pathParameters: [{
|
|
1380
|
+
name: "locationKey",
|
|
1381
|
+
description: "The location's key",
|
|
1382
|
+
required: true
|
|
1383
|
+
}],
|
|
1384
|
+
queryFlags: [],
|
|
1385
|
+
takesBody: false
|
|
1386
|
+
}),
|
|
1387
|
+
defineOperation({
|
|
1388
|
+
name: "update",
|
|
1389
|
+
summary: "Patch location",
|
|
1390
|
+
method: "PATCH",
|
|
1391
|
+
path: "/location/{locationKey}",
|
|
1392
|
+
pathParameters: [{
|
|
1393
|
+
name: "locationKey",
|
|
1394
|
+
description: "The location's key",
|
|
1395
|
+
required: true
|
|
1396
|
+
}],
|
|
1397
|
+
queryFlags: [],
|
|
1398
|
+
takesBody: true
|
|
1399
|
+
}),
|
|
1400
|
+
{
|
|
1401
|
+
name: "zones",
|
|
1402
|
+
summary: "Zones commands",
|
|
1403
|
+
arguments: [],
|
|
1404
|
+
flags: [],
|
|
1405
|
+
examples: [],
|
|
1406
|
+
subcommands: [defineOperation({
|
|
1407
|
+
name: "list",
|
|
1408
|
+
summary: "Get zones",
|
|
1409
|
+
method: "GET",
|
|
1410
|
+
path: "/location/{locationKey}/zones",
|
|
1411
|
+
pathParameters: [{
|
|
1412
|
+
name: "locationKey",
|
|
1413
|
+
description: "The key of the site whose zones to list",
|
|
1414
|
+
required: true
|
|
1415
|
+
}],
|
|
1416
|
+
queryFlags: [{
|
|
1417
|
+
name: "archived",
|
|
1418
|
+
queryName: "archived",
|
|
1419
|
+
description: "Whether to return unarchived zones, archived zones, or all of them",
|
|
1420
|
+
valueName: "value",
|
|
1421
|
+
schema: z.enum([
|
|
1422
|
+
"all",
|
|
1423
|
+
"false",
|
|
1424
|
+
"true"
|
|
1425
|
+
])
|
|
1426
|
+
}],
|
|
1427
|
+
takesBody: false
|
|
1428
|
+
})]
|
|
1429
|
+
}
|
|
1430
|
+
]
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
name: "url-link",
|
|
1434
|
+
summary: "URL link commands",
|
|
1435
|
+
arguments: [],
|
|
1436
|
+
flags: [],
|
|
1437
|
+
examples: [],
|
|
1438
|
+
subcommands: [
|
|
1439
|
+
defineOperation({
|
|
1440
|
+
name: "get",
|
|
1441
|
+
summary: "Get URL link by key",
|
|
1442
|
+
method: "GET",
|
|
1443
|
+
path: "/url-link/{linkKey}",
|
|
1444
|
+
pathParameters: [{
|
|
1445
|
+
name: "linkKey",
|
|
1446
|
+
description: "The URL link's key",
|
|
1447
|
+
required: true
|
|
1448
|
+
}],
|
|
1449
|
+
queryFlags: [],
|
|
1450
|
+
takesBody: false
|
|
1451
|
+
}),
|
|
1452
|
+
defineOperation({
|
|
1453
|
+
name: "update",
|
|
1454
|
+
summary: "Update URL link",
|
|
1455
|
+
method: "PATCH",
|
|
1456
|
+
path: "/url-link/{linkKey}",
|
|
1457
|
+
pathParameters: [{
|
|
1458
|
+
name: "linkKey",
|
|
1459
|
+
description: "The URL link's key",
|
|
1460
|
+
required: true
|
|
1461
|
+
}],
|
|
1462
|
+
queryFlags: [],
|
|
1463
|
+
takesBody: true
|
|
1464
|
+
}),
|
|
1465
|
+
defineOperation({
|
|
1466
|
+
name: "delete",
|
|
1467
|
+
summary: "Delete URL link",
|
|
1468
|
+
method: "DELETE",
|
|
1469
|
+
path: "/url-link/{linkKey}",
|
|
1470
|
+
pathParameters: [{
|
|
1471
|
+
name: "linkKey",
|
|
1472
|
+
description: "The URL link's key",
|
|
1473
|
+
required: true
|
|
1474
|
+
}],
|
|
1475
|
+
queryFlags: [],
|
|
1476
|
+
takesBody: false
|
|
1477
|
+
})
|
|
1478
|
+
]
|
|
1479
|
+
}
|
|
1480
|
+
],
|
|
1481
|
+
apiCommand,
|
|
1482
|
+
agentGuideCommand
|
|
1483
|
+
];
|
|
1484
|
+
//#endregion
|
|
1485
|
+
//#region src/command/validate.ts
|
|
1486
|
+
/** toRejectedFlag names the first flag whose value its schema refuses. */
|
|
1487
|
+
function toRejectedFlag(command, flags) {
|
|
1488
|
+
for (const flag of command.flags) {
|
|
1489
|
+
const value = flags[toOptionKey(flag.name)];
|
|
1490
|
+
if (value === void 0) continue;
|
|
1491
|
+
if (!flag.schema.safeParse(value).success) return `--${flag.name} does not accept ${JSON.stringify(value)}`;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
//#endregion
|
|
1495
|
+
//#region src/cli.ts
|
|
1496
|
+
const program = new Command();
|
|
1497
|
+
program.name("hardfin").description("Call the Hardfin API from a terminal or an agent").version(version, "-v, --version").showHelpAfterError().enablePositionalOptions();
|
|
1498
|
+
for (const command of commands) program.addCommand(toProgram(command));
|
|
1499
|
+
await program.parseAsync(process.argv);
|
|
1500
|
+
/** toProgram wires one registry command into the parser. */
|
|
1501
|
+
function toProgram(command) {
|
|
1502
|
+
const program = new Command(command.name).summary(command.summary).description(command.description ?? command.summary);
|
|
1503
|
+
for (const argument of command.arguments) {
|
|
1504
|
+
const name = argument.variadic ? `${argument.name}...` : argument.name;
|
|
1505
|
+
program.argument(argument.required ? `<${name}>` : `[${name}]`, argument.description);
|
|
1506
|
+
}
|
|
1507
|
+
for (const flag of command.flags) {
|
|
1508
|
+
const short = flag.short ? `-${flag.short}, ` : "";
|
|
1509
|
+
const value = flag.valueName ? ` <${flag.valueName}>` : "";
|
|
1510
|
+
const option = new Option(`${short}--${flag.name}${value}`, flag.description);
|
|
1511
|
+
if (flag.repeatable) option.argParser(collect);
|
|
1512
|
+
if (flag.defaultValue !== void 0) option.default(flag.defaultValue);
|
|
1513
|
+
program.addOption(option);
|
|
1514
|
+
}
|
|
1515
|
+
for (const example of command.examples) program.addHelpText("after", `\n${example.description}:\n $ ${example.command}`);
|
|
1516
|
+
for (const subcommand of command.subcommands ?? []) program.addCommand(toProgram(subcommand));
|
|
1517
|
+
if (!command.run) return program;
|
|
1518
|
+
program.action(async (...parsed) => {
|
|
1519
|
+
const flags = parsed[parsed.length - 2] ?? {};
|
|
1520
|
+
const args = parsed.slice(0, parsed.length - 2).flatMap(toArgumentList);
|
|
1521
|
+
process.exitCode = await toExitCode(command, args, flags);
|
|
1522
|
+
});
|
|
1523
|
+
return program;
|
|
1524
|
+
}
|
|
1525
|
+
async function toExitCode(command, args, flags) {
|
|
1526
|
+
const isJSON = isJSONOutput(flags);
|
|
1527
|
+
const rejected = toRejectedFlag(command, flags);
|
|
1528
|
+
if (rejected) {
|
|
1529
|
+
writeFailure(rejected, isJSON);
|
|
1530
|
+
return ExitCode.USAGE;
|
|
1531
|
+
}
|
|
1532
|
+
try {
|
|
1533
|
+
return await command.run?.({
|
|
1534
|
+
args,
|
|
1535
|
+
flags,
|
|
1536
|
+
isJSON,
|
|
1537
|
+
commands
|
|
1538
|
+
}) ?? ExitCode.OK;
|
|
1539
|
+
} catch (error) {
|
|
1540
|
+
writeFailure(error instanceof Error ? error.message : String(error), isJSON);
|
|
1541
|
+
return ExitCode.ERROR;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
function toArgumentList(value) {
|
|
1545
|
+
if (Array.isArray(value)) return value.map(String);
|
|
1546
|
+
return value === void 0 ? [] : [String(value)];
|
|
1547
|
+
}
|
|
1548
|
+
function collect(value, previous) {
|
|
1549
|
+
return [...previous ?? [], value];
|
|
1550
|
+
}
|
|
1551
|
+
//#endregion
|
|
1552
|
+
export {};
|