zyrk 0.5.4 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -4
- package/VERSION +1 -1
- package/dist/cli/main.js +18 -2
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +9 -2
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +28 -3
- package/dist/dlx/create.d.ts +5 -2
- package/dist/dlx/create.d.ts.map +1 -1
- package/dist/dlx/create.js +9 -4
- package/dist/dlx/next.d.ts +7 -0
- package/dist/dlx/next.d.ts.map +1 -0
- package/dist/dlx/next.js +164 -0
- package/dist/dlx/run.d.ts +9 -1
- package/dist/dlx/run.d.ts.map +1 -1
- package/dist/dlx/run.js +29 -5
- package/dist/install/import-npm-workspace.d.ts.map +1 -1
- package/dist/install/import-npm-workspace.js +1 -3
- package/dist/install/import-npm.d.ts.map +1 -1
- package/dist/install/import-npm.js +10 -28
- package/dist/install/lock.d.ts.map +1 -1
- package/dist/install/lock.js +8 -6
- package/dist/install/platform.d.ts +5 -0
- package/dist/install/platform.d.ts.map +1 -0
- package/dist/install/platform.js +104 -0
- package/dist/install/run.d.ts +3 -0
- package/dist/install/run.d.ts.map +1 -1
- package/dist/install/run.js +19 -48
- package/dist/install/workspace-graph.d.ts +1 -0
- package/dist/install/workspace-graph.d.ts.map +1 -1
- package/dist/install/workspace-graph.js +12 -3
- package/dist/install/workspace-install.d.ts.map +1 -1
- package/dist/install/workspace-install.js +6 -5
- package/dist/install/workspace-lock.d.ts +1 -1
- package/dist/install/workspace-lock.d.ts.map +1 -1
- package/dist/install/workspace-lock.js +16 -1
- package/dist/lockfile/fingerprints.js +0 -1
- package/dist/lockfile/read.d.ts +1 -1
- package/dist/lockfile/read.d.ts.map +1 -1
- package/dist/lockfile/read.js +11 -1
- package/dist/lockfile/types.d.ts +1 -0
- package/dist/lockfile/types.d.ts.map +1 -1
- package/dist/lockfile/types.js +1 -0
- package/dist/lockfile/write.d.ts.map +1 -1
- package/dist/lockfile/write.js +1 -0
- package/dist/resolve/resolver.d.ts +1 -21
- package/dist/resolve/resolver.d.ts.map +1 -1
- package/dist/resolve/resolver.js +13 -1
- package/dist/util/engines.d.ts +2 -0
- package/dist/util/engines.d.ts.map +1 -0
- package/dist/util/engines.js +23 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -122,7 +122,10 @@ registry; private names never fall back to a public endpoint. Disabled TLS
|
|
|
122
122
|
verification is rejected before lookup. Git sources and non-workspace local sources remain unsupported;
|
|
123
123
|
they fail explicitly. Optional dependencies incompatible with the selected platform
|
|
124
124
|
are omitted; missing packages, integrity failures, and other optional failures
|
|
125
|
-
remain errors.
|
|
125
|
+
remain errors. Locks retain exact platform-qualified optional variants; each machine
|
|
126
|
+
selects its compatible local closure without rewriting the lock or recording store
|
|
127
|
+
paths. Older platform-pruned locks need an intentional non-frozen refresh; incomplete
|
|
128
|
+
npm locks must be freshly resolved before portable adoption. macOS, Windows, and
|
|
126
129
|
broad framework compatibility have not passed their release gates.
|
|
127
130
|
|
|
128
131
|
### Workspaces
|
|
@@ -164,9 +167,29 @@ JavaScript, shell, or native executable bin entry with the supplied arguments. I
|
|
|
164
167
|
removed afterward; verified sources and shared realizations remain in the
|
|
165
168
|
store.
|
|
166
169
|
|
|
167
|
-
`create`
|
|
168
|
-
`
|
|
169
|
-
|
|
170
|
+
`create` maps initializer names to their `create-*` packages. For example,
|
|
171
|
+
`vite` maps to `create-vite`, while a scoped initializer stays in its scope.
|
|
172
|
+
Initializers run from an independent writable private closure so copied templates
|
|
173
|
+
can be edited without modifying verified store files. The temporary closure is
|
|
174
|
+
removed afterward; generic `dlx` tools continue to use immutable shared files.
|
|
175
|
+
|
|
176
|
+
For `create next-app`, the native adapter accepts resolved create-next-app
|
|
177
|
+
15.x and 16.x releases, whose official CLI provides `--skip-install`; the real
|
|
178
|
+
scaffold check covers 16.4.2. Other versions fail before execution. zyrk passes the official `--skip-install` flag to
|
|
179
|
+
create-next-app, validates the generated project manifest, then installs its
|
|
180
|
+
dependencies through zyrk using the same store and registry configuration. An
|
|
181
|
+
explicit `--skip-install` leaves the generated project uninstalled. The official
|
|
182
|
+
flag can select create-next-app's configuration defaults instead of prompting
|
|
183
|
+
for each choice; pass its explicit configuration flags to customize them. Its
|
|
184
|
+
interactive project-name prompt remains available. Supply an explicit target
|
|
185
|
+
for nested or existing empty directories; automatic interactive discovery is
|
|
186
|
+
limited to one newly created direct child directory. If generation exits without
|
|
187
|
+
a valid manifest, zyrk reports failure and retains any generated files for review.
|
|
188
|
+
|
|
189
|
+
Other initializers control their own dependency-install step and may invoke
|
|
190
|
+
another package manager. Use their skip-install option, when available, then run
|
|
191
|
+
`zyrk install` in the generated project to keep installation native to zyrk.
|
|
192
|
+
Compatibility depends on the selected tool:
|
|
170
193
|
closures declaring install lifecycle scripts, implicit native builds, or bundled
|
|
171
194
|
install hooks are blocked. Dependency executables are available on the tool
|
|
172
195
|
PATH. Parent cancellation terminates the supervised process group with bounded
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v0.5.
|
|
1
|
+
v0.5.7
|
package/dist/cli/main.js
CHANGED
|
@@ -13,7 +13,7 @@ import { installRegistry } from "../install/registry.js";
|
|
|
13
13
|
import { readFileSync } from "node:fs";
|
|
14
14
|
import * as path from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
|
-
import { runCreate } from "../dlx/create.js";
|
|
16
|
+
import { runCreate, starterSpecFor } from "../dlx/create.js";
|
|
17
17
|
import { runDlx } from "../dlx/run.js";
|
|
18
18
|
import { runDependencyCommand, } from "../commands/dependencies.js";
|
|
19
19
|
import { runProjectCommand, } from "../commands/project.js";
|
|
@@ -610,5 +610,21 @@ async function runToolCommand(command, parsed, options, version) {
|
|
|
610
610
|
if (command === "dlx") {
|
|
611
611
|
return (await runDlx({ ...base, spec: first })).exitCode;
|
|
612
612
|
}
|
|
613
|
-
|
|
613
|
+
const isNext = starterSpecFor(first).startsWith("create-next-app@");
|
|
614
|
+
options.stderr.write(isNext
|
|
615
|
+
? tail.includes("--skip-install")
|
|
616
|
+
? "zyrk: Next scaffolding only; dependency installation was explicitly skipped.\n"
|
|
617
|
+
: "zyrk: Next scaffolder runs with --skip-install; zyrk will install dependencies.\n"
|
|
618
|
+
: "zyrk: This initializer controls its own dependency installation.\n");
|
|
619
|
+
const progress = createInstallProgress(options.stderr, false);
|
|
620
|
+
try {
|
|
621
|
+
return (await runCreate({
|
|
622
|
+
...base,
|
|
623
|
+
input: first,
|
|
624
|
+
onInstallProgress: progress.update,
|
|
625
|
+
})).exitCode;
|
|
626
|
+
}
|
|
627
|
+
finally {
|
|
628
|
+
progress.close();
|
|
629
|
+
}
|
|
614
630
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAwEA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAwEF,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAoajB"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { selectPlatformGraph, selectWorkspacePlatform, } from "../install/platform.js";
|
|
1
2
|
import { installedRegistryConfig } from "../install/registry-policy.js";
|
|
2
3
|
/** Self-contained runtime deployment and explicit local Docker commands. */
|
|
3
4
|
import { constants } from "node:fs";
|
|
@@ -179,7 +180,13 @@ export async function runDeployCommand(options) {
|
|
|
179
180
|
const installedKeys = new Set(Array.isArray(state.contexts)
|
|
180
181
|
? state.contexts.filter((v) => typeof v === "string")
|
|
181
182
|
: []);
|
|
182
|
-
const
|
|
183
|
+
const activeResolved = selectPlatformGraph({
|
|
184
|
+
...resolved,
|
|
185
|
+
roots: resolved.roots.filter((root) => installedKeys.has(root.target)),
|
|
186
|
+
}, new Set(Object.keys(object(manifest.optionalDependencies)
|
|
187
|
+
? manifest.optionalDependencies
|
|
188
|
+
: {})));
|
|
189
|
+
const installedNodes = activeResolved.nodes.filter((n) => installedKeys.has(n.key));
|
|
183
190
|
const graph = createGraphDoc(installedNodes.map((n) => ({ ...n, deps: n.edges })));
|
|
184
191
|
const directories = privateGraph
|
|
185
192
|
? await privateDirectories(project, store, graph, state)
|
|
@@ -830,7 +837,7 @@ async function exportWorkspace(options, project, manifest, state, out, parent, f
|
|
|
830
837
|
throw error("ZYRK_DEPLOY_ESCAPE", "Deployment output must be outside the managed store.");
|
|
831
838
|
const barrier = await acquireLock(path.join(store.paths.locksDir, "liveness.lock"), { name: "workspace deployment retention" });
|
|
832
839
|
try {
|
|
833
|
-
const graph = locked.graph, byKey = new Map(graph.nodes.map((n) => [n.key, n]));
|
|
840
|
+
const graph = selectWorkspacePlatform(locked.graph, undefined, true), byKey = new Map(graph.nodes.map((n) => [n.key, n]));
|
|
834
841
|
const selected = new Set();
|
|
835
842
|
const visit = (key) => {
|
|
836
843
|
if (selected.has(key))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"AA4DA,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA+LF,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAgRjB"}
|
package/dist/commands/project.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { selectPlatformGraph, selectWorkspacePlatform, } from "../install/platform.js";
|
|
1
2
|
import { discoverWorkspaces, findWorkspaceRoot, planWorkspaceDependencies, selectWorkspaceImporters, workspaceScriptOrder, } from "../install/workspaces.js";
|
|
2
3
|
import { readWorkspaceLock } from "../install/workspace-lock.js";
|
|
3
4
|
/** Project inspection and explicit execution (SPEC 12.2, 18.3.1, D-1). */
|
|
@@ -48,6 +49,7 @@ function validateState(raw) {
|
|
|
48
49
|
(raw.linker !== undefined &&
|
|
49
50
|
raw.linker !== "private" &&
|
|
50
51
|
raw.linker !== "shared") ||
|
|
52
|
+
(raw.omitDev !== undefined && typeof raw.omitDev !== "boolean") ||
|
|
51
53
|
!Array.isArray(raw.direct) ||
|
|
52
54
|
raw.direct.some((e) => !object(e) ||
|
|
53
55
|
typeof e.name !== "string" ||
|
|
@@ -67,7 +69,8 @@ async function load(project) {
|
|
|
67
69
|
state.lockDigest !== sha512Hex(canonicalJson(locked.doc)))
|
|
68
70
|
throw fail("ZYRK_LOCK_MISMATCH", "The workspace manifests, authoritative lock and installed generation disagree.");
|
|
69
71
|
const importer = workspace.importers.find((item) => item.directory === project);
|
|
70
|
-
const
|
|
72
|
+
const activeGraph = selectWorkspacePlatform(locked.graph, undefined, state.omitDev);
|
|
73
|
+
const own = activeGraph.nodes.find((node) => node.kind === "local" && node.importer === importer?.id);
|
|
71
74
|
if (!own)
|
|
72
75
|
throw fail("ZYRK_LOCK_MISMATCH", "The selected workspace importer is absent from the authoritative graph.");
|
|
73
76
|
return {
|
|
@@ -77,7 +80,7 @@ async function load(project) {
|
|
|
77
80
|
roots: {
|
|
78
81
|
".": Object.fromEntries(own.edges.map((edge) => [edge.name, edge.target])),
|
|
79
82
|
},
|
|
80
|
-
nodes: Object.fromEntries(
|
|
83
|
+
nodes: Object.fromEntries(activeGraph.nodes.map((node) => [
|
|
81
84
|
node.key,
|
|
82
85
|
{
|
|
83
86
|
name: node.name,
|
|
@@ -103,7 +106,29 @@ async function load(project) {
|
|
|
103
106
|
if (sha512Hex(canonicalJson(doc)) !== state.lockDigest ||
|
|
104
107
|
doc.zyrk === undefined)
|
|
105
108
|
throw fail("ZYRK_LOCK_MISMATCH", "The installed generation and package-lock.json disagree.");
|
|
106
|
-
|
|
109
|
+
const graph = selectPlatformGraph({
|
|
110
|
+
...lockedGraph(doc),
|
|
111
|
+
roots: lockedGraph(doc).roots.filter((root) => state.direct.some((entry) => entry.name === root.name)),
|
|
112
|
+
}, new Set(Object.keys(object(doc.packages?.[""]?.optionalDependencies)
|
|
113
|
+
? doc.packages[""].optionalDependencies
|
|
114
|
+
: {})));
|
|
115
|
+
return {
|
|
116
|
+
state,
|
|
117
|
+
extension: {
|
|
118
|
+
...doc.zyrk,
|
|
119
|
+
roots: {
|
|
120
|
+
".": Object.fromEntries(graph.roots.map((root) => [root.name, root.target])),
|
|
121
|
+
},
|
|
122
|
+
nodes: Object.fromEntries(graph.nodes.map((node) => [
|
|
123
|
+
node.key,
|
|
124
|
+
{
|
|
125
|
+
...doc.zyrk.nodes[node.key],
|
|
126
|
+
edges: Object.fromEntries(node.edges.map((edge) => [edge.name, edge.target])),
|
|
127
|
+
peers: Object.fromEntries(node.peerBindings.map((peer) => [peer.name, peer.target])),
|
|
128
|
+
},
|
|
129
|
+
])),
|
|
130
|
+
},
|
|
131
|
+
};
|
|
107
132
|
}
|
|
108
133
|
function emit(options, result, human) {
|
|
109
134
|
options.stdout.write(options.json
|
package/dist/dlx/create.d.ts
CHANGED
|
@@ -5,13 +5,16 @@
|
|
|
5
5
|
* `init` command): `foo` runs `create-foo`, `@scope/bar` runs
|
|
6
6
|
* `@scope/create-bar`, and a bare `@scope` runs `@scope/create`, each with
|
|
7
7
|
* the requested version or `*` when none was given. An already-prefixed
|
|
8
|
-
* `create-foo` is used as-is.
|
|
9
|
-
*
|
|
8
|
+
* `create-foo` is used as-is. Initializers use writable private temporary
|
|
9
|
+
* closures; trust policy and cleanup match dlx. The Next adapter installs
|
|
10
|
+
* generated dependencies natively after the initializer's skip-install step.
|
|
10
11
|
*/
|
|
12
|
+
import type { InstallOptions } from "../install/run.ts";
|
|
11
13
|
import { type DlxOptions, type DlxResult } from "./run.ts";
|
|
12
14
|
export type CreateOptions = Omit<DlxOptions, "spec"> & {
|
|
13
15
|
/** Initializer as typed: `next-app`, `vite@^5`, `@scope`, `@scope/kit@beta`. */
|
|
14
16
|
input: string;
|
|
17
|
+
onInstallProgress?: InstallOptions["onProgress"];
|
|
15
18
|
};
|
|
16
19
|
/**
|
|
17
20
|
* Map an initializer to its starter package specifier. Throws ZYRK_USAGE
|
package/dist/dlx/create.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/dlx/create.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/dlx/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAkB,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAE3E,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG;IACrD,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;CAClD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA6BpD;AAWD,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,CAM1E"}
|
package/dist/dlx/create.js
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
* `init` command): `foo` runs `create-foo`, `@scope/bar` runs
|
|
6
6
|
* `@scope/create-bar`, and a bare `@scope` runs `@scope/create`, each with
|
|
7
7
|
* the requested version or `*` when none was given. An already-prefixed
|
|
8
|
-
* `create-foo` is used as-is.
|
|
9
|
-
*
|
|
8
|
+
* `create-foo` is used as-is. Initializers use writable private temporary
|
|
9
|
+
* closures; trust policy and cleanup match dlx. The Next adapter installs
|
|
10
|
+
* generated dependencies natively after the initializer's skip-install step.
|
|
10
11
|
*/
|
|
12
|
+
import { runNextInitializer } from "./next.js";
|
|
11
13
|
import npa from "npm-package-arg";
|
|
12
14
|
import { ZyrkError } from "../errors.js";
|
|
13
|
-
import {
|
|
15
|
+
import { runInitializer } from "./run.js";
|
|
14
16
|
/**
|
|
15
17
|
* Map an initializer to its starter package specifier. Throws ZYRK_USAGE
|
|
16
18
|
* for non-registry inputs (Git/hosted initializers are deferred along with
|
|
@@ -55,5 +57,8 @@ function usage(input, cause) {
|
|
|
55
57
|
}
|
|
56
58
|
export async function runCreate(options) {
|
|
57
59
|
const { input, ...rest } = options;
|
|
58
|
-
|
|
60
|
+
const spec = starterSpecFor(input);
|
|
61
|
+
return spec.startsWith("create-next-app@")
|
|
62
|
+
? runNextInitializer({ ...rest, spec })
|
|
63
|
+
: runInitializer({ ...rest, spec });
|
|
59
64
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type InstallOptions } from "../install/run.ts";
|
|
2
|
+
import { type DlxOptions, type DlxResult } from "./run.ts";
|
|
3
|
+
export declare function nextTarget(args: readonly string[]): string | undefined;
|
|
4
|
+
export declare function runNextInitializer(options: DlxOptions & {
|
|
5
|
+
onInstallProgress?: InstallOptions["onProgress"];
|
|
6
|
+
}): Promise<DlxResult>;
|
|
7
|
+
//# sourceMappingURL=next.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../src/dlx/next.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAkB,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAuC3E,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAEtE;AA4CD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,GAAG;IAAE,iBAAiB,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;CAAE,GACzE,OAAO,CAAC,SAAS,CAAC,CAkGpB"}
|
package/dist/dlx/next.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/** create-next-app's documented --skip-install keeps installation native.
|
|
2
|
+
* Target validation prevents a successful-but-aborted initializer from making
|
|
3
|
+
* zyrk install an unrelated project. No generated files are deleted on failure.
|
|
4
|
+
*/
|
|
5
|
+
import { lstat, readFile, readdir } from "node:fs/promises";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { satisfies } from "semver";
|
|
8
|
+
import { ZyrkError } from "../errors.js";
|
|
9
|
+
import { installProject } from "../install/run.js";
|
|
10
|
+
import { isErrno } from "../util/fsx.js";
|
|
11
|
+
import { runInitializer } from "./run.js";
|
|
12
|
+
function failed(message) {
|
|
13
|
+
return new ZyrkError("ZYRK_RESOLUTION_FAILED", message, {
|
|
14
|
+
remedy: "Check the generated project, then run zyrk install there; rerun create with an explicit project directory when needed.",
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/** Value-bearing options from the official create-next-app CLI. All original
|
|
18
|
+
* arguments are still forwarded verbatim; these only locate the target. */
|
|
19
|
+
function parseNextArgs(args) {
|
|
20
|
+
const values = new Set([
|
|
21
|
+
"--import-alias",
|
|
22
|
+
"--example",
|
|
23
|
+
"-e",
|
|
24
|
+
"--example-path",
|
|
25
|
+
]);
|
|
26
|
+
const flags = new Set();
|
|
27
|
+
let target;
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
const arg = args[i];
|
|
30
|
+
if (arg === "--") {
|
|
31
|
+
target ??= args[i + 1]?.trim();
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (values.has(arg)) {
|
|
35
|
+
i++;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (arg.startsWith("-"))
|
|
39
|
+
flags.add(arg);
|
|
40
|
+
else
|
|
41
|
+
target ??= arg.trim();
|
|
42
|
+
}
|
|
43
|
+
return { target, flags };
|
|
44
|
+
}
|
|
45
|
+
export function nextTarget(args) {
|
|
46
|
+
return parseNextArgs(args).target;
|
|
47
|
+
}
|
|
48
|
+
async function info(file) {
|
|
49
|
+
try {
|
|
50
|
+
return await lstat(file);
|
|
51
|
+
}
|
|
52
|
+
catch (cause) {
|
|
53
|
+
if (isErrno(cause, "ENOENT"))
|
|
54
|
+
return undefined;
|
|
55
|
+
throw cause;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function manifestExists(directory) {
|
|
59
|
+
return (await info(path.join(directory, "package.json"))) !== undefined;
|
|
60
|
+
}
|
|
61
|
+
async function verifyManifest(directory) {
|
|
62
|
+
const file = path.join(directory, "package.json");
|
|
63
|
+
const entry = await info(file);
|
|
64
|
+
if (!entry?.isFile() || entry.isSymbolicLink())
|
|
65
|
+
throw failed("Next initializer did not generate a regular project manifest.");
|
|
66
|
+
let raw;
|
|
67
|
+
try {
|
|
68
|
+
raw = JSON.parse(await readFile(file, "utf8"));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
throw failed("Next initializer generated an unreadable project manifest.");
|
|
72
|
+
}
|
|
73
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
74
|
+
throw failed("Next initializer generated an invalid project manifest.");
|
|
75
|
+
const manifest = raw;
|
|
76
|
+
const deps = manifest.dependencies;
|
|
77
|
+
if (typeof manifest.name !== "string" ||
|
|
78
|
+
!manifest.name ||
|
|
79
|
+
typeof deps !== "object" ||
|
|
80
|
+
deps === null ||
|
|
81
|
+
Array.isArray(deps) ||
|
|
82
|
+
typeof deps.next !== "string" ||
|
|
83
|
+
!deps.next)
|
|
84
|
+
throw failed("Next initializer did not generate a Next project manifest.");
|
|
85
|
+
}
|
|
86
|
+
export async function runNextInitializer(options) {
|
|
87
|
+
const args = options.args ?? [];
|
|
88
|
+
const { target, flags } = parseNextArgs(args);
|
|
89
|
+
// Help/version/reset are valid successful commands that generate no app.
|
|
90
|
+
if ([...flags].some((arg) => [
|
|
91
|
+
"--help",
|
|
92
|
+
"-h",
|
|
93
|
+
"--version",
|
|
94
|
+
"-v",
|
|
95
|
+
"--reset",
|
|
96
|
+
"--reset-preferences",
|
|
97
|
+
].includes(arg)))
|
|
98
|
+
return runInitializer(options);
|
|
99
|
+
const cwd = options.cwd ?? process.cwd();
|
|
100
|
+
const explicit = target === undefined ? undefined : path.resolve(cwd, target);
|
|
101
|
+
const before = explicit === undefined ? undefined : await info(explicit);
|
|
102
|
+
if (before !== undefined &&
|
|
103
|
+
(!before.isDirectory() || before.isSymbolicLink()))
|
|
104
|
+
throw failed("Next initializer target must be a real project directory.");
|
|
105
|
+
if (explicit !== undefined && (await manifestExists(explicit)))
|
|
106
|
+
throw failed("Next initializer target already has a project manifest.");
|
|
107
|
+
const entries = explicit === undefined ? new Set(await readdir(cwd)) : undefined;
|
|
108
|
+
const skipInstall = flags.has("--skip-install");
|
|
109
|
+
// Insert before -- so it remains an option when the user supplies a literal target.
|
|
110
|
+
const forwarded = [...args];
|
|
111
|
+
if (!skipInstall) {
|
|
112
|
+
const separator = forwarded.indexOf("--");
|
|
113
|
+
forwarded.splice(separator < 0 ? forwarded.length : separator, 0, "--skip-install");
|
|
114
|
+
}
|
|
115
|
+
const result = await runInitializer({
|
|
116
|
+
...options,
|
|
117
|
+
args: forwarded,
|
|
118
|
+
validateTool(tool) {
|
|
119
|
+
options.validateTool?.(tool);
|
|
120
|
+
if (!satisfies(tool.version, ">=15.0.0 <17.0.0"))
|
|
121
|
+
throw new ZyrkError("ZYRK_RESOLUTION_FAILED", "The resolved Next initializer version has no verified skip-install adapter.", {
|
|
122
|
+
detail: { name: tool.name, version: tool.version },
|
|
123
|
+
remedy: "Select create-next-app 15.x or 16.x; the native create adapter requires the verified --skip-install contract.",
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
if (result.exitCode !== 0)
|
|
128
|
+
return result;
|
|
129
|
+
let directory = explicit;
|
|
130
|
+
if (directory === undefined) {
|
|
131
|
+
const generated = [];
|
|
132
|
+
for (const entry of await readdir(cwd)) {
|
|
133
|
+
if (entries.has(entry))
|
|
134
|
+
continue;
|
|
135
|
+
const candidate = path.join(cwd, entry);
|
|
136
|
+
const current = await info(candidate);
|
|
137
|
+
if (current?.isDirectory() &&
|
|
138
|
+
!current.isSymbolicLink() &&
|
|
139
|
+
(await manifestExists(candidate)))
|
|
140
|
+
generated.push(candidate);
|
|
141
|
+
}
|
|
142
|
+
if (generated.length !== 1)
|
|
143
|
+
throw failed("Cannot identify one generated Next project after the initializer exited.");
|
|
144
|
+
directory = generated[0];
|
|
145
|
+
}
|
|
146
|
+
const after = await info(directory);
|
|
147
|
+
if (!after?.isDirectory() ||
|
|
148
|
+
after.isSymbolicLink() ||
|
|
149
|
+
(before !== undefined &&
|
|
150
|
+
(before.dev !== after.dev || before.ino !== after.ino)))
|
|
151
|
+
throw failed("Next initializer did not preserve its project directory.");
|
|
152
|
+
await verifyManifest(directory);
|
|
153
|
+
if (!skipInstall)
|
|
154
|
+
await installProject({
|
|
155
|
+
projectDir: directory,
|
|
156
|
+
store: options.store,
|
|
157
|
+
registry: options.registry,
|
|
158
|
+
...(options.env === undefined ? {} : { env: options.env }),
|
|
159
|
+
...(options.onInstallProgress === undefined
|
|
160
|
+
? {}
|
|
161
|
+
: { onProgress: options.onInstallProgress }),
|
|
162
|
+
});
|
|
163
|
+
return result;
|
|
164
|
+
}
|
package/dist/dlx/run.d.ts
CHANGED
|
@@ -31,13 +31,18 @@ export type DlxOptions = {
|
|
|
31
31
|
/** Capture stdio instead of inheriting it (used by tests). */
|
|
32
32
|
capture?: boolean;
|
|
33
33
|
logger?: Logger;
|
|
34
|
+
/** Adapter contract checked against the exact resolved tool before execution. */
|
|
35
|
+
validateTool?: (tool: {
|
|
36
|
+
name: string;
|
|
37
|
+
version: string;
|
|
38
|
+
}) => void;
|
|
34
39
|
};
|
|
35
40
|
export type DlxResult = {
|
|
36
41
|
exitCode: number;
|
|
37
42
|
key: string;
|
|
38
43
|
name: string;
|
|
39
44
|
version: string;
|
|
40
|
-
/** True when every needed realization already existed. */
|
|
45
|
+
/** True when every needed shared realization already existed. */
|
|
41
46
|
reused: boolean;
|
|
42
47
|
stdout: string;
|
|
43
48
|
stderr: string;
|
|
@@ -50,4 +55,7 @@ export declare function splitDlxSpec(spec: string): {
|
|
|
50
55
|
versionSpec: string;
|
|
51
56
|
};
|
|
52
57
|
export declare function runDlx(options: DlxOptions): Promise<DlxResult>;
|
|
58
|
+
/** Initializers copy and rewrite their shipped templates, so their full
|
|
59
|
+
* closure must use independent writable files (I-001, I-002, F-017). */
|
|
60
|
+
export declare function runInitializer(options: DlxOptions): Promise<DlxResult>;
|
|
53
61
|
//# sourceMappingURL=run.d.ts.map
|
package/dist/dlx/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/dlx/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/dlx/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAgBhD,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAqBA;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAEpE;AAED;wEACwE;AACxE,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAE5E"}
|
package/dist/dlx/run.js
CHANGED
|
@@ -29,6 +29,8 @@ import { currentProcessIdentity, superviseChild } from "../util/proc.js";
|
|
|
29
29
|
import { acquireLock } from "../util/locks.js";
|
|
30
30
|
import { registerGeneration } from "../install/metadata.js";
|
|
31
31
|
import { openStoreDb } from "../store/db.js";
|
|
32
|
+
import { installBudgets } from "../install/budgets.js";
|
|
33
|
+
import { materializePrivate } from "../install/private.js";
|
|
32
34
|
import { randomId } from "../util/ids.js";
|
|
33
35
|
/** Split a tool specifier into its edge name and version part. */
|
|
34
36
|
export function splitDlxSpec(spec) {
|
|
@@ -53,6 +55,14 @@ export function splitDlxSpec(spec) {
|
|
|
53
55
|
return { name: parsed.name, versionSpec: spec.slice(parsed.name.length + 1) };
|
|
54
56
|
}
|
|
55
57
|
export async function runDlx(options) {
|
|
58
|
+
return runTemporaryTool(options, false);
|
|
59
|
+
}
|
|
60
|
+
/** Initializers copy and rewrite their shipped templates, so their full
|
|
61
|
+
* closure must use independent writable files (I-001, I-002, F-017). */
|
|
62
|
+
export async function runInitializer(options) {
|
|
63
|
+
return runTemporaryTool(options, true);
|
|
64
|
+
}
|
|
65
|
+
async function runTemporaryTool(options, writable) {
|
|
56
66
|
const { store, registry } = options;
|
|
57
67
|
const args = options.args ?? [];
|
|
58
68
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -60,6 +70,7 @@ export async function runDlx(options) {
|
|
|
60
70
|
const split = splitDlxSpec(options.spec);
|
|
61
71
|
const resolved = await resolveRequirements({
|
|
62
72
|
provider: registry,
|
|
73
|
+
limits: installBudgets(env).resolveBudget,
|
|
63
74
|
requirements: [{ name: split.name, spec: split.versionSpec }],
|
|
64
75
|
});
|
|
65
76
|
const root = resolved.roots.find((entry) => entry.name === split.name);
|
|
@@ -69,10 +80,12 @@ export async function runDlx(options) {
|
|
|
69
80
|
const tool = byKey.get(root.target);
|
|
70
81
|
if (tool === undefined)
|
|
71
82
|
throw internal(`resolution lost node ${root.target}`);
|
|
83
|
+
options.validateTool?.({ name: tool.name, version: tool.version });
|
|
72
84
|
// Retain the publication/GC barrier until the child and temporary projection
|
|
73
85
|
// are gone. The durable lease additionally protects recovery after a crash.
|
|
74
86
|
const barrier = await acquireLock(path.join(store.paths.locksDir, "liveness.lock"), { name: "temporary tool liveness" });
|
|
75
87
|
let txn;
|
|
88
|
+
let envDir;
|
|
76
89
|
try {
|
|
77
90
|
txn = await Transaction.begin(store, "dlx");
|
|
78
91
|
await txn.setState("fetching");
|
|
@@ -109,17 +122,27 @@ export async function runDlx(options) {
|
|
|
109
122
|
target: edge.target,
|
|
110
123
|
})),
|
|
111
124
|
})));
|
|
112
|
-
const
|
|
125
|
+
const sharedRealized = await realizeGraph({
|
|
113
126
|
store,
|
|
114
127
|
graph,
|
|
115
128
|
...(options.logger === undefined ? {} : { logger: options.logger }),
|
|
116
129
|
});
|
|
117
130
|
await txn.setState("realizations-ready");
|
|
131
|
+
await assertNoInstallScripts(sharedRealized.packageDirByKey, byKey);
|
|
132
|
+
envDir = await mkdtemp(path.join(os.tmpdir(), "zyrk-dlx-"));
|
|
133
|
+
const generationId = randomId("gen1_");
|
|
134
|
+
const realized = writable
|
|
135
|
+
? await materializePrivate({
|
|
136
|
+
project: envDir,
|
|
137
|
+
store,
|
|
138
|
+
graph,
|
|
139
|
+
generationId,
|
|
140
|
+
})
|
|
141
|
+
: sharedRealized;
|
|
118
142
|
const toolRealization = realized.realizationDirByKey.get(tool.key);
|
|
119
143
|
if (toolRealization === undefined)
|
|
120
144
|
throw internal(`missing realization for ${tool.key}`);
|
|
121
145
|
const toolPkgDir = packageDirIn(toolRealization, tool.name);
|
|
122
|
-
await assertNoInstallScripts(realized.packageDirByKey, byKey);
|
|
123
146
|
const binKey = selectBin(tool, options.binName);
|
|
124
147
|
const binTarget = tool.bin[binKey];
|
|
125
148
|
if (binTarget === undefined)
|
|
@@ -139,8 +162,6 @@ export async function runDlx(options) {
|
|
|
139
162
|
bins[name] = await resolveBinScript(directory, dependency, name, target);
|
|
140
163
|
}
|
|
141
164
|
}
|
|
142
|
-
const envDir = await mkdtemp(path.join(os.tmpdir(), "zyrk-dlx-"));
|
|
143
|
-
const generationId = randomId("gen1_");
|
|
144
165
|
const projectId = randomId("proj1_");
|
|
145
166
|
const leaseId = randomId("lease1_");
|
|
146
167
|
let registered = false;
|
|
@@ -152,6 +173,7 @@ export async function runDlx(options) {
|
|
|
152
173
|
generationId,
|
|
153
174
|
graph,
|
|
154
175
|
realized,
|
|
176
|
+
sharedRealized,
|
|
155
177
|
roots: [tool.key],
|
|
156
178
|
readiness: "ready",
|
|
157
179
|
});
|
|
@@ -185,7 +207,7 @@ export async function runDlx(options) {
|
|
|
185
207
|
key: tool.key,
|
|
186
208
|
name: tool.name,
|
|
187
209
|
version: tool.version,
|
|
188
|
-
reused:
|
|
210
|
+
reused: sharedRealized.created.length === 0,
|
|
189
211
|
envDir,
|
|
190
212
|
};
|
|
191
213
|
}
|
|
@@ -206,6 +228,8 @@ export async function runDlx(options) {
|
|
|
206
228
|
}
|
|
207
229
|
finally {
|
|
208
230
|
try {
|
|
231
|
+
if (envDir !== undefined)
|
|
232
|
+
await rmrfNoFollow(envDir);
|
|
209
233
|
await txn?.finish();
|
|
210
234
|
}
|
|
211
235
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-npm-workspace.d.ts","sourceRoot":"","sources":["../../src/install/import-npm-workspace.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"import-npm-workspace.d.ts","sourceRoot":"","sources":["../../src/install/import-npm-workspace.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,sBAAsB,CAAC;AA6V9B,oEAAoE;AACpE,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,GAC1C,cAAc,CAWhB"}
|
|
@@ -8,7 +8,6 @@ import { canonicalJson } from "../util/json.js";
|
|
|
8
8
|
import { importNpmLock } from "./import-npm.js";
|
|
9
9
|
import { lockMismatch, cleanUrl } from "./lock.js";
|
|
10
10
|
import { ZyrkError } from "../errors.js";
|
|
11
|
-
import { assertWorkspacePlatform } from "./workspace-graph.js";
|
|
12
11
|
function importNpmWorkspaceLockPass(doc, project, origin, overrideState) {
|
|
13
12
|
if (!doc ||
|
|
14
13
|
typeof doc !== "object" ||
|
|
@@ -173,7 +172,6 @@ function importNpmWorkspaceLockPass(doc, project, origin, overrideState) {
|
|
|
173
172
|
peers: {},
|
|
174
173
|
optionalPeers: [],
|
|
175
174
|
};
|
|
176
|
-
assertWorkspacePlatform({ nodes: [node], importers: {}, omissions: [] });
|
|
177
175
|
graph.nodes.push(node);
|
|
178
176
|
locations.set(contextKey, node);
|
|
179
177
|
contexts.set(node.key, selectedOverride.context);
|
|
@@ -230,7 +228,7 @@ function importNpmWorkspaceLockPass(doc, project, origin, overrideState) {
|
|
|
230
228
|
continue;
|
|
231
229
|
}
|
|
232
230
|
if (requirement.kind === "optional")
|
|
233
|
-
|
|
231
|
+
throw lockMismatch("npm workspace lock lacks an exact optional selection; restore a complete npm lock or intentionally resolve fresh without the pruned lock");
|
|
234
232
|
throw lockMismatch("npm workspace lock is missing a required selection");
|
|
235
233
|
}
|
|
236
234
|
let target;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import-npm.d.ts","sourceRoot":"","sources":["../../src/install/import-npm.ts"],"names":[],"mappings":"AACA,qFAAqF;AACrF,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAKhC,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,EAC3C,SAAS,GAAE,cAAwC,GAClD,cAAc,CAkLhB"}
|