@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
|
@@ -2,55 +2,89 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { isAlias, parseDocument, visit } from "yaml";
|
|
5
|
+
import { readCanonicalSourceFile } from "./canonical-source-file.js";
|
|
6
|
+
import { isGeneratedOutputDirectoryName } from "./generated-output-reset.js";
|
|
5
7
|
export const hostRuntimeContractPath = ".forge/forge.runtime.yml";
|
|
8
|
+
export const hostRuntimeTestPostgresAdminEnvironment = "FORGE_TEST_POSTGRES_ADMIN_CONNECTION_STRING";
|
|
9
|
+
export const hostRuntimeLegacyTestPostgresEnvironment = "FORGE_TEST_POSTGRES_CONNECTION_STRING";
|
|
6
10
|
const maximumContractBytes = 64 * 1024;
|
|
7
11
|
const maximumDepth = 12;
|
|
12
|
+
// Every discovery scan stops after this many directory entries. A monorepo needs a few
|
|
13
|
+
// thousand; the bound only keeps a pathological tree from stalling attempt preparation.
|
|
14
|
+
const maximumDiscoveryEntries = 20_000;
|
|
15
|
+
/**
|
|
16
|
+
* A discovery scan reached its entry budget before seeing the whole tree, so what it did not
|
|
17
|
+
* find may still exist. Discovery must not treat that as absence: a partial runtime (for
|
|
18
|
+
* example a web app without its API) would send the attempt's traffic to the wrong server.
|
|
19
|
+
*/
|
|
20
|
+
class IncompleteRuntimeDiscoveryError extends Error {
|
|
21
|
+
}
|
|
22
|
+
// Dependency, build and editor folders never hold an application entrypoint, and counting
|
|
23
|
+
// them would exhaust the budget and serialize a repository for no reason.
|
|
8
24
|
const ignoredDiscoveryDirectories = new Set([
|
|
9
25
|
".forge",
|
|
10
26
|
".forge-designer",
|
|
11
27
|
".git",
|
|
28
|
+
".gradle",
|
|
29
|
+
".idea",
|
|
12
30
|
".local",
|
|
31
|
+
".next",
|
|
32
|
+
".pnpm",
|
|
33
|
+
".turbo",
|
|
34
|
+
".venv",
|
|
35
|
+
".vs",
|
|
36
|
+
".vscode",
|
|
37
|
+
".yarn",
|
|
13
38
|
"bin",
|
|
39
|
+
"build",
|
|
14
40
|
"coverage",
|
|
15
41
|
"dist",
|
|
16
42
|
"node_modules",
|
|
17
43
|
"obj",
|
|
44
|
+
"target",
|
|
45
|
+
"vendor",
|
|
46
|
+
"venv",
|
|
18
47
|
]);
|
|
19
48
|
const topLevelKeys = new Set(["schemaVersion", "runtime"]);
|
|
20
49
|
const runtimeKeys = new Set(["hostConcurrency", "ports", "playwright", "browserProfile", "singletonResources"]);
|
|
21
50
|
const portKeys = new Set(["adapter", "launch", "env", "baseUrlEnv", "format"]);
|
|
22
51
|
const launchKeys = new Set(["command", "args", "workingDirectory", "environment"]);
|
|
23
52
|
const playwrightKeys = new Set(["config", "baseUrlPort", "workers"]);
|
|
24
|
-
export async function loadHostRuntimeContract(worktreePath) {
|
|
53
|
+
export async function loadHostRuntimeContract(worktreePath, snapshot, directorySnapshot) {
|
|
54
|
+
worktreePath = await fs.realpath(worktreePath);
|
|
25
55
|
const target = path.join(path.resolve(worktreePath), hostRuntimeContractPath);
|
|
26
|
-
let
|
|
56
|
+
let source;
|
|
27
57
|
try {
|
|
28
|
-
|
|
58
|
+
const captured = snapshot ? await snapshot(target) : await readCanonicalSourceFile(target, maximumContractBytes);
|
|
59
|
+
if (captured === null)
|
|
60
|
+
return await discoverHostRuntimeContract(worktreePath, snapshot, directorySnapshot);
|
|
61
|
+
source = captured;
|
|
29
62
|
}
|
|
30
63
|
catch (error) {
|
|
31
64
|
if (isFileNotFound(error))
|
|
32
|
-
return await discoverHostRuntimeContract(worktreePath);
|
|
65
|
+
return await discoverHostRuntimeContract(worktreePath, snapshot, directorySnapshot);
|
|
33
66
|
throw error;
|
|
34
67
|
}
|
|
35
|
-
if (!targetStat.isFile() || targetStat.size < 1 || targetStat.size > maximumContractBytes) {
|
|
36
|
-
throw new Error(`runtime_contract_invalid: forge.runtime.yml must be a regular 1-${maximumContractBytes} byte file.`);
|
|
37
|
-
}
|
|
38
|
-
const [realWorktree, realTarget] = await Promise.all([fs.realpath(worktreePath), fs.realpath(target)]);
|
|
39
|
-
const relative = path.relative(realWorktree, realTarget);
|
|
40
|
-
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
41
|
-
throw new Error("runtime_contract_invalid: forge.runtime.yml must remain inside the prepared worktree.");
|
|
42
|
-
}
|
|
43
68
|
return {
|
|
44
|
-
contract: validateHostRuntimeContract(
|
|
69
|
+
contract: validateHostRuntimeContract(source.toString("utf8")),
|
|
45
70
|
source: "project",
|
|
46
71
|
};
|
|
47
72
|
}
|
|
48
|
-
async function discoverHostRuntimeContract(worktreePath) {
|
|
73
|
+
async function discoverHostRuntimeContract(worktreePath, snapshot, directorySnapshot) {
|
|
49
74
|
const root = path.resolve(worktreePath);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
let nodeDiscovery;
|
|
76
|
+
let aspNetDiscovery;
|
|
77
|
+
try {
|
|
78
|
+
[nodeDiscovery, aspNetDiscovery] = await Promise.all([
|
|
79
|
+
discoverNodeRuntimes(root, snapshot, directorySnapshot),
|
|
80
|
+
discoverAspNetRuntimes(root, snapshot, directorySnapshot),
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof IncompleteRuntimeDiscoveryError)
|
|
85
|
+
return incompleteRuntimeDiscovery();
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
54
88
|
if (nodeDiscovery.ambiguous || aspNetDiscovery.ambiguous) {
|
|
55
89
|
return ambiguousRuntimeDiscovery();
|
|
56
90
|
}
|
|
@@ -99,16 +133,16 @@ async function discoverHostRuntimeContract(worktreePath) {
|
|
|
99
133
|
},
|
|
100
134
|
};
|
|
101
135
|
}
|
|
102
|
-
async function discoverNodeRuntimes(root) {
|
|
136
|
+
async function discoverNodeRuntimes(root, snapshot, directorySnapshot) {
|
|
103
137
|
const manifests = [...new Set([
|
|
104
138
|
path.join(root, "package.json"),
|
|
105
|
-
...await findFiles(root, file => path.basename(file).toLowerCase() === "package.json", 4,
|
|
139
|
+
...await findFiles(root, file => path.basename(file).toLowerCase() === "package.json", 4, maximumDiscoveryEntries, directorySnapshot),
|
|
106
140
|
])];
|
|
107
|
-
const candidates = (await Promise.all(manifests.map(async (manifestPath) => await discoverNodeRuntime(root, manifestPath)))).filter((candidate) => candidate !== null);
|
|
141
|
+
const candidates = (await Promise.all(manifests.map(async (manifestPath) => await discoverNodeRuntime(root, manifestPath, snapshot, directorySnapshot)))).filter((candidate) => candidate !== null);
|
|
108
142
|
return { candidates: candidates.length === 1 ? candidates : [], ambiguous: candidates.length > 1 };
|
|
109
143
|
}
|
|
110
|
-
async function discoverNodeRuntime(root, manifestPath) {
|
|
111
|
-
const source = await readBoundedOptionalFile(manifestPath, 256 * 1024);
|
|
144
|
+
async function discoverNodeRuntime(root, manifestPath, snapshot, directorySnapshot) {
|
|
145
|
+
const source = await readBoundedOptionalFile(manifestPath, 256 * 1024, snapshot);
|
|
112
146
|
if (source === null)
|
|
113
147
|
return null;
|
|
114
148
|
let manifest;
|
|
@@ -130,15 +164,15 @@ async function discoverNodeRuntime(root, manifestPath) {
|
|
|
130
164
|
const next = Object.hasOwn(dependencies, "next") || /(^|\s)next(?:\s|$)/u.test(script);
|
|
131
165
|
if (vite === next)
|
|
132
166
|
return null;
|
|
133
|
-
const packageManager = await nearestPackageManager(root, path.dirname(manifestPath));
|
|
167
|
+
const packageManager = await nearestPackageManager(root, path.dirname(manifestPath), snapshot);
|
|
134
168
|
if (!packageManager)
|
|
135
169
|
return null;
|
|
136
170
|
const adapter = vite ? "vite" : "next";
|
|
137
171
|
const playwrightConfigs = [...new Set((await Promise.all([
|
|
138
172
|
...["playwright.config.ts", "playwright.config.js", "playwright.config.mjs", "playwright.config.cjs"]
|
|
139
173
|
.flatMap(file => [file, `e2e/${file}`, `tests/e2e/${file}`])
|
|
140
|
-
.map(async (candidate) => await optionalFileExists(path.join(root, candidate)) ? path.join(root, candidate) : null),
|
|
141
|
-
findFiles(root, file => /^playwright\.config\.(?:ts|js|mjs|cjs)$/iu.test(path.basename(file)), 4,
|
|
174
|
+
.map(async (candidate) => await optionalFileExists(path.join(root, candidate), snapshot) ? path.join(root, candidate) : null),
|
|
175
|
+
findFiles(root, file => /^playwright\.config\.(?:ts|js|mjs|cjs)$/iu.test(path.basename(file)), 4, maximumDiscoveryEntries, directorySnapshot),
|
|
142
176
|
])).flat().filter((value) => value !== null))]
|
|
143
177
|
.map(config => portableRelativePath(root, config));
|
|
144
178
|
const playwright = playwrightConfigs.length === 1
|
|
@@ -182,11 +216,13 @@ async function discoverNodeRuntime(root, manifestPath) {
|
|
|
182
216
|
}),
|
|
183
217
|
};
|
|
184
218
|
}
|
|
185
|
-
async function discoverAspNetRuntimes(root) {
|
|
186
|
-
|
|
219
|
+
async function discoverAspNetRuntimes(root, snapshot, directorySnapshot) {
|
|
220
|
+
// Deep enough for nested solutions (src/<area>/<Project>/<Project>.csproj); the entry budget,
|
|
221
|
+
// not the depth, bounds the scan, and a scan that exceeds it is reported as incomplete.
|
|
222
|
+
const projects = await findFiles(root, file => file.toLowerCase().endsWith(".csproj"), 6, maximumDiscoveryEntries, directorySnapshot);
|
|
187
223
|
const webProjects = [];
|
|
188
224
|
for (const projectPath of projects) {
|
|
189
|
-
const source = await readBoundedOptionalFile(projectPath, 512 * 1024);
|
|
225
|
+
const source = await readBoundedOptionalFile(projectPath, 512 * 1024, snapshot);
|
|
190
226
|
if (source && /<Project\s+Sdk=["']Microsoft\.NET\.Sdk\.Web["']/iu.test(source)) {
|
|
191
227
|
webProjects.push({ relativePath: path.relative(root, projectPath).replaceAll("\\", "/"), source });
|
|
192
228
|
}
|
|
@@ -194,7 +230,7 @@ async function discoverAspNetRuntimes(root) {
|
|
|
194
230
|
if (webProjects.length !== 1)
|
|
195
231
|
return { candidates: [], ambiguous: webProjects.length > 1 };
|
|
196
232
|
const project = webProjects[0];
|
|
197
|
-
const launchProfile = await discoverAspNetLaunchProfile(root, project.relativePath);
|
|
233
|
+
const launchProfile = await discoverAspNetLaunchProfile(root, project.relativePath, snapshot);
|
|
198
234
|
const contract = {
|
|
199
235
|
schemaVersion: 1,
|
|
200
236
|
runtime: {
|
|
@@ -277,6 +313,17 @@ function combineBrowserAndApiRuntime(browser, api) {
|
|
|
277
313
|
}),
|
|
278
314
|
};
|
|
279
315
|
}
|
|
316
|
+
function incompleteRuntimeDiscovery() {
|
|
317
|
+
return {
|
|
318
|
+
contract: defaultHostRuntimeContract(),
|
|
319
|
+
source: "default",
|
|
320
|
+
discovery: {
|
|
321
|
+
status: "ambiguous",
|
|
322
|
+
reasonCode: "runtime_discovery_incomplete",
|
|
323
|
+
summary: "Forge could not scan the whole repository within its discovery budget, so host application runs remain serialized.",
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
280
327
|
function ambiguousRuntimeDiscovery() {
|
|
281
328
|
return {
|
|
282
329
|
contract: defaultHostRuntimeContract(),
|
|
@@ -288,15 +335,15 @@ function ambiguousRuntimeDiscovery() {
|
|
|
288
335
|
},
|
|
289
336
|
};
|
|
290
337
|
}
|
|
291
|
-
async function nearestPackageManager(root, start) {
|
|
338
|
+
async function nearestPackageManager(root, start, snapshot) {
|
|
292
339
|
let directory = path.resolve(start);
|
|
293
340
|
const resolvedRoot = path.resolve(root);
|
|
294
341
|
while (directory === resolvedRoot || directory.startsWith(`${resolvedRoot}${path.sep}`)) {
|
|
295
342
|
const lockfiles = (await Promise.all([
|
|
296
|
-
optionalFileExists(path.join(directory, "pnpm-lock.yaml")).then(exists => exists ? "pnpm" : null),
|
|
297
|
-
optionalFileExists(path.join(directory, "yarn.lock")).then(exists => exists ? "yarn" : null),
|
|
298
|
-
optionalFileExists(path.join(directory, "package-lock.json")).then(exists => exists ? "npm" : null),
|
|
299
|
-
optionalFileExists(path.join(directory, "npm-shrinkwrap.json")).then(exists => exists ? "npm" : null),
|
|
343
|
+
optionalFileExists(path.join(directory, "pnpm-lock.yaml"), snapshot).then(exists => exists ? "pnpm" : null),
|
|
344
|
+
optionalFileExists(path.join(directory, "yarn.lock"), snapshot).then(exists => exists ? "yarn" : null),
|
|
345
|
+
optionalFileExists(path.join(directory, "package-lock.json"), snapshot).then(exists => exists ? "npm" : null),
|
|
346
|
+
optionalFileExists(path.join(directory, "npm-shrinkwrap.json"), snapshot).then(exists => exists ? "npm" : null),
|
|
300
347
|
])).filter((value) => value !== null);
|
|
301
348
|
const packageManagers = [...new Set(lockfiles)];
|
|
302
349
|
if (packageManagers.length > 1)
|
|
@@ -312,9 +359,9 @@ async function nearestPackageManager(root, start) {
|
|
|
312
359
|
function portableRelativePath(root, target) {
|
|
313
360
|
return path.relative(root, target).replaceAll("\\", "/");
|
|
314
361
|
}
|
|
315
|
-
async function discoverAspNetLaunchProfile(root, projectRelativePath) {
|
|
362
|
+
async function discoverAspNetLaunchProfile(root, projectRelativePath, snapshot) {
|
|
316
363
|
const target = path.join(root, path.dirname(projectRelativePath), "Properties", "launchSettings.json");
|
|
317
|
-
const source = await readBoundedOptionalFile(target, 512 * 1024);
|
|
364
|
+
const source = await readBoundedOptionalFile(target, 512 * 1024, snapshot);
|
|
318
365
|
if (!source)
|
|
319
366
|
return { name: null, source: null, environment: {} };
|
|
320
367
|
try {
|
|
@@ -339,7 +386,13 @@ async function discoverAspNetLaunchProfile(root, projectRelativePath) {
|
|
|
339
386
|
return { name: null, source, environment: {} };
|
|
340
387
|
}
|
|
341
388
|
}
|
|
389
|
+
// A project's "forge-attempt" profile configures its API for managed attempts. The
|
|
390
|
+
// attempt's pre-publication checks then run against the same settings the project's own
|
|
391
|
+
// e2e suite uses, instead of the developer's "http" profile.
|
|
392
|
+
const attemptLaunchProfileName = "forge-attempt";
|
|
342
393
|
function aspNetProfilePriority(name) {
|
|
394
|
+
if (name.toLowerCase() === attemptLaunchProfileName)
|
|
395
|
+
return -1;
|
|
343
396
|
if (name.toLowerCase() === "http")
|
|
344
397
|
return 0;
|
|
345
398
|
if (name.toLowerCase() === "https")
|
|
@@ -354,6 +407,7 @@ function safeAspNetLaunchEnvironment(name, value) {
|
|
|
354
407
|
return false;
|
|
355
408
|
const normalized = name.toUpperCase();
|
|
356
409
|
return !normalized.startsWith("FORGE_")
|
|
410
|
+
&& !isUnsafeDotnetEnvironmentName(name)
|
|
357
411
|
&& !new Set([
|
|
358
412
|
"ASPNETCORE_URLS",
|
|
359
413
|
"ASPNETCORE_HTTP_PORTS",
|
|
@@ -368,34 +422,53 @@ function safeAspNetLaunchEnvironment(name, value) {
|
|
|
368
422
|
"TMPDIR",
|
|
369
423
|
]).has(normalized);
|
|
370
424
|
}
|
|
371
|
-
async function findFiles(root, accepts, maximumDepth, maximumEntries) {
|
|
425
|
+
async function findFiles(root, accepts, maximumDepth, maximumEntries, snapshot) {
|
|
372
426
|
const results = [];
|
|
373
427
|
let examined = 0;
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
428
|
+
const directories = [{ directory: root, depth: 0 }];
|
|
429
|
+
while (directories.length > 0) {
|
|
430
|
+
const current = directories.shift();
|
|
431
|
+
if (current.depth > maximumDepth)
|
|
432
|
+
continue;
|
|
433
|
+
const entries = snapshot
|
|
434
|
+
? await snapshot(current.directory)
|
|
435
|
+
: await fs.readdir(current.directory, { withFileTypes: true }).then(found => found.map(entry => ({
|
|
436
|
+
name: entry.name,
|
|
437
|
+
isDirectory: entry.isDirectory(),
|
|
438
|
+
isFile: entry.isFile(),
|
|
439
|
+
}))).catch((error) => {
|
|
440
|
+
// A directory removed since it was listed holds nothing; one that cannot be read
|
|
441
|
+
// (permissions, open-file limits) may hold the entrypoint discovery is looking for.
|
|
442
|
+
if (isFileNotFound(error))
|
|
443
|
+
return [];
|
|
444
|
+
throw new IncompleteRuntimeDiscoveryError();
|
|
445
|
+
});
|
|
446
|
+
const orderedEntries = [...entries].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
447
|
+
for (const entry of orderedEntries) {
|
|
448
|
+
if (entry.isDirectory
|
|
449
|
+
&& (ignoredDiscoveryDirectories.has(entry.name.toLowerCase()) || isGeneratedOutputDirectoryName(entry.name)))
|
|
382
450
|
continue;
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
451
|
+
if (examined++ >= maximumEntries)
|
|
452
|
+
throw new IncompleteRuntimeDiscoveryError();
|
|
453
|
+
const target = path.join(current.directory, entry.name);
|
|
454
|
+
if (entry.isDirectory)
|
|
455
|
+
directories.push({ directory: target, depth: current.depth + 1 });
|
|
456
|
+
else if (entry.isFile && accepts(target))
|
|
387
457
|
results.push(target);
|
|
388
458
|
}
|
|
389
|
-
}
|
|
390
|
-
await visitDirectory(root, 0);
|
|
459
|
+
}
|
|
391
460
|
return results.sort((left, right) => left.localeCompare(right));
|
|
392
461
|
}
|
|
393
|
-
async function readBoundedOptionalFile(target, maximumBytes) {
|
|
462
|
+
async function readBoundedOptionalFile(target, maximumBytes, snapshot) {
|
|
463
|
+
if (snapshot) {
|
|
464
|
+
const source = await snapshot(target);
|
|
465
|
+
return source && source.length > 0 && source.length <= maximumBytes ? source.toString("utf8") : null;
|
|
466
|
+
}
|
|
394
467
|
try {
|
|
395
468
|
const stat = await fs.stat(target);
|
|
396
469
|
if (!stat.isFile() || stat.size < 1 || stat.size > maximumBytes)
|
|
397
470
|
return null;
|
|
398
|
-
return await
|
|
471
|
+
return (await readCanonicalSourceFile(target, maximumBytes)).toString("utf8");
|
|
399
472
|
}
|
|
400
473
|
catch (error) {
|
|
401
474
|
if (isFileNotFound(error))
|
|
@@ -403,7 +476,9 @@ async function readBoundedOptionalFile(target, maximumBytes) {
|
|
|
403
476
|
throw error;
|
|
404
477
|
}
|
|
405
478
|
}
|
|
406
|
-
async function optionalFileExists(target) {
|
|
479
|
+
async function optionalFileExists(target, snapshot) {
|
|
480
|
+
if (snapshot)
|
|
481
|
+
return await snapshot(target) !== null;
|
|
407
482
|
try {
|
|
408
483
|
return (await fs.stat(target)).isFile();
|
|
409
484
|
}
|
|
@@ -574,6 +649,7 @@ function parseLaunch(value, adapter, name) {
|
|
|
574
649
|
throw new Error(`runtime_contract_invalid: runtime.ports.${name}.launch.args must contain at most 128 strings.`);
|
|
575
650
|
}
|
|
576
651
|
const parsedArgs = args.map((argument, index) => boundedString(argument, 4096, `runtime.ports.${name}.launch.args[${index}]`));
|
|
652
|
+
rejectProjectAuthoredForgeArguments(parsedArgs, adapter, name);
|
|
577
653
|
const portableDirectory = launch.workingDirectory === undefined || launch.workingDirectory === null
|
|
578
654
|
? "."
|
|
579
655
|
: containedPortablePath(launch.workingDirectory, `runtime.ports.${name}.launch.workingDirectory`);
|
|
@@ -596,9 +672,46 @@ function parseLaunchEnvironment(value, portName) {
|
|
|
596
672
|
if (!/^[A-Za-z_][A-Za-z0-9_]{0,127}$/u.test(name)) {
|
|
597
673
|
throw new Error(`runtime_contract_invalid: launch environment name '${name}' is invalid.`);
|
|
598
674
|
}
|
|
675
|
+
if (name.toLowerCase().startsWith("forge_") || isUnsafeDotnetEnvironmentName(name)) {
|
|
676
|
+
throw new Error(`runtime_contract_invalid: launch environment name '${name}' is host-owned or enables pre-startup code injection and cannot be project-authored.`);
|
|
677
|
+
}
|
|
599
678
|
return [name, boundedString(raw, 8192, `runtime.ports.${portName}.launch.environment.${name}`)];
|
|
600
679
|
}));
|
|
601
680
|
}
|
|
681
|
+
function isUnsafeDotnetEnvironmentName(name) {
|
|
682
|
+
const normalized = name.toUpperCase();
|
|
683
|
+
return normalized === "DOTNET_STARTUP_HOOKS"
|
|
684
|
+
|| normalized === "DOTNET_ADDITIONAL_DEPS"
|
|
685
|
+
|| normalized === "DOTNET_SHARED_STORE"
|
|
686
|
+
|| normalized === "DOTNET_HOST_PATH"
|
|
687
|
+
|| normalized === "MSBUILD_EXE_PATH"
|
|
688
|
+
|| normalized === "MSBUILDSDKSPATH"
|
|
689
|
+
|| normalized === "NUGET_PLUGIN_PATHS"
|
|
690
|
+
|| normalized === "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES"
|
|
691
|
+
|| normalized === "ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES"
|
|
692
|
+
|| normalized.startsWith("CUSTOMBEFOREMICROSOFTCOMMON")
|
|
693
|
+
|| normalized.startsWith("CUSTOMAFTERMICROSOFTCOMMON")
|
|
694
|
+
|| normalized.startsWith("DOTNET_ROOT")
|
|
695
|
+
|| normalized.startsWith("CORECLR_")
|
|
696
|
+
|| normalized.startsWith("COR_")
|
|
697
|
+
|| normalized.startsWith("COMPLUS_")
|
|
698
|
+
|| normalized.startsWith("LD_")
|
|
699
|
+
|| normalized.startsWith("DYLD_");
|
|
700
|
+
}
|
|
701
|
+
function rejectProjectAuthoredForgeArguments(args, adapter, portName) {
|
|
702
|
+
if (adapter !== "aspnetcore")
|
|
703
|
+
return;
|
|
704
|
+
const applicationArgumentIndex = args.indexOf("--");
|
|
705
|
+
if (applicationArgumentIndex < 0)
|
|
706
|
+
return;
|
|
707
|
+
const forbidden = args.slice(applicationArgumentIndex + 1).find(argument => {
|
|
708
|
+
const key = argument.split("=", 1)[0].replace(/^(?:--?|\/)/u, "");
|
|
709
|
+
return /^forge(?:[_:.-]|$)/iu.test(key);
|
|
710
|
+
});
|
|
711
|
+
if (forbidden) {
|
|
712
|
+
throw new Error(`runtime_contract_invalid: runtime.ports.${portName}.launch.args cannot override the host-owned FORGE_* namespace.`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
602
715
|
function containedPortablePath(value, label) {
|
|
603
716
|
const original = boundedString(value, 1024, label);
|
|
604
717
|
const portable = original.replaceAll("\\", "/");
|
|
@@ -4,8 +4,11 @@ import { type RuntimeIsolationLease } from "./runtime-isolation-lease.js";
|
|
|
4
4
|
import { type LoadedHostRuntimeContract } from "./host-runtime-contract.js";
|
|
5
5
|
import { HostPortBroker } from "./host-port-broker.js";
|
|
6
6
|
import { NodeHostRuntimeAdapter, type NodeRuntimeAdapterLaunch, type NodeRuntimeCommand, type NodeRuntimeCommandLauncher } from "./node-host-runtime-adapter.js";
|
|
7
|
+
import type { AttemptProcessTreeMemoryTelemetry } from "./attempt-process-supervisor.js";
|
|
7
8
|
import { AttemptProcessSupervisorRegistry } from "./attempt-process-supervisor-registry.js";
|
|
9
|
+
import { type AttemptDatabaseBroker } from "./attempt-database-broker.js";
|
|
8
10
|
import { HostListenerInspector } from "./host-listener-inspector.js";
|
|
11
|
+
import { type MemoryAdmissionDiagnostics } from "./memory-capacity.js";
|
|
9
12
|
import { PlaywrightHostRuntimeAdapter } from "./playwright-host-runtime-adapter.js";
|
|
10
13
|
import { HostParallelPromotionStore } from "./host-runtime-promotion.js";
|
|
11
14
|
import { type HostProcessRecovery } from "../shared/process/host-process-recovery.js";
|
|
@@ -15,6 +18,18 @@ export interface HostRuntimeLeaseStart {
|
|
|
15
18
|
readonly runtimeContract: LoadedHostRuntimeContract;
|
|
16
19
|
readonly executionClass: HostRuntimeExecutionClass;
|
|
17
20
|
}
|
|
21
|
+
export interface HostRuntimeAdmissionCheckpoint {
|
|
22
|
+
readonly code: "host_runtime_serial_admission_waiting" | "host_runtime_prepared_probe_started" | "host_runtime_prepared_probe_progress" | "host_runtime_prepared_probe_completed" | "host_runtime_prepared_admission_waiting" | "host_runtime_prepared_admission_acquired";
|
|
23
|
+
readonly message: string;
|
|
24
|
+
readonly expiresAt: string;
|
|
25
|
+
}
|
|
26
|
+
export type HostRuntimeAdmissionCheckpointHandler = (checkpoint: HostRuntimeAdmissionCheckpoint) => void | Promise<void>;
|
|
27
|
+
export interface HostRuntimeProjectCheckpoint {
|
|
28
|
+
readonly code: "host_runtime_build_started" | "host_runtime_build_cached" | "host_runtime_build_completed" | "host_runtime_database_provisioned";
|
|
29
|
+
readonly message: string;
|
|
30
|
+
readonly data?: Readonly<Record<string, unknown>>;
|
|
31
|
+
}
|
|
32
|
+
export type HostRuntimeProjectCheckpointHandler = (checkpoint: HostRuntimeProjectCheckpoint) => void | Promise<void>;
|
|
18
33
|
export type HostRuntimeExecutionClass = "analysis_only" | "managed_runtime";
|
|
19
34
|
export type HostRuntimeSafetyClass = "host_serial_only" | "host_parallel_candidate" | "host_parallel_safe";
|
|
20
35
|
export interface HostRuntimeProjectCapacitySnapshot {
|
|
@@ -29,12 +44,25 @@ export interface HostRuntimeProjectCapacitySnapshot {
|
|
|
29
44
|
readonly promotedAt?: string | null;
|
|
30
45
|
}
|
|
31
46
|
export interface HostRuntimeCapacitySnapshot {
|
|
47
|
+
readonly preparedWorktreeReadiness?: boolean;
|
|
32
48
|
readonly activeAttempts: number;
|
|
33
49
|
readonly reservedAttempts: number;
|
|
34
50
|
readonly waitingAttempts: number;
|
|
35
51
|
readonly degradedAttempts: number;
|
|
36
52
|
readonly exclusiveReservations: number;
|
|
37
53
|
readonly sharedReservations: number;
|
|
54
|
+
readonly hardMaxAttempts: number;
|
|
55
|
+
readonly effectiveMaxAttempts: number;
|
|
56
|
+
readonly availableAttempts: number;
|
|
57
|
+
readonly totalMemoryBytes: number;
|
|
58
|
+
readonly availableMemoryBytes: number;
|
|
59
|
+
readonly hostReserveBytes: number;
|
|
60
|
+
readonly availableCpuMillis: number;
|
|
61
|
+
readonly availableWorkspaceBytes: number;
|
|
62
|
+
readonly activeReservationMemoryBytes: number;
|
|
63
|
+
readonly memoryAdmission: MemoryAdmissionDiagnostics;
|
|
64
|
+
readonly unavailableCode?: string | null;
|
|
65
|
+
readonly unavailableReason?: string | null;
|
|
38
66
|
readonly projects: readonly HostRuntimeProjectCapacitySnapshot[];
|
|
39
67
|
}
|
|
40
68
|
export interface HostRuntimeReapOptions {
|
|
@@ -48,21 +76,41 @@ export interface HostRuntimeReapReport {
|
|
|
48
76
|
readonly processesTerminated: number;
|
|
49
77
|
readonly reusedPidsProtected: number;
|
|
50
78
|
readonly degraded: number;
|
|
79
|
+
/**
|
|
80
|
+
* Active attempts of a previous runner instance whose every supervised
|
|
81
|
+
* process tree was proved absent, terminated or PID-reused. Forge may settle
|
|
82
|
+
* these exact attempts instead of leaving their launch outcome unknown.
|
|
83
|
+
*/
|
|
84
|
+
readonly recoveredAttempts?: readonly HostRuntimeRecoveredAttempt[];
|
|
85
|
+
}
|
|
86
|
+
export interface HostRuntimeRecoveredAttempt {
|
|
87
|
+
readonly dispatchAttemptId: string;
|
|
88
|
+
readonly fencingToken: string;
|
|
89
|
+
readonly runnerInstanceId: string;
|
|
51
90
|
}
|
|
52
91
|
export interface HostNodeRuntimeLaunch<T> extends NodeRuntimeAdapterLaunch<T> {
|
|
53
92
|
readonly runtimeLease: RuntimeIsolationLease;
|
|
54
93
|
}
|
|
55
94
|
export interface HostRuntimeLeaseRuntime {
|
|
95
|
+
acquirePreparation?(dispatch: RunOnceDispatchPacket, signal?: AbortSignal): Promise<readonly string[]>;
|
|
56
96
|
acquire(dispatch: RunOnceDispatchPacket, signal?: AbortSignal): Promise<readonly string[]>;
|
|
57
|
-
start(dispatch: RunOnceDispatchPacket, worktreePath: string, signal?: AbortSignal): Promise<HostRuntimeLeaseStart>;
|
|
58
|
-
startConfiguredProject(dispatchAttemptId: string, fencingToken: string, signal?: AbortSignal): Promise<HostRuntimeLeaseStart>;
|
|
97
|
+
start(dispatch: RunOnceDispatchPacket, worktreePath: string, signal?: AbortSignal, onAdmissionCheckpoint?: HostRuntimeAdmissionCheckpointHandler): Promise<HostRuntimeLeaseStart>;
|
|
98
|
+
startConfiguredProject(dispatchAttemptId: string, fencingToken: string, signal?: AbortSignal, onProjectCheckpoint?: HostRuntimeProjectCheckpointHandler): Promise<HostRuntimeLeaseStart>;
|
|
59
99
|
updateLease(dispatchAttemptId: string, fencingToken: string, expiresAt: string): Promise<void>;
|
|
60
100
|
providerProcessRunner?(dispatchAttemptId: string, fencingToken: string): ProviderProcessRunner | null;
|
|
101
|
+
providerMemoryTelemetry?(dispatchAttemptId: string, fencingToken: string): AttemptProcessTreeMemoryTelemetry | null;
|
|
61
102
|
release(dispatchAttemptId: string, fencingToken: string): Promise<RuntimeIsolationLease | null>;
|
|
62
|
-
invalidatePromotion?(repoId: string): Promise<void>;
|
|
103
|
+
invalidatePromotion?(repoId: string, scope?: "all" | "discovery"): Promise<void>;
|
|
104
|
+
hasForegroundDemand?(): boolean;
|
|
63
105
|
reap?(options: HostRuntimeReapOptions): Promise<HostRuntimeReapReport>;
|
|
64
106
|
snapshot?(): HostRuntimeCapacitySnapshot;
|
|
65
107
|
}
|
|
108
|
+
export interface HostCapacityResourceSample {
|
|
109
|
+
readonly totalMemoryBytes: number;
|
|
110
|
+
readonly availableMemoryBytes: number;
|
|
111
|
+
readonly totalCpuMillis: number;
|
|
112
|
+
readonly availableWorkspaceBytes: number;
|
|
113
|
+
}
|
|
66
114
|
export declare class HostRuntimeLeaseManager implements HostRuntimeLeaseRuntime {
|
|
67
115
|
private readonly stateRoot;
|
|
68
116
|
private readonly processSupervisors;
|
|
@@ -71,30 +119,58 @@ export declare class HostRuntimeLeaseManager implements HostRuntimeLeaseRuntime
|
|
|
71
119
|
private readonly promotionStore;
|
|
72
120
|
private readonly playwrightAdapter;
|
|
73
121
|
private readonly processRecovery;
|
|
122
|
+
private readonly capacityResourceSample?;
|
|
123
|
+
private readonly databaseBroker;
|
|
124
|
+
private readonly preparedReadiness;
|
|
74
125
|
private readonly active;
|
|
75
126
|
private readonly pendingRenewals;
|
|
127
|
+
private readonly acquiringAdmissions;
|
|
76
128
|
private readonly admissions;
|
|
77
129
|
private readonly singletonOwners;
|
|
78
130
|
private readonly singletonWaiters;
|
|
79
131
|
private readonly parallelProjectOwners;
|
|
80
132
|
private readonly parallelProjectWaiters;
|
|
133
|
+
private readonly capacityReservations;
|
|
134
|
+
private readonly capacityWaiters;
|
|
135
|
+
private capacityWaiterScanCursor;
|
|
136
|
+
private readonly backgroundAdmissionWaiters;
|
|
81
137
|
private readonly degraded;
|
|
82
138
|
private readonly knownPromotions;
|
|
139
|
+
private ledgerWriteTail;
|
|
140
|
+
private workspaceAvailableBytes;
|
|
83
141
|
private readonly portBroker;
|
|
84
142
|
private readonly nodeAdapter;
|
|
85
|
-
|
|
143
|
+
private readonly capacityConfiguration;
|
|
144
|
+
private readonly memoryAvailability;
|
|
145
|
+
private readonly executionRoot;
|
|
146
|
+
constructor(stateRoot: string, portBroker?: HostPortBroker, nodeAdapter?: NodeHostRuntimeAdapter, processSupervisors?: AttemptProcessSupervisorRegistry, processRunner?: ProviderProcessRunner, listenerInspector?: HostListenerInspector, promotionStore?: HostParallelPromotionStore, playwrightAdapter?: PlaywrightHostRuntimeAdapter, processRecovery?: HostProcessRecovery, capacityResourceSample?: HostCapacityResourceSample | undefined, executionRoot?: string, databaseBroker?: AttemptDatabaseBroker | null);
|
|
86
147
|
reap(options: HostRuntimeReapOptions): Promise<HostRuntimeReapReport>;
|
|
87
148
|
snapshot(): HostRuntimeCapacitySnapshot;
|
|
149
|
+
hasForegroundDemand(): boolean;
|
|
150
|
+
acquirePreparation(dispatch: RunOnceDispatchPacket, signal?: AbortSignal): Promise<readonly string[]>;
|
|
88
151
|
acquire(dispatch: RunOnceDispatchPacket, signal?: AbortSignal): Promise<readonly string[]>;
|
|
152
|
+
private reserveHostCapacity;
|
|
153
|
+
private reserveBackgroundAdmission;
|
|
154
|
+
private hostCapacityAvailable;
|
|
155
|
+
private hostCapacityImpossibleReason;
|
|
156
|
+
private hostResourceSnapshot;
|
|
157
|
+
private refreshWorkspaceCapacity;
|
|
158
|
+
private releaseHostCapacity;
|
|
159
|
+
private drainCapacityWaiters;
|
|
160
|
+
private capacityWaitersForScan;
|
|
161
|
+
private detachCapacityWaiter;
|
|
89
162
|
private reserveSingletonKeys;
|
|
90
163
|
private reserveParallelProject;
|
|
91
|
-
|
|
164
|
+
private upgradeParallelProjectToSingleton;
|
|
165
|
+
start(dispatch: RunOnceDispatchPacket, worktreePath: string, signal?: AbortSignal, onAdmissionCheckpoint?: HostRuntimeAdmissionCheckpointHandler): Promise<HostRuntimeLeaseStart>;
|
|
92
166
|
updateLease(dispatchAttemptId: string, fencingToken: string, expiresAt: string): Promise<void>;
|
|
93
|
-
startConfiguredProject(dispatchAttemptId: string, fencingToken: string, signal?: AbortSignal): Promise<HostRuntimeLeaseStart>;
|
|
167
|
+
startConfiguredProject(dispatchAttemptId: string, fencingToken: string, signal?: AbortSignal, onProjectCheckpoint?: HostRuntimeProjectCheckpointHandler): Promise<HostRuntimeLeaseStart>;
|
|
94
168
|
providerProcessRunner(dispatchAttemptId: string, fencingToken: string): ProviderProcessRunner | null;
|
|
169
|
+
private markCapacityReservationRunning;
|
|
170
|
+
providerMemoryTelemetry(dispatchAttemptId: string, fencingToken: string): AttemptProcessTreeMemoryTelemetry | null;
|
|
95
171
|
private promoteVerifiedRuntime;
|
|
96
172
|
launchNodeRuntime<T>(dispatchAttemptId: string, fencingToken: string, portName: string, command: NodeRuntimeCommand, launcher: NodeRuntimeCommandLauncher<T>, signal?: AbortSignal): Promise<HostNodeRuntimeLaunch<T>>;
|
|
97
|
-
release(dispatchAttemptId: string, fencingToken: string): Promise<RuntimeIsolationLease | null>;
|
|
173
|
+
release(dispatchAttemptId: string, fencingToken: string, preservePreparation?: boolean): Promise<RuntimeIsolationLease | null>;
|
|
98
174
|
private readLedgers;
|
|
99
175
|
private recoverPersistedProcesses;
|
|
100
176
|
private markLedgerDegraded;
|
|
@@ -102,6 +178,7 @@ export declare class HostRuntimeLeaseManager implements HostRuntimeLeaseRuntime
|
|
|
102
178
|
private forgetDegraded;
|
|
103
179
|
private attemptRoot;
|
|
104
180
|
private writeLedger;
|
|
181
|
+
private writeLedgerAtomic;
|
|
105
182
|
private ledgerPath;
|
|
106
183
|
private singletonKeysAvailable;
|
|
107
184
|
private assignSingletonKeys;
|
|
@@ -118,9 +195,13 @@ export declare class HostRuntimeLeaseManager implements HostRuntimeLeaseRuntime
|
|
|
118
195
|
private cancelAdmissionWaiters;
|
|
119
196
|
private drainSingletonWaiters;
|
|
120
197
|
private drainParallelProjectWaiters;
|
|
198
|
+
private drainBackgroundAdmissionWaiters;
|
|
121
199
|
private refreshKnownPromotions;
|
|
122
|
-
invalidatePromotion(repoId: string): Promise<void>;
|
|
200
|
+
invalidatePromotion(repoId: string, scope?: "all" | "discovery"): Promise<void>;
|
|
123
201
|
private drainAdmissionWaiters;
|
|
202
|
+
private reconcileReservationOwners;
|
|
203
|
+
private reservationOwnerIsLive;
|
|
204
|
+
private hasAttemptRepresentation;
|
|
124
205
|
}
|
|
125
206
|
export declare class HostRuntimeLeaseCleanupError extends Error {
|
|
126
207
|
readonly lease: RuntimeIsolationLease;
|
|
@@ -129,5 +210,8 @@ export declare class HostRuntimeLeaseCleanupError extends Error {
|
|
|
129
210
|
export declare class HostRuntimeAdmissionExpiredError extends Error {
|
|
130
211
|
constructor();
|
|
131
212
|
}
|
|
213
|
+
export declare class HostRuntimeCapacityRequestImpossibleError extends Error {
|
|
214
|
+
constructor(reason: string);
|
|
215
|
+
}
|
|
132
216
|
export declare function hostRuntimeEventResources(lease: RuntimeIsolationLease, runtimeContract?: LoadedHostRuntimeContract, executionClass?: HostRuntimeExecutionClass): Record<string, unknown>;
|
|
133
217
|
export declare function hostRuntimeSingletonKeys(dispatch: RunOnceDispatchPacket): readonly string[];
|