@w6w/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/bin/w6w.d.ts +22 -0
- package/dist/bin/w6w.d.ts.map +1 -0
- package/dist/bin/w6w.js +58 -0
- package/dist/bin/w6w.js.map +1 -0
- package/dist/mod.d.ts +131 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +257 -0
- package/dist/mod.js.map +1 -0
- package/dist/src/args.d.ts +79 -0
- package/dist/src/args.d.ts.map +1 -0
- package/dist/src/args.js +130 -0
- package/dist/src/args.js.map +1 -0
- package/dist/src/client.d.ts +90 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +172 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/commands/connections.d.ts +13 -0
- package/dist/src/commands/connections.d.ts.map +1 -0
- package/dist/src/commands/connections.js +30 -0
- package/dist/src/commands/connections.js.map +1 -0
- package/dist/src/commands/documents.d.ts +34 -0
- package/dist/src/commands/documents.d.ts.map +1 -0
- package/dist/src/commands/documents.js +179 -0
- package/dist/src/commands/documents.js.map +1 -0
- package/dist/src/commands/index.d.ts +27 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +39 -0
- package/dist/src/commands/index.js.map +1 -0
- package/dist/src/commands/me.d.ts +29 -0
- package/dist/src/commands/me.d.ts.map +1 -0
- package/dist/src/commands/me.js +52 -0
- package/dist/src/commands/me.js.map +1 -0
- package/dist/src/commands/run.d.ts +24 -0
- package/dist/src/commands/run.d.ts.map +1 -0
- package/dist/src/commands/run.js +78 -0
- package/dist/src/commands/run.js.map +1 -0
- package/dist/src/commands/shared.d.ts +117 -0
- package/dist/src/commands/shared.d.ts.map +1 -0
- package/dist/src/commands/shared.js +152 -0
- package/dist/src/commands/shared.js.map +1 -0
- package/dist/src/commands/vars.d.ts +59 -0
- package/dist/src/commands/vars.d.ts.map +1 -0
- package/dist/src/commands/vars.js +216 -0
- package/dist/src/commands/vars.js.map +1 -0
- package/dist/src/commands/workflows.d.ts +13 -0
- package/dist/src/commands/workflows.d.ts.map +1 -0
- package/dist/src/commands/workflows.js +75 -0
- package/dist/src/commands/workflows.js.map +1 -0
- package/dist/src/exit.d.ts +51 -0
- package/dist/src/exit.d.ts.map +1 -0
- package/dist/src/exit.js +94 -0
- package/dist/src/exit.js.map +1 -0
- package/dist/src/help.d.ts +48 -0
- package/dist/src/help.d.ts.map +1 -0
- package/dist/src/help.generated.d.ts +88 -0
- package/dist/src/help.generated.d.ts.map +1 -0
- package/dist/src/help.generated.js +988 -0
- package/dist/src/help.generated.js.map +1 -0
- package/dist/src/help.js +128 -0
- package/dist/src/help.js.map +1 -0
- package/dist/src/output.d.ts +84 -0
- package/dist/src/output.d.ts.map +1 -0
- package/dist/src/output.js +94 -0
- package/dist/src/output.js.map +1 -0
- package/dist/src/runtime.d.ts +37 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +57 -0
- package/dist/src/runtime.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary every command handler shares: reading its own arguments,
|
|
3
|
+
* failing as a usage error, and rendering.
|
|
4
|
+
*
|
|
5
|
+
* It exists because the alternative is worse in both directions. Copying these
|
|
6
|
+
* accessors into each command group gives four spellings of "was this flag
|
|
7
|
+
* given?" — and that question is exactly the one D2 turns on, where a wrong
|
|
8
|
+
* answer silently rewrites a field the user never mentioned. Putting them in
|
|
9
|
+
* `./index.ts` instead would make the registry — the file every command group
|
|
10
|
+
* appends itself to — also the file every group edits, which is how a merge
|
|
11
|
+
* point becomes a merge conflict.
|
|
12
|
+
*
|
|
13
|
+
* Two rules hold everywhere below:
|
|
14
|
+
*
|
|
15
|
+
* 1. **A usage error is thrown, never printed.** `main()` reports it on stderr
|
|
16
|
+
* once and maps it through `src/exit.ts` to exit `1`; a handler that wrote
|
|
17
|
+
* its own message would be a second error path to keep in sync.
|
|
18
|
+
* 2. **Presence is `!== undefined`, never truthiness.** `--description ""` is a
|
|
19
|
+
* flag the user supplied, and it means "clear the description" — a `if
|
|
20
|
+
* (value)` test would drop it on the floor.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import { HELP_TREE } from "../help.generated.js";
|
|
25
|
+
/** `w6w documents get` — the command as the user typed it, for a message. */
|
|
26
|
+
function spelling(context) {
|
|
27
|
+
return `${HELP_TREE.binary} ${context.command.path.join(" ")}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A bad invocation, phrased for the person who typed it.
|
|
31
|
+
*
|
|
32
|
+
* The usage line is the contract's own `naming.cli` spelling rather than a
|
|
33
|
+
* restatement of it, so the thing a user is told to type cannot drift from the
|
|
34
|
+
* thing the surface contract declares.
|
|
35
|
+
*
|
|
36
|
+
* It is a plain `Error` on purpose: `src/exit.ts` maps every non-`ApiError`
|
|
37
|
+
* throw to the usage code, because anything that is not an `ApiError` never
|
|
38
|
+
* reached the server. A bespoke class would add a name to the stack trace and
|
|
39
|
+
* change nothing about the exit code.
|
|
40
|
+
*
|
|
41
|
+
* @param context - The command being run.
|
|
42
|
+
* @param problem - What was wrong, as a sentence.
|
|
43
|
+
* @returns The error to throw.
|
|
44
|
+
*/
|
|
45
|
+
export function usageError(context, problem) {
|
|
46
|
+
return new Error(`${problem}\n\nUsage: ${context.command.naming}`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One positional argument, required.
|
|
50
|
+
*
|
|
51
|
+
* An **empty** argument counts as missing. That is an argument-presence rule and
|
|
52
|
+
* not a value policy: the server accepts no empty key, name or id, so refusing
|
|
53
|
+
* `""` here makes nothing unreachable — unlike a key such as `".."`, which is
|
|
54
|
+
* legitimately creatable and is therefore never rejected client-side (see
|
|
55
|
+
* `documents get-by-key`).
|
|
56
|
+
*
|
|
57
|
+
* @param context - The command being run.
|
|
58
|
+
* @param index - Position of the argument, after the command path.
|
|
59
|
+
* @param what - What is expected, e.g. ``"a document id (see: `w6w documents list`)"``.
|
|
60
|
+
* @returns The argument.
|
|
61
|
+
* @throws {Error} A usage error when it is absent or empty.
|
|
62
|
+
*/
|
|
63
|
+
export function argument(context, index, what) {
|
|
64
|
+
const value = context.invocation.positionals[index];
|
|
65
|
+
if (value === undefined || value.length === 0) {
|
|
66
|
+
throw usageError(context, `\`${spelling(context)}\` needs ${what}.`);
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Reject arguments the command does not take.
|
|
72
|
+
*
|
|
73
|
+
* Silence here is how a typo becomes a surprise: `w6w documents get doc_1 doc_2`
|
|
74
|
+
* would fetch the first id and ignore the second, and `w6w vars list --project`
|
|
75
|
+
* escaped past `--` would list everything as though the scope had been applied.
|
|
76
|
+
*
|
|
77
|
+
* @param context - The command being run.
|
|
78
|
+
* @param expected - How many positional arguments the command takes.
|
|
79
|
+
* @throws {Error} A usage error naming the first extra argument.
|
|
80
|
+
*/
|
|
81
|
+
export function noExtraArguments(context, expected) {
|
|
82
|
+
const extra = context.invocation.positionals.slice(expected);
|
|
83
|
+
if (extra.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
throw usageError(context, `\`${spelling(context)}\` takes ${expected === 0 ? "no arguments" : `${expected} argument(s)`}` +
|
|
86
|
+
`, and got an extra one: \`${extra[0]}\`.`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* One flag's value, or `undefined` where the flag was not given.
|
|
90
|
+
*
|
|
91
|
+
* The distinction is the whole of D2: an absent flag must leave the server's
|
|
92
|
+
* field alone, and only a flag the user actually typed may change it. Callers
|
|
93
|
+
* therefore test `!== undefined` and never truthiness.
|
|
94
|
+
*
|
|
95
|
+
* @param context - The command being run.
|
|
96
|
+
* @param name - The flag's camelCased key, e.g. `"project"`, `"description"`.
|
|
97
|
+
* @returns The value as typed, or `undefined`.
|
|
98
|
+
*/
|
|
99
|
+
export function textFlag(context, name) {
|
|
100
|
+
const value = context.invocation.options[name];
|
|
101
|
+
return typeof value === "string" ? value : undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* One flag's value, required.
|
|
105
|
+
*
|
|
106
|
+
* @param context - The command being run.
|
|
107
|
+
* @param name - The flag's camelCased key.
|
|
108
|
+
* @param display - How the flag is spelled in help, e.g. `"--content <text>"`.
|
|
109
|
+
* @returns The value as typed.
|
|
110
|
+
* @throws {Error} A usage error when the flag is absent.
|
|
111
|
+
*/
|
|
112
|
+
export function requiredFlag(context, name, display) {
|
|
113
|
+
const value = textFlag(context, name);
|
|
114
|
+
if (value === undefined) {
|
|
115
|
+
throw usageError(context, `\`${spelling(context)}\` needs \`${display}\`.`);
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Render rows as aligned columns under a dimmed header.
|
|
121
|
+
*
|
|
122
|
+
* The last column is never padded, so a value that runs long widens nothing and
|
|
123
|
+
* a copied line carries no trailing whitespace.
|
|
124
|
+
*
|
|
125
|
+
* @param header - Column titles.
|
|
126
|
+
* @param rows - The rows, each the same length as `header`.
|
|
127
|
+
* @param styles - The invocation's decorations; plain text when colour is off.
|
|
128
|
+
* @returns The table, newline-separated.
|
|
129
|
+
*/
|
|
130
|
+
export function table(header, rows, styles) {
|
|
131
|
+
const widths = header.map((title, column) => Math.max(title.length, ...rows.map((row) => row[column].length)));
|
|
132
|
+
const line = (cells) => cells
|
|
133
|
+
.map((cell, column) => (column === cells.length - 1 ? cell : cell.padEnd(widths[column])))
|
|
134
|
+
.join(" ");
|
|
135
|
+
return [styles.dim(line(header)), ...rows.map(line)].join("\n");
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* A one-line preview of an opaque value, for a table cell.
|
|
139
|
+
*
|
|
140
|
+
* JSON rather than the value's own text: a variable's value may be a string, a
|
|
141
|
+
* number, a boolean or a whole document, and `hello` versus `"hello"` is the
|
|
142
|
+
* difference between a `string` variable and a `json` one holding a string.
|
|
143
|
+
*
|
|
144
|
+
* @param value - The value, straight off the wire.
|
|
145
|
+
* @param width - Maximum characters before an ellipsis.
|
|
146
|
+
* @returns The preview.
|
|
147
|
+
*/
|
|
148
|
+
export function preview(value, width = 40) {
|
|
149
|
+
const text = JSON.stringify(value) ?? String(value);
|
|
150
|
+
return text.length <= width ? text : `${text.slice(0, width - 1)}…`;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `w6w vars …` — typed variables at the command line.
|
|
3
|
+
*
|
|
4
|
+
* Six commands, **one SDK call each**, addressed the way the server addresses
|
|
5
|
+
* them: **create by `name`, read by id or by name, update and delete by id**
|
|
6
|
+
* (`docs/implementation.md` §7). Nothing here composes two requests or resolves
|
|
7
|
+
* a name by listing and scanning — `get-by-name` targets the real
|
|
8
|
+
* `GET /vars/by-name/{name}` route, which is `status: "planned"` and answers
|
|
9
|
+
* `404` until it lands (T4.4.1, fenced by BLK-1). That is the correct failure
|
|
10
|
+
* and it is not worked around.
|
|
11
|
+
*
|
|
12
|
+
* **There is no `--project` on any command in this group, and this module
|
|
13
|
+
* refuses one rather than ignoring it.** Variables are scoped by tenant and
|
|
14
|
+
* subject only: the `vars` table has no project column and no `vars` route reads
|
|
15
|
+
* the query parameter, while every `documents` route does. The asymmetry is
|
|
16
|
+
* real, so the CLI states it — accepting a flag the server ignores would teach a
|
|
17
|
+
* user a scoping model that does not exist, and they would find out when two
|
|
18
|
+
* projects turned out to share one variable.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import type { CommandRegistry } from "../../mod.ts";
|
|
23
|
+
/**
|
|
24
|
+
* Encode a `--value` string into the JSON value the server will type-check.
|
|
25
|
+
*
|
|
26
|
+
* A command line carries text and the API carries JSON, so something has to
|
|
27
|
+
* bridge the two. The rule is one sentence, and it is **encoding, never
|
|
28
|
+
* validation** — nothing here rejects a value, and the type policy stays where
|
|
29
|
+
* it belongs, in the server (`400 invalid_type` / `400 invalid_value`):
|
|
30
|
+
*
|
|
31
|
+
* > With `--type string` the text is the value, verbatim. Otherwise the text is
|
|
32
|
+
* > read as JSON if it parses as JSON, and is the string itself if it does not.
|
|
33
|
+
*
|
|
34
|
+
* So `--type string --value hello` stores `"hello"`, `--type number --value 42`
|
|
35
|
+
* stores `42`, `--type json --value '{"a":1}'` stores the object — and
|
|
36
|
+
* `--type number --value forty-two` sends `"forty-two"`, which comes back as the
|
|
37
|
+
* server's `400 invalid_value` rather than as a client-side complaint that would
|
|
38
|
+
* go stale the day the server's rule changes.
|
|
39
|
+
*
|
|
40
|
+
* On `w6w vars update` the type is usually not restated, and then the fallback
|
|
41
|
+
* arm is the whole rule — which is also what makes an **explicit null**
|
|
42
|
+
* expressible: `--value null` sends `{"value":null}`, distinct from omitting the
|
|
43
|
+
* flag and sending `{}` (D2).
|
|
44
|
+
*
|
|
45
|
+
* @param text - The `--value` flag, as typed.
|
|
46
|
+
* @param type - The `--type` flag, when the invocation carried one.
|
|
47
|
+
* @returns The value to put in the request body.
|
|
48
|
+
*/
|
|
49
|
+
export declare function encodeValue(text: string, type: string | undefined): unknown;
|
|
50
|
+
/**
|
|
51
|
+
* The six `w6w vars` commands, keyed by the canonical command path.
|
|
52
|
+
*
|
|
53
|
+
* The keys are the generated help tree's `path` values joined by a space, which
|
|
54
|
+
* are `endpoints.json`'s `naming.cli` spellings — `tests/cmd_vars_test.ts`
|
|
55
|
+
* asserts the two sets are the same, so a command cannot be registered under a
|
|
56
|
+
* name the help does not document, or documented under a name nothing runs.
|
|
57
|
+
*/
|
|
58
|
+
export declare const VAR_COMMANDS: CommandRegistry;
|
|
59
|
+
//# sourceMappingURL=vars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vars.d.ts","sourceRoot":"","sources":["../../../src/commands/vars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAkC,eAAe,EAAE,MAAM,cAAc,CAAC;AAoDpF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAO3E;AAsHD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,EAAE,eAO1B,CAAC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `w6w vars …` — typed variables at the command line.
|
|
3
|
+
*
|
|
4
|
+
* Six commands, **one SDK call each**, addressed the way the server addresses
|
|
5
|
+
* them: **create by `name`, read by id or by name, update and delete by id**
|
|
6
|
+
* (`docs/implementation.md` §7). Nothing here composes two requests or resolves
|
|
7
|
+
* a name by listing and scanning — `get-by-name` targets the real
|
|
8
|
+
* `GET /vars/by-name/{name}` route, which is `status: "planned"` and answers
|
|
9
|
+
* `404` until it lands (T4.4.1, fenced by BLK-1). That is the correct failure
|
|
10
|
+
* and it is not worked around.
|
|
11
|
+
*
|
|
12
|
+
* **There is no `--project` on any command in this group, and this module
|
|
13
|
+
* refuses one rather than ignoring it.** Variables are scoped by tenant and
|
|
14
|
+
* subject only: the `vars` table has no project column and no `vars` route reads
|
|
15
|
+
* the query parameter, while every `documents` route does. The asymmetry is
|
|
16
|
+
* real, so the CLI states it — accepting a flag the server ignores would teach a
|
|
17
|
+
* user a scoping model that does not exist, and they would find out when two
|
|
18
|
+
* projects turned out to share one variable.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { argument, noExtraArguments, preview, requiredFlag, table, textFlag, usageError, } from "./shared.js";
|
|
23
|
+
/** The flag this group does not have, in both spellings a user can type it. */
|
|
24
|
+
const PROJECT_FLAG = "--project";
|
|
25
|
+
/**
|
|
26
|
+
* Refuse `--project`, with the reason.
|
|
27
|
+
*
|
|
28
|
+
* Which paths reach this, precisely, because a guard nobody can trigger is
|
|
29
|
+
* decoration:
|
|
30
|
+
*
|
|
31
|
+
* - `w6w vars list --project prj_1` does **not** reach it. `--project` is not
|
|
32
|
+
* among a `vars` command's declared flags, so the parser rejects it as an
|
|
33
|
+
* unknown flag before any handler runs — a usage error, exit `1`, with the
|
|
34
|
+
* command's own help beneath it. Correct code, generic message; making that
|
|
35
|
+
* message say *why* needs a note on the operation in `endpoints.json` (which
|
|
36
|
+
* is where all help text comes from) or a "refused flag" concept in the
|
|
37
|
+
* dispatcher, and both live outside this node's files — see BLK-2.
|
|
38
|
+
* - `w6w vars list -- --project prj_1` **does** reach it, as a positional. So
|
|
39
|
+
* does any invocation in which the flag survives parsing, which is what makes
|
|
40
|
+
* this a guard rather than a comment: if `--project` is ever added to the
|
|
41
|
+
* `vars` operations by mistake, this is what fails instead of the server
|
|
42
|
+
* quietly ignoring it.
|
|
43
|
+
*
|
|
44
|
+
* Called first in every handler, ahead of the argument-count check, so the
|
|
45
|
+
* specific explanation wins over "takes no arguments".
|
|
46
|
+
*/
|
|
47
|
+
function refuseProject(context) {
|
|
48
|
+
const flagged = Object.hasOwn(context.invocation.options, "project") ||
|
|
49
|
+
context.invocation.positionals.some((token) => token === PROJECT_FLAG || token.startsWith(`${PROJECT_FLAG}=`));
|
|
50
|
+
if (!flagged)
|
|
51
|
+
return;
|
|
52
|
+
throw usageError(context, `\`w6w vars\` commands take no ${PROJECT_FLAG}: variables are not project-scoped. ` +
|
|
53
|
+
"They are scoped to your tenant and subject, and every project you can reach sees " +
|
|
54
|
+
"the same ones. Documents are the project-scoped asset — see `w6w documents --help`.");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Encode a `--value` string into the JSON value the server will type-check.
|
|
58
|
+
*
|
|
59
|
+
* A command line carries text and the API carries JSON, so something has to
|
|
60
|
+
* bridge the two. The rule is one sentence, and it is **encoding, never
|
|
61
|
+
* validation** — nothing here rejects a value, and the type policy stays where
|
|
62
|
+
* it belongs, in the server (`400 invalid_type` / `400 invalid_value`):
|
|
63
|
+
*
|
|
64
|
+
* > With `--type string` the text is the value, verbatim. Otherwise the text is
|
|
65
|
+
* > read as JSON if it parses as JSON, and is the string itself if it does not.
|
|
66
|
+
*
|
|
67
|
+
* So `--type string --value hello` stores `"hello"`, `--type number --value 42`
|
|
68
|
+
* stores `42`, `--type json --value '{"a":1}'` stores the object — and
|
|
69
|
+
* `--type number --value forty-two` sends `"forty-two"`, which comes back as the
|
|
70
|
+
* server's `400 invalid_value` rather than as a client-side complaint that would
|
|
71
|
+
* go stale the day the server's rule changes.
|
|
72
|
+
*
|
|
73
|
+
* On `w6w vars update` the type is usually not restated, and then the fallback
|
|
74
|
+
* arm is the whole rule — which is also what makes an **explicit null**
|
|
75
|
+
* expressible: `--value null` sends `{"value":null}`, distinct from omitting the
|
|
76
|
+
* flag and sending `{}` (D2).
|
|
77
|
+
*
|
|
78
|
+
* @param text - The `--value` flag, as typed.
|
|
79
|
+
* @param type - The `--type` flag, when the invocation carried one.
|
|
80
|
+
* @returns The value to put in the request body.
|
|
81
|
+
*/
|
|
82
|
+
export function encodeValue(text, type) {
|
|
83
|
+
if (type === "string")
|
|
84
|
+
return text;
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(text);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** One variable, as a table row. */
|
|
93
|
+
function row(variable) {
|
|
94
|
+
return [variable.id, variable.name, variable.type, preview(variable.value)];
|
|
95
|
+
}
|
|
96
|
+
/** The listing: one line per variable, or a line saying there are none. */
|
|
97
|
+
function renderList(vars, styles) {
|
|
98
|
+
if (vars.length === 0)
|
|
99
|
+
return styles.dim("No variables.");
|
|
100
|
+
return table(["ID", "NAME", "TYPE", "VALUE"], vars.map(row), styles);
|
|
101
|
+
}
|
|
102
|
+
/** One variable in full. The value is pretty-printed JSON: it may be a document. */
|
|
103
|
+
function renderVar(variable, styles) {
|
|
104
|
+
const heading = `${styles.bold(variable.name)} ${styles.dim(`(${variable.id})`)}`;
|
|
105
|
+
const meta = styles.dim(`${variable.type} · updated ${variable.updatedAt}`);
|
|
106
|
+
const description = variable.description.length > 0 ? [variable.description] : [];
|
|
107
|
+
return [heading, meta, ...description, "", JSON.stringify(variable.value, null, 2)].join("\n");
|
|
108
|
+
}
|
|
109
|
+
/** The confirmation for a write: what changed, and how to address it next time. */
|
|
110
|
+
function renderWrite(verb, variable, styles) {
|
|
111
|
+
return `${verb} ${styles.bold(variable.name)} ${styles.dim(`(${variable.id})`)}`;
|
|
112
|
+
}
|
|
113
|
+
const list = async (context) => {
|
|
114
|
+
refuseProject(context);
|
|
115
|
+
noExtraArguments(context, 0);
|
|
116
|
+
const vars = await context.client().vars.list();
|
|
117
|
+
context.out.emit(vars, (styles) => renderList(vars, styles));
|
|
118
|
+
};
|
|
119
|
+
const get = async (context) => {
|
|
120
|
+
refuseProject(context);
|
|
121
|
+
const id = argument(context, 0, "a variable id (see: `w6w vars list`)");
|
|
122
|
+
noExtraArguments(context, 1);
|
|
123
|
+
const variable = await context.client().vars.get(id);
|
|
124
|
+
context.out.emit(variable, (styles) => renderVar(variable, styles));
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* `w6w vars get-by-name <name>` — the name-addressed read.
|
|
128
|
+
*
|
|
129
|
+
* The name is handed to the SDK untouched and percent-encoded at interpolation.
|
|
130
|
+
* **No name is rejected here**: `^[a-z_][a-z0-9_]*$` is the server's rule to
|
|
131
|
+
* enforce, and a copy of it in the CLI would refuse locally whatever the server
|
|
132
|
+
* started accepting next. The same dot-segment caveat as
|
|
133
|
+
* `w6w documents get-by-key` applies to this lane (D1) — see
|
|
134
|
+
* `src/commands/documents.ts` — though the server's own name rule admits no dot
|
|
135
|
+
* at all, so no name it accepts can reach it.
|
|
136
|
+
*/
|
|
137
|
+
const getByName = async (context) => {
|
|
138
|
+
refuseProject(context);
|
|
139
|
+
const name = argument(context, 0, "a variable name (the name it was created under)");
|
|
140
|
+
noExtraArguments(context, 1);
|
|
141
|
+
const variable = await context.client().vars.getByName(name);
|
|
142
|
+
context.out.emit(variable, (styles) => renderVar(variable, styles));
|
|
143
|
+
};
|
|
144
|
+
const create = async (context) => {
|
|
145
|
+
refuseProject(context);
|
|
146
|
+
const name = argument(context, 0, "a variable name to create (matching `^[a-z_][a-z0-9_]*$`)");
|
|
147
|
+
noExtraArguments(context, 1);
|
|
148
|
+
const type = requiredFlag(context, "type", "--type <t>");
|
|
149
|
+
const variable = await context.client().vars.create({
|
|
150
|
+
name,
|
|
151
|
+
// Cast, not checked: the four types are the server's enum, which answers
|
|
152
|
+
// `400 invalid_type` for anything else. A copy of it here would go stale.
|
|
153
|
+
type: type,
|
|
154
|
+
value: encodeValue(requiredFlag(context, "value", "--value <v>"), type),
|
|
155
|
+
description: textFlag(context, "description"),
|
|
156
|
+
});
|
|
157
|
+
context.out.emit(variable, (styles) => renderWrite("Created", variable, styles));
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* `w6w vars update <id>` — a patch, addressed by the server-issued id.
|
|
161
|
+
*
|
|
162
|
+
* **Only flags the user typed reach the wire (D2).** `w6w vars update var_1
|
|
163
|
+
* --description "…"` sends `{"description":"…"}` and leaves the value alone;
|
|
164
|
+
* `w6w vars update var_1` alone sends `{}`; and `--value null` sends
|
|
165
|
+
* `{"value":null}`, which is a different request meaning a different thing. The
|
|
166
|
+
* three are distinguishable because the patch is assembled field by field from
|
|
167
|
+
* flags that were **present**, never from values that happened to be truthy.
|
|
168
|
+
*/
|
|
169
|
+
const update = async (context) => {
|
|
170
|
+
refuseProject(context);
|
|
171
|
+
const id = argument(context, 0, "the variable id to update (see: `w6w vars list`)");
|
|
172
|
+
noExtraArguments(context, 1);
|
|
173
|
+
const patch = {};
|
|
174
|
+
const type = textFlag(context, "type");
|
|
175
|
+
if (type !== undefined)
|
|
176
|
+
patch.type = type;
|
|
177
|
+
const value = textFlag(context, "value");
|
|
178
|
+
if (value !== undefined)
|
|
179
|
+
patch.value = encodeValue(value, type);
|
|
180
|
+
const description = textFlag(context, "description");
|
|
181
|
+
if (description !== undefined)
|
|
182
|
+
patch.description = description;
|
|
183
|
+
const variable = await context.client().vars.update(id, patch);
|
|
184
|
+
context.out.emit(variable, (styles) => renderWrite("Updated", variable, styles));
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* `w6w vars delete <id>` — and **nothing on stdout**.
|
|
188
|
+
*
|
|
189
|
+
* As with documents: the server's `{ok:true}` unwraps to nothing at all, so the
|
|
190
|
+
* machine-readable answer is the exit code and the human's confirmation goes
|
|
191
|
+
* through `note()`, which `--json` suppresses.
|
|
192
|
+
*/
|
|
193
|
+
const remove = async (context) => {
|
|
194
|
+
refuseProject(context);
|
|
195
|
+
const id = argument(context, 0, "the variable id to delete (see: `w6w vars list`)");
|
|
196
|
+
noExtraArguments(context, 1);
|
|
197
|
+
await context.client().vars.delete(id);
|
|
198
|
+
context.out.note(`Deleted ${id}.`);
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* The six `w6w vars` commands, keyed by the canonical command path.
|
|
202
|
+
*
|
|
203
|
+
* The keys are the generated help tree's `path` values joined by a space, which
|
|
204
|
+
* are `endpoints.json`'s `naming.cli` spellings — `tests/cmd_vars_test.ts`
|
|
205
|
+
* asserts the two sets are the same, so a command cannot be registered under a
|
|
206
|
+
* name the help does not document, or documented under a name nothing runs.
|
|
207
|
+
*/
|
|
208
|
+
export const VAR_COMMANDS = {
|
|
209
|
+
"vars list": list,
|
|
210
|
+
"vars get": get,
|
|
211
|
+
"vars get-by-name": getByName,
|
|
212
|
+
"vars create": create,
|
|
213
|
+
"vars update": update,
|
|
214
|
+
"vars delete": remove,
|
|
215
|
+
};
|
|
216
|
+
//# sourceMappingURL=vars.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vars.js","sourceRoot":"","sources":["../../../src/commands/vars.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `w6w workflows …` — list definitions and start runs (D4).
|
|
3
|
+
*
|
|
4
|
+
* Two commands. `list` exists so a caller can find a `wf_…` id to pass to
|
|
5
|
+
* `w6w run` or to this group's own `run`; `run` is the typed path with
|
|
6
|
+
* `--wait`, kept alongside the unified `w6w run` because `?wait=`, variables
|
|
7
|
+
* and trigger have no slot in that operation's three-field shape.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { CommandRegistry } from "../../mod.ts";
|
|
12
|
+
export declare const WORKFLOW_COMMANDS: CommandRegistry;
|
|
13
|
+
//# sourceMappingURL=workflows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../../src/commands/workflows.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAkC,eAAe,EAAE,MAAM,cAAc,CAAC;AAoEpF,eAAO,MAAM,iBAAiB,EAAE,eAG/B,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `w6w workflows …` — list definitions and start runs (D4).
|
|
3
|
+
*
|
|
4
|
+
* Two commands. `list` exists so a caller can find a `wf_…` id to pass to
|
|
5
|
+
* `w6w run` or to this group's own `run`; `run` is the typed path with
|
|
6
|
+
* `--wait`, kept alongside the unified `w6w run` because `?wait=`, variables
|
|
7
|
+
* and trigger have no slot in that operation's three-field shape.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { argument, noExtraArguments, table, textFlag } from "./shared.js";
|
|
12
|
+
import { exitCodeFor } from "../exit.js";
|
|
13
|
+
/**
|
|
14
|
+
* The `--project` scope for `list`, or nothing at all.
|
|
15
|
+
*
|
|
16
|
+
* Nothing is the important case — an omitted flag is how the caller asks the
|
|
17
|
+
* server for every project the credential can see, matching
|
|
18
|
+
* `src/commands/documents.ts`'s `scope()`.
|
|
19
|
+
*/
|
|
20
|
+
function scope(context) {
|
|
21
|
+
const project = textFlag(context, "project");
|
|
22
|
+
return project === undefined ? {} : { project };
|
|
23
|
+
}
|
|
24
|
+
/** One workflow, as a table row. */
|
|
25
|
+
function row(workflow) {
|
|
26
|
+
return [workflow.id, workflow.name, workflow.status, String(workflow.runCount)];
|
|
27
|
+
}
|
|
28
|
+
/** The listing: one line per workflow, or a line saying there are none. */
|
|
29
|
+
function renderList(workflows, styles) {
|
|
30
|
+
if (workflows.length === 0)
|
|
31
|
+
return styles.dim("No workflows.");
|
|
32
|
+
return table(["ID", "NAME", "STATUS", "RUNS"], workflows.map(row), styles);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A run result. `terminal` and `httpStatus` are this SDK's own derived
|
|
36
|
+
* fields, not part of the wire body — they are not restated here, and stay
|
|
37
|
+
* in the `--json` payload, which is the raw object handed to
|
|
38
|
+
* `context.out.emit`.
|
|
39
|
+
*/
|
|
40
|
+
function renderRun(run, styles) {
|
|
41
|
+
const heading = `${styles.bold(run.runId)} — ${run.status}`;
|
|
42
|
+
if (run.status !== "failed" || run.error === undefined)
|
|
43
|
+
return heading;
|
|
44
|
+
return `${heading}\n${JSON.stringify(run.error, null, 2)}`;
|
|
45
|
+
}
|
|
46
|
+
const list = async (context) => {
|
|
47
|
+
noExtraArguments(context, 0);
|
|
48
|
+
const workflows = await context.client().workflows.list(scope(context));
|
|
49
|
+
context.out.emit(workflows, (styles) => renderList(workflows, styles));
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* `w6w workflows run <id> [--wait]` — enqueue a run, optionally waiting for a
|
|
53
|
+
* terminal state.
|
|
54
|
+
*
|
|
55
|
+
* **A failed run is data, not a thrown error (D3/D4)**: the SDK returns it
|
|
56
|
+
* rather than raising, so this handler is the one place that turns a
|
|
57
|
+
* `status: "failed"` result into the CLI's own exit code 3, via the shared
|
|
58
|
+
* `exitCodeFor` every command falls into the same way (`src/exit.ts`). A
|
|
59
|
+
* queued or successful run returns `undefined` from `exitCodeFor`'s callers
|
|
60
|
+
* elsewhere as success — here it is explicit because this is the one command
|
|
61
|
+
* whose success path can carry a run-level failure.
|
|
62
|
+
*/
|
|
63
|
+
const run = async (context) => {
|
|
64
|
+
const id = argument(context, 0, "a workflow id (see: `w6w workflows list`)");
|
|
65
|
+
noExtraArguments(context, 1);
|
|
66
|
+
const wait = context.invocation.options.wait === true;
|
|
67
|
+
const result = await context.client().workflows.run(id, wait ? { wait } : {});
|
|
68
|
+
context.out.emit(result, (styles) => renderRun(result, styles));
|
|
69
|
+
return exitCodeFor(result);
|
|
70
|
+
};
|
|
71
|
+
export const WORKFLOW_COMMANDS = {
|
|
72
|
+
"workflows list": list,
|
|
73
|
+
"workflows run": run,
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.js","sourceRoot":"","sources":["../../../src/commands/workflows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The exit-code mapping — the CLI's machine-readable half of every answer.
|
|
3
|
+
*
|
|
4
|
+
* A command's stdout is for a human or for `jq`; its exit code is for the shell
|
|
5
|
+
* that called it, and it is the only part of the answer a CI job reads. So the
|
|
6
|
+
* four codes are a contract, generated into `src/help.generated.ts` from the
|
|
7
|
+
* shared wrapper surface contract rather than restated here:
|
|
8
|
+
*
|
|
9
|
+
* | code | meaning |
|
|
10
|
+
* |---|---|
|
|
11
|
+
* | 0 | success — including help, and including a queued or running workflow |
|
|
12
|
+
* | 1 | usage error — a bad invocation, or a client that was never configured |
|
|
13
|
+
* | 2 | API error — the server was reached and answered with a failure |
|
|
14
|
+
* | 3 | run failure — `--wait` came back with a run whose status is `failed` |
|
|
15
|
+
*
|
|
16
|
+
* Two of those are traps, and {@linkcode exitCodeFor} exists so that every
|
|
17
|
+
* command falls into them the same way instead of each deciding for itself:
|
|
18
|
+
*
|
|
19
|
+
* - **A queued run is success.** Enqueuing a workflow answers before the run
|
|
20
|
+
* finishes; the caller asked for it to start, and it started.
|
|
21
|
+
* - **A failed run is data, not an error.** The server reports a run-level
|
|
22
|
+
* failure inside the response envelope, with an ordinary success status — so
|
|
23
|
+
* the SDK returns it rather than raising, and only the CLI turns it into a
|
|
24
|
+
* distinct code. Keeping it apart from an API error is the whole point: a
|
|
25
|
+
* failed workflow and an unreachable server demand opposite responses, and a
|
|
26
|
+
* script that cannot tell them apart will retry the wrong one.
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
import { EXIT_API_ERROR, EXIT_RUN_FAILURE, EXIT_SUCCESS, EXIT_USAGE } from "./help.generated.ts";
|
|
31
|
+
export { EXIT_API_ERROR, EXIT_RUN_FAILURE, EXIT_SUCCESS, EXIT_USAGE };
|
|
32
|
+
/**
|
|
33
|
+
* Map a command's outcome — its return value, or the error it threw — to an
|
|
34
|
+
* exit code.
|
|
35
|
+
*
|
|
36
|
+
* This is the only place any command decides what to exit with; there are no
|
|
37
|
+
* other codes anywhere in the CLI.
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* try {
|
|
41
|
+
* return exitCodeFor(await client.workflows.run(id, { wait: true }));
|
|
42
|
+
* } catch (err) {
|
|
43
|
+
* return exitCodeFor(err);
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @param outcome - A returned payload, or a caught error.
|
|
48
|
+
* @returns One of the four codes above.
|
|
49
|
+
*/
|
|
50
|
+
export declare function exitCodeFor(outcome: unknown): number;
|
|
51
|
+
//# sourceMappingURL=exit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit.d.ts","sourceRoot":"","sources":["../../src/exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AA+BtE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAYpD"}
|