@rness/cli 0.4.0 → 0.5.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/README.md CHANGED
@@ -6,7 +6,8 @@ Not an agent — no LLM loop.
6
6
 
7
7
  ## Install
8
8
 
9
- npm create rness <org> # start a workspace for github.com/<org>, or join its .rness
9
+ npm create rness # prompts for the organization, then the repositories for your workspace
10
+ npm create rness acme # the organization github.com/acme, no first prompt
10
11
  npm i -g @rness/cli # the command is `rness`
11
12
  npx @rness/cli --help
12
13
 
@@ -15,9 +16,12 @@ Inside a workspace, every `rness` delegates to the copy pinned in
15
16
 
16
17
  ## Commands
17
18
 
18
- rness create <org> [--dir <path>] [--repos a,b] [--pm npm|pnpm|yarn|bun] [--ssh] [--skip-install] -y
19
- rness add <repo> [--scopes apps/web,packages/ui] [--ssh] -y
20
- rness sync [--scope <name>] [--check] [--pull] -y
19
+ rness create [<org>] [--repos a,b] [--pm npm|pnpm|yarn|bun] [--ssh|--https] [--skip-install] -y
20
+ rness add <repo> [--scopes apps/web,packages/ui] [--ssh|--https] -y
21
+ rness sync [--all] [--scope <name>] [--check] [--pull] -y
22
+ rness upgrade [<version>] -y
23
+ rness login [--setup-git|--no-setup-git]
24
+ rness logout
21
25
  rness context [--scope <name>] [--json]
22
26
  rness validate
23
27
 
@@ -25,9 +29,157 @@ Inside a workspace, every `rness` delegates to the copy pinned in
25
29
  confirmation in a terminal; pass `-y`/`--yes` in scripts. `sync --check`
26
30
  writes nothing and exits 1 when a block is out of date — use it in CI.
27
31
 
32
+ ### Log in
33
+
34
+ rness login # shows a code and https://github.com/login/device
35
+ rness logout
36
+
37
+ `rness login` connects rness to your GitHub account (OAuth device flow: you
38
+ approve a code in a browser, on any machine). Logged in, `create` lists the
39
+ private repositories you can access, offers your organizations to choose
40
+ from, and says as whom it looks at one (`member acme (as you)`). The
41
+ `create` wizard offers the login itself when it would otherwise list
42
+ anonymously.
43
+
44
+ - The login is one file, `~/.config/rness/auth.json` (`$XDG_CONFIG_HOME`,
45
+ `%APPDATA%` on Windows), readable by you only. The access token lives 8
46
+ hours and is renewed on its own. `GITHUB_TOKEN`, then `GH_TOKEN`, win over
47
+ it — CI needs no login.
48
+ - rness asks for `repo` and `read:org`: GitHub has no read-only scope for
49
+ private repositories. It only lists and clones.
50
+ - A new workspace has to reach GitHub before teammates can join it. Logged
51
+ in, the `create` wizard offers to do it: it creates the private repository
52
+ `<org>/.rness` and pushes the context with `git`. Declined, refused by
53
+ GitHub, anonymous or with `--yes`, it prints the two manual steps instead
54
+ — create the empty repository on github.com, then `git remote add origin …
55
+ && git push`. No other tool is ever needed.
56
+ - An organization that restricts OAuth apps hides its private repositories
57
+ until an owner approves "Rness"; `create` says so, with the link.
58
+ - Over HTTPS, rness's own clones and pulls carry the login — through the
59
+ environment of that one git command, never in a URL or `.git/config`. For
60
+ your own `git pull` and `git push`, `login` offers to make rness git's
61
+ credential helper for github.com (`--setup-git`, `--no-setup-git`);
62
+ `logout` undoes it. It needs a global install (`npm i -g @rness/cli`): a
63
+ copy run through `npx` lives in a cache. Over SSH none of this is needed.
64
+ The helper names `node` by its absolute path: after a Node upgrade through
65
+ a version manager (mise, nvm), run `rness login --setup-git` again.
66
+ - `rness logout` forgets the login; revoke the authorization itself in
67
+ GitHub's settings (the command prints the link).
68
+
69
+ ### SSH or HTTPS
70
+
71
+ `create` and `add` test your SSH access to github.com once
72
+ (`ssh -T git@github.com`) and write `git@github.com:` URLs when GitHub accepts
73
+ your key, `https://github.com/` ones otherwise; `--ssh` and `--https` decide
74
+ without the test. In a terminal `ssh` may ask for your key's passphrase;
75
+ without one (`--yes`, CI) it never prompts, so a key that needs a passphrase
76
+ counts as no access unless an agent holds it.
77
+
78
+ `rness.json` is authoritative: a URL written there is cloned as written, never
79
+ converted. In a workspace whose catalogue clones over SSH, `create` (joining)
80
+ and `sync` stop before the first clone when the SSH test fails and say how to
81
+ set up a key; `add` offers "Clone <name> over HTTPS instead?" (or `--https`),
82
+ which writes an HTTPS URL for that repository only.
83
+
84
+ Without an agent, a protected key is asked for again by every `git clone`.
85
+ Load it once per session: `ssh-add --apple-use-keychain ~/.ssh/id_ed25519` on
86
+ macOS, `ssh-add ~/.ssh/id_ed25519` elsewhere.
87
+
88
+ ### Colour
89
+
90
+ In a terminal `create`, `login`, `add`, `sync` and `upgrade` run as one
91
+ session: an intro, a line per finished step, spinners, a "Next" box, an
92
+ outro — in the same gutter as the questions. A spinner never animates while
93
+ git might ask for a passphrase: rness first tests SSH unattended, and clones
94
+ animate only when that passed. The help and the banner are coloured. Through a pipe, in CI, or with `NO_COLOR=1`, the output is plain text —
95
+ the same bytes as before 0.5.0; `FORCE_COLOR=1` paints it anyway. No
96
+ dependency does this: `util.styleText`, and a banner kept as a constant.
97
+
98
+ ### Upgrade
99
+
100
+ rness upgrade # the latest release; `rness upgrade 0.5.0` for another
101
+ npx @rness/cli@latest upgrade # from a workspace pinned below 0.5.0
102
+
103
+ The version is written in one place, `.rness/package.json`. `upgrade` pins it
104
+ there (exact, the rest of the file untouched), installs with the workspace's
105
+ package manager, then syncs through the new copy; a failed install restores
106
+ the file. Commit `.rness`; teammates pull and install in `.rness`. Until they
107
+ do, every command warns that the workspace pins one version and holds
108
+ another. It is never delegated to the pinned copy, which is what it replaces
109
+ — so a workspace pinned below 0.5.0, whose copy has no such command, starts
110
+ with the `npx` form.
111
+
112
+ An upgrade touches `.rness` only: a generated block is current when its hash
113
+ is, whatever wrote it, so no `AGENTS.md` of the organization changes unless
114
+ its content does.
115
+
28
116
  Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
29
117
  `RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
30
118
 
119
+ ## 0.5.0 — the organization is the workspace; rness.json is its catalogue
120
+
121
+ - `create <org>` names the organization, not a directory any more (`--org
122
+ <org>` and the prompt "What is your GitHub organization named?" do the
123
+ same). The workspace directory is `./<org>`, with the organization's exact
124
+ name; `--dir` is removed. With `npm create`, flags go after `--`:
125
+ `npm create rness acme -- --yes`.
126
+ - SSH first: `create` and `add` write `git@github.com:` URLs when
127
+ `ssh -T git@github.com` accepts your key, HTTPS ones otherwise (0.4.0
128
+ wrote HTTPS unless `--ssh`). `--https` is new. A private `.rness` you reach
129
+ over SSH is now found when joining. See "SSH or HTTPS" above.
130
+ - `create` does not offer repositories whose name starts with a dot
131
+ (`.github`, …).
132
+ - Colour, a banner and progress lines in a terminal (see "Colour" above);
133
+ nothing changes for scripts.
134
+ - `rness login` / `rness logout` are new: private repositories are listed,
135
+ and cloned over HTTPS with the login (see "Log in" above). Without a login
136
+ the note reads `rness login lists the private ones you can access`.
137
+ - `rness upgrade` is new (see "Upgrade" above). From 0.4.0:
138
+ `npx @rness/cli@latest upgrade`.
139
+ - The header of a generated block no longer names the CLI version
140
+ (`<!-- rness · scope: … -->`), and `sync` decides by the hash like
141
+ `validate`: upgrading rewrites no `AGENTS.md`. Blocks written by 0.2–0.4
142
+ stay as they are until their content changes. A 0.4.0 CLI calls the new
143
+ header stale — upgrade every copy together.
144
+ - The scaffold's CI workflow reads the version from `package.json` instead of
145
+ naming it; `upgrade` migrates the old line.
146
+ - `.rness/rness.json` is the organization's catalogue — every repository
147
+ rness knows about, shared by the team. Your workspace is the part of it
148
+ you cloned into `org/`; two teammates can clone different repositories,
149
+ and nothing but `org/` records the choice. A choice never removes a
150
+ repository from the catalogue.
151
+ - `create` lists the organization's repositories to search and pick from,
152
+ with every catalogue repository pre-selected when joining (a catalogue
153
+ repository the listing does not return is still offered, marked
154
+ `in .rness`). A picked catalogue repository is cloned; a picked new one is
155
+ added to the catalogue, as `rness add` does. Without a picker, `--repos`
156
+ is the selection; a join without `--repos` clones the whole catalogue. A
157
+ cancelled or declined prompt writes nothing and exits 0.
158
+ - The listing needs no credentials. Without a `GITHUB_TOKEN` (or `GH_TOKEN`)
159
+ only public repositories are listed — and a personal account always lists
160
+ only its public ones; add the others later with `rness add <repo>`.
161
+ - `rness sync` works on your clones: it writes the blocks of the repositories
162
+ in `org/`, never of `rness.json` as a whole. In a terminal it asks "Do you
163
+ want to sync as well?" with the catalogue repositories you have not cloned
164
+ ("Select all", or pick some); what you pick is cloned first. With `--yes`,
165
+ or `--check`, nothing is cloned and one `not cloned:` line names them
166
+ (`--check` does not fail on it). `rness sync --all` clones them all without
167
+ asking. A clone `rness.json` does not know gets no block and a
168
+ `not in rness.json:` line pointing at `rness add`.
169
+ - A workspace pinned to 0.4.x clones every catalogue repository on sync —
170
+ `create` runs the pinned copy's sync after joining.
171
+ - Joining a workspace whose `.rness` pins an older `@rness/cli` than the one
172
+ you run says so, and that `rness upgrade` moves it.
173
+ - Repository and scope names take what GitHub allows, in lowercase: letters,
174
+ digits, `.`, `_` and `-` (`my_lib`, `angular.js`). A name that differs only
175
+ by case is declared in lowercase. A 0.4.0 CLI rejects a `rness.json` that
176
+ holds a `.` or a `_` in a name — upgrade every copy together.
177
+ - Organization names follow GitHub's rule — letters, digits and single
178
+ hyphens, not at either end, at most 39 characters — in `--org` and in
179
+ `rness.json`'s `"org"`; the case is kept as typed.
180
+ - `"org"` in `rness.json` now accepts uppercase letters: a 0.4.0 CLI rejects
181
+ a workspace whose `"org"` has any, so upgrade every copy together.
182
+
31
183
  ## 0.4.0 — create, add, the shims
32
184
 
33
185
  - `npm create rness <org>` starts a new workspace for `github.com/<org>` or
package/dist/bin/rness.js CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION,
4
+ driftWarning,
4
5
  findDelegate,
5
6
  reportError,
6
7
  run
7
- } from "../chunk-IW5IHSPC.js";
8
+ } from "../chunk-WSGPDTPQ.js";
8
9
 
9
10
  // src/bin/rness.ts
10
11
  import { pathToFileURL } from "url";
@@ -33,7 +34,22 @@ async function main() {
33
34
  return 1;
34
35
  }
35
36
  const argv = process.argv.slice(2);
36
- const skipDelegation = argv[0] === "create" || process.env["RNESS_NO_DELEGATE"] === "1";
37
+ const own = [
38
+ "create",
39
+ "upgrade",
40
+ "update",
41
+ "login",
42
+ "logout",
43
+ "git-credential"
44
+ ].includes(argv[0] ?? "");
45
+ const noDelegate = process.env["RNESS_NO_DELEGATE"] === "1";
46
+ const skipDelegation = own || noDelegate;
47
+ const command = argv[0];
48
+ if (command !== void 0 && !command.startsWith("-") && !own && !noDelegate) {
49
+ const warning = await driftWarning(process.cwd());
50
+ if (warning !== null) process.stderr.write(`${warning}
51
+ `);
52
+ }
37
53
  const delegate = skipDelegation ? null : await findDelegate(process.cwd(), VERSION);
38
54
  if (delegate !== null) {
39
55
  const broken = (reason) => new Error(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/rness.ts","../../src/core/node-version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { findDelegate } from '../core/delegate.ts'\nimport { MIN_NODE_MAJOR, isSupportedNode } from '../core/node-version.ts'\nimport { reportError } from '../report.ts'\nimport { VERSION } from '../version.ts'\n\n// `rness context | head`: once the reader has its lines it closes the pipe and\n// every further write emits EPIPE on stdout. Nothing is left to deliver, so end\n// quietly with success. This is the one process.exit() in the code base — it\n// runs only when there is no output left to drain (see main() below).\nprocess.stdout.on('error', (e: NodeJS.ErrnoException) => {\n if (e.code === 'EPIPE') process.exit(0)\n throw e\n})\n\n// Set process.exitCode rather than calling process.exit(): process.exit()\n// terminates before Node drains an async stdout pipe, truncating piped output\n// at the ~64 KiB pipe buffer (breaks `rness context --json | jq`, `$(...)`).\nasync function main(): Promise<number> {\n if (!isSupportedNode(process.versions.node)) {\n process.stderr.write(\n `rness needs Node ${MIN_NODE_MAJOR} or newer (running ${process.version})\\n`\n )\n return 1\n }\n const argv = process.argv.slice(2)\n const skipDelegation =\n argv[0] === 'create' || process.env['RNESS_NO_DELEGATE'] === '1'\n const delegate = skipDelegation\n ? null\n : await findDelegate(process.cwd(), VERSION)\n if (delegate !== null) {\n const broken = (reason: string): Error =>\n new Error(\n `@rness/cli ${delegate.version} pinned in ${delegate.root}/.rness is not installed correctly (${reason}); reinstall in .rness/`\n )\n if (process.env['RNESS_DEBUG'] === '1') {\n process.stderr.write(\n `rness: delegating to @rness/cli ${delegate.version} (${delegate.entry})\\n`\n )\n }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(delegate.entry).href)) as Record<\n string,\n unknown\n >\n } catch (e) {\n throw broken(e instanceof Error ? e.message : String(e))\n }\n if (typeof mod['run'] !== 'function')\n throw broken('dist/index.js does not export run')\n const delegateRun = mod['run'] as (argv: string[]) => Promise<unknown>\n const code = await delegateRun(argv)\n return typeof code === 'number' ? code : 1\n }\n return run(argv)\n}\n\nmain()\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n process.exitCode = reportError(e)\n })\n","export const MIN_NODE_MAJOR = 24\n\nexport function nodeMajor(version: string): number {\n const major = Number.parseInt(version.split('.')[0] ?? '', 10)\n return Number.isNaN(major) ? 0 : major\n}\n\nexport function isSupportedNode(version: string): boolean {\n return nodeMajor(version) >= MIN_NODE_MAJOR\n}\n"],"mappings":";;;;;;;;;AACA,SAAS,qBAAqB;;;ACDvB,IAAM,iBAAiB;AAEvB,SAAS,UAAU,SAAyB;AACjD,QAAM,QAAQ,OAAO,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE;AAC7D,SAAO,OAAO,MAAM,KAAK,IAAI,IAAI;AACnC;AAEO,SAAS,gBAAgB,SAA0B;AACxD,SAAO,UAAU,OAAO,KAAK;AAC/B;;;ADIA,QAAQ,OAAO,GAAG,SAAS,CAAC,MAA6B;AACvD,MAAI,EAAE,SAAS,QAAS,SAAQ,KAAK,CAAC;AACtC,QAAM;AACR,CAAC;AAKD,eAAe,OAAwB;AACrC,MAAI,CAAC,gBAAgB,QAAQ,SAAS,IAAI,GAAG;AAC3C,YAAQ,OAAO;AAAA,MACb,oBAAoB,cAAc,sBAAsB,QAAQ,OAAO;AAAA;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,iBACJ,KAAK,CAAC,MAAM,YAAY,QAAQ,IAAI,mBAAmB,MAAM;AAC/D,QAAM,WAAW,iBACb,OACA,MAAM,aAAa,QAAQ,IAAI,GAAG,OAAO;AAC7C,MAAI,aAAa,MAAM;AACrB,UAAM,SAAS,CAAC,WACd,IAAI;AAAA,MACF,cAAc,SAAS,OAAO,cAAc,SAAS,IAAI,uCAAuC,MAAM;AAAA,IACxG;AACF,QAAI,QAAQ,IAAI,aAAa,MAAM,KAAK;AACtC,cAAQ,OAAO;AAAA,QACb,mCAAmC,SAAS,OAAO,KAAK,SAAS,KAAK;AAAA;AAAA,MACxE;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,YAAO,MAAM,OAAO,cAAc,SAAS,KAAK,EAAE;AAAA,IAIpD,SAAS,GAAG;AACV,YAAM,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACzD;AACA,QAAI,OAAO,IAAI,KAAK,MAAM;AACxB,YAAM,OAAO,mCAAmC;AAClD,UAAM,cAAc,IAAI,KAAK;AAC7B,UAAM,OAAO,MAAM,YAAY,IAAI;AACnC,WAAO,OAAO,SAAS,WAAW,OAAO;AAAA,EAC3C;AACA,SAAO,IAAI,IAAI;AACjB;AAEA,KAAK,EACF,KAAK,CAAC,SAAS;AACd,UAAQ,WAAW;AACrB,CAAC,EACA,MAAM,CAAC,MAAe;AACrB,UAAQ,WAAW,YAAY,CAAC;AAClC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/bin/rness.ts","../../src/core/node-version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { findDelegate } from '../core/delegate.ts'\nimport { MIN_NODE_MAJOR, isSupportedNode } from '../core/node-version.ts'\nimport { driftWarning } from '../core/pinned.ts'\nimport { reportError } from '../report.ts'\nimport { VERSION } from '../version.ts'\n\n// `rness context | head`: once the reader has its lines it closes the pipe and\n// every further write emits EPIPE on stdout. Nothing is left to deliver, so end\n// quietly with success. This is the one process.exit() in the code base — it\n// runs only when there is no output left to drain (see main() below).\nprocess.stdout.on('error', (e: NodeJS.ErrnoException) => {\n if (e.code === 'EPIPE') process.exit(0)\n throw e\n})\n\n// Set process.exitCode rather than calling process.exit(): process.exit()\n// terminates before Node drains an async stdout pipe, truncating piped output\n// at the ~64 KiB pipe buffer (breaks `rness context --json | jq`, `$(...)`).\nasync function main(): Promise<number> {\n if (!isSupportedNode(process.versions.node)) {\n process.stderr.write(\n `rness needs Node ${MIN_NODE_MAJOR} or newer (running ${process.version})\\n`\n )\n return 1\n }\n const argv = process.argv.slice(2)\n // `create` makes a workspace and `upgrade` replaces the pinned copy: both\n // are served by the copy the user invoked (spec 0006 §3). The login concerns\n // the machine, not a workspace — and git runs `git-credential` from inside\n // a clone, on every fetch: no delegation, and no warning there either.\n const own = [\n 'create',\n 'upgrade',\n 'update',\n 'login',\n 'logout',\n 'git-credential',\n ].includes(argv[0] ?? '')\n const noDelegate = process.env['RNESS_NO_DELEGATE'] === '1'\n const skipDelegation = own || noDelegate\n const command = argv[0]\n if (\n command !== undefined &&\n !command.startsWith('-') &&\n !own &&\n !noDelegate\n ) {\n const warning = await driftWarning(process.cwd())\n if (warning !== null) process.stderr.write(`${warning}\\n`)\n }\n const delegate = skipDelegation\n ? null\n : await findDelegate(process.cwd(), VERSION)\n if (delegate !== null) {\n const broken = (reason: string): Error =>\n new Error(\n `@rness/cli ${delegate.version} pinned in ${delegate.root}/.rness is not installed correctly (${reason}); reinstall in .rness/`\n )\n if (process.env['RNESS_DEBUG'] === '1') {\n process.stderr.write(\n `rness: delegating to @rness/cli ${delegate.version} (${delegate.entry})\\n`\n )\n }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(delegate.entry).href)) as Record<\n string,\n unknown\n >\n } catch (e) {\n throw broken(e instanceof Error ? e.message : String(e))\n }\n if (typeof mod['run'] !== 'function')\n throw broken('dist/index.js does not export run')\n const delegateRun = mod['run'] as (argv: string[]) => Promise<unknown>\n const code = await delegateRun(argv)\n return typeof code === 'number' ? code : 1\n }\n return run(argv)\n}\n\nmain()\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n process.exitCode = reportError(e)\n })\n","export const MIN_NODE_MAJOR = 24\n\nexport function nodeMajor(version: string): number {\n const major = Number.parseInt(version.split('.')[0] ?? '', 10)\n return Number.isNaN(major) ? 0 : major\n}\n\nexport function isSupportedNode(version: string): boolean {\n return nodeMajor(version) >= MIN_NODE_MAJOR\n}\n"],"mappings":";;;;;;;;;;AACA,SAAS,qBAAqB;;;ACDvB,IAAM,iBAAiB;AAEvB,SAAS,UAAU,SAAyB;AACjD,QAAM,QAAQ,OAAO,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE;AAC7D,SAAO,OAAO,MAAM,KAAK,IAAI,IAAI;AACnC;AAEO,SAAS,gBAAgB,SAA0B;AACxD,SAAO,UAAU,OAAO,KAAK;AAC/B;;;ADKA,QAAQ,OAAO,GAAG,SAAS,CAAC,MAA6B;AACvD,MAAI,EAAE,SAAS,QAAS,SAAQ,KAAK,CAAC;AACtC,QAAM;AACR,CAAC;AAKD,eAAe,OAAwB;AACrC,MAAI,CAAC,gBAAgB,QAAQ,SAAS,IAAI,GAAG;AAC3C,YAAQ,OAAO;AAAA,MACb,oBAAoB,cAAc,sBAAsB,QAAQ,OAAO;AAAA;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAKjC,QAAM,MAAM;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,SAAS,KAAK,CAAC,KAAK,EAAE;AACxB,QAAM,aAAa,QAAQ,IAAI,mBAAmB,MAAM;AACxD,QAAM,iBAAiB,OAAO;AAC9B,QAAM,UAAU,KAAK,CAAC;AACtB,MACE,YAAY,UACZ,CAAC,QAAQ,WAAW,GAAG,KACvB,CAAC,OACD,CAAC,YACD;AACA,UAAM,UAAU,MAAM,aAAa,QAAQ,IAAI,CAAC;AAChD,QAAI,YAAY,KAAM,SAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,EAC3D;AACA,QAAM,WAAW,iBACb,OACA,MAAM,aAAa,QAAQ,IAAI,GAAG,OAAO;AAC7C,MAAI,aAAa,MAAM;AACrB,UAAM,SAAS,CAAC,WACd,IAAI;AAAA,MACF,cAAc,SAAS,OAAO,cAAc,SAAS,IAAI,uCAAuC,MAAM;AAAA,IACxG;AACF,QAAI,QAAQ,IAAI,aAAa,MAAM,KAAK;AACtC,cAAQ,OAAO;AAAA,QACb,mCAAmC,SAAS,OAAO,KAAK,SAAS,KAAK;AAAA;AAAA,MACxE;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,YAAO,MAAM,OAAO,cAAc,SAAS,KAAK,EAAE;AAAA,IAIpD,SAAS,GAAG;AACV,YAAM,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACzD;AACA,QAAI,OAAO,IAAI,KAAK,MAAM;AACxB,YAAM,OAAO,mCAAmC;AAClD,UAAM,cAAc,IAAI,KAAK;AAC7B,UAAM,OAAO,MAAM,YAAY,IAAI;AACnC,WAAO,OAAO,SAAS,WAAW,OAAO;AAAA,EAC3C;AACA,SAAO,IAAI,IAAI;AACjB;AAEA,KAAK,EACF,KAAK,CAAC,SAAS;AACd,UAAQ,WAAW;AACrB,CAAC,EACA,MAAM,CAAC,MAAe;AACrB,UAAQ,WAAW,YAAY,CAAC;AAClC,CAAC;","names":[]}