create-next-hydra 0.2.1 → 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 (204) hide show
  1. package/README.md +156 -26
  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 +27 -15
  138. package/schema/selection-definition.json +206 -5
  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 -453
  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 -313
  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 -63
  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 -54
  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 -320
  166. package/dist/composition/schema.d.ts +0 -235
  167. package/dist/composition/schema.d.ts.map +0 -1
  168. package/dist/composition/schema.js +0 -115
  169. package/dist/composition/types.d.ts +0 -87
  170. package/dist/composition/types.d.ts.map +0 -1
  171. package/dist/composition/types.js +0 -6
  172. package/dist/composition/use.d.ts +0 -23
  173. package/dist/composition/use.d.ts.map +0 -1
  174. package/dist/composition/use.js +0 -182
  175. package/dist/composition/workspace.d.ts +0 -10
  176. package/dist/composition/workspace.d.ts.map +0 -1
  177. package/dist/composition/workspace.js +0 -208
  178. package/dist/constants.d.ts +0 -11
  179. package/dist/constants.d.ts.map +0 -1
  180. package/dist/constants.js +0 -38
  181. package/dist/fs-utils.d.ts +0 -9
  182. package/dist/fs-utils.d.ts.map +0 -1
  183. package/dist/fs-utils.js +0 -64
  184. package/dist/git.d.ts +0 -28
  185. package/dist/git.d.ts.map +0 -1
  186. package/dist/git.js +0 -107
  187. package/dist/instruction-renderer.d.ts +0 -17
  188. package/dist/instruction-renderer.d.ts.map +0 -1
  189. package/dist/instruction-renderer.js +0 -132
  190. package/dist/logger.d.ts +0 -13
  191. package/dist/logger.d.ts.map +0 -1
  192. package/dist/logger.js +0 -26
  193. package/dist/prompts.d.ts +0 -7
  194. package/dist/prompts.d.ts.map +0 -1
  195. package/dist/prompts.js +0 -47
  196. package/dist/sanitize.d.ts +0 -10
  197. package/dist/sanitize.d.ts.map +0 -1
  198. package/dist/sanitize.js +0 -23
  199. package/dist/scaffold.d.ts +0 -7
  200. package/dist/scaffold.d.ts.map +0 -1
  201. package/dist/scaffold.js +0 -325
  202. package/dist/version.d.ts +0 -2
  203. package/dist/version.d.ts.map +0 -1
  204. package/dist/version.js +0 -2
@@ -0,0 +1,218 @@
1
+ import { createHash } from "node:crypto";
2
+ import { Context, Effect, FileSystem, Layer, Path, Schema, Stream, } from "effect";
3
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
4
+ import { SnapshotFailed, SnapshotUnavailable } from "./errors.js";
5
+ import { cacheDirectories, isEnvironmentFile } from "./file-policy.js";
6
+ import { relativeFile, writeFile } from "./files.js";
7
+ export const snapshotTarget = (target) => !target
8
+ .split("/")
9
+ .some((part) => cacheDirectories.has(part) ||
10
+ isEnvironmentFile(part) ||
11
+ [".git", ".npmrc", ".netrc", ".ssh", ".aws", ".azure"].includes(part) ||
12
+ /\.(?:pem|key|p12|pfx|keystore|tsbuildinfo)$/iu.test(part) ||
13
+ /^id_(?:rsa|ed25519|ecdsa)(?:\.|$)/u.test(part));
14
+ export class WorkspaceSnapshots extends Context.Service()("create-next-hydra/WorkspaceSnapshots") {
15
+ static layer = Layer.effect(WorkspaceSnapshots, Effect.gen(function* () {
16
+ const fs = yield* FileSystem.FileSystem;
17
+ const path = yield* Path.Path;
18
+ const processes = yield* ChildProcessSpawner.ChildProcessSpawner;
19
+ const directoryFor = (identity) => path.join(identity.sourceRoot, ".cache", "workspace-snapshots", `${createHash("sha256").update(path.resolve(identity.directory)).digest("hex")}.git`);
20
+ const use = (identity, operation, callback) => Effect.scoped(Effect.gen(function* () {
21
+ const temporary = yield* Effect.acquireRelease(fs.makeTempDirectory({ prefix: "composition-snapshot-" }), (directory) => fs.remove(directory, { recursive: true }).pipe(Effect.orDie));
22
+ const tree = path.join(temporary, "tree");
23
+ yield* fs.makeDirectory(tree).pipe(Effect.uninterruptible);
24
+ const repository = directoryFor(identity);
25
+ // Private Git commands must never inherit an index, object store or config
26
+ // selected by the maintainer's shell/hooks. No live workspace is staged.
27
+ const env = Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.startsWith("GIT_")));
28
+ Object.assign(env, {
29
+ GIT_ATTR_NOSYSTEM: "1",
30
+ GIT_CONFIG_GLOBAL: "/dev/null",
31
+ GIT_CONFIG_NOSYSTEM: "1",
32
+ GIT_INDEX_FILE: path.join(temporary, "index"),
33
+ GIT_OPTIONAL_LOCKS: "0",
34
+ });
35
+ if (operation === "diff") {
36
+ const objects = path.join(temporary, "objects");
37
+ yield* fs.makeDirectory(objects).pipe(Effect.uninterruptible);
38
+ // Intent-to-add may create an empty blob. Keep all inspection writes in
39
+ // disposable storage; read saved objects through an explicit alternate.
40
+ Object.assign(env, {
41
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: yield* Schema.encodeEffect(Schema.fromJsonString(Schema.String))(path.join(repository, "objects")).pipe(Effect.mapError(() => new SnapshotFailed({
42
+ directory: identity.directory,
43
+ operation,
44
+ }))),
45
+ GIT_OBJECT_DIRECTORY: objects,
46
+ });
47
+ }
48
+ const git = (args) => Effect.scoped(Effect.gen(function* () {
49
+ const handle = yield* processes.spawn(ChildProcess.make("git", [
50
+ `--git-dir=${repository}`,
51
+ ...(args[0] === "init" ? [] : [`--work-tree=${tree}`]),
52
+ "--literal-pathspecs",
53
+ "-c",
54
+ "core.hooksPath=/dev/null",
55
+ "-c",
56
+ "core.attributesFile=/dev/null",
57
+ "-c",
58
+ "core.autocrlf=false",
59
+ "-c",
60
+ "core.fileMode=true",
61
+ "-c",
62
+ "core.fsmonitor=false",
63
+ "-c",
64
+ "commit.gpgsign=false",
65
+ "-c",
66
+ "user.name=Workspace composition",
67
+ "-c",
68
+ "user.email=workspace@localhost",
69
+ ...args,
70
+ ], { cwd: tree, env, stderr: "ignore", stdin: "ignore" }));
71
+ const [output, code] = yield* Effect.all([
72
+ Stream.mkString(Stream.decodeText(handle.stdout)),
73
+ handle.exitCode,
74
+ ], { concurrency: "unbounded" });
75
+ if (code !== 0) {
76
+ return yield* new SnapshotFailed({
77
+ directory: identity.directory,
78
+ operation,
79
+ });
80
+ }
81
+ return output;
82
+ })).pipe(Effect.mapError(() => new SnapshotFailed({
83
+ directory: identity.directory,
84
+ operation: `${operation}:${args[0]}`,
85
+ })), Effect.uninterruptible);
86
+ return yield* callback({ git, repository, tree });
87
+ }));
88
+ const populate = (tree, files) => Effect.gen(function* () {
89
+ for (const file of files) {
90
+ if (snapshotTarget(file.target)) {
91
+ yield* writeFile(tree, file, true);
92
+ }
93
+ }
94
+ }).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
95
+ const capture = Effect.fn("WorkspaceSnapshots.capture")(function* (identity, files, previous) {
96
+ return yield* use(identity, "capture", ({ git, repository, tree }) => Effect.gen(function* () {
97
+ yield* fs
98
+ .makeDirectory(repository, { mode: 0o700, recursive: true })
99
+ .pipe(Effect.uninterruptible);
100
+ yield* git([
101
+ "init",
102
+ "--bare",
103
+ "--template=",
104
+ "--object-format=sha1",
105
+ "--initial-branch=composition",
106
+ repository,
107
+ ]);
108
+ yield* fs
109
+ .makeDirectory(path.join(repository, "info"), { recursive: true })
110
+ .pipe(Effect.uninterruptible);
111
+ yield* fs
112
+ .writeFileString(path.join(repository, "info/attributes"), "* -text -filter -ident -working-tree-encoding !diff\n")
113
+ .pipe(Effect.uninterruptible);
114
+ yield* populate(tree, files).pipe(Effect.mapError(() => new SnapshotFailed({
115
+ directory: identity.directory,
116
+ operation: "capture",
117
+ })));
118
+ yield* git(["read-tree", "--empty"]);
119
+ yield* git(["add", "--force", "--all", "--", "."]);
120
+ const treeId = (yield* git(["write-tree"])).trim();
121
+ const previousTree = previous
122
+ ? yield* git([
123
+ "rev-parse",
124
+ "--verify",
125
+ `${previous}^{tree}`,
126
+ ]).pipe(Effect.map((value) => value.trim()), Effect.orElseSucceed(() => null))
127
+ : null;
128
+ const commit = previous && previousTree === treeId
129
+ ? previous
130
+ : (yield* git([
131
+ "commit-tree",
132
+ treeId,
133
+ "-m",
134
+ "Compose workspace",
135
+ ])).trim();
136
+ if (!/^[a-f0-9]{40}$/u.test(commit)) {
137
+ return yield* new SnapshotFailed({
138
+ directory: identity.directory,
139
+ operation: "capture",
140
+ });
141
+ }
142
+ // Each checkpoint stays reachable, including the old receipt's commit
143
+ // if publishing a newer receipt fails. HEAD is never baseline authority.
144
+ yield* git(["update-ref", `refs/snapshots/${commit}`, commit]);
145
+ return commit;
146
+ }));
147
+ });
148
+ const diff = Effect.fn("WorkspaceSnapshots.diff")(function* (identity, commit, files) {
149
+ if (!(yield* fs.exists(path.join(directoryFor(identity), "HEAD")))) {
150
+ return yield* new SnapshotUnavailable({
151
+ directory: identity.directory,
152
+ });
153
+ }
154
+ return yield* use(identity, "diff", ({ git, tree }) => Effect.gen(function* () {
155
+ const saved = yield* git([
156
+ "ls-tree",
157
+ "--name-only",
158
+ "-rz",
159
+ commit,
160
+ ]).pipe(Effect.mapError(() => new SnapshotUnavailable({ directory: identity.directory })));
161
+ const targets = new Set(saved.split("\0").filter(Boolean));
162
+ for (const target of targets) {
163
+ if (!snapshotTarget(target) ||
164
+ (yield* relativeFile(target).pipe(Effect.orElseSucceed(() => ""))) !== target) {
165
+ return yield* new SnapshotUnavailable({
166
+ directory: identity.directory,
167
+ });
168
+ }
169
+ }
170
+ yield* populate(tree, files).pipe(Effect.mapError(() => new SnapshotFailed({
171
+ directory: identity.directory,
172
+ operation: "diff",
173
+ })));
174
+ yield* git(["read-tree", commit]);
175
+ for (const file of files) {
176
+ if (snapshotTarget(file.target) && !targets.has(file.target)) {
177
+ yield* git([
178
+ "add",
179
+ "--intent-to-add",
180
+ "--force",
181
+ "--",
182
+ file.target,
183
+ ]);
184
+ }
185
+ }
186
+ const flags = [
187
+ "--no-ext-diff",
188
+ "--no-textconv",
189
+ "--no-renames",
190
+ "--no-color",
191
+ "--src-prefix=a/",
192
+ "--dst-prefix=b/",
193
+ ];
194
+ const names = (yield* git([
195
+ "diff",
196
+ ...flags,
197
+ "--name-status",
198
+ "-z",
199
+ commit,
200
+ "--",
201
+ ])).split("\0");
202
+ const changes = [];
203
+ for (let index = 0; index + 1 < names.length; index += 2) {
204
+ const target = names[index + 1];
205
+ const status = names[index];
206
+ if (target && status) {
207
+ changes.push({ status, target });
208
+ }
209
+ }
210
+ return {
211
+ changes,
212
+ patch: yield* git(["diff", ...flags, commit, "--"]),
213
+ };
214
+ }));
215
+ });
216
+ return WorkspaceSnapshots.of({ capture, diff });
217
+ }));
218
+ }
@@ -0,0 +1,27 @@
1
+ import { Context, Effect, FileSystem, Layer, Path } from "effect";
2
+ import type { PlatformError, Scope } from "effect";
3
+ import { ChildProcessSpawner } from "effect/unstable/process";
4
+ import { SourceAcquisitionFailed, SourceStorageRetained } from "./errors.ts";
5
+ export interface WorkingTree {
6
+ readonly kind: "working-tree";
7
+ readonly root: string;
8
+ }
9
+ export type SourceRequest = WorkingTree | {
10
+ readonly kind: "repository";
11
+ readonly repository: string;
12
+ readonly ref?: string;
13
+ };
14
+ export type WorkspaceSource = WorkingTree | {
15
+ readonly kind: "repository";
16
+ readonly root: string;
17
+ readonly commit: string;
18
+ };
19
+ export type SourceError = PlatformError.PlatformError | SourceAcquisitionFailed | SourceStorageRetained;
20
+ declare const WorkspaceSources_base: Context.ServiceClass<WorkspaceSources, "create-next-hydra/WorkspaceSources", {
21
+ readonly use: <A, E, R>(request: SourceRequest, use: (source: WorkspaceSource) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | SourceError, Exclude<R, Scope.Scope>>;
22
+ }>;
23
+ export declare class WorkspaceSources extends WorkspaceSources_base {
24
+ static readonly layer: Layer.Layer<WorkspaceSources, never, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
25
+ }
26
+ export {};
27
+ //# sourceMappingURL=workspace-sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-sources.d.ts","sourceRoot":"","sources":["../src/workspace-sources.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,MAAM,EACN,UAAU,EACV,KAAK,EACL,IAAI,EAIL,MAAM,QAAQ,CAAC;AAChB,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE5E,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAG7E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GACrB,WAAW,GACX;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AACN,MAAM,MAAM,eAAe,GACvB,WAAW,GACX;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,WAAW,GACnB,aAAa,CAAC,aAAa,GAC3B,uBAAuB,GACvB,qBAAqB,CAAC;;kBAKR,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EACpB,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KACrD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;;AANnE,qBAAa,gBAAiB,SAAQ,qBAQG;IACvC,MAAM,CAAC,QAAQ,CAAC,KAAK,oHAoJnB;CACH"}
@@ -0,0 +1,88 @@
1
+ import { Context, Effect, FileSystem, Layer, Path, Redacted, Ref, Stream, } from "effect";
2
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
3
+ import { SourceAcquisitionFailed, SourceStorageRetained } from "./errors.js";
4
+ import { confirmStopped } from "./process-group.js";
5
+ export class WorkspaceSources extends Context.Service()("create-next-hydra/WorkspaceSources") {
6
+ static layer = Layer.effect(WorkspaceSources, Effect.gen(function* () {
7
+ const fs = yield* FileSystem.FileSystem;
8
+ const path = yield* Path.Path;
9
+ const processes = yield* ChildProcessSpawner.ChildProcessSpawner;
10
+ return WorkspaceSources.of({
11
+ use: (request, use) => Effect.gen(function* () {
12
+ if (request.kind === "working-tree") {
13
+ const root = path.resolve(request.root);
14
+ yield* fs.access(root);
15
+ return yield* Effect.scoped(use({ kind: "working-tree", root }));
16
+ }
17
+ if (process.platform === "win32" || request.ref?.startsWith("-")) {
18
+ return yield* new SourceAcquisitionFailed({
19
+ diagnostic: Redacted.make("Unsupported platform or revision"),
20
+ phase: "validation",
21
+ });
22
+ }
23
+ return yield* Effect.acquireUseRelease(Effect.gen(function* () {
24
+ const directory = yield* fs.makeTempDirectory({
25
+ prefix: "hydra-source-",
26
+ });
27
+ return { active: yield* Ref.make(false), directory };
28
+ }), (storage) => Effect.gen(function* () {
29
+ const root = path.join(storage.directory, "checkout");
30
+ const git = Effect.fn("WorkspaceSources.git")((phase, args, cwd) => Effect.scoped(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
31
+ yield* Ref.set(storage.active, true);
32
+ const handle = yield* processes
33
+ .spawn(ChildProcess.make("git", args, {
34
+ cwd,
35
+ forceKillAfter: "100 millis",
36
+ stderr: "ignore",
37
+ stdin: "ignore",
38
+ }))
39
+ .pipe(Effect.tapError(() => Ref.set(storage.active, false)), Effect.mapError((error) => new SourceAcquisitionFailed({
40
+ diagnostic: Redacted.make(error),
41
+ phase,
42
+ })));
43
+ return yield* restore(Effect.gen(function* () {
44
+ const [output, code] = yield* Effect.all([
45
+ Stream.mkString(Stream.decodeText(handle.stdout)),
46
+ handle.exitCode,
47
+ ], { concurrency: "unbounded" });
48
+ if (code !== 0) {
49
+ return yield* new SourceAcquisitionFailed({
50
+ diagnostic: Redacted.make({
51
+ exitCode: code,
52
+ }),
53
+ phase,
54
+ });
55
+ }
56
+ return output.trim();
57
+ })).pipe(Effect.mapError((error) => new SourceAcquisitionFailed({
58
+ diagnostic: Redacted.make(error),
59
+ phase,
60
+ })), Effect.onExit(() => confirmStopped(handle).pipe(Effect.mapError((error) => new SourceAcquisitionFailed({
61
+ diagnostic: Redacted.make(error),
62
+ phase: "stop",
63
+ })), Effect.andThen(Ref.set(storage.active, false)), Effect.onExit(() => handle.unref.pipe(Effect.asVoid)))));
64
+ }))));
65
+ yield* git("clone", [
66
+ "clone",
67
+ ...(request.ref ? [] : ["--depth", "1"]),
68
+ "--",
69
+ request.repository,
70
+ root,
71
+ ], storage.directory);
72
+ if (request.ref) {
73
+ yield* git("checkout", ["checkout", "--detach", request.ref], root);
74
+ }
75
+ const commit = yield* git("revision", ["rev-parse", "HEAD"], root);
76
+ return yield* Effect.scoped(use({ commit, kind: "repository", root }));
77
+ }), (storage) => Effect.gen(function* () {
78
+ if (yield* Ref.get(storage.active)) {
79
+ return yield* new SourceStorageRetained({
80
+ directory: storage.directory,
81
+ });
82
+ }
83
+ yield* fs.remove(storage.directory, { recursive: true });
84
+ }));
85
+ }),
86
+ });
87
+ }));
88
+ }
@@ -0,0 +1,325 @@
1
+ import { Context, Effect, FileSystem, Layer, Path, Schema } from "effect";
2
+ import type { PlatformError } from "effect";
3
+ import type { WorkspaceLockAuthorizationRequired, WorkspaceLockChanged } from "./errors.ts";
4
+ import { WorkspaceBusy, WorkspaceRecoveryRequired, WorkspaceStateInvalid } from "./errors.ts";
5
+ declare const Fingerprint: Schema.Struct<{
6
+ readonly hash: Schema.String;
7
+ readonly mode: Schema.Int;
8
+ }>;
9
+ export type Fingerprint = typeof Fingerprint.Type;
10
+ export declare const sameFingerprint: (left: Fingerprint | null, right: Fingerprint | null) => boolean;
11
+ declare const Intent: Schema.Struct<{
12
+ readonly after: Schema.NullOr<Schema.Struct<{
13
+ readonly hash: Schema.String;
14
+ readonly mode: Schema.Int;
15
+ }>>;
16
+ readonly before: Schema.NullOr<Schema.Struct<{
17
+ readonly hash: Schema.String;
18
+ readonly mode: Schema.Int;
19
+ }>>;
20
+ readonly desired: Schema.NullOr<Schema.Struct<{
21
+ readonly hash: Schema.String;
22
+ readonly mode: Schema.Int;
23
+ }>>;
24
+ readonly origin: Schema.NullOr<Schema.Union<readonly [Schema.Struct<{
25
+ readonly kind: Schema.Literal<"registry">;
26
+ readonly owner: Schema.String;
27
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
28
+ }>, Schema.Struct<{
29
+ readonly kind: Schema.Literal<"workspace-setting">;
30
+ readonly source: Schema.String;
31
+ }>, Schema.Struct<{
32
+ readonly kind: Schema.Literal<"source">;
33
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
34
+ readonly owner: Schema.NullOr<Schema.String>;
35
+ readonly source: Schema.String;
36
+ }>, Schema.Struct<{
37
+ readonly bindings: Schema.$Array<Schema.Struct<{
38
+ readonly owner: Schema.String;
39
+ readonly as: Schema.optionalKey<Schema.String>;
40
+ readonly export: Schema.String;
41
+ readonly module: Schema.NonEmptyString;
42
+ readonly order: Schema.optionalKey<Schema.Int>;
43
+ readonly slot: Schema.NonEmptyString;
44
+ readonly target: Schema.NonEmptyString;
45
+ }>>;
46
+ readonly kind: Schema.Literal<"template">;
47
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
48
+ readonly owner: Schema.String;
49
+ readonly source: Schema.String;
50
+ }>, Schema.Struct<{
51
+ readonly kind: Schema.Literal<"policy">;
52
+ readonly policy: Schema.Literals<readonly ["application-manifest", "workspace-settings", "lockfile-seed", "application-tasks", "application-ignore"]>;
53
+ readonly sources: Schema.$Array<Schema.String>;
54
+ }>]>>;
55
+ readonly target: Schema.String;
56
+ readonly temporary: Schema.NullOr<Schema.String>;
57
+ }>;
58
+ export type FileIntent = typeof Intent.Type;
59
+ declare const Installation: Schema.Struct<{
60
+ readonly inputs: Schema.String;
61
+ readonly lockfile: Schema.Struct<{
62
+ readonly hash: Schema.String;
63
+ readonly mode: Schema.Int;
64
+ }>;
65
+ readonly modules: Schema.Struct<{
66
+ readonly hash: Schema.String;
67
+ readonly mode: Schema.Int;
68
+ }>;
69
+ readonly toolchain: Schema.String;
70
+ readonly virtualLock: Schema.Struct<{
71
+ readonly hash: Schema.String;
72
+ readonly mode: Schema.Int;
73
+ }>;
74
+ }>;
75
+ declare const Snapshot: Schema.Struct<{
76
+ readonly commit: Schema.String;
77
+ readonly filesRevision: Schema.Int;
78
+ readonly origins: Schema.$Array<Schema.Struct<{
79
+ readonly origin: Schema.Union<readonly [Schema.Struct<{
80
+ readonly kind: Schema.Literal<"registry">;
81
+ readonly owner: Schema.String;
82
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
83
+ }>, Schema.Struct<{
84
+ readonly kind: Schema.Literal<"workspace-setting">;
85
+ readonly source: Schema.String;
86
+ }>, Schema.Struct<{
87
+ readonly kind: Schema.Literal<"source">;
88
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
89
+ readonly owner: Schema.NullOr<Schema.String>;
90
+ readonly source: Schema.String;
91
+ }>, Schema.Struct<{
92
+ readonly bindings: Schema.$Array<Schema.Struct<{
93
+ readonly owner: Schema.String;
94
+ readonly as: Schema.optionalKey<Schema.String>;
95
+ readonly export: Schema.String;
96
+ readonly module: Schema.NonEmptyString;
97
+ readonly order: Schema.optionalKey<Schema.Int>;
98
+ readonly slot: Schema.NonEmptyString;
99
+ readonly target: Schema.NonEmptyString;
100
+ }>>;
101
+ readonly kind: Schema.Literal<"template">;
102
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
103
+ readonly owner: Schema.String;
104
+ readonly source: Schema.String;
105
+ }>, Schema.Struct<{
106
+ readonly kind: Schema.Literal<"policy">;
107
+ readonly policy: Schema.Literals<readonly ["application-manifest", "workspace-settings", "lockfile-seed", "application-tasks", "application-ignore"]>;
108
+ readonly sources: Schema.$Array<Schema.String>;
109
+ }>]>;
110
+ readonly target: Schema.String;
111
+ }>>;
112
+ readonly revision: Schema.Int;
113
+ }>;
114
+ export type Installation = typeof Installation.Type;
115
+ declare const Receipt: Schema.Struct<{
116
+ readonly directory: Schema.String;
117
+ readonly entries: Schema.$Array<Schema.Struct<{
118
+ readonly applied: Schema.Struct<{
119
+ readonly hash: Schema.String;
120
+ readonly mode: Schema.Int;
121
+ }>;
122
+ readonly desired: Schema.Struct<{
123
+ readonly hash: Schema.String;
124
+ readonly mode: Schema.Int;
125
+ }>;
126
+ readonly origin: Schema.Union<readonly [Schema.Struct<{
127
+ readonly kind: Schema.Literal<"registry">;
128
+ readonly owner: Schema.String;
129
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
130
+ }>, Schema.Struct<{
131
+ readonly kind: Schema.Literal<"workspace-setting">;
132
+ readonly source: Schema.String;
133
+ }>, Schema.Struct<{
134
+ readonly kind: Schema.Literal<"source">;
135
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
136
+ readonly owner: Schema.NullOr<Schema.String>;
137
+ readonly source: Schema.String;
138
+ }>, Schema.Struct<{
139
+ readonly bindings: Schema.$Array<Schema.Struct<{
140
+ readonly owner: Schema.String;
141
+ readonly as: Schema.optionalKey<Schema.String>;
142
+ readonly export: Schema.String;
143
+ readonly module: Schema.NonEmptyString;
144
+ readonly order: Schema.optionalKey<Schema.Int>;
145
+ readonly slot: Schema.NonEmptyString;
146
+ readonly target: Schema.NonEmptyString;
147
+ }>>;
148
+ readonly kind: Schema.Literal<"template">;
149
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
150
+ readonly owner: Schema.String;
151
+ readonly source: Schema.String;
152
+ }>, Schema.Struct<{
153
+ readonly kind: Schema.Literal<"policy">;
154
+ readonly policy: Schema.Literals<readonly ["application-manifest", "workspace-settings", "lockfile-seed", "application-tasks", "application-ignore"]>;
155
+ readonly sources: Schema.$Array<Schema.String>;
156
+ }>]>;
157
+ readonly target: Schema.String;
158
+ }>>;
159
+ readonly filesRevision: Schema.Int;
160
+ readonly format: Schema.Literal<"effect-workspace">;
161
+ readonly installation: Schema.NullOr<Schema.Struct<{
162
+ readonly inputs: Schema.String;
163
+ readonly lockfile: Schema.Struct<{
164
+ readonly hash: Schema.String;
165
+ readonly mode: Schema.Int;
166
+ }>;
167
+ readonly modules: Schema.Struct<{
168
+ readonly hash: Schema.String;
169
+ readonly mode: Schema.Int;
170
+ }>;
171
+ readonly toolchain: Schema.String;
172
+ readonly virtualLock: Schema.Struct<{
173
+ readonly hash: Schema.String;
174
+ readonly mode: Schema.Int;
175
+ }>;
176
+ }>>;
177
+ readonly pending: Schema.NullOr<Schema.Union<readonly [Schema.Struct<{
178
+ readonly files: Schema.$Array<Schema.Struct<{
179
+ readonly after: Schema.NullOr<Schema.Struct<{
180
+ readonly hash: Schema.String;
181
+ readonly mode: Schema.Int;
182
+ }>>;
183
+ readonly before: Schema.NullOr<Schema.Struct<{
184
+ readonly hash: Schema.String;
185
+ readonly mode: Schema.Int;
186
+ }>>;
187
+ readonly desired: Schema.NullOr<Schema.Struct<{
188
+ readonly hash: Schema.String;
189
+ readonly mode: Schema.Int;
190
+ }>>;
191
+ readonly origin: Schema.NullOr<Schema.Union<readonly [Schema.Struct<{
192
+ readonly kind: Schema.Literal<"registry">;
193
+ readonly owner: Schema.String;
194
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
195
+ }>, Schema.Struct<{
196
+ readonly kind: Schema.Literal<"workspace-setting">;
197
+ readonly source: Schema.String;
198
+ }>, Schema.Struct<{
199
+ readonly kind: Schema.Literal<"source">;
200
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
201
+ readonly owner: Schema.NullOr<Schema.String>;
202
+ readonly source: Schema.String;
203
+ }>, Schema.Struct<{
204
+ readonly bindings: Schema.$Array<Schema.Struct<{
205
+ readonly owner: Schema.String;
206
+ readonly as: Schema.optionalKey<Schema.String>;
207
+ readonly export: Schema.String;
208
+ readonly module: Schema.NonEmptyString;
209
+ readonly order: Schema.optionalKey<Schema.Int>;
210
+ readonly slot: Schema.NonEmptyString;
211
+ readonly target: Schema.NonEmptyString;
212
+ }>>;
213
+ readonly kind: Schema.Literal<"template">;
214
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
215
+ readonly owner: Schema.String;
216
+ readonly source: Schema.String;
217
+ }>, Schema.Struct<{
218
+ readonly kind: Schema.Literal<"policy">;
219
+ readonly policy: Schema.Literals<readonly ["application-manifest", "workspace-settings", "lockfile-seed", "application-tasks", "application-ignore"]>;
220
+ readonly sources: Schema.$Array<Schema.String>;
221
+ }>]>>;
222
+ readonly target: Schema.String;
223
+ readonly temporary: Schema.NullOr<Schema.String>;
224
+ }>>;
225
+ readonly initialization: Schema.$Array<Schema.Struct<{
226
+ readonly status: Schema.Literals<readonly ["planned", "started", "completed"]>;
227
+ readonly target: Schema.String;
228
+ }>>;
229
+ readonly kind: Schema.Literal<"files">;
230
+ readonly preserved: Schema.withDecodingDefaultKey<Schema.$Array<Schema.String>, never>;
231
+ }>, Schema.Struct<{
232
+ readonly inputs: Schema.String;
233
+ readonly kind: Schema.Literal<"installation">;
234
+ readonly stopped: Schema.Boolean;
235
+ }>]>>;
236
+ readonly preserved: Schema.withDecodingDefaultKey<Schema.$Array<Schema.String>, never>;
237
+ readonly revision: Schema.Int;
238
+ readonly snapshot: Schema.NullOr<Schema.Struct<{
239
+ readonly commit: Schema.String;
240
+ readonly filesRevision: Schema.Int;
241
+ readonly origins: Schema.$Array<Schema.Struct<{
242
+ readonly origin: Schema.Union<readonly [Schema.Struct<{
243
+ readonly kind: Schema.Literal<"registry">;
244
+ readonly owner: Schema.String;
245
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
246
+ }>, Schema.Struct<{
247
+ readonly kind: Schema.Literal<"workspace-setting">;
248
+ readonly source: Schema.String;
249
+ }>, Schema.Struct<{
250
+ readonly kind: Schema.Literal<"source">;
251
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
252
+ readonly owner: Schema.NullOr<Schema.String>;
253
+ readonly source: Schema.String;
254
+ }>, Schema.Struct<{
255
+ readonly bindings: Schema.$Array<Schema.Struct<{
256
+ readonly owner: Schema.String;
257
+ readonly as: Schema.optionalKey<Schema.String>;
258
+ readonly export: Schema.String;
259
+ readonly module: Schema.NonEmptyString;
260
+ readonly order: Schema.optionalKey<Schema.Int>;
261
+ readonly slot: Schema.NonEmptyString;
262
+ readonly target: Schema.NonEmptyString;
263
+ }>>;
264
+ readonly kind: Schema.Literal<"template">;
265
+ readonly transforms: Schema.optionalKey<Schema.$Array<Schema.Literal<"remove-demo-architecture">>>;
266
+ readonly owner: Schema.String;
267
+ readonly source: Schema.String;
268
+ }>, Schema.Struct<{
269
+ readonly kind: Schema.Literal<"policy">;
270
+ readonly policy: Schema.Literals<readonly ["application-manifest", "workspace-settings", "lockfile-seed", "application-tasks", "application-ignore"]>;
271
+ readonly sources: Schema.$Array<Schema.String>;
272
+ }>]>;
273
+ readonly target: Schema.String;
274
+ }>>;
275
+ readonly revision: Schema.Int;
276
+ }>>;
277
+ readonly sourceRoot: Schema.String;
278
+ readonly version: Schema.Literal<1>;
279
+ }>;
280
+ type Receipt = typeof Receipt.Type;
281
+ export type WorkspaceStateError = WorkspaceLockAuthorizationRequired | WorkspaceLockChanged | PlatformError.PlatformError | WorkspaceStateInvalid | WorkspaceRecoveryRequired | WorkspaceBusy;
282
+ export interface WorkspaceIdentity {
283
+ readonly directory: string;
284
+ readonly sourceRoot: string;
285
+ }
286
+ export interface WorkspaceObservation {
287
+ readonly directory: string;
288
+ readonly initialized: boolean;
289
+ readonly entries: Receipt["entries"];
290
+ readonly installation: Installation | null;
291
+ readonly snapshot: typeof Snapshot.Type | null;
292
+ readonly revision: number;
293
+ readonly filesRevision: number;
294
+ readonly pending: Receipt["pending"];
295
+ readonly preserved: readonly string[];
296
+ }
297
+ export interface WorkspaceWriteAccess {
298
+ readonly recoveryEvidence: string | null;
299
+ readonly directory: string;
300
+ readonly observation: Effect.Effect<WorkspaceObservation>;
301
+ readonly recoverFiles: (observed: ReadonlyMap<string, Fingerprint | null>, expectedRevision: number) => Effect.Effect<void, WorkspaceStateError>;
302
+ readonly publishSnapshot: (commit: string, expectedRevision: number) => Effect.Effect<void, WorkspaceStateError>;
303
+ readonly begin: (files: readonly FileIntent[], initialization: readonly string[], preserved?: readonly string[]) => Effect.Effect<void, WorkspaceStateError>;
304
+ readonly complete: Effect.Effect<void, WorkspaceStateError>;
305
+ readonly initialize: <A, E, R>(target: string, write: Effect.Effect<A, E, R>) => Effect.Effect<A, E | WorkspaceStateError, R>;
306
+ readonly installation: Effect.Effect<Installation | null>;
307
+ readonly appliedEntries: Effect.Effect<Receipt["entries"]>;
308
+ readonly beginInstall: (inputs: string) => Effect.Effect<void, WorkspaceStateError>;
309
+ readonly installStopped: Effect.Effect<void, WorkspaceStateError>;
310
+ readonly recoverInstall: (expectedRevision: number) => Effect.Effect<void, WorkspaceStateError>;
311
+ readonly finishInstall: (evidence: Installation | null, lockfile: Fingerprint) => Effect.Effect<void, WorkspaceStateError>;
312
+ }
313
+ declare const WorkspaceState_base: Context.ServiceClass<WorkspaceState, "create-next-hydra/WorkspaceState", {
314
+ readonly withRead: <A, E, R>(identity: WorkspaceIdentity, use: (observation: WorkspaceObservation) => Effect.Effect<A, E, R>, options?: {
315
+ readonly allowIncomplete: boolean;
316
+ }) => Effect.Effect<A, E | WorkspaceStateError, R>;
317
+ readonly withWrite: <A, E, R>(identity: WorkspaceIdentity, use: (access: WorkspaceWriteAccess) => Effect.Effect<A, E, R>, options?: {
318
+ readonly breakLock?: string;
319
+ }) => Effect.Effect<A, E | WorkspaceStateError, R>;
320
+ }>;
321
+ export declare class WorkspaceState extends WorkspaceState_base {
322
+ static readonly layer: Layer.Layer<WorkspaceState, never, FileSystem.FileSystem | Path.Path>;
323
+ }
324
+ export {};
325
+ //# sourceMappingURL=workspace-state.d.ts.map