@loucompanion/forge-bridge 0.1.3-dev.fbe15023cdfe → 0.1.4-dev.1ff37038366e
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 +88 -2
- package/dist/bridge/bridge-chat.types.d.ts +111 -0
- package/dist/bridge/bridge-chat.types.js +401 -0
- package/dist/bridge/bridge.base.d.ts +4 -1
- package/dist/bridge/bridge.service.d.ts +72 -3
- package/dist/bridge/bridge.service.js +1563 -152
- package/dist/bridge/bridge.types.d.ts +46 -1
- package/dist/bridge/dispatch-result-outbox.d.ts +25 -0
- package/dist/bridge/dispatch-result-outbox.js +62 -0
- package/dist/bridge/dispatch-result-worker.d.ts +2 -0
- package/dist/bridge/dispatch-result-worker.js +122 -0
- package/dist/bridge/internals.d.ts +2 -0
- package/dist/bridge/internals.js +1 -0
- package/dist/bridge/readiness-result-outbox.d.ts +21 -0
- package/dist/bridge/readiness-result-outbox.js +54 -0
- package/dist/bridge/readiness-result-worker.d.ts +2 -0
- package/dist/bridge/readiness-result-worker.js +121 -0
- package/dist/bridge/runner-host-capabilities.d.ts +15 -0
- package/dist/bridge/runner-host-capabilities.js +93 -0
- package/dist/cleanup/cleanup.service.d.ts +1 -0
- package/dist/cleanup/cleanup.service.js +70 -9
- package/dist/cli/cli.help.js +2 -2
- package/dist/cli/cli.service.d.ts +14 -6
- package/dist/cli/cli.service.js +75 -16
- package/dist/cli/local-config.d.ts +1 -0
- package/dist/cli/local-config.js +4 -0
- package/dist/runtime/aspnet-runtime-prebuild.d.ts +36 -0
- package/dist/runtime/aspnet-runtime-prebuild.js +341 -0
- package/dist/runtime/attempt-database-broker.d.ts +89 -0
- package/dist/runtime/attempt-database-broker.js +390 -0
- package/dist/runtime/attempt-node-runtime-launcher.d.ts +2 -1
- package/dist/runtime/attempt-node-runtime-launcher.js +57 -18
- package/dist/runtime/attempt-path-operation.d.ts +21 -0
- package/dist/runtime/attempt-path-operation.js +94 -0
- package/dist/runtime/attempt-private-directory.d.ts +6 -0
- package/dist/runtime/attempt-private-directory.js +54 -0
- package/dist/runtime/attempt-process-supervisor.d.ts +11 -0
- package/dist/runtime/attempt-process-supervisor.js +67 -20
- package/dist/runtime/canonical-source-file.d.ts +3 -0
- package/dist/runtime/canonical-source-file.js +54 -0
- package/dist/runtime/docker-engine-probe.d.ts +90 -0
- package/dist/runtime/docker-engine-probe.js +333 -0
- package/dist/runtime/generated-output-reset.d.ts +10 -0
- package/dist/runtime/generated-output-reset.js +62 -8
- package/dist/runtime/host-database-capability-boundary.d.ts +16 -0
- package/dist/runtime/host-database-capability-boundary.js +62 -0
- package/dist/runtime/host-diagnostics.d.ts +11 -0
- package/dist/runtime/host-diagnostics.js +191 -0
- package/dist/runtime/host-execution-root.d.ts +4 -0
- package/dist/runtime/host-execution-root.js +39 -0
- package/dist/runtime/host-listener-inspector.d.ts +8 -1
- package/dist/runtime/host-listener-inspector.js +121 -60
- package/dist/runtime/host-runtime-contract.d.ts +12 -1
- package/dist/runtime/host-runtime-contract.js +168 -55
- package/dist/runtime/host-runtime-lease.d.ts +92 -8
- package/dist/runtime/host-runtime-lease.js +1141 -114
- package/dist/runtime/host-runtime-promotion.d.ts +12 -3
- package/dist/runtime/host-runtime-promotion.js +59 -12
- package/dist/runtime/memory-capacity.d.ts +70 -0
- package/dist/runtime/memory-capacity.js +123 -0
- package/dist/runtime/native-test-postgres-fallback.d.ts +25 -0
- package/dist/runtime/native-test-postgres-fallback.js +91 -0
- package/dist/runtime/node-host-runtime-adapter.d.ts +3 -0
- package/dist/runtime/node-host-runtime-adapter.js +28 -11
- package/dist/runtime/pinned-directory-process.d.ts +9 -0
- package/dist/runtime/pinned-directory-process.js +61 -0
- package/dist/runtime/pinned-source-directory.d.ts +17 -0
- package/dist/runtime/pinned-source-directory.js +94 -0
- package/dist/runtime/playwright-host-runtime-adapter.d.ts +1 -0
- package/dist/runtime/playwright-host-runtime-adapter.js +53 -5
- package/dist/runtime/prepared-runtime-identity.d.ts +6 -0
- package/dist/runtime/prepared-runtime-identity.js +218 -0
- package/dist/runtime/prepared-runtime-readiness.d.ts +30 -0
- package/dist/runtime/prepared-runtime-readiness.js +285 -0
- package/dist/runtime/runtime-isolation-lease.js +4 -1
- package/dist/runtime/workspace-resource-estimator.d.ts +17 -0
- package/dist/runtime/workspace-resource-estimator.js +174 -0
- package/dist/sandbox/preflight.d.ts +31 -1
- package/dist/sandbox/preflight.js +237 -51
- package/dist/sandbox/repository-lock.d.ts +2 -1
- package/dist/sandbox/repository-lock.js +17 -8
- package/dist/sandbox/runtime.d.ts +6 -1
- package/dist/sandbox/runtime.js +132 -103
- package/dist/sandbox/sandbox.types.d.ts +7 -0
- package/dist/sandbox/workspace.service.js +2 -0
- package/dist/session/managed-attempt-tools.d.ts +17 -1
- package/dist/session/managed-attempt-tools.js +485 -31
- package/dist/session/managed-build-coordinator.d.ts +5 -0
- package/dist/session/managed-build-coordinator.js +105 -0
- package/dist/session/managed-build-receipt.d.ts +21 -0
- package/dist/session/managed-build-receipt.js +337 -0
- package/dist/session/managed-verification-timeouts.d.ts +8 -0
- package/dist/session/managed-verification-timeouts.js +17 -0
- package/dist/session/phase-completion.artifacts.d.ts +17 -0
- package/dist/session/phase-completion.artifacts.js +224 -22
- package/dist/session/phase-completion.d.ts +11 -1
- package/dist/session/phase-completion.helpers.d.ts +5 -0
- package/dist/session/phase-completion.helpers.js +30 -7
- package/dist/session/phase-completion.js +14 -3
- package/dist/session/phase-completion.prompts.js +17 -18
- package/dist/session/phase-completion.runtime.d.ts +3 -1
- package/dist/session/phase-completion.runtime.js +126 -17
- package/dist/session/phase-completion.schemas.js +49 -2
- package/dist/session/phase-completion.validation.d.ts +1 -0
- package/dist/session/phase-completion.validation.js +111 -21
- package/dist/session/pre-publication-validation.d.ts +75 -0
- package/dist/session/pre-publication-validation.js +661 -0
- package/dist/session/provider-cli/bridge-cli.conformance-fixtures.d.ts +72 -0
- package/dist/session/provider-cli/bridge-cli.conformance-fixtures.js +462 -0
- package/dist/session/provider-cli/ci-repair-readiness.d.ts +8 -0
- package/dist/session/provider-cli/ci-repair-readiness.js +23 -3
- package/dist/session/provider-cli/provider-cli.artifacts.d.ts +4 -2
- package/dist/session/provider-cli/provider-cli.artifacts.js +47 -13
- package/dist/session/provider-cli/provider-cli.deterministic.js +34 -2
- package/dist/session/provider-cli/provider-cli.process.d.ts +51 -0
- package/dist/session/provider-cli/provider-cli.process.js +422 -22
- package/dist/session/provider-cli/provider-cli.prompts.d.ts +5 -0
- package/dist/session/provider-cli/provider-cli.prompts.js +136 -16
- package/dist/session/provider-cli/provider-cli.repair-epoch.d.ts +6 -0
- package/dist/session/provider-cli/provider-cli.repair-epoch.js +11 -0
- package/dist/session/provider-cli/provider-cli.runtime.d.ts +8 -1
- package/dist/session/provider-cli/provider-cli.runtime.js +43 -3
- package/dist/session/provider-cli/provider-cli.service.d.ts +30 -5
- package/dist/session/provider-cli/provider-cli.service.js +771 -68
- package/dist/session/provider-cli/provider-cli.types.d.ts +2 -0
- package/dist/session/provider-cli/provider-output-state.d.ts +10 -0
- package/dist/session/provider-cli/provider-output-state.js +361 -17
- package/dist/session/provider-cli/provider-usage.d.ts +7 -0
- package/dist/session/provider-cli/provider-usage.js +28 -5
- package/dist/session/session-redaction.js +434 -9
- package/dist/session/session.service.js +145 -23
- package/dist/session/session.types.d.ts +147 -2
- package/dist/session/session.types.js +587 -7
- package/dist/session/unreferenced-exports.d.ts +12 -0
- package/dist/session/unreferenced-exports.js +59 -0
- package/dist/shared/format/format-bytes.d.ts +1 -0
- package/dist/shared/format/format-bytes.js +9 -0
- package/dist/shared/git/git.js +2 -1
- package/dist/shared/path/path.d.ts +1 -0
- package/dist/shared/path/path.js +18 -0
- package/dist/shared/process/dotnet-toolchain.d.ts +17 -0
- package/dist/shared/process/dotnet-toolchain.js +307 -0
- package/dist/shared/process/host-process-supervisor.d.ts +2 -0
- package/dist/shared/process/host-process-supervisor.js +57 -9
- package/dist/shared/process/process.d.ts +2 -0
- package/dist/shared/process/process.js +12 -7
- package/dist/shared/provider-capabilities.d.ts +3 -0
- package/dist/shared/provider-capabilities.js +85 -0
- package/dist/shared/redaction/redaction.d.ts +1 -0
- package/dist/shared/redaction/redaction.js +39 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worktree/dependency-warmer.d.ts +41 -9
- package/dist/worktree/dependency-warmer.js +497 -22
- package/dist/worktree/index.d.ts +1 -1
- package/dist/worktree/story-qa-reference-hydrator.d.ts +4 -0
- package/dist/worktree/story-qa-reference-hydrator.js +253 -0
- package/dist/worktree/worktree.service.d.ts +7 -0
- package/dist/worktree/worktree.service.js +253 -21
- package/dist/worktree/worktree.types.d.ts +7 -1
- package/package.json +7 -5
- package/runtime/windows-job-supervisor.ps1 +380 -14
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
1
2
|
import { existsSync, realpathSync } from "node:fs";
|
|
2
3
|
import fs from "node:fs/promises";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
6
|
+
import { assertHostDatabaseCapabilityBoundary } from "../runtime/host-database-capability-boundary.js";
|
|
7
|
+
import { RepositoryCoordinatorLock } from "../sandbox/repository-lock.js";
|
|
5
8
|
import { NodeProcessRunner } from "../shared/process/process.js";
|
|
6
9
|
import { buildWindowsCmdLaunch } from "../shared/process/windows-launch.js";
|
|
7
10
|
import { isSubPath } from "../shared/path/path.js";
|
|
11
|
+
import { defaultWorktreeCoordinatorStateRoot } from "./worktree-paths.js";
|
|
8
12
|
const SKIP_DIR_NAMES = new Set([
|
|
9
13
|
".git",
|
|
10
14
|
"node_modules",
|
|
@@ -24,6 +28,11 @@ const NATIVE_MODULE_HINTS = [
|
|
|
24
28
|
"@swc/core"
|
|
25
29
|
];
|
|
26
30
|
const MAX_COMMAND_FAILURE_OUTPUT_LENGTH = 8_000;
|
|
31
|
+
const DEPENDENCY_RECEIPT_SCHEMA_VERSION = 1;
|
|
32
|
+
const DEPENDENCY_PREPARATION_CONTRACT = "managed-worktree-isolated-v1";
|
|
33
|
+
const WINDOWS_COMMAND_ENVIRONMENT_PATH_LIMIT = 8_191;
|
|
34
|
+
const WINDOWS_PACKAGE_MANAGER_INTERNAL_PATH_RESERVE = 512;
|
|
35
|
+
const dependencyPreparationCoordinator = new RepositoryCoordinatorLock(defaultWorktreeCoordinatorStateRoot());
|
|
27
36
|
export async function detectWarmPaths(repoRoot, warmPathOverrides = []) {
|
|
28
37
|
const entries = new Map();
|
|
29
38
|
await collectDetectedPaths(repoRoot, repoRoot, entries, 0);
|
|
@@ -51,6 +60,7 @@ export async function warmWorktreeDependencies(request, executor = defaultComman
|
|
|
51
60
|
const linked = [];
|
|
52
61
|
const skipped = [];
|
|
53
62
|
const fallbacks = [];
|
|
63
|
+
const receipts = [];
|
|
54
64
|
const restoredDotNetRoots = new Set();
|
|
55
65
|
const installedNodeRoots = new Set();
|
|
56
66
|
for (const entry of warmPaths) {
|
|
@@ -67,8 +77,10 @@ export async function warmWorktreeDependencies(request, executor = defaultComman
|
|
|
67
77
|
continue;
|
|
68
78
|
}
|
|
69
79
|
installedNodeRoots.add(packageKey);
|
|
70
|
-
const
|
|
71
|
-
|
|
80
|
+
const preparation = await ensureInstallFallback({ ...entry, packageRoot: installPackageRoot }, worktreePath, "Managed worktrees require isolated Node dependencies.", executor, request.preparationPolicy);
|
|
81
|
+
receipts.push(preparation.receipt);
|
|
82
|
+
if (preparation.install)
|
|
83
|
+
fallbacks.push(preparation.install);
|
|
72
84
|
continue;
|
|
73
85
|
}
|
|
74
86
|
if (entry.ecosystem === "dotnet") {
|
|
@@ -80,15 +92,19 @@ export async function warmWorktreeDependencies(request, executor = defaultComman
|
|
|
80
92
|
continue;
|
|
81
93
|
}
|
|
82
94
|
restoredDotNetRoots.add(packageKey);
|
|
83
|
-
const
|
|
84
|
-
|
|
95
|
+
const preparation = await ensureInstallFallback(entry, worktreePath, "Managed worktrees require isolated .NET build outputs.", executor, request.preparationPolicy);
|
|
96
|
+
receipts.push(preparation.receipt);
|
|
97
|
+
if (preparation.install)
|
|
98
|
+
fallbacks.push(preparation.install);
|
|
85
99
|
continue;
|
|
86
100
|
}
|
|
87
101
|
const sourceExists = await directoryExists(sourcePath);
|
|
88
102
|
const fallbackReason = await resolveFallbackReason(entry, baseCheckoutPath, worktreePath, sourceExists);
|
|
89
103
|
if (fallbackReason) {
|
|
90
|
-
const
|
|
91
|
-
|
|
104
|
+
const preparation = await ensureInstallFallback(entry, worktreePath, fallbackReason, executor, request.preparationPolicy);
|
|
105
|
+
receipts.push(preparation.receipt);
|
|
106
|
+
if (preparation.install)
|
|
107
|
+
fallbacks.push(preparation.install);
|
|
92
108
|
continue;
|
|
93
109
|
}
|
|
94
110
|
if (!sourceExists) {
|
|
@@ -98,7 +114,7 @@ export async function warmWorktreeDependencies(request, executor = defaultComman
|
|
|
98
114
|
await createDirectoryLink(sourcePath, targetPath, allowedRoot);
|
|
99
115
|
linked.push(entry.relativePath);
|
|
100
116
|
}
|
|
101
|
-
return { linked, skipped, fallbacks };
|
|
117
|
+
return { linked, skipped, fallbacks, receipts };
|
|
102
118
|
}
|
|
103
119
|
async function removeLegacyDirectoryLink(targetPath, allowedRoot) {
|
|
104
120
|
const resolvedTarget = path.resolve(targetPath);
|
|
@@ -225,28 +241,249 @@ export async function lockfilesDiffer(baseCheckoutPath, worktreePath, packageRoo
|
|
|
225
241
|
}
|
|
226
242
|
return false;
|
|
227
243
|
}
|
|
244
|
+
async function ensureInstallFallback(entry, worktreePath, reason, executor, policy) {
|
|
245
|
+
const startedAt = performance.now();
|
|
246
|
+
const cwd = path.resolve(worktreePath, entry.packageRoot === "." ? "" : entry.packageRoot);
|
|
247
|
+
assertWithinRoot(path.resolve(worktreePath), cwd, "Dependency package root");
|
|
248
|
+
const command = await installFallbackCommand(entry, cwd);
|
|
249
|
+
const outputMarker = dependencyOutputMarker(entry.ecosystem, cwd);
|
|
250
|
+
const receiptPath = path.join(outputMarker, ".forge-dependency-preparation.json");
|
|
251
|
+
const fingerprint = await dependencyPreparationFingerprint(entry, worktreePath, cwd, command, policy);
|
|
252
|
+
return await dependencyPreparationCoordinator.withLock(receiptPath, async () => {
|
|
253
|
+
const existing = await readDependencyPreparationReceipt(receiptPath);
|
|
254
|
+
if (existing?.fingerprint === fingerprint
|
|
255
|
+
&& existing.ecosystem === entry.ecosystem
|
|
256
|
+
&& existing.packageRoot === entry.packageRoot
|
|
257
|
+
&& existing.command === command
|
|
258
|
+
&& await directoryExists(outputMarker)) {
|
|
259
|
+
await markNpmCiRestored(outputMarker, command);
|
|
260
|
+
return {
|
|
261
|
+
install: null,
|
|
262
|
+
receipt: {
|
|
263
|
+
ecosystem: entry.ecosystem,
|
|
264
|
+
packageRoot: entry.packageRoot,
|
|
265
|
+
command,
|
|
266
|
+
cacheHit: true,
|
|
267
|
+
fingerprint,
|
|
268
|
+
receiptPath,
|
|
269
|
+
durationMs: elapsedMilliseconds(startedAt),
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const install = await runInstallFallback(entry, worktreePath, reason, executor);
|
|
274
|
+
// npm is allowed to omit node_modules when the package graph is empty. Keep
|
|
275
|
+
// an isolated, ignored output directory so the durable receipt still has a
|
|
276
|
+
// concrete marker whose removal invalidates reuse.
|
|
277
|
+
if (entry.ecosystem === "node") {
|
|
278
|
+
await fs.mkdir(outputMarker, { recursive: true });
|
|
279
|
+
}
|
|
280
|
+
if (!(await directoryExists(outputMarker))) {
|
|
281
|
+
throw new Error(`dependency_preparation_output_missing: ${install.command} succeeded without creating ${outputMarker}.`);
|
|
282
|
+
}
|
|
283
|
+
const receipt = {
|
|
284
|
+
schemaVersion: DEPENDENCY_RECEIPT_SCHEMA_VERSION,
|
|
285
|
+
fingerprint,
|
|
286
|
+
ecosystem: entry.ecosystem,
|
|
287
|
+
packageRoot: entry.packageRoot,
|
|
288
|
+
command,
|
|
289
|
+
outputMarker: path.relative(cwd, outputMarker).replaceAll("\\", "/"),
|
|
290
|
+
completedAt: new Date().toISOString(),
|
|
291
|
+
};
|
|
292
|
+
await persistDependencyPreparationReceipt(receiptPath, receipt);
|
|
293
|
+
await markNpmCiRestored(outputMarker, command);
|
|
294
|
+
return {
|
|
295
|
+
install,
|
|
296
|
+
receipt: {
|
|
297
|
+
ecosystem: entry.ecosystem,
|
|
298
|
+
packageRoot: entry.packageRoot,
|
|
299
|
+
command,
|
|
300
|
+
cacheHit: false,
|
|
301
|
+
fingerprint,
|
|
302
|
+
receiptPath,
|
|
303
|
+
durationMs: elapsedMilliseconds(startedAt),
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
async function markNpmCiRestored(outputMarker, command) {
|
|
309
|
+
if (command !== "npm ci")
|
|
310
|
+
return;
|
|
311
|
+
// Forge.Api's RestoreForgeBridge target uses this stamp as its incremental
|
|
312
|
+
// output. Worktree preparation has already installed and verified the same
|
|
313
|
+
// package graph, so an immediate dotnet build must not repeat npm ci.
|
|
314
|
+
await fs.writeFile(path.join(outputMarker, ".forge-restore.stamp"), "", { mode: 0o600 });
|
|
315
|
+
}
|
|
316
|
+
function elapsedMilliseconds(startedAt) {
|
|
317
|
+
return Math.max(0, Math.round((performance.now() - startedAt) * 1000) / 1000);
|
|
318
|
+
}
|
|
319
|
+
async function installFallbackCommand(entry, cwd) {
|
|
320
|
+
if (entry.ecosystem === "node") {
|
|
321
|
+
if (await pathExists(path.join(cwd, "pnpm-lock.yaml")))
|
|
322
|
+
return "pnpm install --frozen-lockfile";
|
|
323
|
+
return await pathExists(path.join(cwd, "package-lock.json")) ? "npm ci" : "npm install";
|
|
324
|
+
}
|
|
325
|
+
if (entry.ecosystem === "python") {
|
|
326
|
+
return await pathExists(path.join(cwd, "requirements.txt"))
|
|
327
|
+
? "python -m venv .venv && pip install -r requirements.txt"
|
|
328
|
+
: "python -m venv .venv";
|
|
329
|
+
}
|
|
330
|
+
return "dotnet restore";
|
|
331
|
+
}
|
|
332
|
+
function dependencyOutputMarker(ecosystem, cwd) {
|
|
333
|
+
if (ecosystem === "node")
|
|
334
|
+
return path.join(cwd, "node_modules");
|
|
335
|
+
if (ecosystem === "python")
|
|
336
|
+
return path.join(cwd, ".venv");
|
|
337
|
+
return path.join(cwd, "obj");
|
|
338
|
+
}
|
|
339
|
+
async function dependencyPreparationFingerprint(entry, worktreePath, cwd, command, policy) {
|
|
340
|
+
const inputFiles = await dependencyInputFiles(entry.ecosystem, worktreePath, cwd);
|
|
341
|
+
const inputDigests = await Promise.all(inputFiles.map(async (file) => ({
|
|
342
|
+
path: path.relative(worktreePath, file).replaceAll("\\", "/"),
|
|
343
|
+
digest: await sha256File(file),
|
|
344
|
+
})));
|
|
345
|
+
const toolchainVersion = await dependencyToolchainVersion(entry.ecosystem, cwd, policy);
|
|
346
|
+
const trustDomain = policy?.trustDomain ?? process.env.FORGE_TRUST_DOMAIN_ID ?? "default";
|
|
347
|
+
const invalidationEpoch = policy?.invalidationEpoch ?? process.env.FORGE_DEPENDENCY_CACHE_EPOCH ?? "default";
|
|
348
|
+
const contract = {
|
|
349
|
+
schemaVersion: DEPENDENCY_RECEIPT_SCHEMA_VERSION,
|
|
350
|
+
preparationContract: DEPENDENCY_PREPARATION_CONTRACT,
|
|
351
|
+
ecosystem: entry.ecosystem,
|
|
352
|
+
packageRoot: entry.packageRoot.replaceAll("\\", "/"),
|
|
353
|
+
command,
|
|
354
|
+
inputDigests,
|
|
355
|
+
toolchainVersion,
|
|
356
|
+
nodeRuntime: process.version,
|
|
357
|
+
platform: process.platform,
|
|
358
|
+
architecture: process.arch,
|
|
359
|
+
osRelease: os.release(),
|
|
360
|
+
isolation: policy?.isolation ?? process.env.FORGE_RUNTIME_MODE ?? "managed_host_process",
|
|
361
|
+
trustDomainFingerprint: sha256Text(trustDomain),
|
|
362
|
+
invalidationEpochFingerprint: sha256Text(invalidationEpoch),
|
|
363
|
+
};
|
|
364
|
+
return `sha256:${sha256Text(JSON.stringify(contract))}`;
|
|
365
|
+
}
|
|
366
|
+
async function dependencyInputFiles(ecosystem, worktreePath, cwd) {
|
|
367
|
+
const result = new Set();
|
|
368
|
+
const directNames = ecosystem === "node"
|
|
369
|
+
? ["package.json", "package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "pnpm-workspace.yaml", "yarn.lock", ".npmrc", ".yarnrc", ".yarnrc.yml", ".nvmrc", ".node-version"]
|
|
370
|
+
: ecosystem === "python"
|
|
371
|
+
? ["pyproject.toml", "requirements.txt", "requirements-dev.txt", "poetry.lock", "Pipfile", "Pipfile.lock", "uv.lock", "pip.conf", "pyvenv.cfg"]
|
|
372
|
+
: ["global.json", "NuGet.Config", "nuget.config", "Directory.Build.props", "Directory.Build.targets", "Directory.Packages.props", "packages.lock.json"];
|
|
373
|
+
let current = cwd;
|
|
374
|
+
const root = path.resolve(worktreePath);
|
|
375
|
+
while (isSubPath(root, current)) {
|
|
376
|
+
for (const name of directNames) {
|
|
377
|
+
const candidate = path.join(current, name);
|
|
378
|
+
if (await pathExists(candidate))
|
|
379
|
+
result.add(candidate);
|
|
380
|
+
}
|
|
381
|
+
if (ecosystem === "dotnet" && current === cwd) {
|
|
382
|
+
const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => []);
|
|
383
|
+
for (const item of entries) {
|
|
384
|
+
if (item.isFile() && (/\.(?:csproj|fsproj|vbproj|sln|slnx)$/iu.test(item.name))) {
|
|
385
|
+
result.add(path.join(current, item.name));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (current === root)
|
|
390
|
+
break;
|
|
391
|
+
current = path.dirname(current);
|
|
392
|
+
}
|
|
393
|
+
return [...result].sort((left, right) => left.localeCompare(right));
|
|
394
|
+
}
|
|
395
|
+
async function dependencyToolchainVersion(ecosystem, cwd, policy) {
|
|
396
|
+
if (ecosystem === "node") {
|
|
397
|
+
const manager = await pathExists(path.join(cwd, "pnpm-lock.yaml")) ? "pnpm" : "npm";
|
|
398
|
+
const override = policy?.toolchainVersions?.[manager];
|
|
399
|
+
if (override)
|
|
400
|
+
return `${manager}@${override};node@${process.version}`;
|
|
401
|
+
const launch = manager === "pnpm" ? resolvePnpmLaunch(["--version"]) : resolveNpmLaunch(["--version"]);
|
|
402
|
+
return `${manager}@${await readToolVersion(cwd, launch.command, launch.args)};node@${process.version}`;
|
|
403
|
+
}
|
|
404
|
+
const override = policy?.toolchainVersions?.[ecosystem];
|
|
405
|
+
if (override)
|
|
406
|
+
return `${ecosystem}@${override}`;
|
|
407
|
+
const launch = ecosystem === "dotnet"
|
|
408
|
+
? { command: "dotnet", args: ["--version"] }
|
|
409
|
+
: { command: "python", args: ["--version"] };
|
|
410
|
+
return `${ecosystem}@${await readToolVersion(cwd, launch.command, launch.args)}`;
|
|
411
|
+
}
|
|
412
|
+
async function readToolVersion(cwd, command, args) {
|
|
413
|
+
return await defaultProcessRunner.run({ command, cwd, args })
|
|
414
|
+
.then(result => result.exitCode === 0
|
|
415
|
+
? (result.stdout.trim() || result.stderr.trim() || "unknown").slice(0, 256)
|
|
416
|
+
: `unavailable:${result.exitCode}`)
|
|
417
|
+
.catch(() => "unavailable");
|
|
418
|
+
}
|
|
419
|
+
async function readDependencyPreparationReceipt(receiptPath) {
|
|
420
|
+
try {
|
|
421
|
+
const parsed = JSON.parse(await fs.readFile(receiptPath, "utf8"));
|
|
422
|
+
return parsed.schemaVersion === DEPENDENCY_RECEIPT_SCHEMA_VERSION
|
|
423
|
+
&& typeof parsed.fingerprint === "string"
|
|
424
|
+
&& typeof parsed.ecosystem === "string"
|
|
425
|
+
&& typeof parsed.packageRoot === "string"
|
|
426
|
+
&& typeof parsed.command === "string"
|
|
427
|
+
&& typeof parsed.outputMarker === "string"
|
|
428
|
+
? parsed
|
|
429
|
+
: null;
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
if (error.code === "ENOENT" || error instanceof SyntaxError)
|
|
433
|
+
return null;
|
|
434
|
+
throw error;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async function persistDependencyPreparationReceipt(receiptPath, receipt) {
|
|
438
|
+
await fs.mkdir(path.dirname(receiptPath), { recursive: true });
|
|
439
|
+
const temporaryPath = `${receiptPath}.${randomUUID()}.tmp`;
|
|
440
|
+
await fs.writeFile(temporaryPath, `${JSON.stringify(receipt, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
441
|
+
try {
|
|
442
|
+
await fs.rename(temporaryPath, receiptPath);
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
await fs.rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function sha256Text(value) {
|
|
449
|
+
return createHash("sha256").update(value).digest("hex");
|
|
450
|
+
}
|
|
228
451
|
async function runInstallFallback(entry, worktreePath, reason, executor) {
|
|
452
|
+
assertHostDatabaseCapabilityBoundary();
|
|
229
453
|
const cwd = path.join(worktreePath, entry.packageRoot === "." ? "" : entry.packageRoot);
|
|
230
454
|
if (entry.ecosystem === "node") {
|
|
231
455
|
const pnpmLockPath = path.join(cwd, "pnpm-lock.yaml");
|
|
232
456
|
if (await pathExists(pnpmLockPath)) {
|
|
233
457
|
const args = ["install", "--frozen-lockfile"];
|
|
234
458
|
const launch = resolvePnpmLaunch(args);
|
|
235
|
-
await executor.run(cwd, launch.command, launch.args, {
|
|
459
|
+
await executor.run(cwd, launch.command, launch.args, {
|
|
460
|
+
env: unattendedPackageManagerEnvironment(process.env, {
|
|
461
|
+
packageRoot: cwd,
|
|
462
|
+
requiredPathDirectories: launch.requiredPathDirectories,
|
|
463
|
+
}),
|
|
464
|
+
windowsVerbatimArguments: launch.windowsVerbatimArguments,
|
|
465
|
+
});
|
|
236
466
|
return { ecosystem: entry.ecosystem, packageRoot: entry.packageRoot, reason, command: `pnpm ${args.join(" ")}` };
|
|
237
467
|
}
|
|
238
468
|
const lockPath = path.join(cwd, "package-lock.json");
|
|
239
469
|
const args = (await pathExists(lockPath)) ? ["ci"] : ["install"];
|
|
240
470
|
const launch = resolveNpmLaunch(args);
|
|
241
|
-
await executor.run(cwd, launch.command, launch.args, {
|
|
471
|
+
await executor.run(cwd, launch.command, launch.args, {
|
|
472
|
+
env: unattendedPackageManagerEnvironment(process.env, {
|
|
473
|
+
packageRoot: cwd,
|
|
474
|
+
requiredPathDirectories: launch.requiredPathDirectories,
|
|
475
|
+
}),
|
|
476
|
+
windowsVerbatimArguments: launch.windowsVerbatimArguments,
|
|
477
|
+
});
|
|
242
478
|
return { ecosystem: entry.ecosystem, packageRoot: entry.packageRoot, reason, command: `npm ${args.join(" ")}` };
|
|
243
479
|
}
|
|
244
480
|
if (entry.ecosystem === "python") {
|
|
245
|
-
|
|
481
|
+
const environment = unattendedDependencyEnvironment();
|
|
482
|
+
await executor.run(cwd, "python", ["-m", "venv", ".venv"], { env: environment });
|
|
246
483
|
const requirements = path.join(cwd, "requirements.txt");
|
|
247
484
|
if (await pathExists(requirements)) {
|
|
248
485
|
const pip = process.platform === "win32" ? path.join(".venv", "Scripts", "pip") : path.join(".venv", "bin", "pip");
|
|
249
|
-
await executor.run(cwd, pip, ["install", "-r", "requirements.txt"]);
|
|
486
|
+
await executor.run(cwd, pip, ["install", "-r", "requirements.txt"], { env: environment });
|
|
250
487
|
return {
|
|
251
488
|
ecosystem: entry.ecosystem,
|
|
252
489
|
packageRoot: entry.packageRoot,
|
|
@@ -261,7 +498,7 @@ async function runInstallFallback(entry, worktreePath, reason, executor) {
|
|
|
261
498
|
command: "python -m venv .venv"
|
|
262
499
|
};
|
|
263
500
|
}
|
|
264
|
-
await executor.run(cwd, "dotnet", ["restore"]);
|
|
501
|
+
await executor.run(cwd, "dotnet", ["restore"], { env: unattendedDependencyEnvironment() });
|
|
265
502
|
return {
|
|
266
503
|
ecosystem: entry.ecosystem,
|
|
267
504
|
packageRoot: entry.packageRoot,
|
|
@@ -360,14 +597,37 @@ async function sha256File(filePath) {
|
|
|
360
597
|
export function resolveNpmLaunch(args, options = {}) {
|
|
361
598
|
const env = options.env ?? process.env;
|
|
362
599
|
const execPath = options.execPath ?? process.execPath;
|
|
600
|
+
const platform = options.platform ?? process.platform;
|
|
601
|
+
const pathExists = options.pathExists ?? existsSync;
|
|
363
602
|
const npmExecPath = env.npm_execpath;
|
|
364
|
-
|
|
603
|
+
const npmExecPathIsAbsolute = platform === "win32"
|
|
604
|
+
? path.win32.isAbsolute(npmExecPath ?? "")
|
|
605
|
+
: path.posix.isAbsolute(npmExecPath ?? "");
|
|
606
|
+
const npmExecPathBaseName = platform === "win32"
|
|
607
|
+
? path.win32.basename(npmExecPath ?? "")
|
|
608
|
+
: path.posix.basename(npmExecPath ?? "");
|
|
609
|
+
if (npmExecPath
|
|
610
|
+
&& npmExecPathIsAbsolute
|
|
611
|
+
&& npmExecPathBaseName.toLowerCase() === "npm-cli.js"
|
|
612
|
+
&& pathExists(npmExecPath)) {
|
|
365
613
|
return { command: execPath, args: [npmExecPath, ...args] };
|
|
366
614
|
}
|
|
367
|
-
const platform = options.platform ?? process.platform;
|
|
368
615
|
if (platform === "win32") {
|
|
369
|
-
const
|
|
370
|
-
|
|
616
|
+
const command = resolveWindowsPackageManagerCommand("npm.cmd", env, pathExists, [path.win32.dirname(execPath)]);
|
|
617
|
+
if (!command) {
|
|
618
|
+
throw new Error("Windows npm launcher could not be resolved before PATH compaction.");
|
|
619
|
+
}
|
|
620
|
+
const cli = resolveWindowsPackageManagerCli("npm", command, execPath, pathExists);
|
|
621
|
+
if (cli)
|
|
622
|
+
return { command: execPath, args: [cli, ...args] };
|
|
623
|
+
const comSpec = options.env
|
|
624
|
+
? windowsEnvironmentValue(env, "ComSpec") ?? "cmd.exe"
|
|
625
|
+
: windowsEnvironmentValue(env, "ComSpec");
|
|
626
|
+
return {
|
|
627
|
+
...buildWindowsCmdLaunch(command, args, comSpec),
|
|
628
|
+
requiredPathDirectories: [path.win32.dirname(command)],
|
|
629
|
+
windowsVerbatimArguments: true,
|
|
630
|
+
};
|
|
371
631
|
}
|
|
372
632
|
for (const candidate of options.candidates ?? defaultNpmCliCandidates(execPath, options.homeDir ?? os.homedir())) {
|
|
373
633
|
const resolvedCandidate = tryResolveNpmCandidate(candidate);
|
|
@@ -377,9 +637,26 @@ export function resolveNpmLaunch(args, options = {}) {
|
|
|
377
637
|
}
|
|
378
638
|
return { command: "npm", args };
|
|
379
639
|
}
|
|
380
|
-
export function resolvePnpmLaunch(args) {
|
|
381
|
-
|
|
382
|
-
|
|
640
|
+
export function resolvePnpmLaunch(args, options = {}) {
|
|
641
|
+
const platform = options.platform ?? process.platform;
|
|
642
|
+
if (platform === "win32") {
|
|
643
|
+
const env = options.env ?? process.env;
|
|
644
|
+
const execPath = options.execPath ?? process.execPath;
|
|
645
|
+
const command = resolveWindowsPackageManagerCommand("pnpm.cmd", env, options.pathExists ?? existsSync, [path.win32.dirname(execPath)]);
|
|
646
|
+
if (!command) {
|
|
647
|
+
throw new Error("Windows pnpm launcher could not be resolved before PATH compaction.");
|
|
648
|
+
}
|
|
649
|
+
const cli = resolveWindowsPackageManagerCli("pnpm", command, execPath, options.pathExists ?? existsSync);
|
|
650
|
+
if (cli)
|
|
651
|
+
return { command: execPath, args: [cli, ...args] };
|
|
652
|
+
const comSpec = options.env
|
|
653
|
+
? windowsEnvironmentValue(env, "ComSpec") ?? "cmd.exe"
|
|
654
|
+
: windowsEnvironmentValue(env, "ComSpec");
|
|
655
|
+
return {
|
|
656
|
+
...buildWindowsCmdLaunch(command, args, comSpec),
|
|
657
|
+
requiredPathDirectories: [path.win32.dirname(command)],
|
|
658
|
+
windowsVerbatimArguments: true,
|
|
659
|
+
};
|
|
383
660
|
}
|
|
384
661
|
return { command: "pnpm", args };
|
|
385
662
|
}
|
|
@@ -394,8 +671,200 @@ export function formatCommandFailureOutput(stdout, stderr) {
|
|
|
394
671
|
}
|
|
395
672
|
return `[last ${MAX_COMMAND_FAILURE_OUTPUT_LENGTH} characters]\n${output.slice(-MAX_COMMAND_FAILURE_OUTPUT_LENGTH)}`;
|
|
396
673
|
}
|
|
397
|
-
export function unattendedPackageManagerEnvironment(env = process.env) {
|
|
398
|
-
|
|
674
|
+
export function unattendedPackageManagerEnvironment(env = process.env, options = {}) {
|
|
675
|
+
const result = { ...unattendedDependencyEnvironment(env), CI: "true" };
|
|
676
|
+
if ((options.platform ?? process.platform) !== "win32")
|
|
677
|
+
return result;
|
|
678
|
+
const pathValue = windowsEnvironmentValues(env, "Path").join(";");
|
|
679
|
+
for (const key of Object.keys(result)) {
|
|
680
|
+
if (key.toLowerCase() === "path")
|
|
681
|
+
delete result[key];
|
|
682
|
+
}
|
|
683
|
+
result.PATH = compactWindowsPackageManagerPath(pathValue, env, options);
|
|
684
|
+
return result;
|
|
685
|
+
}
|
|
686
|
+
const dependencyEnvironmentAllowlist = new Set([
|
|
687
|
+
"appdata",
|
|
688
|
+
"comspec",
|
|
689
|
+
"corepack_home",
|
|
690
|
+
"dotnet_cli_home",
|
|
691
|
+
"dotnet_root",
|
|
692
|
+
"home",
|
|
693
|
+
"homedrive",
|
|
694
|
+
"homepath",
|
|
695
|
+
"http_proxy",
|
|
696
|
+
"https_proxy",
|
|
697
|
+
"localappdata",
|
|
698
|
+
"no_proxy",
|
|
699
|
+
"npm_config_cache",
|
|
700
|
+
"nuget_http_cache_path",
|
|
701
|
+
"nuget_packages",
|
|
702
|
+
"path",
|
|
703
|
+
"pathext",
|
|
704
|
+
"programdata",
|
|
705
|
+
"programfiles",
|
|
706
|
+
"programfiles(x86)",
|
|
707
|
+
"programw6432",
|
|
708
|
+
"ssl_cert_dir",
|
|
709
|
+
"ssl_cert_file",
|
|
710
|
+
"systemdrive",
|
|
711
|
+
"systemroot",
|
|
712
|
+
"temp",
|
|
713
|
+
"tmp",
|
|
714
|
+
"tmpdir",
|
|
715
|
+
"userdomain",
|
|
716
|
+
"username",
|
|
717
|
+
"userprofile",
|
|
718
|
+
"windir",
|
|
719
|
+
]);
|
|
720
|
+
export function unattendedDependencyEnvironment(env = process.env) {
|
|
721
|
+
return Object.fromEntries(Object.entries(env).filter(([name, value]) => typeof value === "string"
|
|
722
|
+
&& (dependencyEnvironmentAllowlist.has(name.toLowerCase()) || name.toUpperCase().startsWith("LC_"))));
|
|
723
|
+
}
|
|
724
|
+
export function compactWindowsPackageManagerPath(pathValue, env = process.env, options = {}) {
|
|
725
|
+
const pathExists = options.pathExists ?? existsSync;
|
|
726
|
+
const maximumPathLength = options.maximumPathLength
|
|
727
|
+
?? windowsPackageManagerPathBudget(options.packageRoot ?? process.cwd());
|
|
728
|
+
const execPath = options.execPath ?? process.execPath;
|
|
729
|
+
if (!Number.isSafeInteger(maximumPathLength) || maximumPathLength < 1) {
|
|
730
|
+
throw new Error(`Windows package-manager PATH budget is exhausted before launch (${maximumPathLength}).`);
|
|
731
|
+
}
|
|
732
|
+
const normalize = windowsPathNormalizer(env);
|
|
733
|
+
const inherited = [];
|
|
734
|
+
const seen = new Set();
|
|
735
|
+
for (const candidate of pathValue.split(";").map(normalize)) {
|
|
736
|
+
if (candidate.length === 0 || !path.win32.isAbsolute(candidate) || !pathExists(candidate))
|
|
737
|
+
continue;
|
|
738
|
+
const key = candidate.toLowerCase();
|
|
739
|
+
if (seen.has(key))
|
|
740
|
+
continue;
|
|
741
|
+
inherited.push(candidate);
|
|
742
|
+
seen.add(key);
|
|
743
|
+
}
|
|
744
|
+
const nodeDirectory = normalize(path.win32.dirname(execPath));
|
|
745
|
+
if (!nodeDirectory || !path.win32.isAbsolute(nodeDirectory) || !pathExists(nodeDirectory)) {
|
|
746
|
+
throw new Error(`Windows Node runtime directory is unavailable: ${nodeDirectory || "<empty>"}.`);
|
|
747
|
+
}
|
|
748
|
+
const systemRoot = normalize(windowsEnvironmentValue(env, "SystemRoot") ?? "");
|
|
749
|
+
const requiredCandidates = [
|
|
750
|
+
nodeDirectory,
|
|
751
|
+
normalize(path.win32.dirname(windowsEnvironmentValue(env, "ComSpec") ?? "")),
|
|
752
|
+
systemRoot ? path.win32.join(systemRoot, "System32") : "",
|
|
753
|
+
systemRoot,
|
|
754
|
+
].filter(candidate => candidate.length > 0
|
|
755
|
+
&& path.win32.isAbsolute(candidate)
|
|
756
|
+
&& pathExists(candidate));
|
|
757
|
+
const explicitRequired = (options.requiredPathDirectories ?? []).map(normalize);
|
|
758
|
+
for (const candidate of explicitRequired) {
|
|
759
|
+
if (!candidate || !path.win32.isAbsolute(candidate) || !pathExists(candidate)) {
|
|
760
|
+
throw new Error(`Windows package-manager required PATH directory is unavailable: ${candidate || "<empty>"}.`);
|
|
761
|
+
}
|
|
762
|
+
requiredCandidates.push(candidate);
|
|
763
|
+
}
|
|
764
|
+
const required = new Map();
|
|
765
|
+
for (const candidate of requiredCandidates)
|
|
766
|
+
required.set(candidate.toLowerCase(), candidate);
|
|
767
|
+
const ordered = [...inherited];
|
|
768
|
+
for (const candidate of required.values()) {
|
|
769
|
+
if (!seen.has(candidate.toLowerCase()))
|
|
770
|
+
ordered.push(candidate);
|
|
771
|
+
}
|
|
772
|
+
const requiredLength = joinedWindowsPathLength([...required.values()]);
|
|
773
|
+
if (requiredLength > maximumPathLength) {
|
|
774
|
+
throw new Error(`Windows package-manager PATH cannot retain required runtime directories within ${maximumPathLength} characters.`);
|
|
775
|
+
}
|
|
776
|
+
const selected = new Set(required.keys());
|
|
777
|
+
let selectedLength = requiredLength;
|
|
778
|
+
for (const candidate of inherited) {
|
|
779
|
+
const key = candidate.toLowerCase();
|
|
780
|
+
if (selected.has(key))
|
|
781
|
+
continue;
|
|
782
|
+
const nextLength = selectedLength + (selected.size === 0 ? 0 : 1) + candidate.length;
|
|
783
|
+
if (nextLength > maximumPathLength)
|
|
784
|
+
continue;
|
|
785
|
+
selected.add(key);
|
|
786
|
+
selectedLength = nextLength;
|
|
787
|
+
}
|
|
788
|
+
return ordered.filter(candidate => selected.has(candidate.toLowerCase())).join(";");
|
|
789
|
+
}
|
|
790
|
+
export function windowsPackageManagerLifecyclePathPrefix(packageRoot) {
|
|
791
|
+
const entries = [];
|
|
792
|
+
let current = path.win32.resolve(packageRoot);
|
|
793
|
+
while (true) {
|
|
794
|
+
entries.push(path.win32.join(current, "node_modules", ".bin"));
|
|
795
|
+
const parent = path.win32.dirname(current);
|
|
796
|
+
if (parent === current)
|
|
797
|
+
break;
|
|
798
|
+
current = parent;
|
|
799
|
+
}
|
|
800
|
+
return entries.join(";");
|
|
801
|
+
}
|
|
802
|
+
export function windowsPackageManagerPathBudget(packageRoot) {
|
|
803
|
+
const lifecyclePrefix = windowsPackageManagerLifecyclePathPrefix(packageRoot);
|
|
804
|
+
return WINDOWS_COMMAND_ENVIRONMENT_PATH_LIMIT
|
|
805
|
+
- lifecyclePrefix.length
|
|
806
|
+
- 1
|
|
807
|
+
- WINDOWS_PACKAGE_MANAGER_INTERNAL_PATH_RESERVE;
|
|
808
|
+
}
|
|
809
|
+
function resolveWindowsPackageManagerCommand(commandName, env, pathExists, fallbackDirectories) {
|
|
810
|
+
const normalize = windowsPathNormalizer(env);
|
|
811
|
+
const directories = [
|
|
812
|
+
...windowsEnvironmentValues(env, "Path").flatMap(value => value.split(";")),
|
|
813
|
+
...fallbackDirectories,
|
|
814
|
+
].map(normalize);
|
|
815
|
+
const seen = new Set();
|
|
816
|
+
for (const directory of directories) {
|
|
817
|
+
if (!directory || !path.win32.isAbsolute(directory))
|
|
818
|
+
continue;
|
|
819
|
+
const key = directory.toLowerCase();
|
|
820
|
+
if (seen.has(key))
|
|
821
|
+
continue;
|
|
822
|
+
seen.add(key);
|
|
823
|
+
const candidate = path.win32.join(directory, commandName);
|
|
824
|
+
if (pathExists(candidate))
|
|
825
|
+
return candidate;
|
|
826
|
+
}
|
|
827
|
+
return null;
|
|
828
|
+
}
|
|
829
|
+
function resolveWindowsPackageManagerCli(manager, commandPath, execPath, pathExists) {
|
|
830
|
+
const commandDirectory = path.win32.dirname(commandPath);
|
|
831
|
+
const execDirectory = path.win32.dirname(execPath);
|
|
832
|
+
const candidates = manager === "npm"
|
|
833
|
+
? [
|
|
834
|
+
path.win32.join(commandDirectory, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
835
|
+
path.win32.join(execDirectory, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
836
|
+
path.win32.join(execDirectory, "node_modules", "corepack", "dist", "npm.js"),
|
|
837
|
+
]
|
|
838
|
+
: [
|
|
839
|
+
path.win32.join(commandDirectory, "node_modules", "pnpm", "bin", "pnpm.mjs"),
|
|
840
|
+
path.win32.join(execDirectory, "node_modules", "pnpm", "bin", "pnpm.mjs"),
|
|
841
|
+
path.win32.join(execDirectory, "node_modules", "corepack", "dist", "pnpm.js"),
|
|
842
|
+
];
|
|
843
|
+
return candidates.find(pathExists) ?? null;
|
|
844
|
+
}
|
|
845
|
+
function windowsPathNormalizer(env) {
|
|
846
|
+
const environment = new Map(Object.entries(env).map(([key, value]) => [key.toLowerCase(), value ?? ""]));
|
|
847
|
+
return (value) => {
|
|
848
|
+
const trimmed = value.trim();
|
|
849
|
+
const unquoted = trimmed.length >= 2 && trimmed.startsWith('"') && trimmed.endsWith('"')
|
|
850
|
+
? trimmed.slice(1, -1).trim()
|
|
851
|
+
: trimmed;
|
|
852
|
+
return unquoted.replace(/%([^%]+)%/gu, (match, name) => environment.get(name.toLowerCase()) || match);
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
function windowsEnvironmentValues(env, name) {
|
|
856
|
+
const normalized = name.toLowerCase();
|
|
857
|
+
return Object.entries(env)
|
|
858
|
+
.filter(([key, value]) => key.toLowerCase() === normalized && Boolean(value))
|
|
859
|
+
.map(([, value]) => value);
|
|
860
|
+
}
|
|
861
|
+
function windowsEnvironmentValue(env, name) {
|
|
862
|
+
return windowsEnvironmentValues(env, name)[0];
|
|
863
|
+
}
|
|
864
|
+
function joinedWindowsPathLength(entries) {
|
|
865
|
+
return entries.length === 0
|
|
866
|
+
? 0
|
|
867
|
+
: entries.reduce((total, entry) => total + entry.length, entries.length - 1);
|
|
399
868
|
}
|
|
400
869
|
function tryResolveNpmCandidate(candidate) {
|
|
401
870
|
try {
|
|
@@ -419,7 +888,13 @@ function defaultNpmCliCandidates(execPath, homeDir) {
|
|
|
419
888
|
}
|
|
420
889
|
const defaultCommandExecutor = {
|
|
421
890
|
async run(cwd, command, args, options) {
|
|
422
|
-
const result = await defaultProcessRunner.run({
|
|
891
|
+
const result = await defaultProcessRunner.run({
|
|
892
|
+
command,
|
|
893
|
+
cwd,
|
|
894
|
+
args,
|
|
895
|
+
env: options?.env,
|
|
896
|
+
windowsVerbatimArguments: options?.windowsVerbatimArguments,
|
|
897
|
+
});
|
|
423
898
|
if (result.exitCode !== 0) {
|
|
424
899
|
const output = formatCommandFailureOutput(result.stdout, result.stderr);
|
|
425
900
|
const details = output.length > 0 ? `\n${output}` : " no output was captured";
|
package/dist/worktree/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { GitWorktreeService } from "./worktree.service.js";
|
|
2
2
|
export { managedRepoRoot, resolveManagedWorktreeRoot, resolveManagedWorktreeRootForRepo, } from "./worktree-paths.js";
|
|
3
3
|
export { detectWarmPaths, warmWorktreeDependencies, createDirectoryLink, lockfilesDiffer, requiresInstallFallback } from "./dependency-warmer.js";
|
|
4
|
-
export type { WarmDependenciesResult, WarmPathEntry, InstallFallbackResult } from "./dependency-warmer.js";
|
|
4
|
+
export type { WarmDependenciesResult, WarmPathEntry, InstallFallbackResult, DependencyPreparationPolicy, DependencyPreparationReceiptResult, } from "./dependency-warmer.js";
|
|
5
5
|
export type { WorktreeService } from "./worktree.base.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { GitClient } from "../shared/git/git.js";
|
|
2
|
+
import type { WorktreePrepareRequest } from "./worktree.types.js";
|
|
3
|
+
export declare function storyQaReferenceRoot(storyId: string, runId: string): string;
|
|
4
|
+
export declare function materializeStoryQaReferences(worktreePath: string, request: WorktreePrepareRequest, git?: GitClient): Promise<void>;
|