@rness/cli 0.17.3 → 0.18.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
@@ -102,28 +102,38 @@ the files a given agent needs, for the agents the team declares in
102
102
  `.claude-plugin/plugin.json`, also carries the agent-plugins.org
103
103
  `$schema`, the author, homepage, repository, licence and keywords, so a
104
104
  scanner that looks for an Agent Plugins manifest finds one; Claude Code
105
- reads the same file. Nothing in them depends on
105
+ reads the same file. The repository root also carries a `plugin.json` in
106
+ that form, describing the repository, where a scanner looks first. Nothing in them depends on
106
107
  the version; the last line of the status skill names the workspace's
107
108
  package manager, so changing `packageManager` in `.rness/package.json`
108
109
  leaves it stale until the next `sync`. Claude Code loads the plugin once
109
110
  the folder is trusted, in a session started there.
110
- - **The lifecycle skills**: `/rness:adr [subject | NNNN]` records a decision
111
- as an ADR, `/rness:spec [subject | NNNN]` writes a specification,
112
- `/rness:plan <spec>` turns an approved specification into a plan, and
113
- `/rness:done [plan]` closes a piece of work — each task checked on
114
- evidence, then the plan `Completed`, its specification `Implemented`, and
115
- the documents the work made inaccurate corrected. Each is a procedure
116
- loaded into the conversation, not a file generator: after a decision has
117
- been discussed, `/rness:adr` writes it from the conversation; otherwise
118
- it asks, one question at a time. The skill stays in the conversation for
119
- the next turns, and the file carries the work to the next session
120
- (`/rness:adr 0010` reopens it). The agent may start one itself — an ADR
121
- when a choice is expensive to reverse — but writes nothing without a yes,
122
- except `/rness:done` on a plan whose last task has just passed.
123
- The rules stay in `.rness/CONVENTIONS.md`; the skills only add the steps.
124
- A new document takes the collection's first status (`Proposed` for an
125
- ADR, `Draft` otherwise) and the next number of the local checkout; two
126
- branches can pick the same one. Each skill records its session: it adds
111
+ - **The lifecycle skills**, one per collection, on one grammar: the first
112
+ word is the verb, a bare number reopens, anything else is the subject of
113
+ a `create`. `/rness:adr [create <subject> | open NNNN]` records a decision
114
+ as an ADR or reopens one; `/rness:spec [create <subject> | open NNNN]`
115
+ writes a specification or reopens one; `/rness:plan` takes four verbs:
116
+ `from <spec NNNN>` writes a plan from a specification and approves it
117
+ (typing the command is the approval), `create [subject]` writes a plan
118
+ from the conversation for work too small for a specification, `open NNNN`
119
+ reopens a plan, and `check NNNN` runs the proofs of a plan — each task's
120
+ command, run now — and closes it when they all pass: the plan `Completed`,
121
+ its specification `Implemented`, the documents the work made inaccurate
122
+ corrected; one task without evidence and nothing moves. Each is a
123
+ procedure loaded into the conversation, not a file generator: after a
124
+ decision has been discussed, `/rness:adr` writes it from the
125
+ conversation; otherwise it asks, one question at a time. The skill stays
126
+ in the conversation for the next turns, and the file carries the work to
127
+ the next session (`/rness:adr 0010` reopens it). The agent may start one
128
+ itself — an ADR when a choice is expensive to reverse — but writes nothing
129
+ without a yes, except `/rness:plan check` on a plan whose last task has
130
+ just passed. The rules stay in `.rness/CONVENTIONS.md`; the skills only
131
+ add the steps. A new document takes the collection's first status
132
+ (`Proposed` for an ADR, `Draft` otherwise) and the next number, allocated
133
+ by `rness doc new <collection>` — the second pre-approved line of each
134
+ skill, so that every runtime and a bare terminal get the same number;
135
+ `rness validate` refuses two documents with one number, the case a merge
136
+ of two branches can still produce. Each skill records its session: it adds
127
137
  `{ id: <session id>, agent: <model> }` to `sessions:` in the front matter
128
138
  of what it writes or closes. The agent is the model it runs as, as Claude
129
139
  Code names it (`Claude Opus 5.5`): no variable gives it to a skill. An
@@ -385,11 +395,13 @@ it through one adapter; `git` still does what git does (clone, pull, push,
385
395
  credentials), and the provider's API the rest (organizations, creating a
386
396
  repository, the board).
387
397
 
388
- - `rness create` asks `Where does your organization live?`: GitHub, and
389
- GitLab and Atlassian (Bitbucket + Jira) shown disabled, coming later.
390
- `--provider github` answers it off a terminal. A blank workspace asks
391
- nothing. Joining an organization asks first as well, then takes the
392
- provider its `rness.json` names.
398
+ - `rness create` asks `Where does your organization live?` first: GitHub,
399
+ GitLab and Atlassian (Bitbucket + Jira) shown disabled, coming later, and
400
+ `No organization yet: a blank local workspace` (the `--blank` of
401
+ "Blank workspace"). `--provider github` answers it off a terminal;
402
+ `--org`, `--repos` and `--blank` settle it unasked. Joining an
403
+ organization asks first as well, then takes the provider its `rness.json`
404
+ names.
393
405
  - A workspace without the key is read from its first repository URL: a
394
406
  GitLab host reads as `gitlab`, any other host — or no repository — as
395
407
  `github`. Nothing to change: `pulse create` writes it, and refuses a
@@ -461,8 +473,23 @@ anonymously.
461
473
  GitHub, anonymous or with `--yes`, it prints the two manual steps instead
462
474
  — create the empty repository on github.com, then `git remote add origin …
463
475
  && git push`. No other tool is ever needed.
464
- - An organization that restricts OAuth apps hides its private repositories
465
- until an owner approves "Rness"; `create` says so, with the link.
476
+ - Logged in, the wizard lists the organizations you belong to that have
477
+ approved "Rness" — GitHub shows an OAuth app no other — your account
478
+ last, then `an organization not listed here…` for a typed name: one that
479
+ has not approved rness yet, an outside collaborator's, a public one.
480
+ Right after the
481
+ organization, before the SSH test, the probe of `<org>/.rness` and the
482
+ listing, `create` checks your access: an organization that restricts
483
+ OAuth apps and has not approved "Rness" hides its private repositories,
484
+ so the wizard asks `Open github.com to approve rness for <org> now?`,
485
+ opens the approval page in your browser (printed only over SSH) and waits
486
+ — polling every 5 seconds, for 10 minutes at most — until an owner's
487
+ click makes you a member in its eyes; then it goes on with the full
488
+ listing. Declined, or timed out, it goes on with what is visible and
489
+ names the page for later; with `--yes` or off a terminal it prints the
490
+ warning and the page, and asks nothing. The order matters: a private
491
+ `.rness` probed through a token the organization has not approved would
492
+ read as absent, and `create` would start a second one.
466
493
  - Over HTTPS, rness's own clones and pulls carry the login — through the
467
494
  environment of that one git command, never in a URL or `.git/config`. For
468
495
  your own `git pull` and `git push`, `login` offers to make rness git's
@@ -576,6 +603,38 @@ per repository, the files to commit there.
576
603
  Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
577
604
  `RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
578
605
 
606
+ ## 0.18.0 — the wizard asks where first and waits for the approval; the skills on one grammar; Node 22.17
607
+
608
+ - The published CLI runs on **Node 22.17 or later** (ADR 0010); the guard
609
+ compares major and minor. A workspace pinned to 0.17.x keeps refusing
610
+ Node 22 until its pin moves: from inside it, `npx @rness/cli@latest
611
+ upgrade` works under Node 22, since `upgrade` is served by the copy
612
+ invoked, never the pinned one.
613
+ - `rness create` asks **where the organization lives first** — the blank
614
+ workspace is that question's last answer — then offers the login, which
615
+ now lists **the organizations you belong to that have approved rness**
616
+ (your account last, then `an organization not listed here…` for the
617
+ rest). Right after the organization and
618
+ before anything reads it, an organization that restricts OAuth apps and
619
+ has not approved "Rness" gets its **approval page opened in your
620
+ browser**; the wizard waits for the owner's click (10 minutes at most)
621
+ and then lists the private repositories too. See "GitHub login".
622
+ - `/rness:adr`, `/rness:spec` and `/rness:plan` read their first word as
623
+ the verb: `create`, `open` (a bare number), and for a plan `from <spec>`
624
+ — which **approves the specification** it plans — and `check NNNN`, the
625
+ proofs of a plan, in place of `/rness:done`. `/rness:done` is retired:
626
+ `rness sync` removes its `SKILL.md` where an earlier release wrote it
627
+ (`removed` in its output); commit the deletion in each repository, as
628
+ `upgrade`'s next steps list. Note: `/rness:plan 0028` now opens plan
629
+ 0028; a plan is made with `from <spec>`. See "Agent targets".
630
+ - `rness doc new <collection> [--title <text>]` writes the next numbered
631
+ document of `adr`, `specs` or `plans` and prints its path: the skills
632
+ allocate with it instead of counting. `rness validate` and the edit hook
633
+ refuse two documents with one number in a collection.
634
+ - The day of a release, `pnpm create rness` runs the previous version:
635
+ pnpm ≥ 11 holds back a package younger than 24 hours
636
+ (`minimumReleaseAge`). `rness upgrade` installs the latest all the same.
637
+
579
638
  ## 0.17.3 — the packages name the product; the plugin manifest for scanners
580
639
 
581
640
  - `homepage` of `@rness/cli`, `create-rness` and `@rness/create` is
@@ -1076,4 +1135,4 @@ workspace pins exactly that build and no cache serves an older one under its
1076
1135
  number. To try it in a workspace that exists, run `rness upgrade <version>`
1077
1136
  inside it; the deploy prints the line.
1078
1137
 
1079
- Node ≥ 24. MIT.
1138
+ Node ≥ 22.17. MIT.
package/dist/bin/rness.js CHANGED
@@ -6,19 +6,24 @@ import {
6
6
  findDelegate,
7
7
  reportError,
8
8
  run
9
- } from "../chunk-MMPMXYZU.js";
9
+ } from "../chunk-VGBS7HDY.js";
10
10
 
11
11
  // src/bin/rness.ts
12
12
  import { pathToFileURL } from "url";
13
13
 
14
14
  // src/core/node-version.ts
15
- var MIN_NODE_MAJOR = 24;
16
- function nodeMajor(version) {
17
- const major = Number.parseInt(version.split(".")[0] ?? "", 10);
18
- return Number.isNaN(major) ? 0 : major;
15
+ var MIN_NODE = { major: 22, minor: 17 };
16
+ var MIN_NODE_LABEL = `${MIN_NODE.major}.${MIN_NODE.minor}`;
17
+ function component(version, index) {
18
+ const n = Number.parseInt(version.split(".")[index] ?? "", 10);
19
+ return Number.isNaN(n) ? -1 : n;
19
20
  }
20
21
  function isSupportedNode(version) {
21
- return nodeMajor(version) >= MIN_NODE_MAJOR;
22
+ const major = component(version, 0);
23
+ const minor = component(version, 1);
24
+ if (major < 0 || minor < 0) return false;
25
+ if (major !== MIN_NODE.major) return major > MIN_NODE.major;
26
+ return minor >= MIN_NODE.minor;
22
27
  }
23
28
 
24
29
  // src/bin/rness.ts
@@ -29,7 +34,7 @@ process.stdout.on("error", (e) => {
29
34
  async function main() {
30
35
  if (!isSupportedNode(process.versions.node)) {
31
36
  process.stderr.write(
32
- `rness needs Node ${MIN_NODE_MAJOR} or newer (running ${process.version})
37
+ `rness needs Node ${MIN_NODE_LABEL} or newer (running ${process.version})
33
38
  `
34
39
  );
35
40
  return 1;
@@ -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 { 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":[]}
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_LABEL, 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_LABEL} 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","/** The runtime floor of the published CLI (ADR 0010): Node 22.17, the line where `fs.glob` is stable. */\nexport const MIN_NODE = { major: 22, minor: 17 } as const\nexport const MIN_NODE_LABEL = `${MIN_NODE.major}.${MIN_NODE.minor}`\n\nfunction component(version: string, index: number): number {\n const n = Number.parseInt(version.split('.')[index] ?? '', 10)\n return Number.isNaN(n) ? -1 : n\n}\n\nexport function nodeMajor(version: string): number {\n return Math.max(component(version, 0), 0)\n}\n\n/** True from `MIN_NODE` on: a newer major, or the same major from its minor. */\nexport function isSupportedNode(version: string): boolean {\n const major = component(version, 0)\n const minor = component(version, 1)\n if (major < 0 || minor < 0) return false\n if (major !== MIN_NODE.major) return major > MIN_NODE.major\n return minor >= MIN_NODE.minor\n}\n"],"mappings":";;;;;;;;;;;AACA,SAAS,qBAAqB;;;ACAvB,IAAM,WAAW,EAAE,OAAO,IAAI,OAAO,GAAG;AACxC,IAAM,iBAAiB,GAAG,SAAS,KAAK,IAAI,SAAS,KAAK;AAEjE,SAAS,UAAU,SAAiB,OAAuB;AACzD,QAAM,IAAI,OAAO,SAAS,QAAQ,MAAM,GAAG,EAAE,KAAK,KAAK,IAAI,EAAE;AAC7D,SAAO,OAAO,MAAM,CAAC,IAAI,KAAK;AAChC;AAOO,SAAS,gBAAgB,SAA0B;AACxD,QAAM,QAAQ,UAAU,SAAS,CAAC;AAClC,QAAM,QAAQ,UAAU,SAAS,CAAC;AAClC,MAAI,QAAQ,KAAK,QAAQ,EAAG,QAAO;AACnC,MAAI,UAAU,SAAS,MAAO,QAAO,QAAQ,SAAS;AACtD,SAAO,SAAS,SAAS;AAC3B;;;ADNA,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":[]}