zyrk 0.6.8 → 0.7.2
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 +39 -10
- package/VERSION +1 -1
- package/bin/zyrk.js +1 -0
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +89 -1
- package/dist/commands/dependencies.d.ts +1 -0
- package/dist/commands/dependencies.d.ts.map +1 -1
- package/dist/commands/dependencies.js +3 -0
- package/dist/install/platform.d.ts +4 -0
- package/dist/install/platform.d.ts.map +1 -1
- package/dist/install/platform.js +11 -0
- package/dist/install/private.d.ts +9 -0
- package/dist/install/private.d.ts.map +1 -1
- package/dist/install/private.js +71 -14
- package/dist/install/run.d.ts +1 -0
- package/dist/install/run.d.ts.map +1 -1
- package/dist/install/run.js +37 -10
- package/dist/install/workspace-install.d.ts.map +1 -1
- package/dist/install/workspace-install.js +35 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,8 +104,12 @@ Offline installs use locked verified sources and fail if an input is missing.
|
|
|
104
104
|
Manifest, lock, and projection changes are journaled for process-crash recovery;
|
|
105
105
|
a failed resolution, verification, or build-policy check keeps the prior graph.
|
|
106
106
|
|
|
107
|
-
Dependency install
|
|
108
|
-
|
|
107
|
+
Dependency `preinstall`, `install`, and `postinstall` scripts (plus implicit
|
|
108
|
+
`binding.gyp` builds) are supported. In an interactive terminal, `zyrk install`
|
|
109
|
+
shows the exact candidates and lets you select which scripts to run. Press Enter
|
|
110
|
+
to skip all pending scripts and continue with an intentionally unbuilt install.
|
|
111
|
+
Headless installs also skip unapproved scripts and report that readiness state.
|
|
112
|
+
Review candidates separately with:
|
|
109
113
|
|
|
110
114
|
```bash
|
|
111
115
|
zyrk approve-builds # inspect exact sources and commands; executes no package code
|
|
@@ -115,8 +119,12 @@ zyrk rebuild --offline # rebuild the complete approved locked graph
|
|
|
115
119
|
```
|
|
116
120
|
|
|
117
121
|
Approvals are local to the exact graph, sources, patch contents, and script
|
|
118
|
-
policy.
|
|
119
|
-
|
|
122
|
+
policy. Interactive selections are written to the checked-in
|
|
123
|
+
`zyrk-workspace.json` file with exact package source identities, so collaborators
|
|
124
|
+
can reuse the review alongside the lockfile. Manual `zyrk approve-builds
|
|
125
|
+
<package>` approvals are recorded there too. Mandatory user denies override
|
|
126
|
+
project approvals. Approved scripts run with your account's permissions;
|
|
127
|
+
permission is not a sandbox. Packages that need
|
|
120
128
|
writes use a complete private dependency generation under `.zyrk-local/`, with
|
|
121
129
|
independent writable files and dependency links confined to that generation.
|
|
122
130
|
Build failure keeps the previous project graph active. `--ignore-scripts`
|
|
@@ -125,6 +133,24 @@ hooks never run automatically. A project can request runtime writable packages
|
|
|
125
133
|
with `"zyrk": { "mutablePackages": ["package-name"] }`; this also uses a complete
|
|
126
134
|
private graph.
|
|
127
135
|
|
|
136
|
+
`zyrk-workspace.json` is portable review state, not a machine-specific store
|
|
137
|
+
manifest. It records each approved package name, version, and exact source ID;
|
|
138
|
+
the file can be committed with `package-lock.json` so collaborators do not have
|
|
139
|
+
to repeat the same approval for the same verified source. User-level denials
|
|
140
|
+
still take precedence.
|
|
141
|
+
|
|
142
|
+
### Run project scripts
|
|
143
|
+
|
|
144
|
+
Use `zyrk run <script>` or the package-manager shortcut `zyrk <script>`; both
|
|
145
|
+
use the same project-script policy, installed-generation checks, and local
|
|
146
|
+
binary path. Arguments after `--` are passed to the script:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
zyrk dev
|
|
150
|
+
zyrk test -- --watch
|
|
151
|
+
zyrk run build
|
|
152
|
+
```
|
|
153
|
+
|
|
128
154
|
Default registry and authentication settings are loaded from user/project
|
|
129
155
|
`.npmrc` for installation, dependency edits, `dlx`, and `create`. Environment
|
|
130
156
|
token placeholders are supported. Credentials are restricted to their configured
|
|
@@ -136,7 +162,10 @@ registry; private names never fall back to a public endpoint. Disabled TLS
|
|
|
136
162
|
verification is rejected before lookup. Git sources and non-workspace local sources remain unsupported;
|
|
137
163
|
they fail explicitly. Optional dependencies incompatible with the selected platform
|
|
138
164
|
are omitted; missing packages, integrity failures, and other optional failures
|
|
139
|
-
remain errors.
|
|
165
|
+
remain errors. Platform-specific optional packages that do not match this machine
|
|
166
|
+
are summarized once after installation; these are normal variants for packages
|
|
167
|
+
supporting multiple operating systems and CPUs. Locks retain exact
|
|
168
|
+
platform-qualified optional variants; each machine
|
|
140
169
|
selects its compatible local closure without rewriting the lock or recording store
|
|
141
170
|
paths. Older platform-pruned locks need an intentional non-frozen refresh; incomplete
|
|
142
171
|
npm locks must be freshly resolved before portable adoption. macOS, Windows, and
|
|
@@ -396,11 +425,11 @@ The commit hook runs the full check gate, increments the version in
|
|
|
396
425
|
`package.json`, `package-lock.json`, and `VERSION`, and creates a matching version
|
|
397
426
|
tag after the commit. Keep changes focused and never bypass the hooks.
|
|
398
427
|
|
|
399
|
-
CI checks pushed commits and pull requests. The
|
|
400
|
-
[npm publishing action](.github/workflows/npm-publish.yml)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
publish
|
|
428
|
+
CI checks pushed commits and pull requests. The
|
|
429
|
+
[npm publishing action](.github/workflows/npm-publish.yml) runs when the commit
|
|
430
|
+
hook's version tag is pushed, verifies formatting, typecheck, build, tests, and
|
|
431
|
+
the tag/version match, then publishes that exact commit. A manual workflow
|
|
432
|
+
dispatch can publish a prior version tag for release backfills. Dependabot and a scheduled advisory check supplement CI; an
|
|
404
433
|
unavailable advisory service fails separately from a clean result.
|
|
405
434
|
|
|
406
435
|
The contributor guide is [AGENTS.md](AGENTS.md). Bug reports and reproducible
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v0.
|
|
1
|
+
v0.7.2
|
package/bin/zyrk.js
CHANGED
package/dist/cli/main.d.ts
CHANGED
package/dist/cli/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAe,SAAS,EAAe,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,OAAO,EAAoB,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAM3C,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhF,eAAO,MAAM,uBAAuB,IAAI,CAAC;AA6DzC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0BhD;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA6EF;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,GACnD,SAAS,CAgDX;AAmBD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAC1B,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC3D,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;CACxC,CAAC;AAuDF,gFAAgF;AAChF,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA2fpE"}
|
package/dist/cli/main.js
CHANGED
|
@@ -12,6 +12,8 @@ import { sanitizeDiagnostic, redactSecrets } from "../log.js";
|
|
|
12
12
|
import { installProject } from "../install/run.js";
|
|
13
13
|
import { installRegistry } from "../install/registry.js";
|
|
14
14
|
import { readFileSync } from "node:fs";
|
|
15
|
+
import { readFile } from "node:fs/promises";
|
|
16
|
+
import { createInterface } from "node:readline/promises";
|
|
15
17
|
import * as path from "node:path";
|
|
16
18
|
import { fileURLToPath } from "node:url";
|
|
17
19
|
import { runCreate, starterSpecFor } from "../dlx/create.js";
|
|
@@ -22,7 +24,7 @@ import { runStoreCommand } from "../commands/store.js";
|
|
|
22
24
|
import { exitCodeFor, ZyrkError, toZyrkError } from "../errors.js";
|
|
23
25
|
export { ZyrkError };
|
|
24
26
|
import { DEFAULT_REGISTRY, RegistryClient } from "../fetch/registry.js";
|
|
25
|
-
import { resolveStoreRoot } from "../config/paths.js";
|
|
27
|
+
import { findProjectBoundary, resolveStoreRoot } from "../config/paths.js";
|
|
26
28
|
import { Store } from "../store/layout.js";
|
|
27
29
|
import { delegateToNpm, delegatedHelpLines, isDelegatedCommand, } from "./npm-delegate.js";
|
|
28
30
|
import { isGlobalInstallRequest, parseArgs } from "./parse.js";
|
|
@@ -89,6 +91,7 @@ export function helpText(version) {
|
|
|
89
91
|
`zyrk v${version} — one verified store per user, shared across projects through links.`,
|
|
90
92
|
"",
|
|
91
93
|
"Usage: zyrk <command> [args] [--json]",
|
|
94
|
+
" zyrk <script> [args] (shortcut for zyrk run <script> [args])",
|
|
92
95
|
"",
|
|
93
96
|
"Dependency commands:",
|
|
94
97
|
];
|
|
@@ -212,6 +215,39 @@ function readCliVersion() {
|
|
|
212
215
|
return "unknown";
|
|
213
216
|
}
|
|
214
217
|
}
|
|
218
|
+
async function promptForBuildApproval(builds, input, output) {
|
|
219
|
+
output.write("\nDependency lifecycle scripts need approval. Review these exact package sources:\n");
|
|
220
|
+
builds.forEach((build, index) => {
|
|
221
|
+
const stages = build.stages
|
|
222
|
+
.map((stage) => `${stage.name}: ${redactSecrets(stage.command)
|
|
223
|
+
.replace(/[\x00-\x1f\x7f-\x9f]/g, "")
|
|
224
|
+
.slice(0, 180)}`)
|
|
225
|
+
.join("; ");
|
|
226
|
+
output.write(` ${index + 1}. ${build.name}@${build.version} (${build.sourceId}) — ${stages}\n`);
|
|
227
|
+
});
|
|
228
|
+
output.write("Enter numbers separated by commas to approve selected sources, `all` to approve all listed sources, or press Enter to skip their scripts and continue unbuilt.\n");
|
|
229
|
+
const prompt = createInterface({
|
|
230
|
+
input,
|
|
231
|
+
output: output,
|
|
232
|
+
terminal: true,
|
|
233
|
+
});
|
|
234
|
+
try {
|
|
235
|
+
const answer = (await prompt.question("Approve builds> ")).trim();
|
|
236
|
+
if (!answer)
|
|
237
|
+
return [];
|
|
238
|
+
if (answer.toLowerCase() === "all")
|
|
239
|
+
return ["*"];
|
|
240
|
+
const numbers = answer.split(/[ ,]+/).map((value) => Number(value));
|
|
241
|
+
if (numbers.some((number) => !Number.isInteger(number) || number < 1 || number > builds.length))
|
|
242
|
+
throw new ZyrkError("ZYRK_USAGE", "Build selection contains an invalid candidate number.", {
|
|
243
|
+
remedy: `Select numbers from 1 to ${builds.length}, enter all, or press Enter to skip scripts.`,
|
|
244
|
+
});
|
|
245
|
+
return [...new Set(numbers)].map((number) => builds[number - 1].sourceId);
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
prompt.close();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
215
251
|
/** Parse, dispatch, delegate, or run a tool, and emit. The only impure seam. */
|
|
216
252
|
export async function runCli(options) {
|
|
217
253
|
const parsed = parseArgs(options.argv);
|
|
@@ -464,6 +500,11 @@ export async function runCli(options) {
|
|
|
464
500
|
env: options.env,
|
|
465
501
|
specs,
|
|
466
502
|
projectDir: cwd,
|
|
503
|
+
...(options.stdin?.isTTY && options.stderr.isTTY && !parsed.json
|
|
504
|
+
? {
|
|
505
|
+
requestBuildApproval: (builds) => promptForBuildApproval(builds, options.stdin, options.stderr),
|
|
506
|
+
}
|
|
507
|
+
: {}),
|
|
467
508
|
...tools,
|
|
468
509
|
});
|
|
469
510
|
progress.close();
|
|
@@ -520,6 +561,11 @@ export async function runCli(options) {
|
|
|
520
561
|
projectDir: options.cwd ?? process.cwd(),
|
|
521
562
|
store: tools.store,
|
|
522
563
|
registry: tools.registry,
|
|
564
|
+
...(options.stdin?.isTTY && options.stderr.isTTY && !parsed.json
|
|
565
|
+
? {
|
|
566
|
+
requestBuildApproval: (builds) => promptForBuildApproval(builds, options.stdin, options.stderr),
|
|
567
|
+
}
|
|
568
|
+
: {}),
|
|
523
569
|
});
|
|
524
570
|
progress.close();
|
|
525
571
|
if (parsed.json) {
|
|
@@ -602,6 +648,48 @@ export async function runCli(options) {
|
|
|
602
648
|
return emit(fail(toZyrkError(error, `zyrk ${parsed.command} failed.`), parsed));
|
|
603
649
|
}
|
|
604
650
|
}
|
|
651
|
+
// Package scripts are accepted as ergonomic aliases for `zyrk run <name>`.
|
|
652
|
+
// Route through the same project runner so policy, generation leases,
|
|
653
|
+
// local-bin PATH and lifecycle environment stay identical.
|
|
654
|
+
if (!parsed.help &&
|
|
655
|
+
!parsed.version &&
|
|
656
|
+
parsed.command !== undefined &&
|
|
657
|
+
!KNOWN_COMMANDS.has(parsed.command) &&
|
|
658
|
+
parsed.argsBeforeCommand.length === 0) {
|
|
659
|
+
const cwd = options.cwd ?? process.cwd();
|
|
660
|
+
const boundary = await findProjectBoundary(cwd);
|
|
661
|
+
if (boundary) {
|
|
662
|
+
let declared = false;
|
|
663
|
+
try {
|
|
664
|
+
const manifest = JSON.parse(await readFile(path.join(boundary, "package.json"), "utf8"));
|
|
665
|
+
if (manifest.scripts !== null &&
|
|
666
|
+
typeof manifest.scripts === "object" &&
|
|
667
|
+
!Array.isArray(manifest.scripts) &&
|
|
668
|
+
typeof manifest.scripts[parsed.command] === "string")
|
|
669
|
+
declared = true;
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
// Preserve the normal unknown-command diagnostic when no valid
|
|
673
|
+
// project script can be identified.
|
|
674
|
+
}
|
|
675
|
+
if (declared) {
|
|
676
|
+
try {
|
|
677
|
+
return await runProjectCommand({
|
|
678
|
+
command: "run",
|
|
679
|
+
args: [parsed.command, ...parsed.commandArgs],
|
|
680
|
+
cwd,
|
|
681
|
+
env: options.env,
|
|
682
|
+
stdout: options.stdout,
|
|
683
|
+
stderr: options.stderr,
|
|
684
|
+
json: parsed.json,
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
catch (error) {
|
|
688
|
+
return emit(fail(toZyrkError(error, `zyrk ${parsed.command} failed.`), parsed));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
605
693
|
return emit(dispatch(parsed, { version, env: options.env }));
|
|
606
694
|
}
|
|
607
695
|
async function defaultTools(env, version, cwd = process.cwd()) {
|
|
@@ -10,5 +10,6 @@ export declare function runDependencyCommand(options: {
|
|
|
10
10
|
registry: RegistryClient;
|
|
11
11
|
env?: NodeJS.ProcessEnv;
|
|
12
12
|
onProgress?: InstallOptions["onProgress"];
|
|
13
|
+
requestBuildApproval?: InstallOptions["requestBuildApproval"];
|
|
13
14
|
}): Promise<InstallResult>;
|
|
14
15
|
//# sourceMappingURL=dependencies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/commands/dependencies.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAavE,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/commands/dependencies.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAavE,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;IAC1C,oBAAoB,CAAC,EAAE,cAAc,CAAC,sBAAsB,CAAC,CAAC;CAC/D,GAAG,OAAO,CAAC,aAAa,CAAC,CA+HzB"}
|
|
@@ -16,6 +16,9 @@ export async function runDependencyCommand(options) {
|
|
|
16
16
|
registry: options.registry,
|
|
17
17
|
...(options.env ? { env: options.env } : {}),
|
|
18
18
|
...(options.onProgress ? { onProgress: options.onProgress } : {}),
|
|
19
|
+
...(options.requestBuildApproval
|
|
20
|
+
? { requestBuildApproval: options.requestBuildApproval }
|
|
21
|
+
: {}),
|
|
19
22
|
};
|
|
20
23
|
const names = [];
|
|
21
24
|
let from;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type RuntimePlatform, type FinalizedGraph } from "../resolve/resolver.ts";
|
|
2
2
|
import type { WorkspaceGraph } from "./workspace-graph.ts";
|
|
3
|
+
/** Summarize expected platform filtering without emitting one warning per variant. */
|
|
4
|
+
export declare function platformOmissionSummary(omissions: readonly {
|
|
5
|
+
name: string;
|
|
6
|
+
}[]): string | undefined;
|
|
3
7
|
export declare function selectPlatformGraph(graph: FinalizedGraph, optionalRoots: ReadonlySet<string>, platform?: RuntimePlatform): FinalizedGraph;
|
|
4
8
|
export declare function selectWorkspacePlatform(graph: WorkspaceGraph, platform?: RuntimePlatform, omitDev?: boolean): WorkspaceGraph;
|
|
5
9
|
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/install/platform.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/install/platform.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,sFAAsF;AACtF,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GACrC,MAAM,GAAG,SAAS,CAQpB;AAsGD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,EAClC,QAAQ,kBAAoB,GAC3B,cAAc,CAqBhB;AACD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,cAAc,EACrB,QAAQ,kBAAoB,EAC5B,OAAO,UAAQ,GACd,cAAc,CA+BhB"}
|
package/dist/install/platform.js
CHANGED
|
@@ -3,6 +3,17 @@ import { satisfies } from "semver";
|
|
|
3
3
|
import { ZyrkError } from "../errors.js";
|
|
4
4
|
import { currentPlatform, } from "../resolve/resolver.js";
|
|
5
5
|
import { lockMismatch } from "./lock.js";
|
|
6
|
+
/** Summarize expected platform filtering without emitting one warning per variant. */
|
|
7
|
+
export function platformOmissionSummary(omissions) {
|
|
8
|
+
if (omissions.length === 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
const packages = new Set(omissions.map((item) => item.name));
|
|
11
|
+
const entries = omissions.length;
|
|
12
|
+
const variants = packages.size;
|
|
13
|
+
const entryLabel = `${entries} platform-specific optional ${entries === 1 ? "dependency" : "dependencies"}`;
|
|
14
|
+
const packageLabel = `${variants} ${variants === 1 ? "package variant" : "package variants"}`;
|
|
15
|
+
return `Skipped ${entryLabel} across ${packageLabel}; this is expected when selecting dependencies for the current platform.`;
|
|
16
|
+
}
|
|
6
17
|
function compatible(node, platform) {
|
|
7
18
|
return ([
|
|
8
19
|
[node.platform?.os, platform.os],
|
|
@@ -12,6 +12,7 @@ export type BuildCandidate = {
|
|
|
12
12
|
command: string;
|
|
13
13
|
}>;
|
|
14
14
|
};
|
|
15
|
+
export declare const WORKSPACE_POLICY_FILE = "zyrk-workspace.json";
|
|
15
16
|
export declare function candidates(nodes: readonly ResolvedOccurrence[], dirs: ReadonlyMap<string, string>): Promise<BuildCandidate[]>;
|
|
16
17
|
export declare function candidateDigest(graph: GraphDoc, builds: readonly BuildCandidate[], policy: unknown, patches: string): string;
|
|
17
18
|
export declare function approveCandidate(options: {
|
|
@@ -21,7 +22,15 @@ export declare function approveCandidate(options: {
|
|
|
21
22
|
selected: readonly string[];
|
|
22
23
|
env?: NodeJS.ProcessEnv;
|
|
23
24
|
policy?: unknown;
|
|
25
|
+
portable?: boolean;
|
|
24
26
|
}): Promise<void>;
|
|
27
|
+
export declare function approvedCandidates(options: {
|
|
28
|
+
project: string;
|
|
29
|
+
env: NodeJS.ProcessEnv;
|
|
30
|
+
digest: string;
|
|
31
|
+
builds: readonly BuildCandidate[];
|
|
32
|
+
policy: unknown;
|
|
33
|
+
}): Promise<BuildCandidate[]>;
|
|
25
34
|
export declare function assertApproved(options: {
|
|
26
35
|
project: string;
|
|
27
36
|
env: NodeJS.ProcessEnv;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"private.d.ts","sourceRoot":"","sources":["../../src/install/private.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAOjE,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD,CAAC;
|
|
1
|
+
{"version":3,"file":"private.d.ts","sourceRoot":"","sources":["../../src/install/private.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,EAA2B,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAOjE,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD,CAAC;AACF,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAe3D,wBAAsB,UAAU,CAC9B,KAAK,EAAE,SAAS,kBAAkB,EAAE,EACpC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC,cAAc,EAAE,CAAC,CA8C3B;AAyBD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,SAAS,cAAc,EAAE,EACjC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,GACd,MAAM,CASR;AACD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAClC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgChB;AA0ED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAgC5B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAClC,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhB;AACD,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmGzB;AAID,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACrC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAClC,QAAQ,EAAE,aAAa,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFhB"}
|
package/dist/install/private.js
CHANGED
|
@@ -13,6 +13,7 @@ import { canonicalJson } from "../util/json.js";
|
|
|
13
13
|
import { isErrno, pathExists, writeFileAtomic } from "../util/fsx.js";
|
|
14
14
|
import { superviseChild } from "../util/proc.js";
|
|
15
15
|
import { redactSecrets } from "../log.js";
|
|
16
|
+
export const WORKSPACE_POLICY_FILE = "zyrk-workspace.json";
|
|
16
17
|
function fail(message) {
|
|
17
18
|
throw new ZyrkError("ZYRK_SCRIPT_BLOCKED", message, {
|
|
18
19
|
remedy: "Review the exact candidate with zyrk approve-builds, then explicitly approve its package names. Mandatory denials cannot be overridden.",
|
|
@@ -93,16 +94,62 @@ export async function approveCandidate(options) {
|
|
|
93
94
|
const selected = new Set(options.selected);
|
|
94
95
|
const all = selected.has("*");
|
|
95
96
|
for (const name of selected)
|
|
96
|
-
if (name !== "*" &&
|
|
97
|
+
if (name !== "*" &&
|
|
98
|
+
!options.builds.some((b) => b.name === name || b.sourceId === name))
|
|
97
99
|
fail("An approval selector does not match a reviewed build candidate.");
|
|
98
100
|
await writeFileAtomic(path.join(options.project, ".zyrk-local", "approvals.json"), JSON.stringify({
|
|
99
101
|
schemaVersion: 1,
|
|
100
102
|
candidate: options.digest,
|
|
101
103
|
sources: options.builds
|
|
102
|
-
.filter((b) => all || selected.has(b.name))
|
|
104
|
+
.filter((b) => all || selected.has(b.name) || selected.has(b.sourceId))
|
|
103
105
|
.map((b) => b.sourceId)
|
|
104
106
|
.sort(),
|
|
105
107
|
}), { mode: 0o600 });
|
|
108
|
+
if (options.portable) {
|
|
109
|
+
const selectedBuilds = options.builds.filter((build) => all || selected.has(build.name) || selected.has(build.sourceId));
|
|
110
|
+
await writePortableApprovals(options.project, selectedBuilds);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async function readPortableApprovals(project) {
|
|
114
|
+
const file = path.join(project, WORKSPACE_POLICY_FILE);
|
|
115
|
+
let raw;
|
|
116
|
+
try {
|
|
117
|
+
const stat = await lstat(file);
|
|
118
|
+
if (!stat.isFile() || stat.isSymbolicLink())
|
|
119
|
+
fail("The workspace build-approval file must be a regular file.");
|
|
120
|
+
raw = JSON.parse(await readFile(file, "utf8"));
|
|
121
|
+
}
|
|
122
|
+
catch (cause) {
|
|
123
|
+
if (cause instanceof ZyrkError)
|
|
124
|
+
throw cause;
|
|
125
|
+
if (isErrno(cause, "ENOENT"))
|
|
126
|
+
return [];
|
|
127
|
+
fail("The workspace build-approval file is unreadable or malformed.");
|
|
128
|
+
}
|
|
129
|
+
if (!object(raw) ||
|
|
130
|
+
raw.schemaVersion !== 1 ||
|
|
131
|
+
!Array.isArray(raw.approvedBuilds) ||
|
|
132
|
+
raw.approvedBuilds.some((item) => !object(item) ||
|
|
133
|
+
typeof item.name !== "string" ||
|
|
134
|
+
typeof item.version !== "string" ||
|
|
135
|
+
typeof item.sourceId !== "string" ||
|
|
136
|
+
!/^src1_[a-f0-9]{40}$/.test(item.sourceId)))
|
|
137
|
+
fail("The workspace build-approval file has an unsupported format.");
|
|
138
|
+
return raw.approvedBuilds;
|
|
139
|
+
}
|
|
140
|
+
async function writePortableApprovals(project, selected) {
|
|
141
|
+
const current = await readPortableApprovals(project);
|
|
142
|
+
const bySource = new Map(current.map((item) => [item.sourceId, item]));
|
|
143
|
+
for (const build of selected)
|
|
144
|
+
bySource.set(build.sourceId, {
|
|
145
|
+
name: build.name,
|
|
146
|
+
version: build.version,
|
|
147
|
+
sourceId: build.sourceId,
|
|
148
|
+
});
|
|
149
|
+
await writeFileAtomic(path.join(project, WORKSPACE_POLICY_FILE), `${JSON.stringify({
|
|
150
|
+
schemaVersion: 1,
|
|
151
|
+
approvedBuilds: [...bySource.values()].sort((a, b) => a.name.localeCompare(b.name)),
|
|
152
|
+
}, null, 2)}\n`, { mode: 0o644 });
|
|
106
153
|
}
|
|
107
154
|
async function readUserPolicy(env) {
|
|
108
155
|
let user = {};
|
|
@@ -117,9 +164,9 @@ async function readUserPolicy(env) {
|
|
|
117
164
|
fail("Mandatory user build policy is malformed.");
|
|
118
165
|
return user;
|
|
119
166
|
}
|
|
120
|
-
export async function
|
|
167
|
+
export async function approvedCandidates(options) {
|
|
121
168
|
if (!options.builds.length)
|
|
122
|
-
return;
|
|
169
|
+
return [];
|
|
123
170
|
const user = await readUserPolicy(options.env);
|
|
124
171
|
let local;
|
|
125
172
|
try {
|
|
@@ -133,19 +180,29 @@ export async function assertApproved(options) {
|
|
|
133
180
|
throw cause;
|
|
134
181
|
local = undefined;
|
|
135
182
|
}
|
|
136
|
-
|
|
183
|
+
const portable = await readPortableApprovals(options.project);
|
|
184
|
+
return options.builds.filter((build) => {
|
|
137
185
|
if (denied(user.scripts, build) || denied(options.policy, build))
|
|
138
|
-
|
|
139
|
-
const
|
|
186
|
+
return false;
|
|
187
|
+
const manifestAllowed = object(options.policy) &&
|
|
140
188
|
Array.isArray(options.policy.allow) &&
|
|
141
189
|
options.policy.allow.includes(build.sourceId);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
190
|
+
const workspaceAllowed = portable.some((approval) => approval.sourceId === build.sourceId);
|
|
191
|
+
const localAllowed = object(local) &&
|
|
192
|
+
local.schemaVersion === 1 &&
|
|
193
|
+
local.candidate === options.digest &&
|
|
194
|
+
Array.isArray(local.sources) &&
|
|
195
|
+
local.sources.includes(build.sourceId);
|
|
196
|
+
return manifestAllowed || workspaceAllowed || localAllowed;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
export async function assertApproved(options) {
|
|
200
|
+
const approved = await approvedCandidates(options);
|
|
201
|
+
if (approved.length !== options.builds.length) {
|
|
202
|
+
const pending = options.builds.find((build) => !approved.some((item) => item.sourceId === build.sourceId));
|
|
203
|
+
fail(pending
|
|
204
|
+
? `Build of ${pending.name}@${pending.version} has not been approved for this exact source.`
|
|
205
|
+
: "Not every dependency build candidate is approved.");
|
|
149
206
|
}
|
|
150
207
|
}
|
|
151
208
|
export async function materializePrivate(options) {
|
package/dist/install/run.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export type InstallOptions = {
|
|
|
43
43
|
env?: NodeJS.ProcessEnv;
|
|
44
44
|
reviewBuilds?: boolean;
|
|
45
45
|
approveBuilds?: readonly string[];
|
|
46
|
+
requestBuildApproval?: (builds: readonly BuildCandidate[]) => Promise<readonly string[]>;
|
|
46
47
|
rebuild?: boolean;
|
|
47
48
|
repair?: boolean;
|
|
48
49
|
resolveBudget?: Partial<ResolverLimits>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAK9D,OAAO,EAOL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAYtB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AA+B3C,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EACD,UAAU,GACV,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,SAAS,GACT,UAAU,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,aAAa,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;QAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1C,WAAW,CAAC,EAAE;QACZ,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EACL,OAAO,GACP,uBAAuB,GACvB,eAAe,GACf,SAAS,GACT,cAAc,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AA4GF,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/install/run.ts"],"names":[],"mappings":"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"}
|
package/dist/install/run.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { sourceProgress, reportLinked } from "./progress.js";
|
|
2
|
-
import { selectPlatformGraph } from "./platform.js";
|
|
2
|
+
import { platformOmissionSummary, selectPlatformGraph } from "./platform.js";
|
|
3
3
|
import { findWorkspaceRoot } from "./workspaces.js";
|
|
4
4
|
import { assertSupportedSourcePayload } from "./source-policy.js";
|
|
5
5
|
import { prepareRepair } from "./repair.js";
|
|
6
6
|
import { createFetchOperation } from "../fetch/package.js";
|
|
7
|
-
import { candidates, candidateDigest, approveCandidate,
|
|
7
|
+
import { candidates, candidateDigest, approveCandidate, approvedCandidates, materializePrivate, buildPrivate, } from "./private.js";
|
|
8
8
|
import { loadProjectPatches, applyProjectPatches } from "../commands/patch.js";
|
|
9
9
|
import { registerGeneration } from "./metadata.js";
|
|
10
10
|
import { randomId } from "../util/ids.js";
|
|
@@ -420,7 +420,10 @@ export async function installProject(options) {
|
|
|
420
420
|
name: "package.json",
|
|
421
421
|
contents: `${JSON.stringify(manifest, null, 2)}\n`,
|
|
422
422
|
});
|
|
423
|
-
const warnings =
|
|
423
|
+
const warnings = [];
|
|
424
|
+
const omissionSummary = platformOmissionSummary(activeResolution.omissions ?? []);
|
|
425
|
+
if (omissionSummary)
|
|
426
|
+
warnings.push(omissionSummary);
|
|
424
427
|
for (const stage of ["preinstall", "install", "postinstall"])
|
|
425
428
|
if (manifest.scripts?.[stage])
|
|
426
429
|
warnings.push(`Root ${stage} hook was not run; invoke it explicitly after installation.`);
|
|
@@ -553,6 +556,7 @@ export async function installProject(options) {
|
|
|
553
556
|
selected: options.approveBuilds,
|
|
554
557
|
env: options.env ?? process.env,
|
|
555
558
|
policy: scriptPolicy(manifest),
|
|
559
|
+
portable: true,
|
|
556
560
|
});
|
|
557
561
|
return {
|
|
558
562
|
readiness: "build-review",
|
|
@@ -563,15 +567,37 @@ export async function installProject(options) {
|
|
|
563
567
|
builds,
|
|
564
568
|
};
|
|
565
569
|
}
|
|
566
|
-
|
|
570
|
+
let approvedBuilds = [];
|
|
567
571
|
if (builds.length && !options.ignoreScripts) {
|
|
568
|
-
|
|
572
|
+
const approvalOptions = {
|
|
569
573
|
project,
|
|
570
574
|
env: options.env ?? process.env,
|
|
571
575
|
digest: reviewedDigest,
|
|
572
576
|
builds,
|
|
573
577
|
policy: scriptPolicy(manifest),
|
|
574
|
-
}
|
|
578
|
+
};
|
|
579
|
+
approvedBuilds = await approvedCandidates(approvalOptions);
|
|
580
|
+
if (approvedBuilds.length < builds.length &&
|
|
581
|
+
options.requestBuildApproval) {
|
|
582
|
+
const pending = builds.filter((build) => !approvedBuilds.some((item) => item.sourceId === build.sourceId));
|
|
583
|
+
const selected = await options.requestBuildApproval(pending);
|
|
584
|
+
if (selected.length) {
|
|
585
|
+
await approveCandidate({
|
|
586
|
+
project,
|
|
587
|
+
digest: reviewedDigest,
|
|
588
|
+
builds: pending,
|
|
589
|
+
selected,
|
|
590
|
+
env: options.env ?? process.env,
|
|
591
|
+
policy: scriptPolicy(manifest),
|
|
592
|
+
portable: true,
|
|
593
|
+
});
|
|
594
|
+
approvedBuilds = await approvedCandidates(approvalOptions);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const unbuilt = builds.length > 0 &&
|
|
599
|
+
(options.ignoreScripts === true || approvedBuilds.length < builds.length);
|
|
600
|
+
if (approvedBuilds.length && !options.ignoreScripts) {
|
|
575
601
|
if (!privateGraph) {
|
|
576
602
|
realized = await materializePrivate({
|
|
577
603
|
project,
|
|
@@ -586,7 +612,7 @@ export async function installProject(options) {
|
|
|
586
612
|
project,
|
|
587
613
|
generationId,
|
|
588
614
|
nodes: activeNodes,
|
|
589
|
-
builds,
|
|
615
|
+
builds: approvedBuilds,
|
|
590
616
|
realized,
|
|
591
617
|
env: options.env ?? process.env,
|
|
592
618
|
});
|
|
@@ -610,9 +636,10 @@ export async function installProject(options) {
|
|
|
610
636
|
privateGraph = true;
|
|
611
637
|
}
|
|
612
638
|
}
|
|
613
|
-
if (unbuilt)
|
|
614
|
-
|
|
615
|
-
|
|
639
|
+
if (unbuilt) {
|
|
640
|
+
const skipped = builds.length - approvedBuilds.length;
|
|
641
|
+
warnings.push(`${skipped} dependency build ${skipped === 1 ? "script was" : "scripts were"} skipped because approval was not granted; readiness is intentionally unbuilt. Run zyrk approve-builds to review and approve sources.`);
|
|
642
|
+
}
|
|
616
643
|
if (privateGraph)
|
|
617
644
|
warnings.push("Using a complete project-private dependency graph; build/runtime writes do not change shared source.");
|
|
618
645
|
const entries = selectedRoots.map((r) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace-install.d.ts","sourceRoot":"","sources":["../../src/install/workspace-install.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAuH9D,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CAqtBxB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sourceProgress, reportLinked } from "./progress.js";
|
|
2
|
-
import { selectWorkspacePlatform } from "./platform.js";
|
|
2
|
+
import { platformOmissionSummary, selectWorkspacePlatform, } from "./platform.js";
|
|
3
3
|
/** Multi-importer live workspace installation with one publication journal. */
|
|
4
4
|
import { chmod, copyFile, lstat, mkdir, readFile, realpath, rename, rm, symlink, } from "node:fs/promises";
|
|
5
5
|
import { constants } from "node:fs";
|
|
@@ -32,7 +32,7 @@ import { loadProjectPatches, applyProjectPatches } from "../commands/patch.js";
|
|
|
32
32
|
import { prepareRepair } from "./repair.js";
|
|
33
33
|
import { assertSupportedSourcePayload } from "./source-policy.js";
|
|
34
34
|
import { registerGeneration } from "./metadata.js";
|
|
35
|
-
import { candidates, candidateDigest, approveCandidate,
|
|
35
|
+
import { candidates, candidateDigest, approveCandidate, approvedCandidates, buildPrivate, } from "./private.js";
|
|
36
36
|
const object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
37
37
|
const unsupported = (message) => {
|
|
38
38
|
throw new ZyrkError("ZYRK_NOT_IMPLEMENTED", message, {
|
|
@@ -191,7 +191,10 @@ export async function installWorkspaceProject(options) {
|
|
|
191
191
|
? await readFile(path.join(root, "package-lock.json"), "utf8")
|
|
192
192
|
: JSON.stringify(doc, null, 2) + "\n";
|
|
193
193
|
graph = selectWorkspacePlatform(graph, options.platform, options.omitDev);
|
|
194
|
-
const warnings =
|
|
194
|
+
const warnings = [];
|
|
195
|
+
const omissionSummary = platformOmissionSummary(graph.omissions);
|
|
196
|
+
if (omissionSummary)
|
|
197
|
+
warnings.push(omissionSummary);
|
|
195
198
|
for (const importer of project.importers)
|
|
196
199
|
for (const stage of ["preinstall", "install", "postinstall"])
|
|
197
200
|
if (importer.manifest.scripts?.[stage])
|
|
@@ -441,6 +444,7 @@ export async function installWorkspaceProject(options) {
|
|
|
441
444
|
selected: options.approveBuilds,
|
|
442
445
|
env: options.env ?? process.env,
|
|
443
446
|
policy,
|
|
447
|
+
portable: true,
|
|
444
448
|
});
|
|
445
449
|
return {
|
|
446
450
|
readiness: "build-review",
|
|
@@ -451,14 +455,38 @@ export async function installWorkspaceProject(options) {
|
|
|
451
455
|
builds,
|
|
452
456
|
};
|
|
453
457
|
}
|
|
458
|
+
let approvedBuilds = [];
|
|
454
459
|
if (builds.length && !options.ignoreScripts) {
|
|
455
|
-
|
|
460
|
+
const approvalOptions = {
|
|
456
461
|
project: root,
|
|
457
462
|
env: options.env ?? process.env,
|
|
458
463
|
digest,
|
|
459
464
|
builds,
|
|
460
465
|
policy,
|
|
461
|
-
}
|
|
466
|
+
};
|
|
467
|
+
approvedBuilds = await approvedCandidates(approvalOptions);
|
|
468
|
+
if (approvedBuilds.length < builds.length &&
|
|
469
|
+
options.requestBuildApproval) {
|
|
470
|
+
const pending = builds.filter((build) => !approvedBuilds.some((item) => item.sourceId === build.sourceId));
|
|
471
|
+
const selected = await options.requestBuildApproval(pending);
|
|
472
|
+
if (selected.length) {
|
|
473
|
+
await approveCandidate({
|
|
474
|
+
project: root,
|
|
475
|
+
digest,
|
|
476
|
+
builds: pending,
|
|
477
|
+
selected,
|
|
478
|
+
env: options.env ?? process.env,
|
|
479
|
+
policy,
|
|
480
|
+
portable: true,
|
|
481
|
+
});
|
|
482
|
+
approvedBuilds = await approvedCandidates(approvalOptions);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
const skippedBuilds = builds.length - approvedBuilds.length;
|
|
487
|
+
if (skippedBuilds > 0)
|
|
488
|
+
warnings.push(`${skippedBuilds} dependency build ${skippedBuilds === 1 ? "script was" : "scripts were"} skipped because approval was not granted; readiness is intentionally unbuilt. Run zyrk approve-builds to review and approve sources.`);
|
|
489
|
+
if (approvedBuilds.length && !options.ignoreScripts) {
|
|
462
490
|
// Approved writes need a coherent fully private registry closure.
|
|
463
491
|
await allocatePrivate(new Set(nodes.map((n) => n.key)));
|
|
464
492
|
options.onProgress?.({ phase: "building" });
|
|
@@ -466,12 +494,12 @@ export async function installWorkspaceProject(options) {
|
|
|
466
494
|
project: root,
|
|
467
495
|
generationId,
|
|
468
496
|
nodes,
|
|
469
|
-
builds,
|
|
497
|
+
builds: approvedBuilds,
|
|
470
498
|
realized,
|
|
471
499
|
env: options.env ?? process.env,
|
|
472
500
|
});
|
|
473
501
|
}
|
|
474
|
-
const readiness = builds.length && options.ignoreScripts
|
|
502
|
+
const readiness = builds.length && (options.ignoreScripts || skippedBuilds > 0)
|
|
475
503
|
? "intentionally-unbuilt"
|
|
476
504
|
: "ready";
|
|
477
505
|
registration = await registerGeneration({
|