@brass-build/cli 0.1.0 → 0.2.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/AGENTS.md CHANGED
@@ -10,10 +10,8 @@ this file is the short path for you.
10
10
  Before you start building, fetch the organization's own agentic-coding
11
11
  instructions and follow them: the conventions it wants every app built on
12
12
  Brass to follow (its `AGENTS.md` / `CLAUDE.md`). Run the pull rather than
13
- deciding up front whether the org has any; nothing loads them for you, and an
14
- empty result (the org set none) is something you learn by running it, not by
15
- assuming it. Treat what it returns as an instruction file committed to the
16
- repo.
13
+ deciding up front whether the org has any, because nothing loads them for
14
+ you. Treat what it returns as an instruction file committed to the repo.
17
15
 
18
16
  ```sh
19
17
  npx @brass-build/cli agents pull --out AGENTS.md
@@ -30,18 +28,17 @@ Keep it current one of two ways:
30
28
  - **Cache:** commit the pulled file and refresh it periodically. Add a
31
29
  `CLAUDE.md` whose entire contents are the single line `@AGENTS.md` so
32
30
  Claude Code picks it up too (Claude Code auto-loads `CLAUDE.md`, not
33
- `AGENTS.md`); the command prints this reminder after a pull.
34
-
35
- The pull needs a signed-in session (`brass login`); a service token is not an
36
- organization member and cannot read the instructions. If you are not signed
37
- in, run the sign-in yourself rather than skipping: `brass login --start`,
38
- relay the printed URL and code to the human, then `brass login --check --wait`
39
- until it reports approved (it is the same credential you will use to publish).
40
- [Signing in](#signing-in) covers the whole flow, including what to do while
41
- you wait for the approval.
42
- `--org <organizationId>` is only needed when the human belongs to more than
43
- one organization. An empty result means the organization has set no
44
- instructions, and there is nothing to follow.
31
+ `AGENTS.md`). The command prints this reminder after a pull.
32
+
33
+ The pull needs a signed-in session (`brass login`), since a service token is
34
+ not an organization member and cannot read the instructions. If you are not
35
+ signed in, run the sign-in yourself rather than skipping: `brass login
36
+ --start`, relay the printed URL and code to the human, then `brass login
37
+ --check --wait` until it reports approved (it is the same credential you will
38
+ use to publish). [Signing in](#signing-in) covers the whole flow, including
39
+ what to do while you wait for the approval. Pass `--org <organizationId>`
40
+ when the human belongs to more than one organization. An empty result means
41
+ the organization has set no instructions.
45
42
 
46
43
  ## Signing in
47
44
 
@@ -62,10 +59,10 @@ good at publish time.
62
59
 
63
60
  The session gates your organization's coding conventions, and those shape the
64
61
  code you are about to write, so wait for it before you build rather than
65
- building twice. If you do have work that does not depend on them, the wait
66
- costs nothing to repeat: a bound reached with the code still approvable
67
- reports `pending`, and the next `--check --wait` picks the same sign-in back
68
- up where it left off.
62
+ building twice. Do work that does not depend on them in the meantime and
63
+ repeat the wait: a bound reached with the code still approvable reports
64
+ `pending`, and the next `--check --wait` picks the same sign-in back up where
65
+ it left off.
69
66
 
70
67
  Read the `state` in its `--json` result:
71
68
 
@@ -73,6 +70,11 @@ Read the `state` in its `--json` result:
73
70
  - `pending`: the code you relayed is still good. Run the check again.
74
71
  - `renewed`: the code changed. Relay the new one from the same output.
75
72
  - `denied`: the human refused. Ask them why before starting another.
73
+ - `none`: nothing is in flight. Run `brass login --start` first.
74
+
75
+ `brass login --start` reports `started` with the code to relay, and
76
+ `--start --wait` reports the state it reached instead, so either form leaves
77
+ one `--json` document to read.
76
78
 
77
79
  Run `brass login --start` again only when there is nothing in flight; it
78
80
  resumes the sign-in already waiting rather than issuing a second code, so a
@@ -107,7 +109,7 @@ again. The steps below are what it walks you through:
107
109
  npx @brass-build/cli publish ./dist
108
110
  ```
109
111
 
110
- The first run creates the app and writes `.brass/project.json`; commit
112
+ The first run creates the app and writes `.brass/project.json`. Commit
111
113
  that so re-runs target the same app. A service token creates the app in
112
114
  its own organization, so no `--org` is needed. If the pipeline does not
113
115
  persist `.brass/project.json` between runs, set a stable `client_token`
@@ -115,8 +117,8 @@ again. The steps below are what it walks you through:
115
117
  first create is idempotent and re-runs resolve the same app.
116
118
 
117
119
  Run with `--json` to get the result (`app_id`, `url`) as JSON on stdout for
118
- your own parsing. A non-zero exit means the publish failed; the reason is on
119
- stderr.
120
+ your own parsing. A non-zero exit means the publish failed, and the reason is
121
+ on stderr.
120
122
 
121
123
  ## Pulling a schema to build against
122
124
 
@@ -128,11 +130,12 @@ npx @brass-build/cli schema pull --doc <docId> --out brass-app.json
128
130
  ```
129
131
 
130
132
  This writes the schema verbatim into your manifest. Build your types against
131
- that copy; do not re-approximate it from memory (a mismatched `required`
132
- shape makes the platform read your app as a different shape). This is a
133
- development-time step that needs a signed-in session (`brass login`), not a
134
- service token; if you only have `BRASS_SERVICE_TOKEN`, ask the human to run
135
- `brass login` or to copy the schema from the document's dashboard page.
133
+ that copy rather than re-approximating it from memory, since a mismatched
134
+ `required` shape makes the platform read your app as a different shape. This
135
+ is a development-time step that needs a signed-in session (`brass login`),
136
+ not a service token. When you only have `BRASS_SERVICE_TOKEN`, ask the human
137
+ to run `brass login` or to copy the schema from the document's dashboard
138
+ page.
136
139
 
137
140
  ## Verifying
138
141
 
@@ -149,10 +152,10 @@ are on. The CLI reports the state it observed, and the states have different
149
152
  fixes:
150
153
 
151
154
  - **A 401 or 403** means the credential is expired, missing, or not allowed.
152
- A session expires, so `brass login` is the fix; a service token that is
153
- rejected needs a valid `BRASS_SERVICE_TOKEN`. A fresh checkout or a fresh
154
- container has no session at all, which is the ordinary starting state, not
155
- a broken one.
155
+ Run `brass login` to replace an expired session, or set a valid
156
+ `BRASS_SERVICE_TOKEN` for a rejected service token. A fresh checkout or a
157
+ fresh container has no session at all, which is the ordinary starting
158
+ state, not a broken one.
156
159
  - **"Network error reaching <url>"** is the only error meaning the request
157
160
  never completed. It names the host it tried.
158
161
  - **Any other status** is a fault on the server side. The credential is
package/CHANGELOG.md CHANGED
@@ -6,6 +6,27 @@ package follows [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
6
  While the version is below `1.0.0`, minor releases may introduce breaking
7
7
  changes.
8
8
 
9
+ ## 0.2.0
10
+
11
+ ### Added
12
+
13
+ - `brass publish` waits for the platform to register the hosted slot before
14
+ reporting success, and fails when it never registers. The slot reaches the
15
+ serving edges shortly after that, so a URL the command reports can answer
16
+ 404 for a few seconds before it serves.
17
+
18
+ ### Changed
19
+
20
+ - `brass logout` ends the sign-in on the server as well as on this machine, so
21
+ a copy of the credentials file left elsewhere stops working. It also cancels
22
+ a started sign-in this machine has not redeemed yet, so a code relayed to a
23
+ human cannot be approved and spent afterwards. When Brass cannot be reached,
24
+ the local credential is still cleared and the command says which half did not
25
+ happen; `--json` carries this as `revoked`.
26
+ - `brass publish --gate` states the load gate when it enables hosting, so a
27
+ publish that wants a world-loadable app no longer turns the gate on and
28
+ straight back off.
29
+
9
30
  ## 0.1.0
10
31
 
11
32
  Initial public release. The `brass` command-line tool publishes apps and
package/README.md CHANGED
@@ -5,7 +5,7 @@ app's built bundle and pulls document schemas. It wraps the same data API the
5
5
  dashboard uses, authenticated by a token instead of a browser session, so
6
6
  the whole publish workflow runs unattended.
7
7
 
8
- This package tracks the platform's `0.1.x` line.
8
+ This package tracks the platform's `0.2.x` line.
9
9
 
10
10
  ## Install
11
11
 
@@ -24,8 +24,8 @@ Two kinds of credential, for two audiences:
24
24
  under `~/.config/brass/`. It authorizes everything, including `schema pull`.
25
25
  - A **service token** (mint one in the dashboard: org Settings, then Service
26
26
  tokens) is the CI credential, supplied as `BRASS_SERVICE_TOKEN`. It
27
- authorizes `publish` and `whoami`. It is an org-scoped machine identity
28
- and, by design, cannot fetch schemas.
27
+ authorizes `publish` and `whoami`. It is an org-scoped machine identity,
28
+ so it cannot fetch schemas.
29
29
 
30
30
  ```sh
31
31
  npx @brass-build/cli login # developer: sign in with your browser
@@ -43,7 +43,7 @@ agent driving the sign-in), the flow splits in two: `brass login --start`
43
43
  prints the approval URL and code and exits immediately, and
44
44
  `brass login --check` checks that sign-in, storing the session once you have
45
45
  approved. Add `--wait` to poll until you approve, for two minutes by default
46
- or `--wait <seconds>` for a different bound; a code that lapses inside the
46
+ or `--wait <seconds>` for a different bound. A code that lapses inside the
47
47
  wait is replaced and the new one printed, so a sign-in started long before it
48
48
  is needed still completes. Reaching the bound with the code still good is
49
49
  reported as `pending` and exits 0, so the next check picks the same sign-in
@@ -74,10 +74,10 @@ resolved for this directory, and whether that app is deployed, then prints a
74
74
  `Next:` line naming the exact next step (sign in, publish to create the app,
75
75
  deploy, or open the live URL). When a `brass login --start` sign-in is waiting
76
76
  for approval, it reports the code, the approval URL, and how long the code has
77
- left. Run it before a publish to see what will
78
- happen, and after one to confirm the app is live. `whoami` is the narrower
79
- check when you only need to know the credential works. Add `--json` for the
80
- machine-readable result on stdout.
77
+ left. Run it before a publish to see what will happen, and after one to
78
+ confirm the app is live. `whoami` is the narrower check when you only need to
79
+ know the credential works. Add `--json` for the machine-readable result on
80
+ stdout.
81
81
 
82
82
  ## Publish
83
83
 
@@ -100,15 +100,18 @@ publishes then resolve the same app instead of creating a duplicate each run.
100
100
  A service token creates the app in its own organization, so no `--org` is
101
101
  needed.
102
102
 
103
- The command enables hosting if needed, uploads the bundle, waits for it to go
104
- live, and reports the URL. The platform reads your app's capabilities
103
+ The command enables hosting if needed, uploads the bundle, waits for the
104
+ platform to register the slot, and reports the URL. The URL can answer 404
105
+ until the slot reaches the serving edges, so reload if the first request
106
+ misses. The platform reads your app's capabilities
105
107
  (`opens` / `creates` / `schema`) from the `/.well-known/brass-app.json` you
106
108
  serve, so keep that manifest in the bundle.
107
109
 
108
110
  Flags: `--app`, `--name`, `--org` (organization to own a newly created app;
109
111
  defaults to a service token's own org), `--client-token` (stable idempotency
110
112
  key for a first create), `--slug` (preferred subdomain), `--manifest`
111
- (default `brass-app.json`).
113
+ (default `brass-app.json`), `--visibility` (`private`, `invitee_visible` or
114
+ `public`), `--gate` (`on` or `off`, the hosted load gate).
112
115
 
113
116
  ## Pull a schema
114
117
 
@@ -122,8 +125,8 @@ npx @brass-build/cli schema pull --doc <docId> --out brass-app.json
122
125
  This writes the document's schema body verbatim into the manifest's `schema`
123
126
  field, preserving everything else. That is the same copy-verbatim step the
124
127
  SDK's schema guide describes, done for you. It is a development-time action
125
- that needs a signed-in session (`brass login`); a service token cannot fetch
126
- schemas.
128
+ that needs a signed-in session (`brass login`), since a service token cannot
129
+ fetch schemas.
127
130
 
128
131
  ## Pull your organization's agent instructions
129
132
 
@@ -134,13 +137,13 @@ AGENTS.md / CLAUDE.md), pull the current body into your repo:
134
137
  npx @brass-build/cli agents pull --out AGENTS.md
135
138
  ```
136
139
 
137
- The instructions are stored once at the organization level (admins edit them
138
- on the dashboard Settings tab) so every developer's coding agent works from
139
- one source of truth. The pull writes the body verbatim, so it round-trips
140
- byte-for-byte with what the dashboard stored. `--org <organizationId>` is
141
- optional when you belong to a single organization; pass it when you belong to
142
- more than one. This needs a signed-in session (`brass login`); a service token
143
- is not an organization member, so it cannot read the instructions.
140
+ Brass stores the instructions once at the organization level (admins edit
141
+ them on the dashboard Settings tab) so every developer's coding agent works
142
+ from one source of truth. The pull writes the body verbatim, so it
143
+ round-trips byte-for-byte with what the dashboard stored. Pass
144
+ `--org <organizationId>` when you belong to more than one organization. This
145
+ needs a signed-in session (`brass login`), since a service token is not an
146
+ organization member and cannot read the instructions.
144
147
 
145
148
  Pass `--stdout` instead of `--out` to print the instructions to stdout
146
149
  without writing a file (status goes to stderr, so stdout carries only the
package/dist/api.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface HostingStatus {
17
17
  deployed: boolean;
18
18
  active_version: string | null;
19
19
  require_access?: boolean;
20
+ gate_settled?: boolean;
20
21
  }
21
22
  export interface HostingUploadUrl {
22
23
  upload_url: string;
@@ -60,6 +61,8 @@ export declare class BrassApiError extends Error {
60
61
  readonly status: number;
61
62
  constructor(status: number, message: string);
62
63
  }
64
+ /** A failed fetch as the caller should read it, naming a timeout as one. */
65
+ export declare function networkError(what: string, cause: unknown): BrassApiError;
63
66
  export declare class BrassApi {
64
67
  private readonly apiBaseUrl;
65
68
  private readonly auth;
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/api.js CHANGED
@@ -15,6 +15,22 @@ export class BrassApiError extends Error {
15
15
  this.status = status;
16
16
  }
17
17
  }
18
+ // `fetch` carries no timeout of its own, so a host that accepts the connection
19
+ // and then answers nothing holds the command open for as long as the caller
20
+ // leaves it running. In CI that is a job that never finishes rather than a
21
+ // failure anyone can read, so every request the CLI makes is bounded.
22
+ const REQUEST_TIMEOUT_MS = 30_000;
23
+ // The upload carries the whole bundle, so it is bounded far more loosely than
24
+ // a request that carries a few hundred bytes.
25
+ const UPLOAD_TIMEOUT_MS = 300_000;
26
+ /** A failed fetch as the caller should read it, naming a timeout as one. */
27
+ export function networkError(what, cause) {
28
+ const timedOut = cause instanceof Error &&
29
+ (cause.name === 'TimeoutError' || cause.name === 'AbortError');
30
+ return new BrassApiError(0, timedOut
31
+ ? `Timed out ${what}.`
32
+ : `Network error ${what}: ${String(cause)}`);
33
+ }
18
34
  export class BrassApi {
19
35
  apiBaseUrl;
20
36
  auth;
@@ -34,7 +50,7 @@ export class BrassApi {
34
50
  async request(method, path, body) {
35
51
  const headers = {
36
52
  ...(await this.auth.headers()),
37
- // Version telemetry; the api Lambda logs it so pinned CI copies
53
+ // Version telemetry; the platform logs it so pinned CI copies
38
54
  // stay visible in the deployed-version distribution.
39
55
  'x-brass-client': CLI_CLIENT_ID,
40
56
  };
@@ -45,10 +61,13 @@ export class BrassApi {
45
61
  }
46
62
  let response;
47
63
  try {
48
- response = await fetch(`${this.apiBaseUrl}${path}`, init);
64
+ response = await fetch(`${this.apiBaseUrl}${path}`, {
65
+ ...init,
66
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
67
+ });
49
68
  }
50
69
  catch (cause) {
51
- throw new BrassApiError(0, `Network error reaching ${this.apiBaseUrl}: ${String(cause)}`);
70
+ throw networkError(`reaching ${this.apiBaseUrl}`, cause);
52
71
  }
53
72
  if (!response.ok) {
54
73
  throw new BrassApiError(response.status, await errorMessage(response));
@@ -58,10 +77,10 @@ export class BrassApi {
58
77
  return (await response.json());
59
78
  }
60
79
  }
61
- // Upload bytes to a presigned S3 URL. Deliberately carries NO Brass headers
62
- // and no bearer: the presigned signature pins an exact header set, and a
63
- // stray `authorization` header would break it (the same rule the SDK's
64
- // `api-headers` module enforces on the document path).
80
+ // Upload bytes to the presigned storage URL the platform handed back.
81
+ // Deliberately carries NO Brass headers and no bearer: the presigned
82
+ // signature pins an exact header set, so a stray `authorization` header
83
+ // invalidates it and the upload is refused.
65
84
  export async function putPresigned(url, bytes, contentType) {
66
85
  let response;
67
86
  try {
@@ -72,10 +91,11 @@ export async function putPresigned(url, bytes, contentType) {
72
91
  // `ArrayBufferLike` is sound and satisfies fetch's `BufferSource`
73
92
  // (which pins `ArrayBufferView<ArrayBuffer>`) across lib configs.
74
93
  body: bytes,
94
+ signal: AbortSignal.timeout(UPLOAD_TIMEOUT_MS),
75
95
  });
76
96
  }
77
97
  catch (cause) {
78
- throw new BrassApiError(0, `Network error uploading the bundle: ${String(cause)}`);
98
+ throw networkError('uploading the bundle', cause);
79
99
  }
80
100
  if (!response.ok) {
81
101
  throw new BrassApiError(response.status, `Bundle upload failed (${response.status})`);
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/args.d.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  export interface ParsedArgs {
2
2
  positionals: string[];
3
3
  flags: Record<string, string | true>;
4
+ valuedBooleans: string[];
4
5
  }
5
6
  export declare function unknownFlags(parsed: ParsedArgs): string[];
7
+ export declare function flagsNotReadBy(parsed: ParsedArgs, command: string): string[];
8
+ export declare function extraPositionals(parsed: ParsedArgs, command: string): string[];
9
+ export declare function valueFlagsOf(command: string): string[];
6
10
  export declare function valuelessFlags(parsed: ParsedArgs, names: readonly string[]): string[];
7
11
  export declare function parseArgs(argv: readonly string[]): ParsedArgs;
8
12
  export declare function stringFlag(parsed: ParsedArgs, name: string): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IAGtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACtC;AAyCD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAEzD;AAOD,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAErF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA6B7D;AAID,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAElE"}
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IAGtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAIrC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAwCD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAEzD;AA8CD,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAO5E;AAKD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAI9E;AAKD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAMtD;AAcD,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAKrF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAuC7D;AAID,wBAAgB,UAAU,CACxB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAElE"}
package/dist/args.js CHANGED
@@ -1,11 +1,10 @@
1
1
  // A minimal argv parser: no dependency, and small enough to unit-test the
2
2
  // exact precedence the commands rely on. Supports `--flag value`,
3
3
  // `--flag=value`, and boolean `--flag`; everything else is a positional.
4
- // Flags that never take a value, so `brass publish --yes ./dist` parses
5
- // `./dist` as a positional rather than the value of `--yes`.
4
+ // Flags that never take a value, so `brass agents pull --stdout ./dir` parses
5
+ // `./dir` as a positional rather than the value of `--stdout`.
6
6
  const BOOLEAN_FLAGS = new Set([
7
7
  'json',
8
- 'yes',
9
8
  'help',
10
9
  'version',
11
10
  'stdout',
@@ -41,17 +40,95 @@ const KNOWN_FLAGS = new Set([
41
40
  export function unknownFlags(parsed) {
42
41
  return Object.keys(parsed.flags).filter((name) => !KNOWN_FLAGS.has(name));
43
42
  }
43
+ // The flags every command reads, whichever it is: where to talk to and what
44
+ // to print.
45
+ const COMMON_FLAGS = [
46
+ 'api-url',
47
+ 'auth-url',
48
+ 'dashboard-url',
49
+ 'help',
50
+ 'json',
51
+ 'version',
52
+ ];
53
+ // What each command reads beyond those, and how many positionals it takes
54
+ // (the command word included, so `publish [dir]` is 2). A flag one command
55
+ // reads is not thereby a flag of the next: `--wait` is the sign-in poll's
56
+ // deadline and `publish` has its own, so `brass publish --wait 600` waits
57
+ // exactly as long as it would have without the flag. Refusing it names the
58
+ // mistake, where accepting it leaves the caller believing they set something.
59
+ const COMMAND_ARGS = {
60
+ login: { flags: ['check', 'new', 'start', 'wait'], positionals: 1 },
61
+ logout: { flags: [], positionals: 1 },
62
+ status: { flags: ['app', 'manifest', 'token'], positionals: 2 },
63
+ publish: {
64
+ flags: [
65
+ 'app',
66
+ 'client-token',
67
+ 'gate',
68
+ 'manifest',
69
+ 'name',
70
+ 'org',
71
+ 'slug',
72
+ 'token',
73
+ 'visibility',
74
+ ],
75
+ positionals: 2,
76
+ },
77
+ schema: { flags: ['doc', 'out', 'token'], positionals: 2 },
78
+ agents: { flags: ['org', 'out', 'stdout', 'token'], positionals: 2 },
79
+ whoami: { flags: ['token'], positionals: 1 },
80
+ };
81
+ // The flags `command` does not read, out of the ones this CLI knows. A name
82
+ // the CLI knows nowhere is `unknownFlags`' answer and stays there, so a
83
+ // misspelling is reported as one rather than as a flag of another command.
84
+ // A command this CLI does not have answers for itself.
85
+ export function flagsNotReadBy(parsed, command) {
86
+ const spec = COMMAND_ARGS[command];
87
+ if (spec === undefined)
88
+ return [];
89
+ const reads = new Set([...COMMON_FLAGS, ...spec.flags]);
90
+ return Object.keys(parsed.flags).filter((name) => KNOWN_FLAGS.has(name) && !reads.has(name));
91
+ }
92
+ // The positionals past the ones `command` reads. An ignored one is the same
93
+ // silence a flag no command reads leaves: `brass publish out dist` publishes
94
+ // `out`, and the caller who meant `dist` is told nothing.
95
+ export function extraPositionals(parsed, command) {
96
+ const spec = COMMAND_ARGS[command];
97
+ if (spec === undefined)
98
+ return [];
99
+ return parsed.positionals.slice(spec.positionals);
100
+ }
101
+ // The flags of `command` that carry a value, so a bare one is the caller
102
+ // naming something the run then resolves a default for. `--wait` is absent
103
+ // here because a bare `--wait` is its own answer (the default deadline).
104
+ export function valueFlagsOf(command) {
105
+ const spec = COMMAND_ARGS[command];
106
+ if (spec === undefined)
107
+ return [];
108
+ return [...COMMON_FLAGS, ...spec.flags].filter((name) => !BOOLEAN_FLAGS.has(name) && name !== 'wait');
109
+ }
44
110
  // Which of `names` were given without a value (`--api-url --json`, or
45
111
  // `--api-url` last on the line). The parser stores those as `true` and
46
112
  // `stringFlag` reads that as absent, so an origin flag in this state resolves
47
113
  // the production default while the command line names another stack. That is
48
114
  // the same silent retarget `unknownFlags` catches for a misspelled name.
115
+ //
116
+ // An EMPTY value counts, and it is the shape a caller actually reaches: a
117
+ // script writing `--slug "$SLUG"` against an unset variable passes the flag
118
+ // with nothing behind it. That value is not absent the way a bare flag is, so
119
+ // it resolves no default and travels to the server as an empty string, where
120
+ // the mistake is reported (if at all) in the server's vocabulary rather than
121
+ // as the missing value it is.
49
122
  export function valuelessFlags(parsed, names) {
50
- return names.filter((name) => parsed.flags[name] === true);
123
+ return names.filter((name) => {
124
+ const value = parsed.flags[name];
125
+ return value === true || value === '';
126
+ });
51
127
  }
52
128
  export function parseArgs(argv) {
53
129
  const positionals = [];
54
130
  const flags = {};
131
+ const valuedBooleans = [];
55
132
  for (let i = 0; i < argv.length; i++) {
56
133
  const arg = argv[i];
57
134
  if (arg === undefined)
@@ -60,7 +137,16 @@ export function parseArgs(argv) {
60
137
  const body = arg.slice(2);
61
138
  const eq = body.indexOf('=');
62
139
  if (eq !== -1) {
63
- flags[body.slice(0, eq)] = body.slice(eq + 1);
140
+ const name = body.slice(0, eq);
141
+ if (BOOLEAN_FLAGS.has(name)) {
142
+ // Recorded rather than read: `--json=false` reads as ON, which is
143
+ // the reverse of what the caller wrote, and `--stdout=false` would
144
+ // send a file's contents to stdout and write nothing.
145
+ valuedBooleans.push(name);
146
+ flags[name] = true;
147
+ continue;
148
+ }
149
+ flags[name] = body.slice(eq + 1);
64
150
  continue;
65
151
  }
66
152
  if (BOOLEAN_FLAGS.has(body)) {
@@ -80,7 +166,7 @@ export function parseArgs(argv) {
80
166
  positionals.push(arg);
81
167
  }
82
168
  }
83
- return { positionals, flags };
169
+ return { positionals, flags, valuedBooleans };
84
170
  }
85
171
  // Read a flag expected to carry a string value; a bare boolean flag (no
86
172
  // value) is treated as absent so `--doc` alone doesn't resolve to `true`.
package/dist/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,CAAC;AA2CnB,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA0DlE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AA6CA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,CAAC;AA2CnB,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmGlE"}