@rness/cli 0.5.2 → 0.6.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,8 +6,12 @@ Not an agent — no LLM loop.
6
6
 
7
7
  ## Install
8
8
 
9
- npm create rness # prompts for the organization, then the repositories for your workspace
9
+ npm create rness # asks how to start: a GitHub organization, or a blank workspace
10
10
  npm create rness acme # the organization github.com/acme, no first prompt
11
+ pnpm create rness demo --blank # ./demo with no GitHub step; npm: npm create rness demo -- --blank
12
+ pnpm create rness # the same with pnpm, yarn or bun: `.rness/` is
13
+ yarn create rness # installed with the manager that ran the command
14
+ bun create rness
11
15
  npm i -g @rness/cli # the command is `rness`
12
16
  npx @rness/cli --help
13
17
 
@@ -17,6 +21,7 @@ Inside a workspace, every `rness` delegates to the copy pinned in
17
21
  ## Commands
18
22
 
19
23
  rness create [<org>] [--repos a,b] [--pm npm|pnpm|yarn|bun] [--ssh|--https] [--skip-install] -y
24
+ rness create <name> --blank [--pm npm|pnpm|yarn|bun] [--skip-install] -y
20
25
  rness add <repo> [--scopes apps/web,packages/ui] [--ssh|--https] -y
21
26
  rness sync [--all] [--scope <name>] [--check] [--pull] -y
22
27
  rness upgrade [<version>] -y
@@ -29,6 +34,12 @@ Inside a workspace, every `rness` delegates to the copy pinned in
29
34
  confirmation in a terminal; pass `-y`/`--yes` in scripts. `sync --check`
30
35
  writes nothing and exits 1 when a block is out of date — use it in CI.
31
36
 
37
+ `create --blank` needs no GitHub organization, account or login: it writes
38
+ `<name>/.rness/` (a `rness.json` without `"org"`, committed), an empty
39
+ `<name>/org/` and the root `AGENTS.md` and `CLAUDE.md`. Only the install of
40
+ `.rness/` goes to the network. Bring repositories in with
41
+ `rness add <owner>/<repo>` or a git URL — a bare name needs an `"org"`.
42
+
32
43
  ### Log in
33
44
 
34
45
  rness login # shows a code and https://github.com/login/device
@@ -110,11 +121,20 @@ clean — and carries on: nothing to remember, nothing to run.
110
121
  container image, or a machine that cannot install. A workspace still on 0.5.0
111
122
  has no such catch-up: moving it to 0.5.1 is the last manual install.
112
123
 
124
+ The catch-up needs one of two things: a launcher — the `rness` you typed,
125
+ usually the global install — at 0.5.1 or later, or an installed copy at 0.5.3
126
+ or later, which checks for itself whatever launched it. With an older global
127
+ and a workspace below 0.5.3, a pin that moved is neither installed nor
128
+ announced: `npm i -g @rness/cli@latest` once.
129
+
113
130
  Usually nobody runs `upgrade` at all. A workspace ships
114
131
  `.github/dependabot.yml`, so each release opens a pull request on the
115
132
  organization's `.rness`: the pin and the lockfile in the diff, `validate`
116
133
  running on the new version, review, merge. `upgrade` writes that file into
117
- workspaces created before 0.5.1.
134
+ workspaces created before 0.5.1. The pull request arrives 3 to 10 days after
135
+ a release: the check is weekly, and Dependabot holds any new version back for
136
+ 3 days by default, a guard against a compromised release. The file's header
137
+ says how to lift that delay for `@rness/cli`.
118
138
 
119
139
  `upgrade` is never delegated to the pinned copy, which is what it replaces
120
140
  — so a workspace pinned below 0.5.0, whose copy has no such command, starts
@@ -127,6 +147,41 @@ its content does.
127
147
  Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
128
148
  `RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
129
149
 
150
+ ## 0.6.0 — a workspace without GitHub
151
+
152
+ - `rness create <name> --blank` writes `<name>/.rness/` (a `rness.json`
153
+ without `"org"`, committed), an empty `<name>/org/` and the root
154
+ `AGENTS.md` and `CLAUDE.md`, with no login, SSH test or GitHub request.
155
+ With `npm create`, flags go after `--`: `npm create rness demo -- --blank`.
156
+ - In a terminal, `create` with no organization and no `--repos` first asks
157
+ how to start: from a GitHub organization, as before, or a blank local
158
+ workspace.
159
+ - A `rness.json` without `"org"` is no longer a warning in `sync`, `add` and
160
+ `validate`. In such a workspace `rness add <repo>` exits 2 and asks for
161
+ `<owner>/<repo>` or a git URL: it used to take the directory name as the
162
+ owner, a repository that almost never exists.
163
+ - The next steps `create` prints are written with the package manager that
164
+ ran it: `npx @rness/cli`, `pnpm dlx @rness/cli`, `yarn dlx @rness/cli`
165
+ (npx on Yarn 1), `bunx @rness/cli`, and `<pm> create rness <org>` for
166
+ teammates. They said `rness …`, a command `npm create` never installs.
167
+ - Blocks are unchanged: no `rness sync` is needed after upgrading.
168
+
169
+ ## 0.5.3 — catching up no longer depends on the global install
170
+
171
+ - After a pull that moved the pin, the next `rness` command installs it. That
172
+ check ran in the launcher only, so a global `@rness/cli` below 0.5.1 — which
173
+ delegates to the installed copy without looking — left the old version in
174
+ place and said nothing: `sync --check` answered `unchanged` with 0.5.1
175
+ blocks under a 0.5.2 pin. The installed copy now checks as well.
176
+ - Reach: the check lives in the installed copy, so it works from the first pin
177
+ move after a workspace holds 0.5.3. The move to 0.5.3 itself still needs a
178
+ launcher at 0.5.1 or later.
179
+ - The scaffold's `dependabot.yml` says why the pin's pull request arrives 3 to
180
+ 10 days after a release (a weekly check, plus Dependabot's default 3-day
181
+ cooldown) and gives the three lines that lift it for `@rness/cli`. The
182
+ default stays: for an adopting organization the CLI is a third-party
183
+ package, and the cooldown guards against a compromised release.
184
+
130
185
  ## 0.5.2 — the block points at a file that exists
131
186
 
132
187
  - The generated block told agents to read `.rness/STATUS.md`, a file neither
package/dist/bin/rness.js CHANGED
@@ -1,18 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ OWN_COMMANDS,
3
4
  VERSION,
4
- driftWarning,
5
- ensureInstalled,
5
+ catchUp,
6
6
  findDelegate,
7
- findWorkspace,
8
- pinDrift,
9
- pinnedBinPath,
10
7
  reportError,
11
8
  run
12
- } from "../chunk-P4YG6P7I.js";
9
+ } from "../chunk-NY3WV7X5.js";
13
10
 
14
11
  // src/bin/rness.ts
15
- import { spawnSync } from "child_process";
16
12
  import { pathToFileURL } from "url";
17
13
 
18
14
  // src/core/node-version.ts
@@ -39,39 +35,9 @@ async function main() {
39
35
  return 1;
40
36
  }
41
37
  const argv = process.argv.slice(2);
42
- const own = [
43
- "create",
44
- "upgrade",
45
- "update",
46
- "login",
47
- "logout",
48
- "git-credential"
49
- ].includes(argv[0] ?? "");
50
- const noDelegate = process.env["RNESS_NO_DELEGATE"] === "1";
51
- const skipDelegation = own || noDelegate;
52
- const command = argv[0];
53
- if (command !== void 0 && !command.startsWith("-") && !skipDelegation) {
54
- const ws = await findWorkspace(process.cwd()).catch(() => null);
55
- const outcome = ws === null ? null : await ensureInstalled(ws.rnessDir, {
56
- announce: (pin) => process.stderr.write(`installing @rness/cli ${pin} in .rness\u2026
57
- `)
58
- });
59
- if (outcome !== null && !outcome.installed) {
60
- const warning = await driftWarning(process.cwd());
61
- if (warning !== null) process.stderr.write(`${warning}
62
- `);
63
- }
64
- if (ws !== null && outcome?.installed === true && await pinDrift(ws.rnessDir) === null) {
65
- const pinnedBin = await pinnedBinPath(ws.rnessDir);
66
- if (pinnedBin !== null) {
67
- const { status } = spawnSync(process.execPath, [pinnedBin, ...argv], {
68
- cwd: process.cwd(),
69
- stdio: "inherit"
70
- });
71
- return status ?? 1;
72
- }
73
- }
74
- }
38
+ const skipDelegation = OWN_COMMANDS.includes(argv[0] ?? "") || process.env["RNESS_NO_DELEGATE"] === "1";
39
+ const handedOff = await catchUp(argv);
40
+ if (handedOff !== null) return handedOff;
75
41
  const delegate = skipDelegation ? null : await findDelegate(process.cwd(), VERSION);
76
42
  if (delegate !== null) {
77
43
  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 { spawnSync } from 'node:child_process'\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { findDelegate, pinnedBinPath } from '../core/delegate.ts'\nimport { MIN_NODE_MAJOR, isSupportedNode } from '../core/node-version.ts'\nimport { driftWarning, ensureInstalled, pinDrift } from '../core/pinned.ts'\nimport { findWorkspace } from '../core/workspace.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 (command !== undefined && !command.startsWith('-') && !skipDelegation) {\n const ws = await findWorkspace(process.cwd()).catch(() => null)\n // The version was decided by the pull request that moved the pin, so\n // catching up asks nothing (spec 0008 §4).\n const outcome =\n ws === null\n ? null\n : await ensureInstalled(ws.rnessDir, {\n announce: (pin) =>\n process.stderr.write(`installing @rness/cli ${pin} in .rness…\\n`),\n })\n if (outcome !== null && !outcome.installed) {\n const warning = await driftWarning(process.cwd())\n if (warning !== null) process.stderr.write(`${warning}\\n`)\n }\n // The pinned tree was just rebuilt: importing out of it in this process is\n // fragile, so the freshly installed copy runs as its own process.\n // Only hand off when the install actually closed the drift: a child that\n // would install again on every run must never be spawned.\n if (\n ws !== null &&\n outcome?.installed === true &&\n (await pinDrift(ws.rnessDir)) === null\n ) {\n const pinnedBin = await pinnedBinPath(ws.rnessDir)\n if (pinnedBin !== null) {\n const { status } = spawnSync(process.execPath, [pinnedBin, ...argv], {\n cwd: process.cwd(),\n stdio: 'inherit',\n })\n return status ?? 1\n }\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,iBAAiB;AAC1B,SAAS,qBAAqB;;;ACFvB,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;;;ADOA,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,MAAI,YAAY,UAAa,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,gBAAgB;AACxE,UAAM,KAAK,MAAM,cAAc,QAAQ,IAAI,CAAC,EAAE,MAAM,MAAM,IAAI;AAG9D,UAAM,UACJ,OAAO,OACH,OACA,MAAM,gBAAgB,GAAG,UAAU;AAAA,MACjC,UAAU,CAAC,QACT,QAAQ,OAAO,MAAM,yBAAyB,GAAG;AAAA,CAAe;AAAA,IACpE,CAAC;AACP,QAAI,YAAY,QAAQ,CAAC,QAAQ,WAAW;AAC1C,YAAM,UAAU,MAAM,aAAa,QAAQ,IAAI,CAAC;AAChD,UAAI,YAAY,KAAM,SAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,IAC3D;AAKA,QACE,OAAO,QACP,SAAS,cAAc,QACtB,MAAM,SAAS,GAAG,QAAQ,MAAO,MAClC;AACA,YAAM,YAAY,MAAM,cAAc,GAAG,QAAQ;AACjD,UAAI,cAAc,MAAM;AACtB,cAAM,EAAE,OAAO,IAAI,UAAU,QAAQ,UAAU,CAAC,WAAW,GAAG,IAAI,GAAG;AAAA,UACnE,KAAK,QAAQ,IAAI;AAAA,UACjB,OAAO;AAAA,QACT,CAAC;AACD,eAAO,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,EACF;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":[]}
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 { OWN_COMMANDS, catchUp } from '../core/catch-up.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 OWN_COMMANDS.includes(argv[0] ?? '') ||\n process.env['RNESS_NO_DELEGATE'] === '1'\n // A pin that moved is installed first, and the fresh copy runs the command\n // as its own process (spec 0008 §4).\n const handedOff = await catchUp(argv)\n if (handedOff !== null) return handedOff\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;AACjC,QAAM,iBACJ,aAAa,SAAS,KAAK,CAAC,KAAK,EAAE,KACnC,QAAQ,IAAI,mBAAmB,MAAM;AAGvC,QAAM,YAAY,MAAM,QAAQ,IAAI;AACpC,MAAI,cAAc,KAAM,QAAO;AAC/B,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":[]}