@brass-build/cli 0.3.0 → 0.4.1
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 +177 -11
- package/CHANGELOG.md +29 -0
- package/README.md +76 -14
- package/dist/api.d.ts +45 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +21 -2
- package/dist/api.js.map +1 -1
- package/dist/approval-prompt.d.ts +25 -0
- package/dist/approval-prompt.d.ts.map +1 -0
- package/dist/approval-prompt.js +44 -0
- package/dist/approval-prompt.js.map +1 -0
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +10 -1
- package/dist/args.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +197 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +28 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +369 -29
- package/dist/commands.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -1
- package/dist/config.js.map +1 -1
- package/dist/login.d.ts +1 -0
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +24 -12
- package/dist/login.js.map +1 -1
- package/dist/project.d.ts +8 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +75 -7
- package/dist/project.js.map +1 -1
- package/dist/sdk-pairing.d.ts +9 -0
- package/dist/sdk-pairing.d.ts.map +1 -0
- package/dist/sdk-pairing.js +42 -0
- package/dist/sdk-pairing.js.map +1 -0
- package/dist/session.d.ts +18 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +95 -12
- package/dist/session.js.map +1 -1
- package/dist/store.d.ts +10 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +41 -0
- package/dist/store.js.map +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +2 -1
- package/src/api.ts +80 -2
- package/src/approval-prompt.ts +75 -0
- package/src/args.ts +10 -1
- package/src/cli.ts +240 -18
- package/src/commands.ts +479 -36
- package/src/config.ts +15 -2
- package/src/login.ts +34 -11
- package/src/project.ts +82 -7
- package/src/sdk-pairing.ts +53 -0
- package/src/session.ts +135 -11
- package/src/store.ts +77 -0
- package/src/version.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Instructions for AI coding agents
|
|
2
2
|
|
|
3
3
|
You are likely an AI coding agent publishing a Brass app you built against
|
|
4
|
-
`@brass-build/client`. This tool is how you ship it and how you
|
|
5
|
-
|
|
4
|
+
`@brass-build/client`. This tool is how you ship it, and how you read the
|
|
5
|
+
document you are building against. The [README](./README.md) is the full reference;
|
|
6
6
|
this file is the short path for you.
|
|
7
7
|
|
|
8
8
|
## Follow your organization's coding instructions first
|
|
@@ -50,8 +50,11 @@ npx @brass-build/cli login --start # prints the approval URL + code
|
|
|
50
50
|
npx @brass-build/cli login --check --wait # polls until they approve
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
`--start` prints an approval URL and a short code and exits.
|
|
54
|
-
|
|
53
|
+
`--start` prints an approval URL and a short code and exits. **Put both in the
|
|
54
|
+
visible text of your next message**, not only in the command output: most
|
|
55
|
+
interfaces collapse tool output, so a link left there reaches nobody and the
|
|
56
|
+
sign-in waits forever. Write the URL and the code out, say what the person has
|
|
57
|
+
to do with them, then run `--check --wait`. It polls for up to two
|
|
55
58
|
minutes (`--wait <seconds>` for a different bound) and stores the session the
|
|
56
59
|
moment they approve. A code that lapses is replaced and the new one printed,
|
|
57
60
|
so the sign-in outlives any single code and a session started early is still
|
|
@@ -95,14 +98,16 @@ publish, deploy, or open the live URL). Run it, do what it says, then run it
|
|
|
95
98
|
again. The steps below are what it walks you through:
|
|
96
99
|
|
|
97
100
|
1. Build the app to a static bundle (its `brass-app.json` capability
|
|
98
|
-
manifest must be in the output).
|
|
101
|
+
manifest must be in the output, at `/.well-known/brass-app.json`).
|
|
102
|
+
Confirm it is there after the build: some bundlers skip dot-directories
|
|
103
|
+
when they copy static assets.
|
|
99
104
|
2. Make sure a credential is available: `BRASS_SERVICE_TOKEN` in the
|
|
100
105
|
environment (or `--token`) for CI, or a `brass login` session for local
|
|
101
106
|
development. When `brass status` reports none, run the sign-in yourself,
|
|
102
107
|
as [Signing in](#signing-in) describes.
|
|
103
108
|
Starting it, relaying the URL, and checking it through to approved is your
|
|
104
109
|
step, not a handoff you stop at. (Or the human mints a service token in
|
|
105
|
-
the dashboard: org Settings, then
|
|
110
|
+
the dashboard: org Settings, then Access tokens.)
|
|
106
111
|
3. Publish:
|
|
107
112
|
|
|
108
113
|
```sh
|
|
@@ -114,22 +119,148 @@ again. The steps below are what it walks you through:
|
|
|
114
119
|
its own organization, so no `--org` is needed. If the pipeline does not
|
|
115
120
|
persist `.brass/project.json` between runs, set a stable `client_token`
|
|
116
121
|
(a `"client_token"` in `brass-app.json`, or `--client-token`) so the
|
|
117
|
-
first create is idempotent and re-runs resolve the same app.
|
|
122
|
+
first create is idempotent and re-runs resolve the same app. A create
|
|
123
|
+
that carries no `client_token` warns on stderr; act on that warning,
|
|
124
|
+
because the duplicate apps it predicts appear only on later runs.
|
|
125
|
+
|
|
126
|
+
The command reads `<dir>/.well-known/brass-app.json`, then
|
|
127
|
+
`brass-app.json` in the working directory, so a manifest in either place
|
|
128
|
+
is found without `--manifest`.
|
|
118
129
|
|
|
119
130
|
Run with `--json` to get the result (`app_id`, `url`) as JSON on stdout for
|
|
120
131
|
your own parsing. A non-zero exit means the publish failed, and the reason is
|
|
121
132
|
on stderr.
|
|
122
133
|
|
|
134
|
+
## Opening the app in a browser, signed in
|
|
135
|
+
|
|
136
|
+
Building the app is not verifying it. What a person will do is open it,
|
|
137
|
+
sign in, and use it, and until you have done that yourself you know only
|
|
138
|
+
that it compiles. `brass browser-session` is how you sign in: it prints a
|
|
139
|
+
URL that opens the app as the human whose machine you are on, so you can
|
|
140
|
+
drive the real thing rather than reporting it verified by types.
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
npx @brass-build/cli browser-session --return-to http://localhost:5173/
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
That prints one URL on stdout. Open it in the browser you drive, and the
|
|
147
|
+
app boots signed in. The URL is single-use and expires two minutes after
|
|
148
|
+
it is printed, so mint it at the moment you are ready to navigate, not
|
|
149
|
+
ahead of time, and put it straight into the browser: it is a credential
|
|
150
|
+
for as long as it lives, so keep it out of files you commit, PR bodies,
|
|
151
|
+
and anything you print back to the human.
|
|
152
|
+
|
|
153
|
+
`--return-to` is where the browser lands, and it has to be on the app's
|
|
154
|
+
redirect allowlist. A new app allows any `localhost` and `127.0.0.1`
|
|
155
|
+
port, so a dev server needs nothing configured. `--app <appId>` names the
|
|
156
|
+
app, and without it the command reads `.brass/project.json`, so after a
|
|
157
|
+
publish in the same directory you can leave it off. `--json` writes the
|
|
158
|
+
result to stdout as `{ state, url, app_id, return_to, expires_in_seconds }`.
|
|
159
|
+
Read the URL from there in a script, rather than parsing the plain output.
|
|
160
|
+
|
|
161
|
+
Run `brass login` before this command. The URL opens the app as the person
|
|
162
|
+
this machine is signed in as, so the command fails without one.
|
|
163
|
+
`BRASS_SERVICE_TOKEN` does not work here, because a service token belongs to
|
|
164
|
+
an organization rather than to a person.
|
|
165
|
+
|
|
166
|
+
Point it at the published URL to drive what you actually shipped:
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
npx @brass-build/cli browser-session --return-to https://<slug>.onbrass.app/
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
A published app allows its own URL, and the printed link carries the
|
|
173
|
+
browser through the hosted app's access gate as well as signing it in, so
|
|
174
|
+
one navigation reaches the running app either way.
|
|
175
|
+
|
|
176
|
+
The published URL is also the one to use when the app was first created by
|
|
177
|
+
your CI rather than from a machine someone works on. Such an app carries no
|
|
178
|
+
`localhost` entry, so a handoff aimed at a dev server answers that the
|
|
179
|
+
`return_to` is not on the allowlist. Add the entry yourself to work locally
|
|
180
|
+
(the app's Redirect URLs, in its dashboard page) or point the handoff at
|
|
181
|
+
what CI published.
|
|
182
|
+
|
|
183
|
+
### You can drive a browser
|
|
184
|
+
|
|
185
|
+
If you have no browser tool to hand, install one rather than concluding
|
|
186
|
+
this cannot be done from where you are: `npm i -D playwright` (then
|
|
187
|
+
`npx playwright install chromium`) or `npm i -D puppeteer` gives you a
|
|
188
|
+
headless Chromium you script from Node, which is all this needs. A
|
|
189
|
+
sandbox with no display still runs headless Chromium. Reaching for a
|
|
190
|
+
`curl` of the page instead does not verify the app: the sign-in and the
|
|
191
|
+
app's own rendering both happen in the browser's JavaScript, so a fetch
|
|
192
|
+
of the HTML shows you a loading shell whatever is wrong underneath.
|
|
193
|
+
|
|
194
|
+
Drive it the way a person would: sign in through the URL, do the thing
|
|
195
|
+
the app is for, and read the result off the screen. Take a screenshot at
|
|
196
|
+
a phone width as well as a desktop one.
|
|
197
|
+
|
|
198
|
+
An app your organization owns needs no approval step: the command mints for
|
|
199
|
+
it directly. That covers the ordinary loop, where `brass publish` creates
|
|
200
|
+
the app after you signed in, and it covers an app somebody else published
|
|
201
|
+
first, from a colleague's machine or from CI.
|
|
202
|
+
|
|
203
|
+
The URL grants no more than your current session: it signs in as the
|
|
204
|
+
same person, in the same apps they have approved. `brass logout` ends
|
|
205
|
+
it along with everything else this machine holds.
|
|
206
|
+
|
|
207
|
+
That is a session for the app, so drive what the app itself renders.
|
|
208
|
+
Brass's own hosted dialogs (the document picker, sharing, version
|
|
209
|
+
history) authenticate from a Brass session the person established in that
|
|
210
|
+
browser by signing in there, which is deliberately more than a machine's
|
|
211
|
+
credential carries: it would reach their whole account. Exercise those in
|
|
212
|
+
a browser you signed in to yourself, and build the app so the paths you
|
|
213
|
+
drive do not depend on one opening.
|
|
214
|
+
|
|
215
|
+
### When it says the app needs approving
|
|
216
|
+
|
|
217
|
+
Opening an app that belongs to another organization is the one case that
|
|
218
|
+
asks a human first. The command answers `needs_approval` with an
|
|
219
|
+
`approval_url`:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{ "state": "needs_approval", "app_id": "brass_app_...", "approval_url": "https://auth.brass.build/device/approve-app?request=..." }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
You cannot approve it. Give the human the `approval_url`, ask them to
|
|
226
|
+
open it and approve, then run the same command again. They have to be
|
|
227
|
+
signed in to Brass as the same account this machine is signed in as: they
|
|
228
|
+
are approving one of their own machines.
|
|
229
|
+
|
|
230
|
+
Re-running the command while you wait hands you the same link, with its
|
|
231
|
+
lifetime refreshed, so nothing you have already relayed stops working and
|
|
232
|
+
there is no second URL to send. `brass status` reports the outstanding
|
|
233
|
+
approval and how long it has left, so you never have to guess whether one
|
|
234
|
+
is still in flight.
|
|
235
|
+
|
|
236
|
+
Do not sign out and back in to attach the app to your session: that
|
|
237
|
+
discards a working credential and still needs the same human approval.
|
|
238
|
+
Relay the URL.
|
|
239
|
+
|
|
240
|
+
When you know that app's id before signing in, and are not signed in yet,
|
|
241
|
+
name it on the sign-in instead and one approval covers the pair:
|
|
242
|
+
|
|
243
|
+
```sh
|
|
244
|
+
npx @brass-build/cli login --start --app brass_app_...
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The approval page then names that app beside the CLI, and
|
|
248
|
+
`brass browser-session` mints for it on the first try.
|
|
249
|
+
|
|
123
250
|
## Pulling a schema to build against
|
|
124
251
|
|
|
125
252
|
To interoperate with documents another app or importer produces, do not
|
|
126
253
|
hand-write the schema. Open one of its documents and pull the real body:
|
|
127
254
|
|
|
128
255
|
```sh
|
|
129
|
-
npx @brass-build/cli schema pull --doc <docId>
|
|
256
|
+
npx @brass-build/cli schema pull --doc <docId>
|
|
130
257
|
```
|
|
131
258
|
|
|
132
|
-
This writes the schema verbatim into your manifest.
|
|
259
|
+
This writes the schema verbatim into your manifest. Without `--out` it
|
|
260
|
+
merges into an existing one (`brass-app.json`, `.well-known/`,
|
|
261
|
+
`public/.well-known/`, `static/.well-known/`, in that order), so the
|
|
262
|
+
schema lands in the file your bundle serves rather than a second one
|
|
263
|
+
beside it. Build your types against
|
|
133
264
|
that copy rather than re-approximating it from memory, since a mismatched
|
|
134
265
|
`required` shape makes the platform read your app as a different shape. This
|
|
135
266
|
is a development-time step that needs a signed-in session (`brass login`),
|
|
@@ -137,13 +268,48 @@ not a service token. When you only have `BRASS_SERVICE_TOKEN`, ask the human
|
|
|
137
268
|
to run `brass login` or to copy the schema from the document's dashboard
|
|
138
269
|
page.
|
|
139
270
|
|
|
271
|
+
## Reading what the document holds
|
|
272
|
+
|
|
273
|
+
The schema is the shape; this is the data. Read it before you write code
|
|
274
|
+
against it, so your field names, types, and the values you branch on come
|
|
275
|
+
from the document rather than from a guess at what the schema's words mean:
|
|
276
|
+
|
|
277
|
+
```sh
|
|
278
|
+
npx @brass-build/cli contents --doc <docId>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
This writes `contents.json`: the whole document, keyed by root container. A
|
|
282
|
+
map root is the object your app reads through `doc.map(root)`, so what is in
|
|
283
|
+
the file is what you will render. `--stdout` pipes it instead.
|
|
284
|
+
|
|
285
|
+
Read the whole file, not the first few records. A file's records are grouped
|
|
286
|
+
by type, so its opening records are a couple of the types it carries and none
|
|
287
|
+
of the rest, and an app built against those breaks on the first record of any
|
|
288
|
+
other type. Work out the full set before you design anything:
|
|
289
|
+
|
|
290
|
+
```sh
|
|
291
|
+
npx @brass-build/cli contents --doc <docId> --stdout \
|
|
292
|
+
| jq '.instances | map(.type) | group_by(.) | map({type: .[0], count: length})'
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Then pull an example of each type you plan to handle and build against those.
|
|
296
|
+
`--stream <name>` reads a stream other than `default`. This needs the same
|
|
297
|
+
signed-in session `schema pull` does.
|
|
298
|
+
|
|
299
|
+
Reading a file Brass is still importing waits for the import to finish, so
|
|
300
|
+
the command runs long on a large one rather than failing. It prints each step
|
|
301
|
+
to stderr; `--no-wait` reads once and fails instead.
|
|
302
|
+
|
|
140
303
|
## Verifying
|
|
141
304
|
|
|
142
305
|
`npx @brass-build/cli status` is the check to run before and after a publish:
|
|
143
306
|
it confirms the credential authenticates and reports whether the app is
|
|
144
307
|
deployed, with the next step to take. `npx @brass-build/cli whoami` is the
|
|
145
|
-
narrower check when you only need to confirm the credential works.
|
|
146
|
-
|
|
308
|
+
narrower check when you only need to confirm the credential works.
|
|
309
|
+
|
|
310
|
+
After a publish, open the reported URL and drive the app signed in, as
|
|
311
|
+
[Opening the app in a browser](#opening-the-app-in-a-browser-signed-in)
|
|
312
|
+
describes. That is the check the others stand in for.
|
|
147
313
|
|
|
148
314
|
## When a command fails
|
|
149
315
|
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,35 @@ 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.4.1
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `brass publish` checks the build output before it changes anything about the
|
|
14
|
+
app, so a publish from a missing or empty directory leaves the app as it
|
|
15
|
+
was.
|
|
16
|
+
- Commands name the CLI as the app making the call, not only the person signed
|
|
17
|
+
in. `brass login` reports a sign-in the server has stopped accepting, rather
|
|
18
|
+
than waiting out its own deadline on a code that can no longer be approved.
|
|
19
|
+
|
|
20
|
+
## 0.4.0
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- `brass contents --doc <docId>` writes a document out as JSON, so you can
|
|
25
|
+
build and test against the data your app will really see rather than
|
|
26
|
+
against a fixture you wrote by hand. Each root container is a key,
|
|
27
|
+
holding what `doc.map(root)` and `doc.list(root)` return.
|
|
28
|
+
- `brass browser-session --return-to <url>` prints a single-use URL that opens
|
|
29
|
+
your app signed in as you, so a coding agent driving a browser can check its
|
|
30
|
+
work as a signed-in user.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- `brass publish` and `brass schema pull` look for `brass-app.json` in the
|
|
35
|
+
current directory and the common bundle locations, so neither needs
|
|
36
|
+
`--manifest` or `--out` unless the manifest sits somewhere else.
|
|
37
|
+
|
|
9
38
|
## 0.3.0
|
|
10
39
|
|
|
11
40
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# @brass-build/cli
|
|
2
2
|
|
|
3
3
|
From a terminal or a CI pipeline, the `brass` command publishes a Brass
|
|
4
|
-
app's built bundle and
|
|
4
|
+
app's built bundle and reads the documents you build against. 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.2.x` line.
|
|
9
|
-
|
|
10
8
|
## Install
|
|
11
9
|
|
|
12
10
|
No install step. Run it with `npx`:
|
|
@@ -62,6 +60,21 @@ export BRASS_SERVICE_TOKEN=brass_sk_...
|
|
|
62
60
|
npx @brass-build/cli whoami
|
|
63
61
|
```
|
|
64
62
|
|
|
63
|
+
## Opening your app signed in
|
|
64
|
+
|
|
65
|
+
`browser-session` prints a single-use URL that opens your app as you, for a
|
|
66
|
+
browser an automated tool is driving:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
npx @brass-build/cli browser-session --return-to http://localhost:5173/
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
It exists for coding agents, which have no browser session of their own and
|
|
73
|
+
otherwise cannot check that what they built works for a signed-in user. If you
|
|
74
|
+
are at your own machine, opening the app in your own browser does the same
|
|
75
|
+
thing with fewer steps. `AGENTS.md` in this package documents the flow,
|
|
76
|
+
including what to do when the app has not been approved for this machine yet.
|
|
77
|
+
|
|
65
78
|
## Status
|
|
66
79
|
|
|
67
80
|
`status` reports the credential and app state for the target environment and
|
|
@@ -99,8 +112,9 @@ For a pipeline that stands the app up from scratch and does not persist
|
|
|
99
112
|
`.brass/project.json` between runs, set a stable `client_token` (a
|
|
100
113
|
`"client_token"` in `brass-app.json`, or `--client-token`). Repeated first
|
|
101
114
|
publishes then resolve the same app instead of creating a duplicate each run.
|
|
102
|
-
A
|
|
103
|
-
|
|
115
|
+
A create that carries no `client_token` says so on stderr, since the duplicate
|
|
116
|
+
it can produce shows up only later. A service token creates the app in its own
|
|
117
|
+
organization, so no `--org` is needed.
|
|
104
118
|
|
|
105
119
|
The command enables hosting if needed, uploads the bundle, waits for the
|
|
106
120
|
platform to register the slot, and reports the URL. The URL can answer 404
|
|
@@ -109,11 +123,17 @@ misses. The platform reads your app's capabilities
|
|
|
109
123
|
(`opens` / `creates` / `schema`) from the `/.well-known/brass-app.json` you
|
|
110
124
|
serve, so keep that manifest in the bundle.
|
|
111
125
|
|
|
126
|
+
Without `--manifest`, the command reads `<dir>/.well-known/brass-app.json`
|
|
127
|
+
and falls back to `brass-app.json` in the working directory, so the manifest
|
|
128
|
+
you ship at `/.well-known/` is found where it already sits. A manifest that is
|
|
129
|
+
present and cannot be parsed fails the publish, naming the file.
|
|
130
|
+
|
|
112
131
|
Flags: `--app`, `--name`, `--org` (organization to own a newly created app;
|
|
113
132
|
defaults to a service token's own org), `--client-token` (stable idempotency
|
|
114
|
-
key for a first create), `--slug` (preferred subdomain), `--manifest`
|
|
115
|
-
|
|
116
|
-
`public`), `--gate` (`on` or `off`, the hosted load
|
|
133
|
+
key for a first create), `--slug` (preferred subdomain), `--manifest` (a
|
|
134
|
+
manifest path, overriding the search above), `--visibility` (`private`,
|
|
135
|
+
`invitee_visible` or `public`), `--gate` (`on` or `off`, the hosted load
|
|
136
|
+
gate).
|
|
117
137
|
|
|
118
138
|
## Pull a schema
|
|
119
139
|
|
|
@@ -121,14 +141,55 @@ To build against a shape another app or importer produces, open one of its
|
|
|
121
141
|
documents and copy its schema into your manifest:
|
|
122
142
|
|
|
123
143
|
```sh
|
|
124
|
-
npx @brass-build/cli schema pull --doc <docId>
|
|
144
|
+
npx @brass-build/cli schema pull --doc <docId>
|
|
125
145
|
```
|
|
126
146
|
|
|
127
147
|
This writes the document's schema body verbatim into the manifest's `schema`
|
|
128
148
|
field, preserving everything else. That is the same copy-verbatim step the
|
|
129
|
-
SDK's schema guide describes, done for you.
|
|
130
|
-
|
|
131
|
-
|
|
149
|
+
SDK's schema guide describes, done for you.
|
|
150
|
+
|
|
151
|
+
Without `--out` it merges into an existing manifest, checking
|
|
152
|
+
`brass-app.json`, `.well-known/`, `public/.well-known/` and
|
|
153
|
+
`static/.well-known/` in that order, and writes `brass-app.json` when it finds
|
|
154
|
+
none. It never writes into a build output directory, where the next build
|
|
155
|
+
would drop it.
|
|
156
|
+
|
|
157
|
+
Pulling a schema is a development-time action that needs a signed-in session
|
|
158
|
+
(`brass login`), since a service token cannot fetch schemas.
|
|
159
|
+
|
|
160
|
+
## Read what a document holds
|
|
161
|
+
|
|
162
|
+
A schema says what shape the records take; to get the records themselves,
|
|
163
|
+
write the document out as JSON:
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
npx @brass-build/cli contents --doc <docId>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This writes `contents.json` (`--out <path>` for somewhere else, `--stdout` to
|
|
170
|
+
pipe it). The file is the whole document, keyed by root container: a map root
|
|
171
|
+
is the object your app reads through `doc.map(root)`, a list root its items,
|
|
172
|
+
in the same shapes your code will see.
|
|
173
|
+
|
|
174
|
+
The whole document, not a sample. A file's records are grouped by type, so any
|
|
175
|
+
slice off the front carries a couple of the types it holds and none of the
|
|
176
|
+
rest; with the file on disk you can count the types, pull an example of each,
|
|
177
|
+
or filter to one, and every answer covers everything the document has:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
npx @brass-build/cli contents --doc <docId> --stdout \
|
|
181
|
+
| jq '.instances | map(.type) | group_by(.) | map({type: .[0], count: length})'
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Brass fetches the document the way an app does, as the compact CRDT snapshot
|
|
185
|
+
plus the ops after it, and unpacks it here, so the download stays small
|
|
186
|
+
whatever the file's size. `--stream <name>` reads a stream other than
|
|
187
|
+
`default` and `--branch <id>` a branch other than the default. Like
|
|
188
|
+
`schema pull`, this needs a signed-in session (`brass login`).
|
|
189
|
+
|
|
190
|
+
Reading a file Brass is still importing waits for the import to finish, and
|
|
191
|
+
reports each step it moves through. `--wait <seconds>` moves the deadline
|
|
192
|
+
(900 by default) and `--no-wait` reads once and fails instead.
|
|
132
193
|
|
|
133
194
|
## Pull your organization's agent instructions
|
|
134
195
|
|
|
@@ -169,9 +230,10 @@ whenever you pull to any file other than `CLAUDE.md`.
|
|
|
169
230
|
```
|
|
170
231
|
|
|
171
232
|
The service token creates the app in its own organization on the first run.
|
|
172
|
-
Give `brass-app.json` a stable `"client_token"` so that first create is
|
|
233
|
+
Give your `brass-app.json` a stable `"client_token"` so that first create is
|
|
173
234
|
idempotent (repeated runs resolve the same app rather than duplicating it),
|
|
174
|
-
or commit `.brass/project.json` to pin the app id.
|
|
235
|
+
or commit `.brass/project.json` to pin the app id. A run with neither creates
|
|
236
|
+
a new app each time, and warns that it did.
|
|
175
237
|
|
|
176
238
|
Add `--json` to any command to emit the machine-readable result on stdout
|
|
177
239
|
(human status stays on stderr).
|
package/dist/api.d.ts
CHANGED
|
@@ -42,6 +42,45 @@ export interface DocumentStreams {
|
|
|
42
42
|
export interface DocumentTypeSummary {
|
|
43
43
|
schema_type?: string;
|
|
44
44
|
}
|
|
45
|
+
export type DocumentJoinSnapshot = {
|
|
46
|
+
kind: 'inline';
|
|
47
|
+
data_b64: string;
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'presigned';
|
|
50
|
+
url: string;
|
|
51
|
+
expires_at: string;
|
|
52
|
+
raw_bytes: number;
|
|
53
|
+
};
|
|
54
|
+
export type DocumentJoinTailOp = {
|
|
55
|
+
seq: number;
|
|
56
|
+
op_blob_b64: string;
|
|
57
|
+
} | {
|
|
58
|
+
seq: number;
|
|
59
|
+
op_blob_url: string;
|
|
60
|
+
op_blob_bytes: number;
|
|
61
|
+
};
|
|
62
|
+
export interface DocumentWorkStatus {
|
|
63
|
+
message: string;
|
|
64
|
+
pending: boolean;
|
|
65
|
+
blocking: boolean;
|
|
66
|
+
progress?: number;
|
|
67
|
+
}
|
|
68
|
+
export interface DocumentJoin {
|
|
69
|
+
doc_id: string;
|
|
70
|
+
branch_id: string;
|
|
71
|
+
stream_branch_id?: string;
|
|
72
|
+
name?: string;
|
|
73
|
+
schema_type?: string;
|
|
74
|
+
snapshot: DocumentJoinSnapshot | null;
|
|
75
|
+
tail_ops: DocumentJoinTailOp[];
|
|
76
|
+
snapshot_seq: number;
|
|
77
|
+
current_seq: number;
|
|
78
|
+
status?: DocumentWorkStatus;
|
|
79
|
+
}
|
|
80
|
+
export interface DocumentDetail {
|
|
81
|
+
doc_id: string;
|
|
82
|
+
status?: DocumentWorkStatus;
|
|
83
|
+
}
|
|
45
84
|
export interface AgentInstructionsResponse {
|
|
46
85
|
content: string;
|
|
47
86
|
updated_at?: string;
|
|
@@ -61,6 +100,12 @@ export declare class BrassApiError extends Error {
|
|
|
61
100
|
readonly status: number;
|
|
62
101
|
constructor(status: number, message: string);
|
|
63
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Fetch bytes from a presigned URL. Not an API call: the signature is the
|
|
105
|
+
* credential, so no auth header goes with it, and sending one is refused as
|
|
106
|
+
* a second credential on the request.
|
|
107
|
+
*/
|
|
108
|
+
export declare function getPresigned(url: string): Promise<Uint8Array>;
|
|
64
109
|
/** A failed fetch as the caller should read it, naming a timeout as one. */
|
|
65
110
|
export declare function networkError(what: string, cause: unknown): BrassApiError;
|
|
66
111
|
export declare class BrassApi {
|
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
|
@@ -23,6 +23,24 @@ const REQUEST_TIMEOUT_MS = 30_000;
|
|
|
23
23
|
// The upload carries the whole bundle, so it is bounded far more loosely than
|
|
24
24
|
// a request that carries a few hundred bytes.
|
|
25
25
|
const UPLOAD_TIMEOUT_MS = 300_000;
|
|
26
|
+
/**
|
|
27
|
+
* Fetch bytes from a presigned URL. Not an API call: the signature is the
|
|
28
|
+
* credential, so no auth header goes with it, and sending one is refused as
|
|
29
|
+
* a second credential on the request.
|
|
30
|
+
*/
|
|
31
|
+
export async function getPresigned(url) {
|
|
32
|
+
let response;
|
|
33
|
+
try {
|
|
34
|
+
response = await fetch(url, { signal: AbortSignal.timeout(UPLOAD_TIMEOUT_MS) });
|
|
35
|
+
}
|
|
36
|
+
catch (cause) {
|
|
37
|
+
throw networkError('fetching document bytes', cause);
|
|
38
|
+
}
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new BrassApiError(response.status, `Could not fetch the document's bytes (${response.status}).`);
|
|
41
|
+
}
|
|
42
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
43
|
+
}
|
|
26
44
|
/** A failed fetch as the caller should read it, naming a timeout as one. */
|
|
27
45
|
export function networkError(what, cause) {
|
|
28
46
|
const timedOut = cause instanceof Error &&
|
|
@@ -50,8 +68,9 @@ export class BrassApi {
|
|
|
50
68
|
async request(method, path, body) {
|
|
51
69
|
const headers = {
|
|
52
70
|
...(await this.auth.headers()),
|
|
53
|
-
//
|
|
54
|
-
//
|
|
71
|
+
// Names this CLI and its version. Brass answers a build too old to
|
|
72
|
+
// serve with an upgrade message, rather than a failure that names
|
|
73
|
+
// something else.
|
|
55
74
|
'x-brass-client': CLI_CLIENT_ID,
|
|
56
75
|
};
|
|
57
76
|
let init = { method, headers };
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,mEAAmE;AAGnE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,mEAAmE;AAGnE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAyJ7C,yEAAyE;AACzE,6EAA6E;AAC7E,8CAA8C;AAC9C,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,MAAM,CAAS;IACxB,YAAY,MAAc,EAAE,OAAe;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,sEAAsE;AACtE,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,8EAA8E;AAC9E,8CAA8C;AAC9C,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,aAAa,CACrB,QAAQ,CAAC,MAAM,EACf,yCAAyC,QAAQ,CAAC,MAAM,IAAI,CAC7D,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,KAAc;IACvD,MAAM,QAAQ,GACZ,KAAK,YAAY,KAAK;QACtB,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;IACjE,OAAO,IAAI,aAAa,CACtB,CAAC,EACD,QAAQ;QACN,CAAC,CAAC,aAAa,IAAI,GAAG;QACtB,CAAC,CAAC,iBAAiB,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9C,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,QAAQ;IACF,UAAU,CAAS;IACnB,IAAI,CAAe;IAEpC,YAAY,UAAkB,EAAE,IAAkB;QAChD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,GAAG,CAAI,IAAY;QACjB,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,CAAI,IAAY,EAAE,IAAc;QAClC,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAI,IAAY,EAAE,IAAc;QACnC,OAAO,IAAI,CAAC,OAAO,CAAI,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,IAAc;QACnE,MAAM,OAAO,GAA2B;YACtC,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAC9B,mEAAmE;YACnE,kEAAkE;YAClE,kBAAkB;YAClB,gBAAgB,EAAE,aAAa;SAChC,CAAC;QACF,IAAI,IAAI,GAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC5C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YAC7C,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,CAAC;QACD,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,EAAE,EAAE;gBAClD,GAAG,IAAI;gBACP,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC;aAChD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,YAAY,CAAC,YAAY,IAAI,CAAC,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QACnD,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;IACtC,CAAC;CACF;AAED,sEAAsE;AACtE,qEAAqE;AACrE,wEAAwE;AACxE,4CAA4C;AAC5C,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,KAAiB,EACjB,WAAmB;IAEnB,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC1B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE;YACxC,qEAAqE;YACrE,kEAAkE;YAClE,kEAAkE;YAClE,IAAI,EAAE,KAAgC;YACtC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAC/C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,8DAA8D;AAC9D,KAAK,UAAU,YAAY,CAAC,QAAkB;IAC5C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;QAC5D,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;IACD,OAAO,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ApprovalPromptInput {
|
|
2
|
+
/** Where the human approves, user code prefilled where the server offers it. */
|
|
3
|
+
url: string;
|
|
4
|
+
/** The code they confirm on that page, for a request that carries one. An
|
|
5
|
+
* app approval names the app on its own page instead, so it has none. */
|
|
6
|
+
code?: string;
|
|
7
|
+
/** What the reader is being asked to approve. Defaults to the device grant,
|
|
8
|
+
* which is what most of these are. */
|
|
9
|
+
heading?: string;
|
|
10
|
+
/** Why this prompt is showing again, when it is not the first time. */
|
|
11
|
+
lead?: string | null;
|
|
12
|
+
/** The command that finishes the sign-in, for a caller that exits before
|
|
13
|
+
* approval. A blocking sign-in polls on its own and passes the line it
|
|
14
|
+
* waits under instead. */
|
|
15
|
+
nextCommand?: string | null;
|
|
16
|
+
/** What a caller with no command to name says under the block. */
|
|
17
|
+
closing?: string | null;
|
|
18
|
+
/** Set by the flow a caller who cannot approve is the usual reason to run
|
|
19
|
+
* (`--start` / `--check`), which adds the note asking an agent to pass the
|
|
20
|
+
* link on. The blocking `brass login` leaves it unset: whoever ran it is
|
|
21
|
+
* waiting to approve. */
|
|
22
|
+
relaying?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function renderApprovalPrompt(input: ApprovalPromptInput): string;
|
|
25
|
+
//# sourceMappingURL=approval-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-prompt.d.ts","sourceRoot":"","sources":["../src/approval-prompt.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ;8EAC0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;2CACuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;+BAE2B;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;8BAG0B;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CA0BvE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// The one rendering of an approval a human has to give: the URL to open, the
|
|
2
|
+
// code to confirm where there is one, plus what to do next. Every phase of the
|
|
3
|
+
// sign-in prints through here, so a fresh grant, a resumed one, and a renewed
|
|
4
|
+
// one read the same, and so does the app approval `brass browser-session`
|
|
5
|
+
// asks for, which is the same request with a different subject.
|
|
6
|
+
//
|
|
7
|
+
// Whether the reader is the person who approves decides whether the block
|
|
8
|
+
// needs a relay instruction, and the caller narrows it: `brass login` blocks
|
|
9
|
+
// until approval, so whoever ran it is waiting to approve, while `--start` /
|
|
10
|
+
// `--check` exist for a caller that cannot hold a command open, which is
|
|
11
|
+
// usually an agent. Usually, not always, so the note there is addressed to an
|
|
12
|
+
// agent as a condition rather than asserted about the reader, and a person
|
|
13
|
+
// running `--start` themselves reads past it.
|
|
14
|
+
//
|
|
15
|
+
// The caller is what narrows it because `isTTY` answers the wrong question
|
|
16
|
+
// twice: an agent harness that allocates a pty (many do, for colored output)
|
|
17
|
+
// reads as a watched terminal, and `brass login | tee` reads as an agent.
|
|
18
|
+
//
|
|
19
|
+
// The frame is ASCII: this goes to whatever console the caller has, and a
|
|
20
|
+
// box-drawing character that renders as a replacement glyph costs more
|
|
21
|
+
// prominence than the frame buys.
|
|
22
|
+
const RULE = '='.repeat(64);
|
|
23
|
+
export function renderApprovalPrompt(input) {
|
|
24
|
+
const lines = [];
|
|
25
|
+
if (input.lead)
|
|
26
|
+
lines.push(input.lead, '');
|
|
27
|
+
lines.push(RULE, input.heading ?? ' To approve this sign-in, open this link and confirm the code:', '', ` ${input.url}`);
|
|
28
|
+
if (input.code)
|
|
29
|
+
lines.push(` Code: ${input.code}`);
|
|
30
|
+
if (input.relaying === true) {
|
|
31
|
+
lines.push('', input.code
|
|
32
|
+
? ' If you are an AI agent, put the link and the code directly in your'
|
|
33
|
+
: ' If you are an AI agent, put the link directly in your', ' reply. The person who approves often cannot see this output.');
|
|
34
|
+
}
|
|
35
|
+
lines.push(RULE);
|
|
36
|
+
if (input.nextCommand) {
|
|
37
|
+
lines.push('', `Then run \`${input.nextCommand}\` to finish signing in.`);
|
|
38
|
+
}
|
|
39
|
+
else if (input.closing) {
|
|
40
|
+
lines.push('', input.closing);
|
|
41
|
+
}
|
|
42
|
+
return lines.join('\n');
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=approval-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-prompt.js","sourceRoot":"","sources":["../src/approval-prompt.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,8EAA8E;AAC9E,0EAA0E;AAC1E,gEAAgE;AAChE,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,8EAA8E;AAC9E,2EAA2E;AAC3E,8CAA8C;AAC9C,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAC1E,EAAE;AACF,0EAA0E;AAC1E,uEAAuE;AACvE,kCAAkC;AAElC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AA0B5B,MAAM,UAAU,oBAAoB,CAAC,KAA0B;IAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,CACR,IAAI,EACJ,KAAK,CAAC,OAAO,IAAI,gEAAgE,EACjF,EAAE,EACF,MAAM,KAAK,CAAC,GAAG,EAAE,CAClB,CAAC;IACF,IAAI,KAAK,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CACR,EAAE,EACF,KAAK,CAAC,IAAI;YACR,CAAC,CAAC,qEAAqE;YACvE,CAAC,CAAC,wDAAwD,EAC5D,+DAA+D,CAChE,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,KAAK,CAAC,WAAW,0BAA0B,CAAC,CAAC;IAC5E,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
package/dist/args.d.ts.map
CHANGED
|
@@ -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;IAIrC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;
|
|
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;AA4CD,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAEzD;AAmDD,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"}
|