@smoothbricks/cli 0.10.2 → 0.10.4

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 (133) hide show
  1. package/README.md +31 -23
  2. package/dist/bun/preload.d.ts +13 -0
  3. package/dist/bun/preload.d.ts.map +1 -0
  4. package/dist/bun/preload.js +12 -0
  5. package/dist/cli.js +36 -4
  6. package/dist/generate/index.d.ts.map +1 -1
  7. package/dist/generate/index.js +0 -6
  8. package/dist/github-ci/index.d.ts +17 -2
  9. package/dist/github-ci/index.d.ts.map +1 -1
  10. package/dist/github-ci/index.js +192 -26
  11. package/dist/github-ci/outputs.d.ts +22 -0
  12. package/dist/github-ci/outputs.d.ts.map +1 -0
  13. package/dist/github-ci/outputs.js +648 -0
  14. package/dist/lib/cli-package.js +2 -2
  15. package/dist/lib/json.d.ts +118 -11
  16. package/dist/lib/json.d.ts.map +1 -1
  17. package/dist/lib/json.js +317 -29
  18. package/dist/lib/workspace.d.ts +7 -14
  19. package/dist/lib/workspace.d.ts.map +1 -1
  20. package/dist/lib/workspace.js +76 -82
  21. package/dist/monorepo/ci-workflow.d.ts +2 -0
  22. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  23. package/dist/monorepo/ci-workflow.js +28 -2
  24. package/dist/monorepo/git-config.js +2 -2
  25. package/dist/monorepo/index.d.ts +3 -1
  26. package/dist/monorepo/index.d.ts.map +1 -1
  27. package/dist/monorepo/index.js +6 -2
  28. package/dist/monorepo/lockfile.d.ts +13 -1
  29. package/dist/monorepo/lockfile.d.ts.map +1 -1
  30. package/dist/monorepo/lockfile.js +33 -21
  31. package/dist/monorepo/managed-files.d.ts +12 -0
  32. package/dist/monorepo/managed-files.d.ts.map +1 -1
  33. package/dist/monorepo/managed-files.js +86 -28
  34. package/dist/monorepo/package-policy.d.ts.map +1 -1
  35. package/dist/monorepo/package-policy.js +78 -45
  36. package/dist/monorepo/packed-manifest.d.ts +5 -2
  37. package/dist/monorepo/packed-manifest.d.ts.map +1 -1
  38. package/dist/monorepo/packed-manifest.js +16 -47
  39. package/dist/monorepo/packed-package.d.ts.map +1 -1
  40. package/dist/monorepo/packed-package.js +28 -16
  41. package/dist/monorepo/packs/index.d.ts +3 -0
  42. package/dist/monorepo/packs/index.d.ts.map +1 -1
  43. package/dist/monorepo/packs/index.js +18 -6
  44. package/dist/monorepo/publish-workflow.d.ts +1 -0
  45. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  46. package/dist/monorepo/publish-workflow.js +242 -3
  47. package/dist/monorepo/runtime.d.ts +15 -0
  48. package/dist/monorepo/runtime.d.ts.map +1 -1
  49. package/dist/monorepo/runtime.js +66 -12
  50. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  51. package/dist/monorepo/tool-validation.js +32 -23
  52. package/dist/monorepo/wrangler.d.ts.map +1 -1
  53. package/dist/monorepo/wrangler.js +13 -13
  54. package/dist/nx/index.d.ts +12 -4
  55. package/dist/nx/index.d.ts.map +1 -1
  56. package/dist/nx/index.js +86 -19
  57. package/dist/pr/index.d.ts.map +1 -1
  58. package/dist/pr/index.js +28 -32
  59. package/dist/release/candidates.d.ts +3 -2
  60. package/dist/release/candidates.d.ts.map +1 -1
  61. package/dist/release/candidates.js +4 -5
  62. package/dist/release/github-release.d.ts +3 -0
  63. package/dist/release/github-release.d.ts.map +1 -1
  64. package/dist/release/github-release.js +11 -0
  65. package/dist/release/index.d.ts +20 -1
  66. package/dist/release/index.d.ts.map +1 -1
  67. package/dist/release/index.js +221 -89
  68. package/dist/release/orchestration.d.ts +8 -1
  69. package/dist/release/orchestration.d.ts.map +1 -1
  70. package/dist/release/orchestration.js +38 -1
  71. package/dist/wrangler/prepare-env.d.ts +0 -1
  72. package/dist/wrangler/prepare-env.d.ts.map +1 -1
  73. package/dist/wrangler/prepare-env.js +100 -51
  74. package/dist/wrangler/scaffold.d.ts.map +1 -1
  75. package/dist/wrangler/scaffold.js +12 -12
  76. package/managed/raw/git-format-staged.yml +19 -1
  77. package/managed/raw/tooling/direnv/github-actions-bootstrap.sh +6 -0
  78. package/managed/raw/tooling/direnv/merge-newer-pins.sh +3 -3
  79. package/managed/raw/tooling/direnv/setup-environment.ts +187 -19
  80. package/managed/raw/tooling/git-hooks/pre-commit.sh +0 -6
  81. package/managed/templates/github/actions/cache-nix-devenv/action.yml +12 -10
  82. package/managed/templates/github/actions/cache-node-modules/action.yml +6 -2
  83. package/managed/templates/github/actions/cache-nx/action.yml +2 -2
  84. package/managed/templates/github/actions/cache-ttsc-plugins/action.yml +19 -0
  85. package/managed/templates/github/actions/save-nix-devenv/action.yml +11 -3
  86. package/managed/templates/github/actions/setup-devenv/action.yml +5 -0
  87. package/managed/templates/github/workflows/managed-files.yml +80 -0
  88. package/package.json +18 -4
  89. package/src/bun/preload.ts +12 -0
  90. package/src/cli.ts +49 -11
  91. package/src/generate/index.ts +0 -6
  92. package/src/github-ci/index.test.ts +486 -0
  93. package/src/github-ci/index.ts +220 -30
  94. package/src/github-ci/outputs.ts +505 -0
  95. package/src/lib/cli-package.ts +2 -2
  96. package/src/lib/json.ts +291 -32
  97. package/src/lib/workspace.ts +88 -100
  98. package/src/monorepo/__tests__/ci-workflow.test.ts +14 -3
  99. package/src/monorepo/__tests__/publish-workflow.test.ts +222 -1
  100. package/src/monorepo/ci-workflow.ts +28 -2
  101. package/src/monorepo/git-config.ts +2 -2
  102. package/src/monorepo/index.ts +6 -2
  103. package/src/monorepo/lockfile.test.ts +35 -36
  104. package/src/monorepo/lockfile.ts +48 -24
  105. package/src/monorepo/managed-files.test.ts +63 -0
  106. package/src/monorepo/managed-files.ts +94 -34
  107. package/src/monorepo/package-policy.test.ts +70 -51
  108. package/src/monorepo/package-policy.ts +104 -59
  109. package/src/monorepo/packed-manifest.ts +18 -52
  110. package/src/monorepo/packed-package.ts +43 -22
  111. package/src/monorepo/packs/index.test.ts +18 -1
  112. package/src/monorepo/packs/index.ts +20 -7
  113. package/src/monorepo/publish-workflow.ts +482 -3
  114. package/src/monorepo/runtime.test.ts +42 -3
  115. package/src/monorepo/runtime.ts +90 -12
  116. package/src/monorepo/tool-validation.ts +35 -25
  117. package/src/monorepo/wrangler.test.ts +11 -15
  118. package/src/monorepo/wrangler.ts +15 -15
  119. package/src/nx/index.test.ts +43 -0
  120. package/src/nx/index.ts +110 -23
  121. package/src/pr/index.ts +42 -36
  122. package/src/release/__tests__/candidates.test.ts +5 -4
  123. package/src/release/__tests__/fixture-repo.test.ts +18 -16
  124. package/src/release/__tests__/github-release.test.ts +11 -0
  125. package/src/release/__tests__/orchestration.test.ts +57 -2
  126. package/src/release/__tests__/trust-publisher.test.ts +98 -2
  127. package/src/release/candidates.ts +10 -17
  128. package/src/release/github-release.ts +12 -0
  129. package/src/release/index.ts +321 -112
  130. package/src/release/orchestration.ts +55 -3
  131. package/src/wrangler/prepare-env.ts +75 -54
  132. package/src/wrangler/scaffold.test.ts +9 -12
  133. package/src/wrangler/scaffold.ts +13 -13
package/README.md CHANGED
@@ -228,35 +228,43 @@ candidates to downstream dependents because that would duplicate Nx's dependency
228
228
 
229
229
  `smoo` keeps Nx target names predictable and separates tool work from aggregate workflows.
230
230
 
231
- Official Nx plugins own targets they already know how to infer. For example, `@nx/js/typescript` owns TypeScript library
232
- builds, so a package `tsconfig.lib.json` produces the concrete target `tsc-js`.
233
-
234
- `@smoothbricks/nx-plugin` only fills SmoothBricks convention gaps that official plugins do not provide. Today that means
235
- Bun test typechecking, non-TypeScript build-tool steps, and aggregate targets.
231
+ `@smoothbricks/nx-plugin` owns transformer-aware TypeScript targets because this workspace compiles through `ttsc`.
232
+ Configuring `@nx/js/typescript` would run `tsc`/`tsgo` directly and bypass the Typia and LMAO transformers. A package
233
+ `tsconfig.lib.json` therefore produces the concrete `tsc-js` target from the SmoothBricks plugin. The same plugin also
234
+ infers Bun test typechecking, Cargo workspace targets, and aggregate targets.
236
235
 
237
236
  Concrete targets use `{tool}-{output}` names and describe the tool that runs and the artifact or purpose it produces:
238
237
 
239
- - `tsc-js` comes from the official TypeScript plugin and runs `tsc` for package JavaScript/declaration output.
238
+ - `tsc-js` comes from `@smoothbricks/nx-plugin` and runs `ttsc` for package JavaScript/declaration output.
240
239
  - Packages that run `bun test` must have `tsconfig.test.json`. Bun executes tests without typechecking, so smoo creates
241
240
  a no-emit `typecheck-tests` target from that config and wires it into validation. Other test runners may own their own
242
241
  typecheck path.
243
242
  - Test tsconfigs are validation configs, not TypeScript build-mode projects. They must use `noEmit`, must not set
244
243
  `composite: true`, and package root `tsconfig.json` must not reference `./tsconfig.test.json`. The inferred
245
- `typecheck-tests` target runs `tsc --noEmit -p tsconfig.test.json` after `build` instead.
246
- - Non-TypeScript build steps come from explicit tool configuration. For example, a package `build.zig` must expose named
247
- `b.step("name", ...)` entries; each non-reserved step becomes a `zig-name` target such as `zig-wasm`.
244
+ `typecheck-tests` target runs `ttsc --noEmit -p tsconfig.test.json` after `build` instead.
245
+ - A neighboring workspace-root `Cargo.toml` provides Cargo test, lint, mutation, and benchmark targets. Workspaces with
246
+ `cdylib` member crates also receive the cacheable `cargo-wasm` output target.
248
247
  - `build` is an aggregate. It exists only when there is at least one concrete build target such as `tsc-js`,
249
248
  `tsdown-js`, or another tool-output target, and it depends on output-family wildcards such as `*-js`, `*-web`,
250
249
  `*-html`, `*-css`, `*-ios`, `*-android`, `*-native`, `*-napi`, `*-bun`, and `*-wasm` instead of duplicating commands.
251
250
  - `lint` is an aggregate validation target. It is not a formatting target.
252
251
 
252
+ The root `@typescript/native` dependency follows TypeScript's documented side-by-side pattern: it aliases TypeScript 7
253
+ and supplies the native compiler used by `ttsc`. Because `ttsc` resolves only the unscoped package by default, the
254
+ managed devenv shell sets `TTSC_TSGO_BINARY` to `node_modules/@typescript/native/bin/tsc`; the GitHub setup action
255
+ persists that absolute path through `GITHUB_ENV`. Nx and other JavaScript tooling still require the full TypeScript
256
+ compiler API, so workspace `typescript` stays on TypeScript 6. After install, setup-environment forces Bun's shared
257
+ `.bun/node_modules/typescript` hoist onto that API package so Nx does not load `@typescript/native` (TS7) via the store
258
+ ([oven-sh/bun#33834](https://github.com/oven-sh/bun/issues/33834)). Both dependencies and the environment binding are
259
+ required: TypeScript 7 under the unscoped name breaks Nx API calls such as `readConfigFile`.
260
+
253
261
  Explicit Nx target names must not contain `:`. Nx already uses colon syntax at the CLI boundary:
254
262
  `project:target:configuration`. Allowing target names like `build:wasm` makes command parsing and package-script aliases
255
263
  look like configurations, and it prevents a clean split between concrete tool-output targets and aggregate targets.
256
264
 
257
- Use tool-output names for concrete targets, such as `tsc-js`, `tsdown-js`, and `zig-wasm`. Use `build` and `lint` only
265
+ Use tool-output names for concrete targets, such as `tsc-js`, `tsdown-js`, and `cargo-wasm`. Use `build` and `lint` only
258
266
  as aggregate targets. Package scripts may still use developer-friendly colon names, for example `build:wasm`, but those
259
- scripts should delegate to unambiguous Nx targets such as `nx run pkg:zig-wasm`.
267
+ scripts should delegate to unambiguous Nx targets such as `nx run pkg:cargo-wasm`.
260
268
 
261
269
  ## Managed Files
262
270
 
@@ -286,6 +294,9 @@ smoo monorepo diff
286
294
 
287
295
  `check` fails when a managed file is missing or stale. `diff` reports drift without writing files.
288
296
 
297
+ The generated publish workflow is canonical Prettier YAML. Running the repository formatter over
298
+ `.github/workflows/publish.yml` is byte-stable and does not create managed-file drift.
299
+
289
300
  ## Formatting And Git Hooks
290
301
 
291
302
  The root `lint:fix` script runs [`git-format-staged`][git-format-staged] with
@@ -467,12 +478,15 @@ Publishing:
467
478
  for targeted bootstraps.
468
479
  - `smoo release trust-publisher` configures [npm trusted publishing][npm-trusted-publishing] for every owned release
469
480
  package. It uses the root `package.json` `repository.url` as the GitHub `owner/repo`, uses `publish.yml` as the
470
- trusted workflow, and runs `npm trust` through `nix shell nixpkgs#nodejs_latest` because the Lambda-pinned Node 24/npm
471
- toolchain may lag the npm CLI feature. It does not run a separate `npm login` before trust setup; `npm trust list` and
472
- `npm trust github` own authentication so npm can offer the 5-minute trust/publish challenge bypass. Pass
473
- `--package <name...>` to target specific owned packages. Pass `--bootstrap` to create missing npm package names first,
474
- then configure trusted publishing in the same command. With `--bootstrap`, `--skip-login` only skips the placeholder
475
- publish login. Existing matching trusted publishers are skipped via `npm trust list <package> --json`.
481
+ trusted workflow, grants that workflow npm's `--allow-publish` permission, and runs `npm trust` through
482
+ `nix shell nixpkgs#nodejs_latest` because the Lambda-pinned Node 24/npm toolchain may lag the npm CLI feature. It does
483
+ not pre-login: `npm trust list` and `npm trust github` own normal authentication so npm can offer the 5-minute
484
+ trust/publish challenge bypass. If `npm trust list` denies access, smoo reports the active npm identity and package
485
+ owners, opens `npm login --auth-type=web` once so the operator can switch accounts, then retries the lookup. A second
486
+ denial fails instead of looping. Pass `--package <name...>` to target specific owned packages. Pass `--bootstrap` to
487
+ create missing npm package names first, then configure trusted publishing in the same command. With `--bootstrap`,
488
+ `--skip-login` only skips the placeholder publish login. Existing matching trusted publishers are skipped via
489
+ `npm trust list <package> --json`.
476
490
 
477
491
  GitHub Releases:
478
492
 
@@ -514,12 +528,6 @@ nx lint @smoothbricks/cli
514
528
  smoo monorepo validate
515
529
  ```
516
530
 
517
- If validating packages with Zig build steps from outside the devenv shell, add Zig explicitly:
518
-
519
- ```bash
520
- nix shell nixpkgs#zig -c nx run-many -t build --projects=<public-projects>
521
- ```
522
-
523
531
  ## Links
524
532
 
525
533
  [are-the-types-wrong]: https://github.com/arethetypeswrong/arethetypeswrong.github.io/tree/main/packages/cli
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Bun runtime preload for consumers of `@smoothbricks/cli`.
3
+ *
4
+ * Re-exports the Typia/ttsc transform preload from `@smoothbricks/validation`.
5
+ * External repos depend on the CLI package only — they must not need a direct
6
+ * `@smoothbricks/validation` dependency just to run `smoo` against source.
7
+ *
8
+ * Usage:
9
+ * import '@smoothbricks/cli/bun/preload';
10
+ * // or bunfig.toml: preload = ["@smoothbricks/cli/bun/preload"]
11
+ */
12
+ import '@smoothbricks/validation/bun/preload';
13
+ //# sourceMappingURL=preload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preload.d.ts","sourceRoot":"","sources":["../../src/bun/preload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,sCAAsC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Bun runtime preload for consumers of `@smoothbricks/cli`.
3
+ *
4
+ * Re-exports the Typia/ttsc transform preload from `@smoothbricks/validation`.
5
+ * External repos depend on the CLI package only — they must not need a direct
6
+ * `@smoothbricks/validation` dependency just to run `smoo` against source.
7
+ *
8
+ * Usage:
9
+ * import '@smoothbricks/cli/bun/preload';
10
+ * // or bunfig.toml: preload = ["@smoothbricks/cli/bun/preload"]
11
+ */
12
+ import '@smoothbricks/validation/bun/preload';
package/dist/cli.js CHANGED
@@ -52,9 +52,12 @@ function buildProgram() {
52
52
  const { updateManagedFiles } = await import('./monorepo/index.js');
53
53
  updateManagedFiles(await findRepoRoot());
54
54
  });
55
- monorepo.command('check').action(async () => {
55
+ monorepo
56
+ .command('check')
57
+ .option('--warn', 'report drift as warnings (GitHub annotations) instead of failing')
58
+ .action(async (options) => {
56
59
  const { checkManagedFiles } = await import('./monorepo/index.js');
57
- checkManagedFiles(await findRepoRoot());
60
+ checkManagedFiles(await findRepoRoot(), { warn: options.warn });
58
61
  });
59
62
  monorepo.command('diff').action(async () => {
60
63
  const { diffManagedFiles } = await import('./monorepo/index.js');
@@ -69,10 +72,15 @@ function buildProgram() {
69
72
  });
70
73
  monorepo
71
74
  .command('sync-bun-lockfile-versions')
72
- .option('--stage', 'stage bun.lock when versions were resynced (pre-commit self-heal); quiet when clean')
75
+ .option('--stage', 'stage bun.lock when versions were resynced; quiet when clean')
76
+ .option('--mode <mode>', 'install: match package.json (CI); publish: map unpublished -next to last stable tag (pre-pack)', 'publish')
73
77
  .action(async (options) => {
74
78
  const { syncBunLockfileVersions } = await import('./monorepo/index.js');
75
- syncBunLockfileVersions(await findRepoRoot(), options.stage ? { log: false, stage: true } : {});
79
+ const mode = options.mode === 'install' ? 'install' : 'publish';
80
+ syncBunLockfileVersions(await findRepoRoot(), {
81
+ mode,
82
+ ...(options.stage ? { log: false, stage: true } : {}),
83
+ });
76
84
  });
77
85
  monorepo
78
86
  .command('list-release-packages')
@@ -125,10 +133,25 @@ function buildProgram() {
125
133
  .command('repair-pending')
126
134
  .description('Repair incomplete older release commits before releasing the current HEAD')
127
135
  .option('--dry-run [dryRun]', 'run without pushing, publishing, or writing GitHub Releases')
136
+ .option('--ref <ref>', 'fixed release graph ref to inspect')
137
+ .option('--platform-outputs <path>', 'cross-platform repair outputs grouped by release SHA')
128
138
  .action(async (options) => {
139
+ // The source self-hosting shim has no Typia transform; release commands import transformed output validators.
129
140
  const { releaseRepairPending } = await import('./release/index.js');
130
141
  await releaseRepairPending(await findRepoRoot(), { ...options, dryRun: booleanOption(options.dryRun) });
131
142
  });
143
+ release
144
+ .command('build-platform-outputs')
145
+ .description('Build selected current and pending-release platform outputs')
146
+ .requiredOption('--bump <bump>', 'auto, patch, minor, major, or prerelease')
147
+ .requiredOption('--targets <targets>', 'comma-separated Nx platform target names or globs')
148
+ .requiredOption('--output <path>', 'output directory for current and repair artifacts')
149
+ .option('--ref <ref>', 'fixed release graph ref to inspect')
150
+ .action(async (options) => {
151
+ // The source self-hosting shim has no Typia transform; release commands import transformed output validators.
152
+ const { releaseCollectPlatformOutputs } = await import('./release/index.js');
153
+ await releaseCollectPlatformOutputs(await findRepoRoot(), options);
154
+ });
132
155
  release
133
156
  .command('version')
134
157
  .option('--bump <bump>', 'auto, patch, minor, major, or prerelease', 'auto')
@@ -268,10 +291,19 @@ function buildProgram() {
268
291
  .requiredOption('--targets <targets>')
269
292
  .option('--projects <projects>')
270
293
  .option('--configuration <configuration>')
294
+ .option('--collect-outputs <directory>')
271
295
  .action(async (options) => {
272
296
  const { githubCiNxRunMany } = await import('./github-ci/index.js');
273
297
  await githubCiNxRunMany(await findRepoRoot(), options);
274
298
  });
299
+ githubCi
300
+ .command('apply-outputs <directories...>')
301
+ .requiredOption('--source-sha <sha>', 'expected source commit SHA')
302
+ .action(async (directories, options) => {
303
+ // GitHub CI commands stay lazy so source self-hosting can initialize Typia only at manifest boundaries.
304
+ const { githubCiApplyOutputs } = await import('./github-ci/index.js');
305
+ await githubCiApplyOutputs(await findRepoRoot(), directories, options.sourceSha);
306
+ });
275
307
  githubCi
276
308
  .command('nx-deploy')
277
309
  .requiredOption('--configuration <configuration>')
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generate/index.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACjC,sDAAsD;IACtD,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACpC;AAED,UAAU,aAAa;IACrB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAkBpD,CAAC;AAMF,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAyBf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generate/index.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACjC,sDAAsD;IACtD,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACpC;AAED,UAAU,aAAa;IACrB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAYpD,CAAC;AAMF,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -7,12 +7,6 @@ export const variants = {
7
7
  args: (name) => ['--name', name, '--variant', 'ts-lib'],
8
8
  options: [{ flag: '--public', description: 'configure for npm publication' }],
9
9
  },
10
- 'ts-zig': {
11
- generator: 'create-package',
12
- description: 'Create a TypeScript + Zig/WASM hybrid package',
13
- args: (name) => ['--name', name, '--variant', 'ts-zig'],
14
- options: [{ flag: '--public', description: 'configure for npm publication' }],
15
- },
16
10
  'make-public': {
17
11
  generator: 'make-public',
18
12
  description: 'Promote a private package to npm publication',
@@ -1,5 +1,8 @@
1
+ import { type ProjectTargets } from '../nx/index.js';
2
+ import type { NxTargetRun } from './outputs.js';
1
3
  type NxSmartMode = 'auto' | 'affected' | 'run-many';
2
4
  export declare function cleanupGithubCiCache(root: string): Promise<void>;
5
+ export declare function nxSmartArgs(target: string, mode: 'affected' | 'run-many', configuration?: string): string[];
3
6
  export declare function githubCiNxSmart(root: string, options: {
4
7
  target: string;
5
8
  name?: string;
@@ -7,11 +10,23 @@ export declare function githubCiNxSmart(root: string, options: {
7
10
  mode?: NxSmartMode;
8
11
  configuration?: string;
9
12
  }): Promise<void>;
10
- export declare function githubCiNxRunMany(root: string, options: {
13
+ export interface NxRunManyOptions {
11
14
  targets: string;
12
15
  projects?: string;
13
16
  configuration?: string;
14
- }): Promise<void>;
17
+ collectOutputs?: string;
18
+ allowEmptyProjects?: boolean;
19
+ }
20
+ export interface ExpandedNxTargetRuns {
21
+ runs: NxTargetRun[];
22
+ unmatchedGlobs: string[];
23
+ }
24
+ export declare function expandNxTargetRuns(projects: ProjectTargets[], options: NxRunManyOptions): ExpandedNxTargetRuns;
25
+ export declare function expandNxTargetDependencyRuns(runs: NxTargetRun[]): NxTargetRun[];
26
+ export declare function nxRunManyArgs(run: NxTargetRun, configuration?: string): string[];
27
+ export declare function readGitHeadSha(root: string): Promise<string>;
28
+ export declare function githubCiNxRunMany(root: string, options: NxRunManyOptions): Promise<void>;
29
+ export declare function githubCiApplyOutputs(root: string, directories: string[], expectedSourceSha: string): Promise<void>;
15
30
  export declare function githubCiNxDeploy(root: string, options: {
16
31
  configuration: string;
17
32
  mode?: NxSmartMode;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"AAMA,KAAK,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtE;AAmFD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACpG,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACrG,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,gBAAgB,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAmBhD,KAAK,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpD,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBtE;AAmFD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAO3G;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACpG,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,oBAAoB,CAiC9G;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAwC/E;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAehF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGlE;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9F;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CAGf;AAgCD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACrG,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -1,8 +1,30 @@
1
- import { existsSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from 'node:fs';
2
2
  import { appendFile, mkdtemp, realpath, rename, rm } from 'node:fs/promises';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { $ } from 'bun';
5
+ import typia from 'typia';
6
+ import { parseStringArrayText } from '../lib/json.js';
5
7
  import { decode, run, runStatus } from '../lib/run.js';
8
+ import { readProjectTargets } from '../nx/index.js';
9
+ const parseGithubActionsEvent = (() => {
10
+ const _io0 = input => undefined === input.repository || "object" === typeof input.repository && null !== input.repository && false === Array.isArray(input.repository) && _io1(input.repository);
11
+ const _io1 = input => undefined === input.default_branch || "string" === typeof input.default_branch;
12
+ const __is = input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
13
+ return input => { input = JSON.parse(input); return __is(input) ? input : null; };
14
+ })();
15
+ const parseNxProjectDeployConfigurations = (() => {
16
+ const _io0 = input => undefined === input.targets || "object" === typeof input.targets && null !== input.targets && false === Array.isArray(input.targets) && _io1(input.targets);
17
+ const _io1 = input => undefined === input.deploy || "object" === typeof input.deploy && null !== input.deploy && false === Array.isArray(input.deploy) && _io2(input.deploy);
18
+ const _io2 = input => undefined === input.configurations || "object" === typeof input.configurations && null !== input.configurations && false === Array.isArray(input.configurations) && _io3(input.configurations);
19
+ const _io3 = input => Object.keys(input).every(key => {
20
+ const value = input[key];
21
+ if (undefined === value)
22
+ return true;
23
+ return true;
24
+ });
25
+ const __is = input => "object" === typeof input && null !== input && false === Array.isArray(input) && _io0(input);
26
+ return input => { input = JSON.parse(input); return __is(input) ? input : null; };
27
+ })();
6
28
  export async function cleanupGithubCiCache(root) {
7
29
  const githubOutput = process.env.GITHUB_OUTPUT;
8
30
  const markCacheReady = async (ready) => {
@@ -100,31 +122,160 @@ async function addReferencesFrom(roots, path, cwd) {
100
122
  }
101
123
  }
102
124
  }
125
+ export function nxSmartArgs(target, mode, configuration) {
126
+ const args = [mode, '-t', target];
127
+ if (configuration) {
128
+ args.push(`--configuration=${configuration}`);
129
+ }
130
+ args.push(`--exclude=tag:ci:skip:${target}`, '--parallel=5');
131
+ return args;
132
+ }
103
133
  export async function githubCiNxSmart(root, options) {
104
134
  const name = options.name ?? options.target;
105
135
  const step = options.step ?? '';
106
136
  await createGithubStatus(name, step);
107
137
  const mode = resolveNxSmartMode(options.mode ?? 'auto');
108
- const nxArgs = mode === 'run-many' ? ['run-many', '-t', options.target] : ['affected', '-t', options.target];
109
- if (options.configuration) {
110
- nxArgs.push(`--configuration=${options.configuration}`);
111
- }
112
- nxArgs.push('--parallel=5');
138
+ const nxArgs = nxSmartArgs(options.target, mode, options.configuration);
113
139
  const status = await runStatus('nx', nxArgs, root);
114
140
  await updateGithubStatus(name, status === 0 ? 'success' : 'failure', step);
115
141
  if (status !== 0) {
116
142
  throw new Error(`nx ${nxArgs.join(' ')} failed with exit code ${status}`);
117
143
  }
118
144
  }
145
+ export function expandNxTargetRuns(projects, options) {
146
+ const selectedProjects = selectProjects(projects, options.projects);
147
+ if (options.projects !== undefined && selectedProjects.length === 0 && options.allowEmptyProjects !== true) {
148
+ throw new Error(`No Nx projects matched --projects ${options.projects}.`);
149
+ }
150
+ const selectedTargetNames = [...new Set(selectedProjects.flatMap((project) => project.targets))].sort((a, b) => a.localeCompare(b));
151
+ const runs = [];
152
+ const unmatchedGlobs = [];
153
+ const addedTargets = new Set();
154
+ for (const targetPattern of commaSeparatedValues(options.targets)) {
155
+ const isGlob = isGlobPattern(targetPattern);
156
+ const targets = isGlob
157
+ ? selectedTargetNames.filter((target) => new Bun.Glob(targetPattern).match(target))
158
+ : [targetPattern];
159
+ if (isGlob && targets.length === 0) {
160
+ unmatchedGlobs.push(targetPattern);
161
+ }
162
+ for (const target of targets) {
163
+ if (addedTargets.has(target)) {
164
+ continue;
165
+ }
166
+ const owners = selectedProjects.filter((project) => project.targets.includes(target));
167
+ const runProjects = owners.length > 0 ? owners : selectedProjects;
168
+ if (runProjects.length === 0) {
169
+ continue;
170
+ }
171
+ addedTargets.add(target);
172
+ runs.push({ target, projects: runProjects });
173
+ }
174
+ }
175
+ return { runs, unmatchedGlobs };
176
+ }
177
+ export function expandNxTargetDependencyRuns(runs) {
178
+ const expanded = [];
179
+ const added = new Set();
180
+ const visiting = new Set();
181
+ const visit = (project, target) => {
182
+ const key = `${project.project}:${target}`;
183
+ if (added.has(key)) {
184
+ return;
185
+ }
186
+ if (visiting.has(key)) {
187
+ throw new Error(`Nx target dependency cycle detected at ${key}.`);
188
+ }
189
+ visiting.add(key);
190
+ for (const dependency of project.targetDependencies?.get(target) ?? []) {
191
+ if (dependency.startsWith('^')) {
192
+ continue;
193
+ }
194
+ const dependencyTargets = isGlobPattern(dependency)
195
+ ? project.targets.filter((candidate) => new Bun.Glob(dependency).match(candidate))
196
+ : project.targets.includes(dependency)
197
+ ? [dependency]
198
+ : [];
199
+ for (const dependencyTarget of dependencyTargets.sort((left, right) => left.localeCompare(right))) {
200
+ visit(project, dependencyTarget);
201
+ }
202
+ }
203
+ visiting.delete(key);
204
+ added.add(key);
205
+ if ((project.targetOutputs?.get(target)?.length ?? 0) > 0) {
206
+ expanded.push({ target, projects: [project] });
207
+ }
208
+ };
209
+ for (const run of runs) {
210
+ for (const project of run.projects) {
211
+ visit(project, run.target);
212
+ }
213
+ }
214
+ return expanded;
215
+ }
216
+ export function nxRunManyArgs(run, configuration) {
217
+ if (run.projects.length === 0) {
218
+ throw new Error(`Nx target ${run.target} has no selected projects.`);
219
+ }
220
+ const nxArgs = [
221
+ 'run-many',
222
+ '-t',
223
+ run.target,
224
+ `--projects=${run.projects.map((project) => project.project).join(',')}`,
225
+ ];
226
+ if (configuration) {
227
+ nxArgs.push(`--configuration=${configuration}`);
228
+ }
229
+ nxArgs.push('--parallel=5');
230
+ return nxArgs;
231
+ }
232
+ export async function readGitHeadSha(root) {
233
+ // invariant throw: GitHub CI commands require a valid repository root.
234
+ return decode((await $ `git rev-parse HEAD`.cwd(root).quiet()).stdout).trim();
235
+ }
119
236
  export async function githubCiNxRunMany(root, options) {
120
- const nxArgs = ['run-many', '-t', options.targets, '--parallel=5'];
121
- if (options.projects) {
122
- nxArgs.push(`--projects=${options.projects}`);
237
+ const expanded = expandNxTargetRuns(await readProjectTargets(root), options);
238
+ if (expanded.unmatchedGlobs.length > 0) {
239
+ console.log(`No Nx targets matched target glob(s): ${expanded.unmatchedGlobs.join(', ')}; skipping.`);
240
+ }
241
+ for (const targetRun of expanded.runs) {
242
+ await run('nx', nxRunManyArgs(targetRun, options.configuration), root);
243
+ }
244
+ if (options.collectOutputs) {
245
+ const { collectNxOutputs } = await loadOutputBoundary();
246
+ const sourceSha = await readGitHeadSha(root);
247
+ await collectNxOutputs(root, options.collectOutputs, expandNxTargetDependencyRuns(expanded.runs), sourceSha);
123
248
  }
124
- if (options.configuration) {
125
- nxArgs.push(`--configuration=${options.configuration}`);
249
+ }
250
+ export async function githubCiApplyOutputs(root, directories, expectedSourceSha) {
251
+ const { applyCollectedOutputs } = await loadOutputBoundary();
252
+ await applyCollectedOutputs(root, directories, expectedSourceSha);
253
+ }
254
+ async function loadOutputBoundary() {
255
+ if (import.meta.url.endsWith('/src/github-ci/index.ts')) {
256
+ // The source self-hosting shim has no Typia transform; register it before loading manifest validators.
257
+ await import('@smoothbricks/cli/bun/preload');
258
+ }
259
+ // This boundary must stay lazy because the transformed dist and source self-hosting paths initialize Typia differently.
260
+ return import('./outputs.js');
261
+ }
262
+ function isGlobPattern(value) {
263
+ return /[*?{[]/.test(value);
264
+ }
265
+ function selectProjects(projects, selectors) {
266
+ if (selectors === undefined) {
267
+ return projects.slice().sort((left, right) => left.project.localeCompare(right.project));
126
268
  }
127
- await run('nx', nxArgs, root);
269
+ const patterns = commaSeparatedValues(selectors);
270
+ return projects
271
+ .filter((project) => patterns.some((pattern) => new Bun.Glob(pattern).match(project.project)))
272
+ .sort((left, right) => left.project.localeCompare(right.project));
273
+ }
274
+ function commaSeparatedValues(value) {
275
+ return value
276
+ .split(',')
277
+ .map((entry) => entry.trim())
278
+ .filter(Boolean);
128
279
  }
129
280
  export async function githubCiNxDeploy(root, options) {
130
281
  const name = options.name ?? `Deploy ${options.configuration}`;
@@ -156,7 +307,32 @@ function resolveNxSmartMode(mode) {
156
307
  if (mode === 'affected' || mode === 'run-many') {
157
308
  return mode;
158
309
  }
159
- return process.env.GITHUB_EVENT_NAME === 'push' && process.env.GITHUB_REF_NAME === 'main' ? 'run-many' : 'affected';
310
+ const defaultBranch = eventDefaultBranch() ?? 'main';
311
+ if (process.env.GITHUB_EVENT_NAME === 'push') {
312
+ return process.env.GITHUB_REF_NAME === defaultBranch ? 'run-many' : 'affected';
313
+ }
314
+ // A PR into a NON-default branch is an integration surface (e.g. a mirror-sync
315
+ // review branch): its base moves outside the default-branch workflow that
316
+ // affected scoping is calibrated against, so under-selection can pass PR CI
317
+ // and only fail after merge. Validate those PRs in full.
318
+ if (process.env.GITHUB_EVENT_NAME === 'pull_request') {
319
+ const base = process.env.GITHUB_BASE_REF;
320
+ return base && base !== defaultBranch ? 'run-many' : 'affected';
321
+ }
322
+ return 'affected';
323
+ }
324
+ /** The repository default branch from the Actions event payload. */
325
+ function eventDefaultBranch() {
326
+ const eventPath = process.env.GITHUB_EVENT_PATH;
327
+ if (!eventPath)
328
+ return undefined;
329
+ try {
330
+ const payload = parseGithubActionsEvent(readFileSync(eventPath, 'utf8'));
331
+ return payload?.repository?.default_branch || undefined;
332
+ }
333
+ catch {
334
+ return undefined;
335
+ }
160
336
  }
161
337
  async function deployProjectsWithConfiguration(root, configuration, mode) {
162
338
  const listArgs = mode === 'affected'
@@ -174,21 +350,11 @@ async function deployProjectsWithConfiguration(root, configuration, mode) {
174
350
  }
175
351
  async function deployTargetHasConfiguration(root, project, configuration) {
176
352
  const result = await $ `nx show project ${project} --json`.cwd(root).quiet();
177
- const parsed = JSON.parse(decode(result.stdout));
178
- const targets = recordValue(parsed)?.targets;
179
- const deploy = recordValue(targets)?.deploy;
180
- const configurations = recordValue(deploy)?.configurations;
181
- return recordValue(configurations)?.[configuration] !== undefined;
353
+ const parsed = parseNxProjectDeployConfigurations(decode(result.stdout));
354
+ return parsed?.targets?.deploy?.configurations?.[configuration] !== undefined;
182
355
  }
183
356
  function nxProjectList(output) {
184
- const parsed = JSON.parse(output);
185
- return Array.isArray(parsed) ? parsed.filter((project) => typeof project === 'string') : [];
186
- }
187
- function recordValue(value) {
188
- return isRecord(value) ? value : undefined;
189
- }
190
- function isRecord(value) {
191
- return value !== null && typeof value === 'object' && !Array.isArray(value);
357
+ return parseStringArrayText(output) ?? [];
192
358
  }
193
359
  async function createGithubStatus(name, step) {
194
360
  await postGithubStatus(name, 'pending', `Running ${name}...`, step);
@@ -0,0 +1,22 @@
1
+ import { type ProjectTargets } from '../nx/index.js';
2
+ export interface CollectedOutputFile {
3
+ project: string;
4
+ target: string;
5
+ output: string;
6
+ path: string;
7
+ size: number;
8
+ sha256: string;
9
+ }
10
+ export interface CollectedOutputsManifest {
11
+ version: 1;
12
+ sourceSha: string;
13
+ files: CollectedOutputFile[];
14
+ }
15
+ export interface NxTargetRun {
16
+ target: string;
17
+ projects: ProjectTargets[];
18
+ }
19
+ export declare function collectNxOutputs(root: string, destination: string, runs: NxTargetRun[], sourceSha: string): Promise<CollectedOutputsManifest>;
20
+ export declare function applyCollectedOutputs(root: string, directories: string[], expectedSourceSha: string, projects?: ProjectTargets[]): Promise<void>;
21
+ export declare function resolveDeclaredOutput(declaredOutput: string, project: ProjectTargets): string;
22
+ //# sourceMappingURL=outputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputs.d.ts","sourceRoot":"","sources":["../../src/github-ci/outputs.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,gBAAgB,CAAC;AAEzE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAWD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,WAAW,EAAE,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,wBAAwB,CAAC,CAgEnC;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,iBAAiB,EAAE,MAAM,EACzB,QAAQ,CAAC,EAAE,cAAc,EAAE,GAC1B,OAAO,CAAC,IAAI,CAAC,CAqGf;AAED,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAa7F"}