@tayo-dev/rtl 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +89 -86
  2. package/assets/claude/commands/@tayo-dev/rtl/generate.md +15 -0
  3. package/assets/claude/commands/@tayo-dev/rtl/help.md +16 -0
  4. package/assets/codex/@tayo-dev/rtl-conventions/SKILL.md +19 -0
  5. package/assets/codex/@tayo-dev/rtl-generate/SKILL.md +27 -0
  6. package/assets/codex/@tayo-dev/rtl-help/SKILL.md +25 -0
  7. package/assets/codex/@tayo-dev/rtl-mocks/SKILL.md +22 -0
  8. package/assets/gemini/commands/@tayo-dev/rtl/generate.toml +10 -0
  9. package/assets/gemini/commands/@tayo-dev/rtl/help.toml +11 -0
  10. package/assets/opencode/commands/@tayo-dev/rtl-generate.md +11 -0
  11. package/assets/opencode/commands/@tayo-dev/rtl-help.md +12 -0
  12. package/dist/cli/commands/install.d.ts +22 -0
  13. package/dist/cli/commands/install.d.ts.map +1 -0
  14. package/dist/cli/commands/install.js +69 -0
  15. package/dist/cli/commands/install.js.map +1 -0
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +10 -4
  18. package/dist/index.js.map +1 -1
  19. package/dist/install/assets.d.ts +5 -0
  20. package/dist/install/assets.d.ts.map +1 -0
  21. package/dist/install/assets.js +23 -0
  22. package/dist/install/assets.js.map +1 -0
  23. package/dist/install/executor.d.ts +4 -0
  24. package/dist/install/executor.d.ts.map +1 -0
  25. package/dist/install/executor.js +26 -0
  26. package/dist/install/executor.js.map +1 -0
  27. package/dist/install/manifest.d.ts +21 -0
  28. package/dist/install/manifest.d.ts.map +1 -0
  29. package/dist/install/manifest.js +45 -0
  30. package/dist/install/manifest.js.map +1 -0
  31. package/dist/install/options.d.ts +13 -0
  32. package/dist/install/options.d.ts.map +1 -0
  33. package/dist/install/options.js +87 -0
  34. package/dist/install/options.js.map +1 -0
  35. package/dist/install/planner.d.ts +8 -0
  36. package/dist/install/planner.d.ts.map +1 -0
  37. package/dist/install/planner.js +31 -0
  38. package/dist/install/planner.js.map +1 -0
  39. package/dist/install/prompts.d.ts +9 -0
  40. package/dist/install/prompts.d.ts.map +1 -0
  41. package/dist/install/prompts.js +98 -0
  42. package/dist/install/prompts.js.map +1 -0
  43. package/dist/install/registry.d.ts +3 -0
  44. package/dist/install/registry.d.ts.map +1 -0
  45. package/dist/install/registry.js +47 -0
  46. package/dist/install/registry.js.map +1 -0
  47. package/dist/install/resolver.d.ts +8 -0
  48. package/dist/install/resolver.d.ts.map +1 -0
  49. package/dist/install/resolver.js +20 -0
  50. package/dist/install/resolver.js.map +1 -0
  51. package/dist/install/runtimes/claude.d.ts +3 -0
  52. package/dist/install/runtimes/claude.d.ts.map +1 -0
  53. package/dist/install/runtimes/claude.js +8 -0
  54. package/dist/install/runtimes/claude.js.map +1 -0
  55. package/dist/install/runtimes/codex.d.ts +3 -0
  56. package/dist/install/runtimes/codex.d.ts.map +1 -0
  57. package/dist/install/runtimes/codex.js +51 -0
  58. package/dist/install/runtimes/codex.js.map +1 -0
  59. package/dist/install/runtimes/gemini.d.ts +3 -0
  60. package/dist/install/runtimes/gemini.d.ts.map +1 -0
  61. package/dist/install/runtimes/gemini.js +8 -0
  62. package/dist/install/runtimes/gemini.js.map +1 -0
  63. package/dist/install/runtimes/opencode.d.ts +3 -0
  64. package/dist/install/runtimes/opencode.d.ts.map +1 -0
  65. package/dist/install/runtimes/opencode.js +8 -0
  66. package/dist/install/runtimes/opencode.js.map +1 -0
  67. package/dist/install/runtimes/prompt-runtimes.d.ts +3 -0
  68. package/dist/install/runtimes/prompt-runtimes.d.ts.map +1 -0
  69. package/dist/install/runtimes/prompt-runtimes.js +74 -0
  70. package/dist/install/runtimes/prompt-runtimes.js.map +1 -0
  71. package/dist/install/summary.d.ts +12 -0
  72. package/dist/install/summary.d.ts.map +1 -0
  73. package/dist/install/summary.js +112 -0
  74. package/dist/install/summary.js.map +1 -0
  75. package/dist/install/types.d.ts +119 -0
  76. package/dist/install/types.d.ts.map +1 -0
  77. package/dist/install/types.js +5 -0
  78. package/dist/install/types.js.map +1 -0
  79. package/dist/install/verification.d.ts +3 -0
  80. package/dist/install/verification.d.ts.map +1 -0
  81. package/dist/install/verification.js +34 -0
  82. package/dist/install/verification.js.map +1 -0
  83. package/dist/install/writer.d.ts +11 -0
  84. package/dist/install/writer.d.ts.map +1 -0
  85. package/dist/install/writer.js +99 -0
  86. package/dist/install/writer.js.map +1 -0
  87. package/package.json +3 -1
package/README.md CHANGED
@@ -1,73 +1,124 @@
1
1
  # Taro
2
2
 
3
- Generate React Testing Library tests from Chrome Recorder recordings — automatically.
3
+ Install Taro into Claude Code, OpenCode, Gemini CLI, or Codex, then generate React Testing Library tests from Chrome Recorder recordings.
4
4
 
5
- ## Introduction
5
+ Taro ships as an installer-first package. The package entrypoint bootstraps runtime-native commands or skills into your agent environment, and the generated runtime surface still routes back to `taro generate` when you want Recorder-to-RTL output.
6
6
 
7
- Taro is a CLI tool that reads Chrome DevTools Recorder exports (JSON) and Testing Library Recorder JS files and generates RTL test files. It scores its own output, learns your project's test conventions from existing files, and stores per-project state in a local `.taro/` directory. No server, no cloud — just files.
7
+ ## Getting Started
8
8
 
9
- ### Who it is for
9
+ ```bash
10
+ npx @tayo-dev/rtl@latest
11
+ ```
10
12
 
11
- - React developers who write tests with `@testing-library/react`
12
- - Developers who use Chrome DevTools Recorder to capture user flows
13
- - Teams that want test coverage without spending hours writing boilerplate
13
+ The installer prompts you to choose:
14
14
 
15
- ### The problem it solves
15
+ 1. **Runtime** Claude Code, OpenCode, Gemini CLI, Codex, or all
16
+ 2. **Location** — Global (all projects) or local (current project only)
16
17
 
17
- Recording a user flow in Chrome takes 30 seconds. Translating that recording into a well-structured RTL test takes 20–40 minutes and requires knowing which queries to use, how to assert, and how to match your project's test conventions. Taro closes that gap.
18
+ Verify the install with the runtime-native help command:
18
19
 
19
- ### How it works
20
+ - Claude Code: `/@tayo-dev/rtl:help`
21
+ - Gemini CLI: `/@tayo-dev/rtl:help`
22
+ - OpenCode: `/@tayo-dev/rtl-help`
23
+ - Codex: `$@tayo-dev/rtl-help`
20
24
 
21
- 1. Record a user flow in Chrome DevTools → Recorder panel.
22
- 2. Export via the Testing Library Recorder extension (`.js`) or as native Chrome Recorder JSON (`.json`).
23
- 3. Run `taro generate ./recording.js`.
24
- 4. Taro writes a `.test.tsx` file next to your recording, scored and convention-aware.
25
+ > [!NOTE]
26
+ > Codex installation uses skills under `skills/@tayo-dev/rtl-*/SKILL.md`, not prompt files.
25
27
 
26
- ## Quick Start
28
+ ## Staying Updated
27
29
 
28
- ### Prerequisites
30
+ Re-run the installer package to refresh owned assets and repair missing ones:
29
31
 
30
- - Node.js 18 or later
31
- - A React project using `@testing-library/react`
32
- - Chrome DevTools Recorder (built into Chrome — no extension needed for JSON exports)
32
+ ```bash
33
+ npx @tayo-dev/rtl@latest
34
+ ```
35
+
36
+ Taro refreshes unchanged owned files automatically, restores missing owned files, and protects manual edits instead of overwriting them silently.
33
37
 
34
- ### Step 1 — Install
38
+ ## Non-interactive Install
39
+
40
+ Use runtime flags plus exactly one location flag to skip prompts:
35
41
 
36
42
  ```bash
37
- npm install --save-dev @tayo-dev/rtl
38
- # or use npx to skip install entirely
39
- npx @tayo-dev/rtl generate ./my-recording.js
43
+ # Claude Code
44
+ npx @tayo-dev/rtl@latest --claude --global
45
+ npx @tayo-dev/rtl@latest --claude --local
46
+
47
+ # OpenCode
48
+ npx @tayo-dev/rtl@latest --opencode --global
49
+ npx @tayo-dev/rtl@latest --opencode --local
50
+
51
+ # Gemini CLI
52
+ npx @tayo-dev/rtl@latest --gemini --global
53
+ npx @tayo-dev/rtl@latest --gemini --local
54
+
55
+ # Codex
56
+ npx @tayo-dev/rtl@latest --codex --global
57
+ npx @tayo-dev/rtl@latest --codex --local
58
+
59
+ # All runtimes
60
+ npx @tayo-dev/rtl@latest --all --global
61
+ npx @tayo-dev/rtl@latest --all --local
40
62
  ```
41
63
 
42
- ### Step 2 Record a user flow
64
+ Local installs write to hidden runtime directories in the current project:
43
65
 
44
- Open Chrome DevTools → Recorder panel → click "Start new recording" → perform your user flow (clicks, form fills, navigation) → click "End recording". Then either:
66
+ - Claude Code: `./.claude/`
67
+ - OpenCode: `./.opencode/`
68
+ - Gemini CLI: `./.gemini/`
69
+ - Codex: `./.codex/`
45
70
 
46
- - Export as JSON: click the export button → "JSON" → save as `recording.json`
47
- - Export via Testing Library Recorder extension: install the extension, click its export button, save as `recording.js`
71
+ ## Development Installation
48
72
 
49
- ### Step 3 Generate the test
73
+ When you want to test the installer from a local checkout instead of the published package:
50
74
 
51
75
  ```bash
52
- # Using npx (no install required)
53
- npx @tayo-dev/rtl generate ./recording.js
76
+ # Build the CLI
77
+ npm run build
78
+
79
+ # Exercise the installer from the built package entrypoint
80
+ node dist/index.js --all --local
81
+
82
+ # Or verify the publish boundary with a tarball
83
+ env NPM_CONFIG_CACHE=/tmp/taro-npm-cache npm pack --pack-destination /tmp/taro-pack
84
+ npx /tmp/taro-pack/tayo-dev-rtl-1.0.0.tgz --codex --local
85
+ ```
86
+
87
+ The tarball flow is the closest match to what end users get from npm.
88
+
89
+ ## Generate RTL Tests
90
+
91
+ After installation, use `taro generate` directly or call the runtime-native installed command/skill that routes to it.
92
+
93
+ ### Prerequisites
94
+
95
+ - Node.js 18 or later
96
+ - A React project using `@testing-library/react`
97
+ - Chrome DevTools Recorder (built into Chrome — no extension needed for JSON exports)
98
+
99
+ ### Record a user flow
100
+
101
+ Open Chrome DevTools → Recorder panel → click "Start new recording" → perform your user flow → click "End recording". Then either:
54
102
 
55
- # Or if installed globally
103
+ - Export as JSON and save as `recording.json`
104
+ - Export via Testing Library Recorder extension and save as `recording.js`
105
+
106
+ ### Generate the test
107
+
108
+ ```bash
56
109
  taro generate ./recording.js
57
110
  ```
58
111
 
59
112
  Expected output:
60
113
 
61
- ```
114
+ ```text
62
115
  Parsed: my user flow — 8 steps
63
116
  [taro] Score: 78/100 (B) — query: 80, assertions: 70, structure: 85
64
117
  Created: src/components/MyComponent.test.tsx
65
118
  [taro] ✓ post-write verified
66
119
  ```
67
120
 
68
- ### What happens next
69
-
70
- Taro writes a `.test.tsx` file. On subsequent runs in the same project, it reads `.taro/conventions.json` to match your test style (import style, mock pattern, folder structure) automatically.
121
+ On subsequent runs in the same project, Taro reads `.taro/conventions.json` to match your test style automatically.
71
122
 
72
123
  ## CLI Reference
73
124
 
@@ -185,59 +236,11 @@ describe('login flow', () => {
185
236
 
186
237
  > **Note:** The component import path (`../LoginPage`) is a placeholder. Taro generates a comment in the file indicating where to update it.
187
238
 
188
- ## Using Taro as a Claude Code Skill
189
-
190
- ### Overview
191
-
192
- Taro works naturally as a Claude Code skill. You can instruct Claude to run `taro generate` on a recording file and it will generate the test, report the score, and surface any quality hints — all in a single agent turn.
193
-
194
- ### Option A: Direct invocation (no setup required)
195
-
196
- Claude Code can invoke Taro directly using the Bash tool. No skill configuration is needed — Claude calls npx inline. Simply give Claude a prompt like:
197
-
198
- ```
199
- Run: npx @tayo-dev/rtl generate ./recordings/checkout-flow.js
200
- Then report the score and the path of the generated file.
201
- ```
202
-
203
- ### Option B: Register as a Claude Code skill
204
-
205
- Registering Taro as a skill lets Claude invoke it by name without knowing the full command.
239
+ ## Agent Usage
206
240
 
207
- **Step 1** Create the skill file at `.claude/skills/taro/SKILL.md` in your project:
208
-
209
- ```markdown
210
- # Taro — RTL Test Generator
211
-
212
- ## Purpose
213
- Generate a React Testing Library test from a Chrome Recorder export.
214
-
215
- ## Invocation
216
- Run: taro generate <recording-file>
217
-
218
- ## Flags
219
- - `--dry-run` (-d): Preview the generated test without writing to disk
220
- - `--output <path>` (-o): Override the output file path
221
- - `--force` (-f): Overwrite an existing test file
222
-
223
- ## Output
224
- Writes `{recording-name}.test.tsx` next to the recording file.
225
- Reports score (0-100) and any quality hints.
226
- ```
227
-
228
- **Step 2** — Ensure Taro is installed in the project:
229
-
230
- ```bash
231
- npm install --save-dev @tayo-dev/rtl
232
- ```
233
-
234
- **Step 3** — Ask Claude to use the skill:
235
-
236
- ```
237
- Use the taro skill to generate a test from ./recordings/login-flow.js
238
- ```
241
+ After installation, each runtime gets a namespaced help entrypoint plus a generate command or skill that routes back to `taro generate`.
239
242
 
240
- ### Tips for agent use
243
+ ### Tips
241
244
 
242
245
  - Use `--dry-run` first to preview output before committing generated files
243
246
  - If you record multiple flows, run Taro on each to build up convention state in `.taro/conventions.json` — later runs benefit from earlier ones
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: "@tayo-dev/rtl:generate"
3
+ description: "Generate RTL tests from Chrome Recorder exports with Taro"
4
+ ---
5
+
6
+ <objective>
7
+ Generate a React Testing Library test from a Chrome Recorder export.
8
+ </objective>
9
+
10
+ <process>
11
+ 1. Confirm the recording path before running anything destructive.
12
+ 2. Run `taro generate <recording-file>` by default.
13
+ 3. Add `--dry-run`, `--output <path>`, or `--force` only when the user asks for them or the context requires them.
14
+ 4. Report the generated file path and score output.
15
+ </process>
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: "@tayo-dev/rtl:help"
3
+ description: "Show @tayo-dev/rtl install and generation help"
4
+ ---
5
+
6
+ <objective>
7
+ Help the user install and use @tayo-dev/rtl from Claude Code.
8
+ </objective>
9
+
10
+ <process>
11
+ 1. Explain that `/@tayo-dev/rtl:help` is the installed help entrypoint for @tayo-dev/rtl.
12
+ 2. For installation or updates, tell the user to run `npx @tayo-dev/rtl@latest`.
13
+ 3. For test generation, use `/@tayo-dev/rtl:generate` or run `taro generate <recording-file>`.
14
+ 4. Mention `--dry-run`, `--output <path>`, and `--force` only when they fit the request.
15
+ 5. When generation runs, report the score and generated file path.
16
+ </process>
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: "@tayo-dev/rtl-conventions"
3
+ description: "Explain how Tayo learns project test conventions and how to keep them stable."
4
+ ---
5
+
6
+ # Tayo Conventions
7
+
8
+ Use `$@tayo-dev/rtl-conventions` when the user asks why generated tests follow a certain style or how `.taro/conventions.json` affects output.
9
+
10
+ ## Focus
11
+
12
+ - explain that Tayo learns local test conventions from the codebase
13
+ - call out when `.taro/conventions.json` will influence generated imports, mocks, and file placement
14
+ - recommend `--dry-run` when the user wants to inspect convention alignment before writing files
15
+
16
+ ## Guardrails
17
+
18
+ - prefer existing project conventions over generic defaults
19
+ - surface missing context instead of inventing project-specific patterns
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: "@tayo-dev/rtl-generate"
3
+ description: "Generate React Testing Library tests from Recorder exports with Tayo."
4
+ ---
5
+
6
+ # Tayo Generate
7
+
8
+ Use `$@tayo-dev/rtl-generate` when the user wants to turn a Chrome Recorder export into a React Testing Library test.
9
+
10
+ ## Inputs
11
+
12
+ - path to the recording file
13
+ - optional `--output <path>`
14
+ - optional `--dry-run`
15
+ - optional `--force`
16
+
17
+ ## Execution
18
+
19
+ Run `taro generate <recording-file>` with the requested flags.
20
+
21
+ ## Response contract
22
+
23
+ Report:
24
+
25
+ - the generated test path
26
+ - the Tayo score
27
+ - any follow-up work required to fix component imports or flaky selectors
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: "@tayo-dev/rtl-help"
3
+ description: "Show the packaged Tayo Codex skill surface and the expected help entrypoint."
4
+ ---
5
+
6
+ # Tayo Codex Help
7
+
8
+ Use this skill when you need the Codex-facing entrypoint for Tayo or you need to route the user to the right packaged skill.
9
+
10
+ ## Entrypoint
11
+
12
+ Invoke this skill with `$@tayo-dev/rtl-help`.
13
+
14
+ ## Installed skill surface
15
+
16
+ - `$@tayo-dev/rtl-generate` for Recorder-to-RTL generation
17
+ - `$@tayo-dev/rtl-conventions` for convention-aware generation guidance
18
+ - `$@tayo-dev/rtl-mocks` for mock and fixture review
19
+
20
+ ## Default workflow
21
+
22
+ 1. Confirm the recording path or test target.
23
+ 2. Choose the matching packaged Tayo skill.
24
+ 3. If direct CLI execution is appropriate, run `taro generate <recording-file>` with any requested flags.
25
+ 4. Report the generated file path, score, and any blocking issues.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: "@tayo-dev/rtl-mocks"
3
+ description: "Review mock targets, fixture shape, and post-generation follow-up for Tayo output."
4
+ ---
5
+
6
+ # Tayo Mocks
7
+
8
+ Use `$@tayo-dev/rtl-mocks` when the user needs help understanding mock recommendations or fixture strategy around generated RTL tests.
9
+
10
+ ## Focus
11
+
12
+ - identify the API or data boundaries that need mocks
13
+ - explain whether the mock should stay inline or move to a shared fixture
14
+ - keep recommendations aligned with the project's current test stack
15
+
16
+ ## Output
17
+
18
+ Summarize:
19
+
20
+ - the mock targets that matter
21
+ - the preferred mocking pattern
22
+ - any manual follow-up still required after generation
@@ -0,0 +1,10 @@
1
+ description = "Generate RTL tests from Chrome Recorder exports with Taro"
2
+ prompt = """
3
+ You are the installed /@tayo-dev/rtl:generate command for @tayo-dev/rtl.
4
+
5
+ Generate a React Testing Library test from a Chrome Recorder export.
6
+ 1. Confirm the recording path before running anything destructive.
7
+ 2. Run `taro generate <recording-file>` by default.
8
+ 3. Add `--dry-run`, `--output <path>`, or `--force` only when the user asks for them or the context requires them.
9
+ 4. Report the generated file path and score output.
10
+ """
@@ -0,0 +1,11 @@
1
+ description = "Show @tayo-dev/rtl install and generation help"
2
+ prompt = """
3
+ You are the installed /@tayo-dev/rtl:help command for @tayo-dev/rtl.
4
+
5
+ When the user wants help:
6
+ 1. Explain that /@tayo-dev/rtl:help is the runtime-native help entrypoint.
7
+ 2. For installation or updates, tell them to run `npx @tayo-dev/rtl@latest`.
8
+ 3. For generation, direct them to /@tayo-dev/rtl:generate or `taro generate <recording-file>`.
9
+ 4. Mention `--dry-run`, `--output <path>`, and `--force` only when they match the request.
10
+ 5. When generation runs, report the score and generated file path.
11
+ """
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: Generate RTL tests from Chrome Recorder exports with Taro
3
+ ---
4
+
5
+ You are the installed `/@tayo-dev/rtl-generate` command for `@tayo-dev/rtl`.
6
+
7
+ Generate a React Testing Library test from a Chrome Recorder export.
8
+ 1. Confirm the recording path before running anything destructive.
9
+ 2. Run `taro generate <recording-file>` by default.
10
+ 3. Add `--dry-run`, `--output <path>`, or `--force` only when the user asks for them or the context requires them.
11
+ 4. Report the generated file path and score output.
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Show @tayo-dev/rtl install and generation help
3
+ ---
4
+
5
+ You are the installed `/@tayo-dev/rtl-help` command for `@tayo-dev/rtl`.
6
+
7
+ When the user wants help:
8
+ 1. Explain that `/@tayo-dev/rtl-help` is the runtime-native help entrypoint.
9
+ 2. For installation or updates, tell them to run `npx @tayo-dev/rtl@latest`.
10
+ 3. For generation, direct them to `/@tayo-dev/rtl-generate` or `taro generate <recording-file>`.
11
+ 4. Mention `--dry-run`, `--output <path>`, and `--force` only when they match the request.
12
+ 5. When generation runs, report the score and generated file path.
@@ -0,0 +1,22 @@
1
+ import { Command } from 'commander';
2
+ import type { InstallCommandOptions } from '../../install/types.js';
3
+ interface PromptCapability {
4
+ input?: Pick<typeof process.stdin, 'isTTY'>;
5
+ output?: Pick<typeof process.stdout, 'isTTY'>;
6
+ }
7
+ interface PromptIO {
8
+ input?: typeof process.stdin;
9
+ output?: typeof process.stdout;
10
+ }
11
+ interface InstallCommandContext {
12
+ cwd?: string;
13
+ home?: string;
14
+ logger?: Pick<typeof console, 'log' | 'error'>;
15
+ promptCapability?: PromptCapability;
16
+ promptIO?: PromptIO;
17
+ }
18
+ export declare function applyInstallOptions(command: Command): Command;
19
+ export declare function runInstallCommand(options?: InstallCommandOptions, context?: InstallCommandContext): Promise<void>;
20
+ export declare function createInstallCommand(): Command;
21
+ export {};
22
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAgBnC,OAAO,KAAK,EAAE,qBAAqB,EAAoB,MAAM,wBAAwB,CAAA;AAErF,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC3C,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9C;AAED,UAAU,QAAQ;IAChB,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,KAAK,CAAA;IAC5B,MAAM,CAAC,EAAE,OAAO,OAAO,CAAC,MAAM,CAAA;CAC/B;AAED,UAAU,qBAAqB;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,OAAO,EAAE,KAAK,GAAG,OAAO,CAAC,CAAA;IAC9C,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAS7D;AAyBD,wBAAsB,iBAAiB,CACrC,OAAO,GAAE,qBAA0B,EACnC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAY9C"}
@@ -0,0 +1,69 @@
1
+ import { Command } from 'commander';
2
+ import pc from 'picocolors';
3
+ import { executeInstallPlan } from '../../install/executor.js';
4
+ import { InstallValidationError, normalizeInstallOptions, toInstallSelection, } from '../../install/options.js';
5
+ import { buildInstallPlan } from '../../install/planner.js';
6
+ import { promptForInstallChoices } from '../../install/prompts.js';
7
+ import { confirmInstallPlan, renderInstallCancelledMessage, renderInstallExecutionResult, renderInstallSummary, } from '../../install/summary.js';
8
+ export function applyInstallOptions(command) {
9
+ return command
10
+ .option('--claude', 'Install Taro assets for Claude Code')
11
+ .option('--opencode', 'Install Taro assets for OpenCode')
12
+ .option('--gemini', 'Install Taro assets for Gemini CLI')
13
+ .option('--codex', 'Install Taro assets for Codex')
14
+ .option('--all', 'Install Taro assets for all supported runtimes')
15
+ .option('--global', 'Install into the runtime global configuration directory')
16
+ .option('--local', 'Install into the current project only');
17
+ }
18
+ async function resolveInstallSelection(options, context) {
19
+ const normalized = normalizeInstallOptions(options, context.promptCapability);
20
+ if (normalized.mode === 'interactive') {
21
+ return promptForInstallChoices(normalized, context.promptIO);
22
+ }
23
+ return toInstallSelection(normalized);
24
+ }
25
+ function printInstallError(error, logger) {
26
+ if (error instanceof InstallValidationError) {
27
+ logger.error(pc.red(`Error: ${error.message}`));
28
+ process.exitCode = 1;
29
+ return;
30
+ }
31
+ throw error;
32
+ }
33
+ export async function runInstallCommand(options = {}, context = {}) {
34
+ const logger = context.logger ?? console;
35
+ try {
36
+ const selection = await resolveInstallSelection(options, context);
37
+ const plan = buildInstallPlan(selection, {
38
+ cwd: context.cwd,
39
+ home: context.home,
40
+ });
41
+ logger.log(renderInstallSummary(plan));
42
+ if (selection.mode === 'interactive') {
43
+ const confirmed = await confirmInstallPlan(plan, context.promptIO);
44
+ if (!confirmed) {
45
+ logger.log(pc.yellow(renderInstallCancelledMessage()));
46
+ return;
47
+ }
48
+ }
49
+ const result = await executeInstallPlan(plan);
50
+ logger.log(renderInstallExecutionResult(result));
51
+ if (result.status !== 'installed') {
52
+ process.exitCode = 1;
53
+ }
54
+ }
55
+ catch (error) {
56
+ printInstallError(error, logger);
57
+ }
58
+ }
59
+ export function createInstallCommand() {
60
+ const install = new Command('install');
61
+ applyInstallOptions(install);
62
+ install
63
+ .description('Install Taro into Claude Code, OpenCode, Gemini CLI, or Codex')
64
+ .action(async (options) => {
65
+ await runInstallCommand(options);
66
+ });
67
+ return install;
68
+ }
69
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,EACL,kBAAkB,EAClB,6BAA6B,EAC7B,4BAA4B,EAC5B,oBAAoB,GACrB,MAAM,0BAA0B,CAAA;AAqBjC,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO,OAAO;SACX,MAAM,CAAC,UAAU,EAAE,qCAAqC,CAAC;SACzD,MAAM,CAAC,YAAY,EAAE,kCAAkC,CAAC;SACxD,MAAM,CAAC,UAAU,EAAE,oCAAoC,CAAC;SACxD,MAAM,CAAC,SAAS,EAAE,+BAA+B,CAAC;SAClD,MAAM,CAAC,OAAO,EAAE,gDAAgD,CAAC;SACjE,MAAM,CAAC,UAAU,EAAE,yDAAyD,CAAC;SAC7E,MAAM,CAAC,SAAS,EAAE,uCAAuC,CAAC,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,uBAAuB,CACpC,OAA8B,EAC9B,OAA8B;IAE9B,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAE7E,IAAI,UAAU,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QACtC,OAAO,uBAAuB,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9D,CAAC;IAED,OAAO,kBAAkB,CAAC,UAAU,CAAC,CAAA;AACvC,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc,EAAE,MAAqC;IAC9E,IAAI,KAAK,YAAY,sBAAsB,EAAE,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpB,OAAM;IACR,CAAC;IAED,MAAM,KAAK,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAiC,EAAE,EACnC,UAAiC,EAAE;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAA;IAExC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACjE,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,EAAE;YACvC,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAC,CAAA;QAEF,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;QAEtC,IAAI,SAAS,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;YAClE,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,6BAA6B,EAAE,CAAC,CAAC,CAAA;gBACtD,OAAM;YACR,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;QAE7C,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC,CAAA;QAEhD,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAA;IAEtC,mBAAmB,CAAC,OAAO,CAAC,CAAA;IAE5B,OAAO;SACJ,WAAW,CAAC,+DAA+D,CAAC;SAC5E,MAAM,CAAC,KAAK,EAAE,OAA8B,EAAE,EAAE;QAC/C,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEJ,OAAO,OAAO,CAAA;AAChB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Taro CLI entry point
4
- * Generates React Testing Library tests from Chrome Recorder exports.
4
+ * Installer-first package surface with generator access preserved under `generate`.
5
5
  */
6
6
  export {};
7
7
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,18 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Taro CLI entry point
4
- * Generates React Testing Library tests from Chrome Recorder exports.
4
+ * Installer-first package surface with generator access preserved under `generate`.
5
5
  */
6
6
  import { Command } from 'commander';
7
7
  import pc from 'picocolors';
8
8
  import { createGenerateCommand } from './cli/commands/generate.js';
9
+ import { applyInstallOptions, createInstallCommand, runInstallCommand, } from './cli/commands/install.js';
9
10
  const program = new Command();
11
+ applyInstallOptions(program);
10
12
  program
11
13
  .name('taro')
12
- .description(pc.bold('Taro') +
13
- ' — Generate React Testing Library tests from Chrome Recorder exports')
14
+ .description(`${pc.bold('@tayo-dev/rtl')} — Install Taro into Claude Code, OpenCode, Gemini CLI, or Codex`)
14
15
  .version('1.0.0', '-v, --version', 'Output the current version')
15
- .helpOption('-h, --help', 'Display help for command');
16
+ .helpOption('-h, --help', 'Display help for command')
17
+ .addHelpText('after', `\nExisting capability:\n ${pc.bold('taro generate <file>')} Generate RTL tests from Chrome Recorder exports`)
18
+ .action(async () => {
19
+ await runInstallCommand(program.optsWithGlobals());
20
+ });
21
+ program.addCommand(createInstallCommand());
16
22
  program.addCommand(createGenerateCommand());
17
23
  program.parse(process.argv);
18
24
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAElE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CACV,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;IACb,sEAAsE,CACzE;KACA,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,4BAA4B,CAAC;KAC/D,UAAU,CAAC,YAAY,EAAE,0BAA0B,CAAC,CAAA;AAEvD,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAA;AAE3C,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,2BAA2B,CAAA;AAGlC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAE5B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CACV,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,kEAAkE,CAC9F;KACA,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,4BAA4B,CAAC;KAC/D,UAAU,CAAC,YAAY,EAAE,0BAA0B,CAAC;KACpD,WAAW,CACV,OAAO,EACP,6BAA6B,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,mDAAmD,CAChH;KACA,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,iBAAiB,CAAC,OAAO,CAAC,eAAe,EAA2B,CAAC,CAAA;AAC7E,CAAC,CAAC,CAAA;AAEJ,OAAO,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAA;AAC1C,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAA;AAE3C,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { RuntimeTarget } from './types.js';
2
+ export declare function resolvePackageRoot(fromModuleUrl?: string): string;
3
+ export declare function resolveAssetsRoot(fromModuleUrl?: string): string;
4
+ export declare function resolveAssetSource(runtime: RuntimeTarget, sourceSegments?: string[], fromModuleUrl?: string): string;
5
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/install/assets.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,wBAAgB,kBAAkB,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM,CAelF;AAED,wBAAgB,iBAAiB,CAAC,aAAa,GAAE,MAAwB,GAAG,MAAM,CAEjF;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EACtB,cAAc,GAAE,MAAM,EAAO,EAC7B,aAAa,GAAE,MAAwB,GACtC,MAAM,CAER"}
@@ -0,0 +1,23 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ export function resolvePackageRoot(fromModuleUrl = import.meta.url) {
5
+ let current = dirname(fileURLToPath(fromModuleUrl));
6
+ while (true) {
7
+ if (existsSync(join(current, 'package.json'))) {
8
+ return current;
9
+ }
10
+ const parent = dirname(current);
11
+ if (parent === current) {
12
+ throw new Error(`Unable to locate package root from ${fromModuleUrl}.`);
13
+ }
14
+ current = parent;
15
+ }
16
+ }
17
+ export function resolveAssetsRoot(fromModuleUrl = import.meta.url) {
18
+ return join(resolvePackageRoot(fromModuleUrl), 'assets');
19
+ }
20
+ export function resolveAssetSource(runtime, sourceSegments = [], fromModuleUrl = import.meta.url) {
21
+ return join(resolveAssetsRoot(fromModuleUrl), runtime, ...sourceSegments);
22
+ }
23
+ //# sourceMappingURL=assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/install/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAW,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAGxC,MAAM,UAAU,kBAAkB,CAAC,gBAAwB,MAAM,CAAC,IAAI,CAAC,GAAG;IACxE,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAA;IAEnD,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAA;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAC/B,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,sCAAsC,aAAa,GAAG,CAAC,CAAA;QACzE,CAAC;QAED,OAAO,GAAG,MAAM,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,gBAAwB,MAAM,CAAC,IAAI,CAAC,GAAG;IACvE,OAAO,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAA;AAC1D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,iBAA2B,EAAE,EAC7B,gBAAwB,MAAM,CAAC,IAAI,CAAC,GAAG;IAEvC,OAAO,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,CAAA;AAC3E,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { InstallExecutionResult, InstallPlan } from './types.js';
2
+ import type { WriteInstallPlanOptions } from './writer.js';
3
+ export declare function executeInstallPlan(plan: InstallPlan, options?: WriteInstallPlanOptions): Promise<InstallExecutionResult>;
4
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/install/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AAE1D,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,WAAW,EACjB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CA+BjC"}
@@ -0,0 +1,26 @@
1
+ import { verifyInstalledRuntime } from './verification.js';
2
+ import { writeInstallPlan } from './writer.js';
3
+ export async function executeInstallPlan(plan, options = {}) {
4
+ const targets = await Promise.all(plan.targets.map(async (target) => {
5
+ const result = await writeInstallPlan(target, {
6
+ confirmReplace: options.confirmReplace,
7
+ generatedAt: options.generatedAt,
8
+ });
9
+ if (result.status === 'blocked') {
10
+ return result;
11
+ }
12
+ const verification = await verifyInstalledRuntime(target);
13
+ return {
14
+ ...result,
15
+ verification,
16
+ };
17
+ }));
18
+ const hasSuccessfulWrites = targets.some((target) => target.status !== 'blocked');
19
+ const hasFailures = targets.some((target) => target.status === 'blocked' || target.verification?.status === 'missing-installed-assets');
20
+ return {
21
+ packageName: plan.packageName,
22
+ status: hasFailures ? (hasSuccessfulWrites ? 'partial' : 'blocked') : 'installed',
23
+ targets,
24
+ };
25
+ }
26
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/install/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAI9C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAiB,EACjB,UAAmC,EAAE;IAErC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE;YAC5C,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,WAAW,EAAE,OAAO,CAAC,WAAW;SACjC,CAAC,CAAA;QAEF,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,OAAO,MAAM,CAAA;QACf,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,CAAA;QACzD,OAAO;YACL,GAAG,MAAM;YACT,YAAY;SACb,CAAA;IACH,CAAC,CAAC,CACH,CAAA;IAED,MAAM,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;IACjF,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAC9B,CAAC,MAAM,EAAE,EAAE,CACT,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,EAAE,MAAM,KAAK,0BAA0B,CAC5F,CAAA;IAED,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW;QACjF,OAAO;KACR,CAAA;AACH,CAAC"}