create-next-hydra 0.3.0 → 0.4.1

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 (207) hide show
  1. package/README.md +126 -27
  2. package/dist/add-command.d.ts +11 -0
  3. package/dist/add-command.d.ts.map +1 -0
  4. package/dist/add-command.js +75 -0
  5. package/dist/addition.d.ts +67 -0
  6. package/dist/addition.d.ts.map +1 -0
  7. package/dist/addition.js +422 -0
  8. package/dist/application-git.d.ts +20 -0
  9. package/dist/application-git.d.ts.map +1 -0
  10. package/dist/application-git.js +57 -0
  11. package/dist/baseline.d.ts +22 -0
  12. package/dist/baseline.d.ts.map +1 -0
  13. package/dist/baseline.js +90 -0
  14. package/dist/cli.js +5 -18
  15. package/dist/commands.d.ts +22 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +197 -0
  18. package/dist/composition-lint.d.ts +20 -0
  19. package/dist/composition-lint.d.ts.map +1 -0
  20. package/dist/composition-lint.js +288 -0
  21. package/dist/composition.d.ts +24 -0
  22. package/dist/composition.d.ts.map +1 -0
  23. package/dist/composition.js +420 -0
  24. package/dist/create-command.d.ts +21 -0
  25. package/dist/create-command.d.ts.map +1 -0
  26. package/dist/create-command.js +128 -0
  27. package/dist/demo-instrumentation.d.ts +5 -0
  28. package/dist/demo-instrumentation.d.ts.map +1 -0
  29. package/dist/demo-instrumentation.js +300 -0
  30. package/dist/environment.d.ts +7 -0
  31. package/dist/environment.d.ts.map +1 -0
  32. package/dist/environment.js +81 -0
  33. package/dist/errors.d.ts +156 -0
  34. package/dist/errors.d.ts.map +1 -0
  35. package/dist/errors.js +140 -0
  36. package/dist/file-policy.d.ts +6 -0
  37. package/dist/file-policy.d.ts.map +1 -0
  38. package/dist/file-policy.js +38 -0
  39. package/dist/files.d.ts +7 -0
  40. package/dist/files.d.ts.map +1 -0
  41. package/dist/files.js +66 -0
  42. package/dist/hosting.d.ts +5 -0
  43. package/dist/hosting.d.ts.map +1 -0
  44. package/dist/hosting.js +107 -0
  45. package/dist/index.d.ts +4 -6
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +17 -89
  48. package/dist/initialization.d.ts +14 -0
  49. package/dist/initialization.d.ts.map +1 -0
  50. package/dist/initialization.js +266 -0
  51. package/dist/lint-workspaces.d.ts +2 -0
  52. package/dist/lint-workspaces.d.ts.map +1 -0
  53. package/dist/lint-workspaces.js +62 -0
  54. package/dist/model.d.ts +143 -0
  55. package/dist/model.d.ts.map +1 -0
  56. package/dist/model.js +61 -0
  57. package/dist/package-catalog.d.ts +8 -0
  58. package/dist/package-catalog.d.ts.map +1 -0
  59. package/dist/package-catalog.js +61 -0
  60. package/dist/packages.d.ts +57 -0
  61. package/dist/packages.d.ts.map +1 -0
  62. package/dist/packages.js +237 -0
  63. package/dist/process-group.d.ts +5 -0
  64. package/dist/process-group.d.ts.map +1 -0
  65. package/dist/process-group.js +23 -0
  66. package/dist/reference-workspace-bindings.d.ts +38 -0
  67. package/dist/reference-workspace-bindings.d.ts.map +1 -0
  68. package/dist/reference-workspace-bindings.js +41 -0
  69. package/dist/reference-workspace.d.ts +6 -0
  70. package/dist/reference-workspace.d.ts.map +1 -0
  71. package/dist/reference-workspace.js +62 -0
  72. package/dist/registry.d.ts +187 -0
  73. package/dist/registry.d.ts.map +1 -0
  74. package/dist/registry.js +107 -0
  75. package/dist/runtime.d.ts +9 -0
  76. package/dist/runtime.d.ts.map +1 -0
  77. package/dist/runtime.js +22 -0
  78. package/dist/selection.d.ts +704 -0
  79. package/dist/selection.d.ts.map +1 -0
  80. package/dist/selection.js +424 -0
  81. package/dist/shadcn-protocol.d.ts +22 -0
  82. package/dist/shadcn-protocol.d.ts.map +1 -0
  83. package/dist/shadcn-protocol.js +13 -0
  84. package/dist/shadcn-worker.d.ts +2 -0
  85. package/dist/shadcn-worker.d.ts.map +1 -0
  86. package/dist/shadcn-worker.js +43 -0
  87. package/dist/shadcn.d.ts +22 -0
  88. package/dist/shadcn.d.ts.map +1 -0
  89. package/dist/shadcn.js +101 -0
  90. package/dist/source-changes.d.ts +55 -0
  91. package/dist/source-changes.d.ts.map +1 -0
  92. package/dist/source-changes.js +225 -0
  93. package/dist/source-inventory.d.ts +25 -0
  94. package/dist/source-inventory.d.ts.map +1 -0
  95. package/dist/source-inventory.js +212 -0
  96. package/dist/source-root.d.ts +4 -0
  97. package/dist/source-root.d.ts.map +1 -0
  98. package/dist/source-root.js +20 -0
  99. package/dist/staging.d.ts +19 -0
  100. package/dist/staging.d.ts.map +1 -0
  101. package/dist/staging.js +42 -0
  102. package/dist/tasks.d.ts +44 -0
  103. package/dist/tasks.d.ts.map +1 -0
  104. package/dist/tasks.js +137 -0
  105. package/dist/templates.d.ts +217 -0
  106. package/dist/templates.d.ts.map +1 -0
  107. package/dist/templates.js +161 -0
  108. package/dist/test-reference-workspace.d.ts +2 -0
  109. package/dist/test-reference-workspace.d.ts.map +1 -0
  110. package/dist/test-reference-workspace.js +6 -0
  111. package/dist/types.d.ts +2 -9
  112. package/dist/types.d.ts.map +1 -1
  113. package/dist/typescript-paths.d.ts +10 -0
  114. package/dist/typescript-paths.d.ts.map +1 -0
  115. package/dist/typescript-paths.js +52 -0
  116. package/dist/workspace-dependencies.d.ts +26 -0
  117. package/dist/workspace-dependencies.d.ts.map +1 -0
  118. package/dist/workspace-dependencies.js +478 -0
  119. package/dist/workspace-files.d.ts +24 -0
  120. package/dist/workspace-files.d.ts.map +1 -0
  121. package/dist/workspace-files.js +395 -0
  122. package/dist/workspace-lock.d.ts +12 -0
  123. package/dist/workspace-lock.d.ts.map +1 -0
  124. package/dist/workspace-lock.js +104 -0
  125. package/dist/workspace-snapshots.d.ts +24 -0
  126. package/dist/workspace-snapshots.d.ts.map +1 -0
  127. package/dist/workspace-snapshots.js +218 -0
  128. package/dist/workspace-sources.d.ts +27 -0
  129. package/dist/workspace-sources.d.ts.map +1 -0
  130. package/dist/workspace-sources.js +88 -0
  131. package/dist/workspace-state.d.ts +325 -0
  132. package/dist/workspace-state.d.ts.map +1 -0
  133. package/dist/workspace-state.js +571 -0
  134. package/dist/workspaces.d.ts +73 -0
  135. package/dist/workspaces.d.ts.map +1 -0
  136. package/dist/workspaces.js +396 -0
  137. package/package.json +25 -20
  138. package/schema/selection-definition.json +143 -4
  139. package/dist/clone.d.ts +0 -9
  140. package/dist/clone.d.ts.map +0 -1
  141. package/dist/clone.js +0 -19
  142. package/dist/composition/add.d.ts +0 -14
  143. package/dist/composition/add.d.ts.map +0 -1
  144. package/dist/composition/add.js +0 -484
  145. package/dist/composition/catalog.d.ts +0 -26
  146. package/dist/composition/catalog.d.ts.map +0 -1
  147. package/dist/composition/catalog.js +0 -317
  148. package/dist/composition/errors.d.ts +0 -5
  149. package/dist/composition/errors.d.ts.map +0 -1
  150. package/dist/composition/errors.js +0 -8
  151. package/dist/composition/format.d.ts +0 -6
  152. package/dist/composition/format.d.ts.map +0 -1
  153. package/dist/composition/format.js +0 -65
  154. package/dist/composition/install.d.ts +0 -16
  155. package/dist/composition/install.d.ts.map +0 -1
  156. package/dist/composition/install.js +0 -175
  157. package/dist/composition/packages.d.ts +0 -6
  158. package/dist/composition/packages.d.ts.map +0 -1
  159. package/dist/composition/packages.js +0 -55
  160. package/dist/composition/paths.d.ts +0 -4
  161. package/dist/composition/paths.d.ts.map +0 -1
  162. package/dist/composition/paths.js +0 -47
  163. package/dist/composition/planner.d.ts +0 -4
  164. package/dist/composition/planner.d.ts.map +0 -1
  165. package/dist/composition/planner.js +0 -366
  166. package/dist/composition/schema.d.ts +0 -294
  167. package/dist/composition/schema.d.ts.map +0 -1
  168. package/dist/composition/schema.js +0 -166
  169. package/dist/composition/types.d.ts +0 -111
  170. package/dist/composition/types.d.ts.map +0 -1
  171. package/dist/composition/types.js +0 -6
  172. package/dist/composition/typescript-paths.d.ts +0 -6
  173. package/dist/composition/typescript-paths.d.ts.map +0 -1
  174. package/dist/composition/typescript-paths.js +0 -157
  175. package/dist/composition/use.d.ts +0 -23
  176. package/dist/composition/use.d.ts.map +0 -1
  177. package/dist/composition/use.js +0 -187
  178. package/dist/composition/workspace.d.ts +0 -10
  179. package/dist/composition/workspace.d.ts.map +0 -1
  180. package/dist/composition/workspace.js +0 -210
  181. package/dist/constants.d.ts +0 -11
  182. package/dist/constants.d.ts.map +0 -1
  183. package/dist/constants.js +0 -39
  184. package/dist/fs-utils.d.ts +0 -9
  185. package/dist/fs-utils.d.ts.map +0 -1
  186. package/dist/fs-utils.js +0 -64
  187. package/dist/git.d.ts +0 -28
  188. package/dist/git.d.ts.map +0 -1
  189. package/dist/git.js +0 -107
  190. package/dist/instruction-renderer.d.ts +0 -17
  191. package/dist/instruction-renderer.d.ts.map +0 -1
  192. package/dist/instruction-renderer.js +0 -132
  193. package/dist/logger.d.ts +0 -13
  194. package/dist/logger.d.ts.map +0 -1
  195. package/dist/logger.js +0 -26
  196. package/dist/prompts.d.ts +0 -7
  197. package/dist/prompts.d.ts.map +0 -1
  198. package/dist/prompts.js +0 -54
  199. package/dist/sanitize.d.ts +0 -10
  200. package/dist/sanitize.d.ts.map +0 -1
  201. package/dist/sanitize.js +0 -110
  202. package/dist/scaffold.d.ts +0 -7
  203. package/dist/scaffold.d.ts.map +0 -1
  204. package/dist/scaffold.js +0 -330
  205. package/dist/version.d.ts +0 -2
  206. package/dist/version.d.ts.map +0 -1
  207. package/dist/version.js +0 -2
@@ -0,0 +1,22 @@
1
+ import { Effect, Option, Path, Stdio } from "effect";
2
+ import { Command, Prompt } from "effect/unstable/cli";
3
+ import { InvalidComposition, WorkspaceBatchFailed, WorkspaceNotCurrent } from "./errors.ts";
4
+ import { Workspaces } from "./workspaces.ts";
5
+ export declare function command(cwd: string): Command.Command<"create-next-hydra", {} | {
6
+ readonly addOns: readonly string[];
7
+ readonly auth: Option.Option<string>;
8
+ readonly cms: Option.Option<string>;
9
+ readonly commerce: Option.Option<string>;
10
+ readonly search: Option.Option<string>;
11
+ readonly commit: boolean;
12
+ readonly directory: Option.Option<string>;
13
+ readonly preset: Option.Option<string>;
14
+ readonly ref: Option.Option<string>;
15
+ readonly repository: string;
16
+ readonly skipGit: boolean;
17
+ readonly verbose: boolean;
18
+ readonly without: readonly ("search" | "auth" | "cms" | "commerce")[];
19
+ readonly yes: boolean;
20
+ }, {}, import("./errors.ts").DestinationNotEmpty | import("./errors.ts").MaterializationFailed | import("./errors.ts").EnvironmentInitializationFailed | import("./errors.ts").WorkspaceBusy | import("./errors.ts").WorkspaceLockAuthorizationRequired | import("./errors.ts").WorkspaceLockChanged | import("./errors.ts").WorkspaceConflict | import("./errors.ts").WorkspaceRecoveryRequired | import("./errors.ts").WorkspaceStateInvalid | WorkspaceNotCurrent | WorkspaceBatchFailed | import("./errors.ts").SnapshotUnavailable | import("./errors.ts").WorkspaceUninitialized | import("./errors.ts").SnapshotFailed | import("./errors.ts").DependencyInstallationFailed | import("./addition.ts").AdditionChanged | import("./addition.ts").AdditionConflict | import("./addition.ts").AdditionFailed | import("./application-git.ts").ApplicationGitFailed | import("./source-changes.ts").SourceWatchFailure | (import("./errors.ts").IncompatibleSelection | InvalidComposition | import("./errors.ts").SourceChanged | import("./errors.ts").SourceAcquisitionFailed | import("./errors.ts").SourceStorageRetained | import("./errors.ts").RegistryFailure | import("./errors.ts").StagingRetained | import("./errors.ts").RegistryWorkerFailure | import("effect/Schema").SchemaError | import("effect/PlatformError").PlatformError) | import("effect/Terminal").QuitError, Workspaces | Stdio.Stdio | Prompt.Environment>;
21
+ export declare const runCommand: (sourceRoot: string, args: readonly string[], version: string) => Effect.Effect<void, import("./errors.ts").DestinationNotEmpty | import("./errors.ts").MaterializationFailed | import("./errors.ts").EnvironmentInitializationFailed | import("./errors.ts").WorkspaceBusy | import("./errors.ts").WorkspaceLockAuthorizationRequired | import("./errors.ts").WorkspaceLockChanged | import("./errors.ts").WorkspaceConflict | import("./errors.ts").WorkspaceRecoveryRequired | import("./errors.ts").WorkspaceStateInvalid | WorkspaceNotCurrent | WorkspaceBatchFailed | import("./errors.ts").SnapshotUnavailable | import("./errors.ts").WorkspaceUninitialized | import("./errors.ts").SnapshotFailed | import("./errors.ts").DependencyInstallationFailed | import("./addition.ts").AdditionChanged | import("./addition.ts").AdditionConflict | import("./addition.ts").AdditionFailed | import("./application-git.ts").ApplicationGitFailed | import("./source-changes.ts").SourceWatchFailure | (import("./errors.ts").IncompatibleSelection | InvalidComposition | import("./errors.ts").SourceChanged | import("./errors.ts").SourceAcquisitionFailed | import("./errors.ts").SourceStorageRetained | import("./errors.ts").RegistryFailure | import("./errors.ts").StagingRetained | import("./errors.ts").RegistryWorkerFailure | import("effect/Schema").SchemaError | import("effect/PlatformError").PlatformError) | import("effect/unstable/cli/CliError").CliError, import("effect/FileSystem").FileSystem | Path.Path | import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | Workspaces | import("effect/Terminal").Terminal | Stdio.Stdio>;
22
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAS,MAAM,EAAE,IAAI,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAC7E,OAAO,EAAY,OAAO,EAAQ,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAItE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAkE7C,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM;;;;;;;;;;;;;;;42CA2PlC;AAED,eAAO,MAAM,UAAU,GACrB,YAAY,MAAM,EAClB,MAAM,SAAS,MAAM,EAAE,EACvB,SAAS,MAAM,0hDAoBhB,CAAC"}
@@ -0,0 +1,197 @@
1
+ import { Console, Effect, Match, Option, Path, Stdio, Stream } from "effect";
2
+ import { Argument, Command, Flag, Prompt } from "effect/unstable/cli";
3
+ import { addCommand } from "./add-command.js";
4
+ import { createCommand } from "./create-command.js";
5
+ import { InvalidComposition, WorkspaceBatchFailed, WorkspaceNotCurrent, } from "./errors.js";
6
+ import { findSourceRoot } from "./source-root.js";
7
+ import { Workspaces } from "./workspaces.js";
8
+ function explainFile(file, sourceRoot, path) {
9
+ const explanation = Match.value(file.origin).pipe(Match.discriminator("kind")("registry", (origin) => `${file.target}\n published registry artifact: ${origin.owner}`), Match.discriminator("kind")("workspace-setting", (origin) => `${file.target}\n workspace setting: ${path.join(sourceRoot, origin.source)}`), Match.discriminator("kind")("source", (origin) => `${file.target}\n source: ${path.join(sourceRoot, origin.source)}${origin.owner === null ? "" : ` (${origin.owner})`}`), Match.discriminator("kind")("template", (origin) => [
10
+ `${file.target}\n template: ${path.join(sourceRoot, origin.source)} (${origin.owner})`,
11
+ ...origin.bindings.map((binding) => ` ${binding.slot}: ${binding.module}#${binding.export}${binding.as ? ` as ${binding.as}` : ""} (${binding.owner})`),
12
+ ].join("\n")), Match.discriminator("kind")("policy", (origin) => [
13
+ `${file.target}\n composition policy: ${origin.policy}`,
14
+ ...origin.sources.map((source) => ` input: ${path.join(sourceRoot, source)}`),
15
+ ].join("\n")), Match.exhaustive);
16
+ const transformations = "transforms" in file.origin ? (file.origin.transforms ?? []) : [];
17
+ return [
18
+ explanation,
19
+ ...transformations.map((transform) => ` transform: ${transform}`),
20
+ ].join("\n");
21
+ }
22
+ function synchronizationResult(name, result) {
23
+ return [
24
+ result.recoveryEvidence
25
+ ? `Broke the authorized lock; retained evidence at ${result.recoveryEvidence}.`
26
+ : null,
27
+ `${name}: materialized ${result.files.length} files; removed ${result.removedFiles.length} files; copied ${result.environmentFilesCreated.length} environment files. Dependencies ${result.dependencies}.${result.dependencyReasons.length ? ` ${result.dependencyReasons.join("; ")}.` : ""}`,
28
+ ...result.instructions.map(({ item, text }) => `${item}:\n${text}`),
29
+ ]
30
+ .filter((line) => line !== null)
31
+ .join("\n");
32
+ }
33
+ export function command(cwd) {
34
+ return createCommand(cwd).pipe(Command.withSubcommands([
35
+ addCommand(cwd),
36
+ Command.make("compose", {
37
+ all: Flag.Boolean("all").pipe(Flag.withDefault(false), Flag.withDescription("Select all Git-visible workspace definitions under workspaces/.")),
38
+ check: Flag.Boolean("check").pipe(Flag.withDefault(false), Flag.withDescription("Check composed files without changing the workspace or checking installed dependencies.")),
39
+ copyEnv: Flag.Boolean("copy-env").pipe(Flag.withDefault(false), Flag.withDescription("Copy missing ignored environment files from local source without replacing existing values.")),
40
+ diff: Flag.Boolean("diff").pipe(Flag.withDefault(false), Flag.withDescription("Show local changes against the saved composition snapshot without updating.")),
41
+ explain: Flag.Boolean("explain").pipe(Flag.withDefault(false), Flag.withDescription("Locate canonical sources and templates without changing the workspace.")),
42
+ install: Flag.Boolean("install").pipe(Flag.withDefault(true)),
43
+ name: Argument.String("name").pipe(Argument.optional),
44
+ offline: Flag.Boolean("offline").pipe(Flag.withDefault(false)),
45
+ target: Argument.String("file").pipe(Argument.optional, Argument.withDescription("Workspace-relative file to locate with --explain; omit to list all selected files.")),
46
+ watch: Flag.Boolean("watch").pipe(Flag.withDefault(false), Flag.withDescription("Keep the workspace synchronized with canonical source changes. Run development tasks separately.")),
47
+ }, ({ name: nameOption, all, install, copyEnv, offline, explain, target, check, diff, watch, }) => Effect.gen(function* () {
48
+ const requestedName = all && explain ? Option.none() : nameOption;
49
+ const explainTarget = all && explain ? nameOption : target;
50
+ if (all && Option.isSome(target)) {
51
+ return yield* new InvalidComposition({
52
+ message: "Provide at most one file with --all --explain",
53
+ });
54
+ }
55
+ if (all === Option.isSome(requestedName)) {
56
+ return yield* new InvalidComposition({
57
+ message: "Choose one workspace name or --all",
58
+ });
59
+ }
60
+ if ([check, explain, diff, watch].filter(Boolean).length > 1) {
61
+ return yield* new InvalidComposition({
62
+ message: "Choose one of --check, --explain, --diff or --watch",
63
+ });
64
+ }
65
+ if ((explain || diff) && copyEnv) {
66
+ return yield* new InvalidComposition({
67
+ message: "--explain and --diff are read-only; do not combine them with --copy-env.",
68
+ });
69
+ }
70
+ if (!explain && Option.isSome(target)) {
71
+ return yield* new InvalidComposition({
72
+ message: "A file argument requires --explain",
73
+ });
74
+ }
75
+ const workspaces = yield* Workspaces;
76
+ const sourceRoot = yield* findSourceRoot(cwd);
77
+ const references = Option.isSome(requestedName)
78
+ ? [{ name: requestedName.value, sourceRoot }]
79
+ : yield* workspaces.discover(sourceRoot);
80
+ if (references.length === 0) {
81
+ return yield* new InvalidComposition({
82
+ message: "No named workspace definitions found in workspaces/*/next-hydra.json",
83
+ });
84
+ }
85
+ const options = {
86
+ environment: copyEnv ? "copy-missing-local" : "preserve",
87
+ install: install ? "install" : "skip",
88
+ offline,
89
+ };
90
+ if (watch) {
91
+ return yield* Stream.mergeAll(references.map((reference) => Stream.unwrap(workspaces
92
+ .named(reference)
93
+ .pipe(Effect.map((workspace) => workspace.watch(options)))).pipe(Stream.map((event) => ({ event, name: reference.name })))), { concurrency: "unbounded" }).pipe(Stream.runForEach(({ event, name: workspaceName }) => event._tag === "Synchronized"
94
+ ? Console.log(synchronizationResult(workspaceName, event.result))
95
+ : Console.error(`${workspaceName}: ${event.error.message}`)));
96
+ }
97
+ const run = Effect.fn("Compose.run")(function* (reference) {
98
+ const { name } = reference;
99
+ const workspace = yield* workspaces.named(reference);
100
+ if (diff) {
101
+ const report = yield* workspace.diff;
102
+ const path = yield* Path.Path;
103
+ yield* Console.log([
104
+ `${name}: changes against saved composition ${report.snapshot}.`,
105
+ ...(report.incomplete
106
+ ? [
107
+ "Synchronization is incomplete; this patch may include tool-applied changes.",
108
+ ]
109
+ : []),
110
+ ...report.conflicts.map((file) => `conflict: ${file}`),
111
+ ...report.unregisteredFiles.map((file) => `unregistered: ${file}`),
112
+ ...(report.origins.length === 0
113
+ ? []
114
+ : [
115
+ "Sources recorded with the saved composition:",
116
+ ...report.origins.map((file) => explainFile(file, reference.sourceRoot, path)),
117
+ ]),
118
+ report.patch || "No owned-file changes.",
119
+ ].join("\n"));
120
+ return;
121
+ }
122
+ if (check) {
123
+ const report = yield* workspace.check;
124
+ yield* Console.log([
125
+ `${name}: ${report.ready ? "current" : "needs attention"}.`,
126
+ ...(report.initialized
127
+ ? []
128
+ : ["Workspace has not been initialized."]),
129
+ ...report.changes.map((change) => `${change.kind}: ${change.target}`),
130
+ ].join("\n"));
131
+ if (!report.ready) {
132
+ return yield* new WorkspaceNotCurrent({
133
+ directory: report.destination,
134
+ });
135
+ }
136
+ return;
137
+ }
138
+ if (explain) {
139
+ const report = yield* workspace.explain(Option.getOrUndefined(explainTarget));
140
+ const path = yield* Path.Path;
141
+ yield* Console.log([
142
+ `${name}: ${report.files.length} selected source files (current definition, not applied state).`,
143
+ ...report.files.map((entry) => explainFile(entry, report.sourceRoot, path)),
144
+ ].join("\n"));
145
+ return;
146
+ }
147
+ const result = yield* workspace.sync(options).pipe(Effect.catchTag("WorkspaceLockAuthorizationRequired", (error) => Effect.gen(function* () {
148
+ const stdio = yield* Stdio.Stdio;
149
+ if (!(yield* stdio.stdinIsTerminal) ||
150
+ !(yield* stdio.stdoutIsTerminal)) {
151
+ return yield* error;
152
+ }
153
+ yield* Console.warn(`${name}: ${error.reason}. Stop other Compose commands for this workspace before continuing. Breaking the lock does not stop processes. It preserves recovery evidence and does not override local-file conflicts or incomplete state.`);
154
+ const approved = yield* Prompt.Confirm({
155
+ initial: false,
156
+ message: `Other Compose commands are stopped. Break the lock for ${name}?`,
157
+ });
158
+ if (!approved) {
159
+ return yield* error;
160
+ }
161
+ return yield* workspace.sync({
162
+ ...options,
163
+ breakLock: error.token,
164
+ });
165
+ })));
166
+ yield* Console.log(synchronizationResult(name, result));
167
+ });
168
+ if (Option.isSome(requestedName)) {
169
+ return yield* run({ name: requestedName.value, sourceRoot });
170
+ }
171
+ const [failed] = yield* Effect.partition(references, (reference) => run(reference).pipe(Effect.tapError((error) => Console.error(`${reference.name}: ${error.message}`)), Effect.mapError(() => reference.name)), { concurrency: 1 });
172
+ if (failed.length > 0) {
173
+ return yield* new WorkspaceBatchFailed({ names: failed });
174
+ }
175
+ })),
176
+ ]));
177
+ }
178
+ export const runCommand = (sourceRoot, args, version) => {
179
+ // Effect CLI has optional flags, but not optional flag values. Normalize only
180
+ // this spelling; Effect owns parsing, validation, help and every other option.
181
+ const targets = [];
182
+ let literal = false;
183
+ const normalized = args.map((arg) => {
184
+ if (arg === "--") {
185
+ literal = true;
186
+ }
187
+ if (args[0] === "compose" && !literal && arg.startsWith("--explain=")) {
188
+ targets.push(arg.slice("--explain=".length));
189
+ return "--explain";
190
+ }
191
+ return arg;
192
+ });
193
+ return Command.runWith(command(sourceRoot), { version })([
194
+ ...normalized,
195
+ ...targets,
196
+ ]);
197
+ };
@@ -0,0 +1,20 @@
1
+ import { Effect, FileSystem, Path, Schema } from "effect";
2
+ import { ChildProcessSpawner } from "effect/unstable/process";
3
+ import { ApplicationTaskFailed, InvalidComposition } from "./errors.ts";
4
+ import type { FileExplanation } from "./model.ts";
5
+ import { Shadcn } from "./shadcn.ts";
6
+ import { SourceInventory } from "./source-inventory.ts";
7
+ import { Workspaces } from "./workspaces.ts";
8
+ export type CompositionLintScope = {
9
+ readonly kind: "all";
10
+ } | {
11
+ readonly kind: "source";
12
+ } | {
13
+ readonly kind: "workspace";
14
+ readonly name: string;
15
+ };
16
+ export declare const affectedLintWorkspaces: (sourceRoot: string, changedFiles?: readonly string[] | undefined) => Effect.Effect<string[], import("./errors.ts").IncompatibleSelection | InvalidComposition | import("./errors.ts").SourceChanged | import("./errors.ts").SourceAcquisitionFailed | import("./errors.ts").SourceStorageRetained | import("./errors.ts").RegistryFailure | import("./errors.ts").StagingRetained | import("./errors.ts").RegistryWorkerFailure | Schema.SchemaError | import("effect/PlatformError").PlatformError, Workspaces>;
17
+ export declare const executeLintCommand: (cwd: string, executable: string, args: readonly string[], accepted?: readonly number[] | undefined) => Effect.Effect<string, ApplicationTaskFailed | import("effect/PlatformError").PlatformError, ChildProcessSpawner.ChildProcessSpawner>;
18
+ export declare const lintWorkspaceFiles: (root: string, executable: string, files: readonly string[], origins: readonly FileExplanation[], mode?: "typed" | "syntax" | undefined) => Effect.Effect<number, ApplicationTaskFailed | InvalidComposition | Schema.SchemaError | import("effect/PlatformError").PlatformError, Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
19
+ export declare const lintCompositions: (sourceRoot: string, requestedFiles?: readonly string[] | undefined, scope?: CompositionLintScope | undefined) => Effect.Effect<undefined, ApplicationTaskFailed | import("./errors.ts").DestinationNotEmpty | import("./errors.ts").MaterializationFailed | import("./errors.ts").EnvironmentInitializationFailed | import("./errors.ts").WorkspaceBusy | import("./errors.ts").WorkspaceLockAuthorizationRequired | import("./errors.ts").WorkspaceLockChanged | import("./errors.ts").WorkspaceConflict | import("./errors.ts").WorkspaceRecoveryRequired | import("./errors.ts").WorkspaceStateInvalid | import("./errors.ts").DependencyInstallationFailed | import("effect/PlatformError").BadArgument | import("./application-git.ts").ApplicationGitFailed | (import("./errors.ts").IncompatibleSelection | InvalidComposition | import("./errors.ts").SourceChanged | import("./errors.ts").SourceAcquisitionFailed | import("./errors.ts").SourceStorageRetained | import("./errors.ts").RegistryFailure | import("./errors.ts").StagingRetained | import("./errors.ts").RegistryWorkerFailure | Schema.SchemaError | import("effect/PlatformError").PlatformError), FileSystem.FileSystem | Path.Path | Shadcn | ChildProcessSpawner.ChildProcessSpawner | SourceInventory | Workspaces>;
20
+ //# sourceMappingURL=composition-lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composition-lint.d.ts","sourceRoot":"","sources":["../src/composition-lint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AAC3E,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE5E,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAoB1D,eAAO,MAAM,sBAAsB,mfA2DlC,CAAC;AAuBF,eAAO,MAAM,kBAAkB,8OAoC9B,CAAC;AAiBF,eAAO,MAAM,kBAAkB,wUAoD7B,CAAC;AAEH,eAAO,MAAM,gBAAgB,quCAsN3B,CAAC"}
@@ -0,0 +1,288 @@
1
+ import { Console, Effect, FileSystem, Path, Schema, Stream } from "effect";
2
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
3
+ import { ApplicationTaskFailed, InvalidComposition } from "./errors.js";
4
+ import { WorkspaceDefinition } from "./model.js";
5
+ import { Shadcn } from "./shadcn.js";
6
+ import { SourceInventory } from "./source-inventory.js";
7
+ import { TemplateDefinition } from "./templates.js";
8
+ import { Workspaces } from "./workspaces.js";
9
+ const scriptExtension = /\.[cm]?[jt]sx?$/u;
10
+ const allCompositions = { kind: "all" };
11
+ const sharedLintInputs = new Set([
12
+ "package.json",
13
+ "pnpm-lock.yaml",
14
+ "pnpm-workspace.yaml",
15
+ "registry.json",
16
+ "components.json",
17
+ "oxlint.config.ts",
18
+ "tsconfig.json",
19
+ ".node-version",
20
+ ".npmrc",
21
+ ".github/workflows/registry-integrity.yml",
22
+ ]);
23
+ function sourcePath(file) {
24
+ return "source" in file.origin ? file.origin.source : undefined;
25
+ }
26
+ export const affectedLintWorkspaces = Effect.fn("CompositionLint.affected")(function* (sourceRoot, changedFiles) {
27
+ const workspaces = yield* Workspaces;
28
+ const references = yield* workspaces.discover(sourceRoot);
29
+ if (references.length === 0) {
30
+ return yield* new InvalidComposition({
31
+ message: "Composition lint requires at least one named workspace definition.",
32
+ });
33
+ }
34
+ if (changedFiles === undefined ||
35
+ changedFiles.some((file) => sharedLintInputs.has(file) ||
36
+ (file.startsWith("tools/oxlint/") && !file.endsWith(".md")) ||
37
+ file.startsWith("packages/create-next-hydra/src/") ||
38
+ file === "packages/create-next-hydra/package.json")) {
39
+ return references.map((reference) => reference.name);
40
+ }
41
+ const changes = changedFiles.filter((file) => !file.endsWith(".md"));
42
+ if (changes.length === 0) {
43
+ return [];
44
+ }
45
+ const selected = [];
46
+ for (const reference of references) {
47
+ if (changes.some((file) => file.startsWith(`workspaces/${reference.name}/`))) {
48
+ selected.push(reference.name);
49
+ continue;
50
+ }
51
+ const workspace = yield* workspaces.named(reference);
52
+ const origins = (yield* workspace.explain()).files;
53
+ const sources = origins.flatMap((file) => {
54
+ const source = sourcePath(file);
55
+ return source === undefined ? [] : [source];
56
+ });
57
+ // Package ownership also covers additions and deletions that are absent
58
+ // from the current exact-file explanation. Dependencies are included.
59
+ const directories = new Set(sources
60
+ .filter((file) => /^(?:apps|packages)\//u.test(file))
61
+ .map((file) => `${file.split("/").slice(0, 2).join("/")}/`));
62
+ if (changes.some((file) => sources.includes(file) ||
63
+ [...directories].some((directory) => file.startsWith(directory)))) {
64
+ selected.push(reference.name);
65
+ }
66
+ }
67
+ return selected;
68
+ });
69
+ const LintResult = Schema.fromJsonString(Schema.Struct({
70
+ diagnostics: Schema.Array(Schema.Struct({
71
+ code: Schema.optionalKey(Schema.String),
72
+ filename: Schema.String,
73
+ labels: Schema.optionalKey(Schema.Array(Schema.Struct({
74
+ span: Schema.Struct({ column: Schema.Int, line: Schema.Int }),
75
+ }))),
76
+ message: Schema.String,
77
+ severity: Schema.String,
78
+ })),
79
+ number_of_files: Schema.Int,
80
+ }));
81
+ export const executeLintCommand = Effect.fn("CompositionLint.execute")(function* (cwd, executable, args, accepted = [0]) {
82
+ const processes = yield* ChildProcessSpawner.ChildProcessSpawner;
83
+ return yield* Effect.scoped(Effect.gen(function* () {
84
+ const child = yield* processes.spawn(ChildProcess.make(executable, args, {
85
+ cwd,
86
+ env: {
87
+ ...process.env,
88
+ GIT_COMMON_DIR: undefined,
89
+ GIT_DIR: undefined,
90
+ GIT_INDEX_FILE: undefined,
91
+ GIT_WORK_TREE: undefined,
92
+ },
93
+ stderr: "inherit",
94
+ stdin: "ignore",
95
+ stdout: "pipe",
96
+ }));
97
+ const [output, code] = yield* Effect.all([Stream.mkString(Stream.decodeText(child.stdout)), child.exitCode], { concurrency: "unbounded" });
98
+ if (!accepted.includes(code)) {
99
+ return yield* new ApplicationTaskFailed({ code, directory: cwd });
100
+ }
101
+ return output;
102
+ }));
103
+ });
104
+ const assertCoverage = (expected, actual) => {
105
+ const found = new Set(actual);
106
+ const missing = expected.filter((file) => !found.has(file));
107
+ return missing.length === 0
108
+ ? Effect.void
109
+ : Effect.fail(new InvalidComposition({
110
+ message: `Lint did not inspect expected files:\n${missing.join("\n")}`,
111
+ }));
112
+ };
113
+ export const lintWorkspaceFiles = Effect.fn("CompositionLint.files")(function* (root, executable, files, origins, mode = "typed") {
114
+ if (files.length === 0) {
115
+ return 0;
116
+ }
117
+ const path = yield* Path.Path;
118
+ const discovered = (yield* executeLintCommand(root, executable, [
119
+ "--debug",
120
+ "files",
121
+ ...files,
122
+ ]))
123
+ .trim()
124
+ .split(/\r?\n/u)
125
+ .filter(Boolean);
126
+ yield* assertCoverage(files, discovered);
127
+ const result = yield* executeLintCommand(root, executable, [
128
+ ...(mode === "typed" ? ["--type-aware", "--type-check"] : []),
129
+ "--format",
130
+ "json",
131
+ ...discovered,
132
+ ], [0, 1]).pipe(Effect.flatMap(Schema.decodeEffect(LintResult)));
133
+ if (result.number_of_files !== discovered.length) {
134
+ return yield* new InvalidComposition({
135
+ message: `Lint coverage changed: expected ${discovered.length} files, inspected ${result.number_of_files}.`,
136
+ });
137
+ }
138
+ for (const diagnostic of result.diagnostics) {
139
+ const target = path.isAbsolute(diagnostic.filename)
140
+ ? path.relative(root, diagnostic.filename)
141
+ : diagnostic.filename;
142
+ const origin = origins.find((file) => file.target === target);
143
+ const location = origin ? (sourcePath(origin) ?? target) : target;
144
+ const rendered = origin?.origin.kind === "template" ? ` (rendered ${target})` : "";
145
+ const span = diagnostic.labels?.[0]?.span;
146
+ yield* Console.error(`${location}${rendered}:${span?.line ?? 1}:${span?.column ?? 1}: ${diagnostic.severity} ${diagnostic.code ?? ""}: ${diagnostic.message}`);
147
+ }
148
+ return result.diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
149
+ });
150
+ export const lintCompositions = Effect.fn("CompositionLint.run")(function* (sourceRoot, requestedFiles, scope = allCompositions) {
151
+ const fs = yield* FileSystem.FileSystem;
152
+ const path = yield* Path.Path;
153
+ const workspaces = yield* Workspaces;
154
+ const inventory = yield* SourceInventory;
155
+ const registry = yield* Shadcn;
156
+ const requested = new Set(requestedFiles ?? (yield* inventory.list(sourceRoot)));
157
+ const executable = path.join(sourceRoot, "node_modules/.bin/oxlint");
158
+ const candidates = [...requested].filter((file) => scriptExtension.test(file));
159
+ if (candidates.length > 0) {
160
+ const eligible = new Set((yield* executeLintCommand(sourceRoot, executable, [
161
+ "--debug",
162
+ "files",
163
+ ...candidates,
164
+ ]))
165
+ .trim()
166
+ .split(/\r?\n/u)
167
+ .filter(Boolean));
168
+ for (const file of candidates) {
169
+ if (!eligible.has(file)) {
170
+ requested.delete(file);
171
+ }
172
+ }
173
+ }
174
+ const names = yield* workspaces.discover(sourceRoot);
175
+ if (names.length === 0) {
176
+ return yield* new InvalidComposition({
177
+ message: "Composition lint requires at least one named workspace definition.",
178
+ });
179
+ }
180
+ const selected = scope.kind === "workspace"
181
+ ? names.filter((reference) => reference.name === scope.name)
182
+ : names;
183
+ if (scope.kind === "workspace" && selected.length === 0) {
184
+ return yield* new InvalidComposition({
185
+ message: `Unknown lint workspace: ${scope.name}`,
186
+ });
187
+ }
188
+ // The source registry owns production templates. Authored CLI test inputs are
189
+ // not production applications and are verified by their own behavioral tests.
190
+ const declaredTemplates = new Set();
191
+ for (const item of (yield* registry.loadRegistry({
192
+ cwd: sourceRoot,
193
+ registryFile: "registry.json",
194
+ })).items) {
195
+ const definition = yield* Schema.decodeUnknownEffect(TemplateDefinition)(item.meta?.composition ?? {});
196
+ for (const template of definition.templates ?? []) {
197
+ declaredTemplates.add(template.source);
198
+ }
199
+ }
200
+ const covered = new Set();
201
+ let errors = 0;
202
+ for (const reference of selected) {
203
+ if (scope.kind === "source") {
204
+ // Explain establishes ownership without installing or materializing apps.
205
+ const workspace = yield* workspaces.named(reference);
206
+ for (const file of (yield* workspace.explain()).files) {
207
+ const source = sourcePath(file);
208
+ if (source !== undefined) {
209
+ covered.add(source);
210
+ }
211
+ }
212
+ continue;
213
+ }
214
+ errors += yield* Effect.scoped(Effect.gen(function* () {
215
+ const definition = yield* fs
216
+ .readFileString(path.join(sourceRoot, "workspaces", reference.name, "next-hydra.json"))
217
+ .pipe(Effect.flatMap(Schema.decodeEffect(Schema.fromJsonString(WorkspaceDefinition))));
218
+ // Keep this disposable copy below the repository so type-aware lint's
219
+ // plugins can resolve maintainer tooling, never below a named workspace.
220
+ const temporary = yield* fs.makeTempDirectoryScoped({
221
+ directory: path.join(sourceRoot, "workspaces"),
222
+ prefix: ".lint-",
223
+ });
224
+ const destination = path.join(temporary, reference.name);
225
+ const fresh = yield* workspaces.fresh({
226
+ destination,
227
+ name: reference.name,
228
+ selection: {
229
+ addOns: definition.addOns,
230
+ providers: definition.providers,
231
+ },
232
+ source: { kind: "working-tree", root: sourceRoot },
233
+ });
234
+ const result = yield* fresh.materialize({ git: "initialize" });
235
+ yield* executeLintCommand(destination, "pnpm", [
236
+ "-r",
237
+ "--if-present",
238
+ "run",
239
+ "lint:prepare",
240
+ ]);
241
+ const web = path.join(destination, "apps/web");
242
+ const config = path.join(web, "next.config.ts");
243
+ if (yield* fs.exists(config)) {
244
+ yield* Effect.acquireUseRelease(fs.readFile(config), () => Effect.gen(function* () {
245
+ yield* fs.writeFileString(config, 'export { baseConfig as default } from "@repo/next-config";\n');
246
+ yield* executeLintCommand(web, path.join(web, "node_modules/.bin/next"), ["typegen"]);
247
+ }), (content) => fs.writeFile(config, content).pipe(Effect.orDie));
248
+ }
249
+ const encodeString = Schema.encodeEffect(Schema.fromJsonString(Schema.String));
250
+ const configuration = yield* encodeString((yield* path.toFileUrl(path.join(sourceRoot, "oxlint.config.ts")))
251
+ .href);
252
+ yield* fs.writeFileString(path.join(destination, "oxlint.config.mts"), `import path from "node:path";\nimport configuration from ${configuration};\nexport default { ...configuration, jsPlugins: configuration.jsPlugins?.map(plugin => ({ ...plugin, specifier: path.resolve(${yield* encodeString(sourceRoot)}, plugin.specifier) })) };\n`);
253
+ const files = result.origins
254
+ .filter((file) => scriptExtension.test(file.target) &&
255
+ (file.origin.kind === "template" ||
256
+ requested.has(sourcePath(file) ?? "")))
257
+ .map((file) => file.target);
258
+ for (const file of result.origins) {
259
+ const source = sourcePath(file);
260
+ if (source !== undefined) {
261
+ covered.add(source);
262
+ }
263
+ }
264
+ yield* Console.log(`Lint composition: ${reference.name}`);
265
+ return yield* lintWorkspaceFiles(destination, executable, files, result.origins);
266
+ }));
267
+ }
268
+ // A matrix job checks its own application. The separate source job checks
269
+ // files outside every composition and enforces complete application coverage.
270
+ if (scope.kind !== "workspace") {
271
+ const sourceFiles = [...requested].filter((file) => scriptExtension.test(file) && !covered.has(file));
272
+ yield* assertCoverage([
273
+ ...sourceFiles.filter((file) => file.startsWith("apps/web/") || file.startsWith("apps/api/")),
274
+ ...[...requested].filter((file) => declaredTemplates.has(file) && !covered.has(file)),
275
+ ], []);
276
+ // Authored examples are input trees, not installed TypeScript projects.
277
+ // Keep their syntax checks; real application output is checked above.
278
+ const examples = sourceFiles.filter((file) => file.startsWith("packages/create-next-hydra/tests/examples/"));
279
+ const exampleSet = new Set(examples);
280
+ errors += yield* lintWorkspaceFiles(sourceRoot, executable, sourceFiles.filter((file) => !exampleSet.has(file)), []);
281
+ errors += yield* lintWorkspaceFiles(sourceRoot, executable, examples, [], "syntax");
282
+ }
283
+ if (errors > 0) {
284
+ return yield* new InvalidComposition({
285
+ message: `Composition lint failed with ${errors} errors. Fix the reported canonical sources and templates.`,
286
+ });
287
+ }
288
+ });
@@ -0,0 +1,24 @@
1
+ import { Context, Effect, FileSystem, Layer, Path, Schema } from "effect";
2
+ import type { PlatformError } from "effect";
3
+ import { InvalidComposition, SourceChanged } from "./errors.ts";
4
+ import type { RegistryFailure, IncompatibleSelection, RegistryWorkerFailure, StagingRetained } from "./errors.ts";
5
+ import type { PreparedWorkspace, SelectionRequest } from "./model.ts";
6
+ import { Shadcn } from "./shadcn.ts";
7
+ import { SourceInventory } from "./source-inventory.ts";
8
+ import type { WorkspaceSource } from "./workspace-sources.ts";
9
+ export interface PreparationRequest {
10
+ readonly demoArchitecture?: boolean;
11
+ readonly source: WorkspaceSource;
12
+ readonly selection: SelectionRequest;
13
+ readonly name: string;
14
+ readonly port?: number;
15
+ }
16
+ export type PreparationError = InvalidComposition | IncompatibleSelection | SourceChanged | RegistryFailure | RegistryWorkerFailure | StagingRetained | PlatformError.PlatformError | Schema.SchemaError;
17
+ declare const Composition_base: Context.ServiceClass<Composition, "create-next-hydra/Composition", {
18
+ readonly prepare: (request: PreparationRequest) => Effect.Effect<PreparedWorkspace, PreparationError>;
19
+ }>;
20
+ export declare class Composition extends Composition_base {
21
+ static readonly layer: Layer.Layer<Composition, never, FileSystem.FileSystem | Path.Path | Shadcn | SourceInventory>;
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=composition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../src/composition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAe5C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EAChB,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EAEV,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AASxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,MAAM,gBAAgB,GACxB,kBAAkB,GAClB,qBAAqB,GACrB,aAAa,GACb,eAAe,GACf,qBAAqB,GACrB,eAAe,GACf,aAAa,CAAC,aAAa,GAC3B,MAAM,CAAC,WAAW,CAAC;;sBAOD,CAChB,OAAO,EAAE,kBAAkB,KACxB,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;;AAL3D,qBAAa,WAAY,SAAQ,gBAOG;IAClC,MAAM,CAAC,QAAQ,CAAC,KAAK,gGAkiBnB;CACH"}