not-manage 0.2.2 → 0.2.3
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 +42 -6
- package/bin/not-manage.js +15 -2
- package/package.json +1 -1
- package/src/agent-input.js +101 -0
- package/src/cli-errors.js +109 -0
- package/src/cli.js +835 -64
- package/src/clio-api.js +108 -6
- package/src/commands-agent-context.js +119 -0
- package/src/commands-auth.js +336 -148
- package/src/commands-doctor.js +178 -0
- package/src/commands-request.js +144 -0
- package/src/compact-output.js +89 -0
- package/src/prompt.js +48 -0
- package/src/redaction.js +62 -25
- package/src/resource-command-runner.js +75 -4
- package/src/resource-handlers.js +15 -6
- package/src/resource-metadata.js +18 -0
- package/src/store.js +1 -1
package/src/cli.js
CHANGED
|
@@ -3,20 +3,111 @@ const {
|
|
|
3
3
|
authRevoke,
|
|
4
4
|
authSetup,
|
|
5
5
|
authStatus,
|
|
6
|
-
maybeRunSetupOnFirstUse,
|
|
7
6
|
setupWizard,
|
|
8
7
|
whoAmI,
|
|
9
8
|
} = require("./commands-auth");
|
|
10
|
-
const {
|
|
9
|
+
const { readJsonInput } = require("./agent-input");
|
|
10
|
+
const { UsageError } = require("./cli-errors");
|
|
11
|
+
const {
|
|
12
|
+
hasFlag,
|
|
13
|
+
parseOptions,
|
|
14
|
+
readBooleanOption,
|
|
15
|
+
readCommandOptions,
|
|
16
|
+
readStringOption,
|
|
17
|
+
} = require("./cli-options");
|
|
18
|
+
const { agentContext } = require("./commands-agent-context");
|
|
19
|
+
const { doctor } = require("./commands-doctor");
|
|
20
|
+
const { rawRequest } = require("./commands-request");
|
|
11
21
|
const { getResourceHandler } = require("./resource-handlers");
|
|
12
22
|
const {
|
|
13
23
|
RESOURCE_ORDER,
|
|
24
|
+
findMissingRequiredOptions,
|
|
14
25
|
getResourceMetadata,
|
|
15
26
|
listRequiredOptionFlags,
|
|
16
27
|
normalizeResourceCommand,
|
|
17
28
|
} = require("./resource-metadata");
|
|
18
29
|
const { version } = require("../package.json");
|
|
19
30
|
|
|
31
|
+
const HELP_FLAGS = new Set(["-h", "--help"]);
|
|
32
|
+
const VERSION_FLAGS = new Set(["-v", "--version"]);
|
|
33
|
+
const GLOBAL_BOOLEAN_FLAGS = new Set([
|
|
34
|
+
"agent",
|
|
35
|
+
"compact",
|
|
36
|
+
"json",
|
|
37
|
+
"no-color",
|
|
38
|
+
"no-input",
|
|
39
|
+
"yes",
|
|
40
|
+
"force",
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
function parseGlobalBoolean(value, flagName) {
|
|
44
|
+
if (value === undefined || value === "") {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const normalized = String(value).trim().toLowerCase();
|
|
49
|
+
if (normalized === "true") {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (normalized === "false") {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
throw new UsageError(`\`--${flagName}\` must be \`true\` or \`false\`.`, {
|
|
57
|
+
code: "invalid_global_flag",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function readGlobalFlags(args) {
|
|
62
|
+
const values = {
|
|
63
|
+
agent: false,
|
|
64
|
+
compact: false,
|
|
65
|
+
force: false,
|
|
66
|
+
json: false,
|
|
67
|
+
noColor: false,
|
|
68
|
+
noInput: false,
|
|
69
|
+
yes: false,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
73
|
+
const token = args[index];
|
|
74
|
+
if (!token.startsWith("--")) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const [flagName, inlineValue] = token.slice(2).split("=", 2);
|
|
79
|
+
if (!GLOBAL_BOOLEAN_FLAGS.has(flagName)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let value = inlineValue;
|
|
84
|
+
const next = args[index + 1];
|
|
85
|
+
if (
|
|
86
|
+
value === undefined &&
|
|
87
|
+
(next === "true" || next === "false")
|
|
88
|
+
) {
|
|
89
|
+
value = next;
|
|
90
|
+
index += 1;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
values[flagName.replace(/-([a-z])/g, (_match, char) => char.toUpperCase())] =
|
|
94
|
+
parseGlobalBoolean(value, flagName);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (values.agent) {
|
|
98
|
+
values.compact = true;
|
|
99
|
+
values.json = true;
|
|
100
|
+
values.noColor = true;
|
|
101
|
+
values.noInput = true;
|
|
102
|
+
values.yes = true;
|
|
103
|
+
}
|
|
104
|
+
if (values.force) {
|
|
105
|
+
values.yes = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return values;
|
|
109
|
+
}
|
|
110
|
+
|
|
20
111
|
function maybePrintDefaultFields(command, sub, optionValues) {
|
|
21
112
|
if (optionValues.fields !== true) {
|
|
22
113
|
return false;
|
|
@@ -24,8 +115,12 @@ function maybePrintDefaultFields(command, sub, optionValues) {
|
|
|
24
115
|
|
|
25
116
|
const defaults = getResourceMetadata(command)?.defaultFields?.[sub];
|
|
26
117
|
if (!defaults) {
|
|
27
|
-
throw new
|
|
28
|
-
"`--fields` requires a comma-separated value for this command. Example: --fields id,name"
|
|
118
|
+
throw new UsageError(
|
|
119
|
+
"`--fields` requires a comma-separated value for this command. Example: --fields id,name",
|
|
120
|
+
{
|
|
121
|
+
code: "missing_fields_value",
|
|
122
|
+
hint: "--fields id,name",
|
|
123
|
+
}
|
|
29
124
|
);
|
|
30
125
|
}
|
|
31
126
|
|
|
@@ -74,85 +169,693 @@ function warnAboutRedaction(resourceMetadata, sub, optionValues, redacted) {
|
|
|
74
169
|
}
|
|
75
170
|
}
|
|
76
171
|
|
|
77
|
-
function
|
|
172
|
+
function printOptionLines(entries = []) {
|
|
173
|
+
if (entries.length === 0) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
console.log("Options:");
|
|
178
|
+
entries.forEach((entry) => {
|
|
179
|
+
if (typeof entry === "string") {
|
|
180
|
+
console.log(` ${entry}`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log(` ${entry.usage.padEnd(28, " ")} ${entry.description}`);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function printExamples(examples = []) {
|
|
189
|
+
if (examples.length === 0) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log("Examples:");
|
|
194
|
+
examples.forEach((example) => {
|
|
195
|
+
console.log(` ${example}`);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function printCommandHelp(title, details = {}) {
|
|
200
|
+
const {
|
|
201
|
+
description,
|
|
202
|
+
examples = [],
|
|
203
|
+
notes = [],
|
|
204
|
+
options = [],
|
|
205
|
+
usage = [],
|
|
206
|
+
} = details;
|
|
207
|
+
|
|
208
|
+
console.log(title);
|
|
209
|
+
console.log("");
|
|
210
|
+
|
|
211
|
+
if (usage.length > 0) {
|
|
212
|
+
console.log("Usage:");
|
|
213
|
+
usage.forEach((line) => {
|
|
214
|
+
console.log(` ${line}`);
|
|
215
|
+
});
|
|
216
|
+
console.log("");
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (description) {
|
|
220
|
+
console.log("Description:");
|
|
221
|
+
console.log(` ${description}`);
|
|
222
|
+
console.log("");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (notes.length > 0) {
|
|
226
|
+
console.log("Notes:");
|
|
227
|
+
notes.forEach((line) => {
|
|
228
|
+
console.log(` ${line}`);
|
|
229
|
+
});
|
|
230
|
+
console.log("");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
printOptionLines(options);
|
|
234
|
+
if (options.length > 0 && examples.length > 0) {
|
|
235
|
+
console.log("");
|
|
236
|
+
}
|
|
237
|
+
printExamples(examples);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function optionPlaceholder(optionDef) {
|
|
241
|
+
switch (optionDef.kind) {
|
|
242
|
+
case "boolean":
|
|
243
|
+
return " <true|false>";
|
|
244
|
+
case "object":
|
|
245
|
+
return " <json|key=value>";
|
|
246
|
+
case "string-array":
|
|
247
|
+
return " <value[,value]>";
|
|
248
|
+
default:
|
|
249
|
+
return " <value>";
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function formatResourceOption(optionDef) {
|
|
254
|
+
if (optionDef.positional !== undefined) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return `--${optionDef.option}${optionDef.kind === "flag" ? "" : optionPlaceholder(optionDef)}`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function buildResourceOptionLines(resourceMetadata, sub) {
|
|
262
|
+
const optionLines = Object.values(resourceMetadata.optionSchema?.[sub] || {})
|
|
263
|
+
.map((optionDef) => formatResourceOption(optionDef))
|
|
264
|
+
.filter(Boolean);
|
|
265
|
+
|
|
266
|
+
if (sub === "list" || sub === "get") {
|
|
267
|
+
optionLines.push("--options-file <path|->");
|
|
268
|
+
optionLines.push("--json");
|
|
269
|
+
optionLines.push("--compact");
|
|
270
|
+
optionLines.push("--redacted");
|
|
271
|
+
optionLines.push("--unredacted");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (sub === "get") {
|
|
275
|
+
optionLines.push("--ids-file <path|->");
|
|
276
|
+
optionLines.push("--stdin");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
optionLines.push("-h, --help");
|
|
280
|
+
return optionLines;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function buildResourceExamples(command, sub, requiredFlags) {
|
|
284
|
+
if (sub === "get") {
|
|
285
|
+
return [
|
|
286
|
+
`not-manage ${command} get 123 --json`,
|
|
287
|
+
`not-manage ${command} get 123 --fields id,name --json`,
|
|
288
|
+
`printf "123\\n456\\n" | not-manage ${command} get --stdin --json`,
|
|
289
|
+
];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const exampleValues = {
|
|
293
|
+
"--conversation-id": "123",
|
|
294
|
+
"--matter-id": "123",
|
|
295
|
+
"--type": "Matter",
|
|
296
|
+
"--user-id": "123",
|
|
297
|
+
};
|
|
298
|
+
const requiredExample =
|
|
299
|
+
requiredFlags.length > 0
|
|
300
|
+
? `${requiredFlags.map((flag) => `${flag} <value>`).join(" ")} `
|
|
301
|
+
: "";
|
|
302
|
+
const realisticRequiredExample =
|
|
303
|
+
requiredFlags.length > 0
|
|
304
|
+
? `${requiredFlags.map((flag) => `${flag} ${exampleValues[flag] || "123"}`).join(" ")} `
|
|
305
|
+
: "";
|
|
306
|
+
|
|
307
|
+
return [
|
|
308
|
+
`not-manage ${command} list ${realisticRequiredExample}--json`,
|
|
309
|
+
`not-manage ${command} list ${requiredExample}--fields id,name`,
|
|
310
|
+
`not-manage ${command} list --options-file filters.json --json`,
|
|
311
|
+
];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function printGlobalHelp() {
|
|
78
315
|
console.log("not-manage");
|
|
79
316
|
console.log("");
|
|
80
317
|
console.log("Usage:");
|
|
81
318
|
console.log(" not-manage <command> [options]");
|
|
82
319
|
console.log("");
|
|
83
320
|
console.log("Commands:");
|
|
84
|
-
console.log(" setup
|
|
85
|
-
console.log("
|
|
86
|
-
console.log("
|
|
87
|
-
console.log(" auth
|
|
88
|
-
console.log(" auth revoke Revoke token and clear local token storage");
|
|
89
|
-
|
|
90
|
-
RESOURCE_ORDER.forEach((command) => {
|
|
91
|
-
const resourceMetadata = getResourceMetadata(command);
|
|
92
|
-
["list", "get"].forEach((sub) => {
|
|
93
|
-
if (!resourceMetadata.capabilities[sub].enabled) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const usage = `${command} ${sub}`.padEnd(18, " ");
|
|
98
|
-
const requiredFlags = listRequiredOptionFlags(resourceMetadata, sub);
|
|
99
|
-
const requirementNote =
|
|
100
|
-
requiredFlags.length > 0 ? ` (requires ${requiredFlags.join(", ")})` : "";
|
|
101
|
-
console.log(` ${usage} ${resourceMetadata.help[sub]}${requirementNote}`);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
321
|
+
console.log(" setup Guided setup plus OAuth login");
|
|
322
|
+
console.log(" doctor Diagnose config, token, and Clio connectivity");
|
|
323
|
+
console.log(" agent-context Machine-readable command/resource catalog");
|
|
324
|
+
console.log(" auth Manage app credentials and OAuth tokens");
|
|
105
325
|
console.log(" whoami Call /api/v4/users/who_am_i");
|
|
326
|
+
console.log(" request Raw API escape hatch with write guard");
|
|
327
|
+
console.log(" <resource> Read Clio resources with list/get subcommands");
|
|
106
328
|
console.log("");
|
|
107
|
-
console.log("
|
|
108
|
-
console.log("
|
|
109
|
-
console.log("
|
|
329
|
+
console.log("Resources:");
|
|
330
|
+
console.log(" Run `not-manage agent-context` for the full machine-readable catalog.");
|
|
331
|
+
console.log(" Run `not-manage <resource> --help` for resource subcommands.");
|
|
332
|
+
console.log(" Singular aliases are accepted, for example `contact get` and `matter get`.");
|
|
110
333
|
console.log("");
|
|
111
334
|
console.log("Options:");
|
|
335
|
+
console.log(" --agent Agent defaults: --json --compact --no-input --no-color --yes");
|
|
336
|
+
console.log(" --compact Return reduced JSON fields for lower-token output");
|
|
112
337
|
console.log(" --fields <list> Override returned fields; pass `--fields` alone to print defaults");
|
|
113
338
|
console.log(" --json Print machine-readable JSON for supported commands");
|
|
339
|
+
console.log(" --no-input Disable interactive prompts where supported");
|
|
340
|
+
console.log(" --no-color Disable colored output");
|
|
341
|
+
console.log(" --force Alias for --yes");
|
|
114
342
|
console.log(" --redacted Kept for compatibility; data commands are redacted by default");
|
|
115
343
|
console.log(" --unredacted Show raw output without default redaction");
|
|
116
344
|
console.log(" -h, --help Show help");
|
|
117
345
|
console.log(" -v, --version Show version");
|
|
346
|
+
console.log("");
|
|
347
|
+
console.log("Examples:");
|
|
348
|
+
console.log(" not-manage --agent agent-context");
|
|
349
|
+
console.log(" not-manage --agent doctor");
|
|
350
|
+
console.log(" not-manage --agent contacts list --limit 5");
|
|
351
|
+
console.log("");
|
|
352
|
+
console.log("Run `not-manage <command> --help` for command-specific flags and examples.");
|
|
118
353
|
}
|
|
119
354
|
|
|
120
|
-
function
|
|
355
|
+
function printSetupHelp() {
|
|
356
|
+
printCommandHelp("not-manage setup", {
|
|
357
|
+
description: "Run guided credential setup, then continue directly into OAuth login.",
|
|
358
|
+
usage: ["not-manage setup [auth-setup-options]"],
|
|
359
|
+
notes: [
|
|
360
|
+
"This command accepts the same setup flags as `not-manage auth setup`.",
|
|
361
|
+
"If required values are missing, prompts are used only in an interactive terminal.",
|
|
362
|
+
],
|
|
363
|
+
options: [
|
|
364
|
+
{ usage: "--confirm-confidentiality", description: "Acknowledge the confidentiality warning without a prompt" },
|
|
365
|
+
{ usage: "--region <code>", description: "Clio region code: us, ca, eu, or au" },
|
|
366
|
+
{ usage: "--client-id <value>", description: "App Key / Client ID" },
|
|
367
|
+
{ usage: "--client-secret <value>", description: "App Secret / Client Secret" },
|
|
368
|
+
{ usage: "--redirect-uri <url>", description: "Override the loopback OAuth redirect URI" },
|
|
369
|
+
{ usage: "--open-browser <true|false>", description: "Open the regional developer portal during setup" },
|
|
370
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
371
|
+
],
|
|
372
|
+
examples: [
|
|
373
|
+
"not-manage setup",
|
|
374
|
+
"not-manage setup --confirm-confidentiality --region us --client-id <key> --client-secret <secret>",
|
|
375
|
+
],
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function printAuthHelp() {
|
|
380
|
+
printCommandHelp("not-manage auth", {
|
|
381
|
+
description: "Manage Clio app credentials and OAuth tokens.",
|
|
382
|
+
usage: ["not-manage auth <subcommand> [options]"],
|
|
383
|
+
notes: [
|
|
384
|
+
"Subcommands: setup, login, status, revoke",
|
|
385
|
+
"Run `not-manage auth <subcommand> --help` for flags and examples.",
|
|
386
|
+
],
|
|
387
|
+
examples: [
|
|
388
|
+
"not-manage auth setup --help",
|
|
389
|
+
"not-manage auth status --json",
|
|
390
|
+
"not-manage auth revoke --dry-run",
|
|
391
|
+
],
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function printAuthSetupHelp() {
|
|
396
|
+
printCommandHelp("not-manage auth setup", {
|
|
397
|
+
description: "Configure client credentials in the OS keychain.",
|
|
398
|
+
usage: ["not-manage auth setup [options]"],
|
|
399
|
+
notes: [
|
|
400
|
+
"If required values are missing, prompts are used only in an interactive terminal.",
|
|
401
|
+
"Outside a TTY, pass `--confirm-confidentiality`, `--client-id`, and `--client-secret`.",
|
|
402
|
+
],
|
|
403
|
+
options: [
|
|
404
|
+
{ usage: "--confirm-confidentiality", description: "Acknowledge the confidentiality warning without a prompt" },
|
|
405
|
+
{ usage: "--region <code>", description: "Clio region code: us, ca, eu, or au" },
|
|
406
|
+
{ usage: "--client-id <value>", description: "App Key / Client ID" },
|
|
407
|
+
{ usage: "--client-secret <value>", description: "App Secret / Client Secret" },
|
|
408
|
+
{ usage: "--redirect-uri <url>", description: "Override the loopback OAuth redirect URI" },
|
|
409
|
+
{ usage: "--open-browser <true|false>", description: "Open the regional developer portal during setup" },
|
|
410
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
411
|
+
],
|
|
412
|
+
examples: [
|
|
413
|
+
"not-manage auth setup",
|
|
414
|
+
"not-manage auth setup --confirm-confidentiality --region us --client-id <key> --client-secret <secret>",
|
|
415
|
+
],
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function printAuthLoginHelp() {
|
|
420
|
+
printCommandHelp("not-manage auth login", {
|
|
421
|
+
description: "Run the local OAuth login flow using the saved client credentials.",
|
|
422
|
+
usage: ["not-manage auth login"],
|
|
423
|
+
options: [{ usage: "-h, --help", description: "Show help" }],
|
|
424
|
+
examples: ["not-manage auth login"],
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function printAuthStatusHelp() {
|
|
429
|
+
printCommandHelp("not-manage auth status", {
|
|
430
|
+
description: "Show the configured region, token source, and connected user.",
|
|
431
|
+
usage: ["not-manage auth status [options]"],
|
|
432
|
+
options: [
|
|
433
|
+
{ usage: "--json", description: "Print machine-readable JSON" },
|
|
434
|
+
{ usage: "--unredacted", description: "Show raw connected-user details instead of masked values" },
|
|
435
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
436
|
+
],
|
|
437
|
+
examples: ["not-manage auth status", "not-manage auth status --json"],
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function printDoctorHelp() {
|
|
442
|
+
printCommandHelp("not-manage doctor", {
|
|
443
|
+
description:
|
|
444
|
+
"Report CLI version, config source, region/host, and token/auth state. Works without auth so agents can diagnose missing setup without triggering other errors.",
|
|
445
|
+
usage: ["not-manage doctor [options]"],
|
|
446
|
+
options: [
|
|
447
|
+
{ usage: "--json", description: "Print machine-readable JSON" },
|
|
448
|
+
{ usage: "--compact", description: "Print compact JSON when combined with --json" },
|
|
449
|
+
{ usage: "--fail-on <warn|error>", description: "Exit non-zero when the report reaches this severity" },
|
|
450
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
451
|
+
],
|
|
452
|
+
examples: ["not-manage doctor", "not-manage doctor --json", "not-manage doctor --fail-on warn"],
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function printAgentContextHelp() {
|
|
457
|
+
printCommandHelp("not-manage agent-context", {
|
|
458
|
+
description: "Emit a machine-readable command and option map for agents.",
|
|
459
|
+
usage: ["not-manage agent-context [options]"],
|
|
460
|
+
options: [
|
|
461
|
+
{ usage: "--compact", description: "Print compact JSON" },
|
|
462
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
463
|
+
],
|
|
464
|
+
examples: ["not-manage agent-context", "not-manage --agent agent-context"],
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function printRequestHelp() {
|
|
469
|
+
printCommandHelp("not-manage request", {
|
|
470
|
+
description:
|
|
471
|
+
"Raw Clio API escape hatch. Reuses saved auth, base URL trust checks, redaction, and JSON envelope.",
|
|
472
|
+
usage: ["not-manage request <method> <path> [options]"],
|
|
473
|
+
notes: [
|
|
474
|
+
"Reads are safe by default: only GET and HEAD run without an extra confirmation flag.",
|
|
475
|
+
"Non-idempotent methods (POST/PUT/PATCH/DELETE) require `--write` and are treated as live writes.",
|
|
476
|
+
"`--dry-run` previews the validated request plan without sending it.",
|
|
477
|
+
"Paths are validated against the configured region host before the bearer token is sent.",
|
|
478
|
+
"Response bodies are redacted by default; pass `--unredacted` to inspect raw output.",
|
|
479
|
+
],
|
|
480
|
+
options: [
|
|
481
|
+
{ usage: "--query <k=v[,k=v]>", description: "Appended as URL query parameters" },
|
|
482
|
+
{ usage: "--body-file <path|->", description: "JSON body file, or `-` to read from stdin" },
|
|
483
|
+
{ usage: "--write", description: "Required for POST, PUT, PATCH, DELETE" },
|
|
484
|
+
{ usage: "--dry-run", description: "Print the validated request plan without sending it" },
|
|
485
|
+
{ usage: "--json", description: "Print machine-readable JSON (default for this command)" },
|
|
486
|
+
{ usage: "--unredacted", description: "Show raw output without redaction" },
|
|
487
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
488
|
+
],
|
|
489
|
+
examples: [
|
|
490
|
+
"not-manage request get /api/v4/users/who_am_i --json",
|
|
491
|
+
"not-manage request get /api/v4/matters.json --query status=open,limit=5 --json",
|
|
492
|
+
"not-manage request post /api/v4/activities.json --body-file body.json --dry-run --json",
|
|
493
|
+
"cat body.json | not-manage request post /api/v4/activities.json --body-file - --write --json",
|
|
494
|
+
],
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function printAuthRevokeHelp() {
|
|
499
|
+
printCommandHelp("not-manage auth revoke", {
|
|
500
|
+
description: "Revoke the current Clio token and clear the local keychain token.",
|
|
501
|
+
usage: ["not-manage auth revoke [options]"],
|
|
502
|
+
notes: ["Use `--dry-run` to inspect the action without changing remote or local state."],
|
|
503
|
+
options: [
|
|
504
|
+
{ usage: "--yes", description: "Skip the confirmation prompt and revoke immediately" },
|
|
505
|
+
{ usage: "--force", description: "Alias for --yes" },
|
|
506
|
+
{ usage: "--dry-run", description: "Print the revoke plan without revoking or clearing tokens" },
|
|
507
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
508
|
+
],
|
|
509
|
+
examples: ["not-manage auth revoke --dry-run", "not-manage auth revoke --yes"],
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function printWhoAmIHelp() {
|
|
514
|
+
printCommandHelp("not-manage whoami", {
|
|
515
|
+
description: "Call `/api/v4/users/who_am_i` for the authenticated user.",
|
|
516
|
+
usage: ["not-manage whoami [options]"],
|
|
517
|
+
options: [
|
|
518
|
+
{ usage: "--json", description: "Print machine-readable JSON" },
|
|
519
|
+
{ usage: "-h, --help", description: "Show help" },
|
|
520
|
+
],
|
|
521
|
+
examples: ["not-manage whoami", "not-manage whoami --json"],
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function printResourceOverview(command, resourceMetadata) {
|
|
526
|
+
const subcommands = ["list", "get"].filter((sub) => resourceMetadata.capabilities[sub].enabled);
|
|
527
|
+
|
|
528
|
+
printCommandHelp(`not-manage ${command}`, {
|
|
529
|
+
description: `Explore the ${command} command surface.`,
|
|
530
|
+
usage: [`not-manage ${command} <subcommand> [options]`],
|
|
531
|
+
notes: [
|
|
532
|
+
`Subcommands: ${subcommands.join(", ")}`,
|
|
533
|
+
resourceMetadata.aliases.length > 0
|
|
534
|
+
? `Aliases: ${resourceMetadata.aliases.join(", ")}`
|
|
535
|
+
: null,
|
|
536
|
+
`Run \`not-manage ${command} <subcommand> --help\` for flags and examples.`,
|
|
537
|
+
].filter(Boolean),
|
|
538
|
+
examples: [
|
|
539
|
+
`not-manage ${command} list --help`,
|
|
540
|
+
resourceMetadata.capabilities.list.enabled ? `not-manage ${command} list --json` : null,
|
|
541
|
+
resourceMetadata.capabilities.get.enabled ? `not-manage ${command} get <id> --json` : null,
|
|
542
|
+
].filter(Boolean),
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function printResourceCommandHelp(command, sub, resourceMetadata) {
|
|
547
|
+
const requiredFlags = listRequiredOptionFlags(resourceMetadata, sub);
|
|
548
|
+
const usage =
|
|
549
|
+
sub === "get"
|
|
550
|
+
? [`not-manage ${command} get <id> [options]`]
|
|
551
|
+
: [`not-manage ${command} list [options]`];
|
|
552
|
+
const notes = [];
|
|
553
|
+
|
|
554
|
+
if (requiredFlags.length > 0) {
|
|
555
|
+
notes.push(`Required filters: ${requiredFlags.join(", ")}`);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (resourceMetadata.aliases.length > 0) {
|
|
559
|
+
notes.push(`Aliases: ${resourceMetadata.aliases.join(", ")}`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
printCommandHelp(`not-manage ${command} ${sub}`, {
|
|
563
|
+
description: resourceMetadata.help[sub],
|
|
564
|
+
usage,
|
|
565
|
+
notes,
|
|
566
|
+
options: buildResourceOptionLines(resourceMetadata, sub),
|
|
567
|
+
examples: buildResourceExamples(command, sub, requiredFlags),
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function printCommandSpecificHelp(command, sub) {
|
|
572
|
+
if (!command) {
|
|
573
|
+
printGlobalHelp();
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (command === "setup") {
|
|
578
|
+
printSetupHelp();
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (command === "auth") {
|
|
583
|
+
if (!sub) {
|
|
584
|
+
printAuthHelp();
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (sub === "setup") {
|
|
589
|
+
printAuthSetupHelp();
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (sub === "login") {
|
|
594
|
+
printAuthLoginHelp();
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (sub === "status") {
|
|
599
|
+
printAuthStatusHelp();
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (sub === "revoke") {
|
|
604
|
+
printAuthRevokeHelp();
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
throw new UsageError(
|
|
609
|
+
`Unknown subcommand for auth: ${sub}\nRun \`not-manage auth --help\`.`,
|
|
610
|
+
{ code: "unknown_subcommand", hint: "not-manage auth --help" }
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (command === "whoami") {
|
|
615
|
+
printWhoAmIHelp();
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (command === "doctor") {
|
|
620
|
+
printDoctorHelp();
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
if (command === "agent-context") {
|
|
625
|
+
printAgentContextHelp();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (command === "request") {
|
|
630
|
+
printRequestHelp();
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const resourceMetadata = getResourceMetadata(command);
|
|
635
|
+
if (!resourceMetadata) {
|
|
636
|
+
throw new UsageError(
|
|
637
|
+
`Unknown command: ${command}\nRun \`not-manage --help\`.`,
|
|
638
|
+
{ code: "unknown_command", hint: "not-manage --help" }
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (!sub) {
|
|
643
|
+
printResourceOverview(command, resourceMetadata);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (!resourceMetadata.capabilities[sub]?.enabled) {
|
|
648
|
+
throw new UsageError(
|
|
649
|
+
`Unknown subcommand for ${command}: ${sub}\nRun \`not-manage ${command} --help\`.`,
|
|
650
|
+
{ code: "unknown_subcommand", hint: `not-manage ${command} --help` }
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
printResourceCommandHelp(command, sub, resourceMetadata);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function stripRoutingFlags(args) {
|
|
658
|
+
const routingArgs = [];
|
|
659
|
+
|
|
660
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
661
|
+
const arg = args[index];
|
|
662
|
+
if (HELP_FLAGS.has(arg) || VERSION_FLAGS.has(arg)) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (arg.startsWith("--")) {
|
|
667
|
+
const [flagName, inlineValue] = arg.slice(2).split("=", 2);
|
|
668
|
+
if (GLOBAL_BOOLEAN_FLAGS.has(flagName)) {
|
|
669
|
+
const next = args[index + 1];
|
|
670
|
+
if (inlineValue === undefined && (next === "true" || next === "false")) {
|
|
671
|
+
index += 1;
|
|
672
|
+
}
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
routingArgs.push(arg);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
return routingArgs;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function buildResourceOptions(
|
|
684
|
+
resourceMetadata,
|
|
685
|
+
sub,
|
|
686
|
+
optionValues,
|
|
687
|
+
positional,
|
|
688
|
+
json,
|
|
689
|
+
redacted,
|
|
690
|
+
compact
|
|
691
|
+
) {
|
|
692
|
+
const baseOptions = {
|
|
693
|
+
json,
|
|
694
|
+
redacted,
|
|
695
|
+
};
|
|
696
|
+
if (compact) {
|
|
697
|
+
baseOptions.compact = true;
|
|
698
|
+
}
|
|
699
|
+
|
|
121
700
|
return readCommandOptions(
|
|
122
701
|
optionValues,
|
|
123
702
|
resourceMetadata.optionSchema[sub],
|
|
124
703
|
positional,
|
|
125
|
-
|
|
126
|
-
json,
|
|
127
|
-
redacted,
|
|
128
|
-
},
|
|
704
|
+
baseOptions,
|
|
129
705
|
resourceMetadata.fixedOptions?.[sub]
|
|
130
706
|
);
|
|
131
707
|
}
|
|
132
708
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (!startedOnboarding) {
|
|
137
|
-
printHelp();
|
|
138
|
-
}
|
|
709
|
+
function assertRequiredResourceOptions(command, sub, resourceMetadata, options) {
|
|
710
|
+
const missing = findMissingRequiredOptions(resourceMetadata, sub, options);
|
|
711
|
+
if (missing.length === 0) {
|
|
139
712
|
return;
|
|
140
713
|
}
|
|
141
714
|
|
|
142
|
-
|
|
143
|
-
|
|
715
|
+
const missingList = missing.join(", ");
|
|
716
|
+
const exampleFlags = missing.map((flag) => `${flag} <value>`).join(" ");
|
|
717
|
+
const message = [
|
|
718
|
+
`Missing required ${missing.length === 1 ? "flag" : "flags"} for \`not-manage ${command} ${sub}\`: ${missingList}.`,
|
|
719
|
+
`Usage: not-manage ${command} ${sub} ${exampleFlags}`.trim(),
|
|
720
|
+
`Run \`not-manage ${command} ${sub} --help\` for the full flag list.`,
|
|
721
|
+
].join("\n");
|
|
722
|
+
|
|
723
|
+
throw new UsageError(message, {
|
|
724
|
+
code: "missing_required_flags",
|
|
725
|
+
hint: `not-manage ${command} ${sub} --help`,
|
|
726
|
+
details: { command, subcommand: sub, missing_flags: missing },
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function assertResourceIdOption(command, sub, options) {
|
|
731
|
+
if (sub !== "get" || options.id || options.idsFile) {
|
|
144
732
|
return;
|
|
145
733
|
}
|
|
146
734
|
|
|
147
|
-
|
|
148
|
-
|
|
735
|
+
const usage = `Usage: not-manage ${command} get <id>`;
|
|
736
|
+
throw new UsageError(usage, {
|
|
737
|
+
code: "missing_resource_id",
|
|
738
|
+
hint: `not-manage ${command} get <id>`,
|
|
739
|
+
details: { missing: ["id"] },
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function isPlainObject(value) {
|
|
744
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function hasOwn(object, key) {
|
|
748
|
+
return Object.prototype.hasOwnProperty.call(object, key);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
async function mergeOptionsFile(optionValues) {
|
|
752
|
+
const optionsFile = readStringOption(optionValues, "options-file");
|
|
753
|
+
if (!optionsFile) {
|
|
754
|
+
return optionValues;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const fileOptions = await readJsonInput(optionsFile, "`--options-file` input");
|
|
758
|
+
if (!isPlainObject(fileOptions)) {
|
|
759
|
+
throw new UsageError("`--options-file` must contain a JSON object.", {
|
|
760
|
+
code: "invalid_options_file",
|
|
761
|
+
hint: "Use a JSON object like `{ \"limit\": 5 }`.",
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
...fileOptions,
|
|
767
|
+
...optionValues,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function assertSingleStdinConsumer(optionValues) {
|
|
772
|
+
const optionsFile = readStringOption(optionValues, "options-file");
|
|
773
|
+
const idsFile = readStringOption(optionValues, "ids-file");
|
|
774
|
+
const stdinIds = readBooleanOption(optionValues, "stdin") === true;
|
|
775
|
+
const stdinConsumers = [optionsFile === "-", idsFile === "-", stdinIds].filter(Boolean);
|
|
776
|
+
|
|
777
|
+
if (stdinConsumers.length > 1) {
|
|
778
|
+
throw new UsageError("Only one stdin-consuming flag can be used at a time.", {
|
|
779
|
+
code: "conflicting_stdin_inputs",
|
|
780
|
+
hint: "Use either `--options-file -`, `--ids-file -`, or `--stdin`.",
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
function applyAgentInputOptions(sub, optionValues, options) {
|
|
786
|
+
if (sub !== "get") {
|
|
787
|
+
return options;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const idsFile = readStringOption(optionValues, "ids-file");
|
|
791
|
+
const stdinIds = readBooleanOption(optionValues, "stdin") === true;
|
|
792
|
+
if (!idsFile && !stdinIds) {
|
|
793
|
+
return options;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if (hasOwn(optionValues, "stdin") && readBooleanOption(optionValues, "stdin") !== true) {
|
|
797
|
+
return options;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
return {
|
|
801
|
+
...options,
|
|
802
|
+
idsFile: stdinIds ? "-" : idsFile,
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function buildAuthSetupOptions(optionValues, globalFlags = {}) {
|
|
807
|
+
const options = {
|
|
808
|
+
clientId: readStringOption(optionValues, "client-id"),
|
|
809
|
+
clientSecret: readStringOption(optionValues, "client-secret"),
|
|
810
|
+
confirmConfidentiality: readBooleanOption(optionValues, "confirm-confidentiality") === true,
|
|
811
|
+
openBrowser: readBooleanOption(optionValues, "open-browser"),
|
|
812
|
+
redirectUri: readStringOption(optionValues, "redirect-uri"),
|
|
813
|
+
region: readStringOption(optionValues, "region"),
|
|
814
|
+
};
|
|
815
|
+
if (globalFlags.noInput) {
|
|
816
|
+
options.noInput = true;
|
|
817
|
+
}
|
|
818
|
+
return options;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function buildAuthRevokeOptions(optionValues, globalFlags = {}) {
|
|
822
|
+
return {
|
|
823
|
+
dryRun: readBooleanOption(optionValues, "dry-run") === true,
|
|
824
|
+
yes:
|
|
825
|
+
globalFlags.yes === true ||
|
|
826
|
+
readBooleanOption(optionValues, "yes") === true ||
|
|
827
|
+
readBooleanOption(optionValues, "force") === true,
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
async function run(args) {
|
|
832
|
+
const helpRequested = hasFlag(args, "-h", "--help");
|
|
833
|
+
const versionRequested = hasFlag(args, "-v", "--version");
|
|
834
|
+
const globalFlags = readGlobalFlags(args);
|
|
835
|
+
const routingArgs = stripRoutingFlags(args);
|
|
836
|
+
|
|
837
|
+
if (routingArgs.length === 0) {
|
|
838
|
+
if (versionRequested && !helpRequested) {
|
|
839
|
+
console.log(`not-manage v${version}`);
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
printGlobalHelp();
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const command = normalizeResourceCommand(routingArgs[0]);
|
|
848
|
+
const sub = routingArgs[1];
|
|
849
|
+
|
|
850
|
+
if (helpRequested) {
|
|
851
|
+
printCommandSpecificHelp(command, sub);
|
|
149
852
|
return;
|
|
150
853
|
}
|
|
151
854
|
|
|
152
|
-
const json =
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
const
|
|
855
|
+
const json = globalFlags.json;
|
|
856
|
+
const { parsed, positional } = parseOptions(routingArgs.slice(2));
|
|
857
|
+
assertSingleStdinConsumer(parsed);
|
|
858
|
+
const optionValues = await mergeOptionsFile(parsed);
|
|
156
859
|
const redacted = resolveRedactionPreference(optionValues);
|
|
157
860
|
|
|
158
861
|
if (maybePrintDefaultFields(command, sub, optionValues)) {
|
|
@@ -160,47 +863,115 @@ async function run(args) {
|
|
|
160
863
|
}
|
|
161
864
|
|
|
162
865
|
if (command === "setup") {
|
|
163
|
-
await setupWizard();
|
|
866
|
+
await setupWizard(buildAuthSetupOptions(optionValues, globalFlags));
|
|
164
867
|
return;
|
|
165
868
|
}
|
|
166
869
|
|
|
167
|
-
if (command === "auth"
|
|
168
|
-
|
|
169
|
-
|
|
870
|
+
if (command === "auth") {
|
|
871
|
+
if (!sub) {
|
|
872
|
+
printAuthHelp();
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (sub === "setup") {
|
|
877
|
+
await authSetup(buildAuthSetupOptions(optionValues, globalFlags));
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (sub === "login") {
|
|
882
|
+
await authLogin({ json });
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (sub === "status") {
|
|
887
|
+
await authStatus({ json, redacted });
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (sub === "revoke") {
|
|
892
|
+
await authRevoke(buildAuthRevokeOptions(optionValues, globalFlags));
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
throw new UsageError(
|
|
897
|
+
`Unknown subcommand for auth: ${sub}\nRun \`not-manage auth --help\`.`,
|
|
898
|
+
{ code: "unknown_subcommand", hint: "not-manage auth --help" }
|
|
899
|
+
);
|
|
170
900
|
}
|
|
171
901
|
|
|
172
|
-
if (command === "
|
|
173
|
-
await
|
|
902
|
+
if (command === "whoami") {
|
|
903
|
+
await whoAmI({ json, redacted });
|
|
174
904
|
return;
|
|
175
905
|
}
|
|
176
906
|
|
|
177
|
-
if (command === "
|
|
178
|
-
await
|
|
907
|
+
if (command === "doctor") {
|
|
908
|
+
await doctor({
|
|
909
|
+
compact: globalFlags.compact,
|
|
910
|
+
failOn: readStringOption(optionValues, "fail-on"),
|
|
911
|
+
json,
|
|
912
|
+
});
|
|
179
913
|
return;
|
|
180
914
|
}
|
|
181
915
|
|
|
182
|
-
if (command === "
|
|
183
|
-
await
|
|
916
|
+
if (command === "agent-context") {
|
|
917
|
+
await agentContext({
|
|
918
|
+
compact: globalFlags.compact,
|
|
919
|
+
});
|
|
184
920
|
return;
|
|
185
921
|
}
|
|
186
922
|
|
|
187
|
-
if (command === "
|
|
188
|
-
await
|
|
923
|
+
if (command === "request") {
|
|
924
|
+
await rawRequest({
|
|
925
|
+
method: routingArgs[1],
|
|
926
|
+
path: routingArgs[2],
|
|
927
|
+
query: readStringOption(optionValues, "query"),
|
|
928
|
+
bodyFile: readStringOption(optionValues, "body-file"),
|
|
929
|
+
dryRun: readBooleanOption(optionValues, "dry-run") === true,
|
|
930
|
+
write: readBooleanOption(optionValues, "write") === true,
|
|
931
|
+
compact: globalFlags.compact,
|
|
932
|
+
json,
|
|
933
|
+
redacted,
|
|
934
|
+
});
|
|
189
935
|
return;
|
|
190
936
|
}
|
|
191
937
|
|
|
192
938
|
const resourceMetadata = getResourceMetadata(command);
|
|
939
|
+
if (resourceMetadata && !sub) {
|
|
940
|
+
printResourceOverview(command, resourceMetadata);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
|
|
193
944
|
const handler = getResourceHandler(resourceMetadata, sub);
|
|
194
945
|
|
|
195
946
|
if (resourceMetadata && handler) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
947
|
+
const resourceOptions = buildResourceOptions(
|
|
948
|
+
resourceMetadata,
|
|
949
|
+
sub,
|
|
950
|
+
optionValues,
|
|
951
|
+
positional,
|
|
952
|
+
json,
|
|
953
|
+
redacted,
|
|
954
|
+
globalFlags.compact
|
|
199
955
|
);
|
|
956
|
+
const resourceOptionsWithAgentInput = applyAgentInputOptions(sub, optionValues, resourceOptions);
|
|
957
|
+
assertRequiredResourceOptions(command, sub, resourceMetadata, resourceOptionsWithAgentInput);
|
|
958
|
+
assertResourceIdOption(command, sub, resourceOptionsWithAgentInput);
|
|
959
|
+
warnAboutRedaction(resourceMetadata, sub, optionValues, redacted);
|
|
960
|
+
await handler(resourceOptionsWithAgentInput);
|
|
200
961
|
return;
|
|
201
962
|
}
|
|
202
963
|
|
|
203
|
-
|
|
964
|
+
if (resourceMetadata) {
|
|
965
|
+
throw new UsageError(
|
|
966
|
+
`Unknown subcommand for ${command}: ${sub}\nRun \`not-manage ${command} --help\`.`,
|
|
967
|
+
{ code: "unknown_subcommand", hint: `not-manage ${command} --help` }
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
throw new UsageError(
|
|
972
|
+
`Unknown command: ${routingArgs.join(" ")}\nRun \`not-manage --help\`.`,
|
|
973
|
+
{ code: "unknown_command", hint: "not-manage --help" }
|
|
974
|
+
);
|
|
204
975
|
}
|
|
205
976
|
|
|
206
977
|
module.exports = {
|