@kynver-app/runtime 0.1.93 → 0.1.99
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/dist/bounded-build/admission.d.ts +2 -2
- package/dist/bounded-build/exec.d.ts +6 -2
- package/dist/cli.js +752 -420
- package/dist/cli.js.map +4 -4
- package/dist/doctor/runtime-takeover.probes.d.ts +0 -2
- package/dist/harness-verify.d.ts +3 -2
- package/dist/heavy-verification/gate.d.ts +10 -0
- package/dist/heavy-verification/index.d.ts +3 -0
- package/dist/heavy-verification/paths.d.ts +3 -0
- package/dist/heavy-verification/slot.d.ts +49 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1005 -629
- package/dist/index.js.map +4 -4
- package/dist/installed-package-versions.d.ts +2 -0
- package/dist/resource-gate.d.ts +7 -0
- package/dist/vercel/index.d.ts +2 -1
- package/dist/vercel/vercel-api.d.ts +17 -0
- package/dist/vercel/vercel-evidence.d.ts +15 -15
- package/dist/vercel/vercel-url.d.ts +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35,306 +35,21 @@ function handleCliVersionFlag(argv, moduleUrl = import.meta.url, binName) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// src/memory-cost-package-version-guard.ts
|
|
38
|
-
import { existsSync as
|
|
39
|
-
import
|
|
40
|
-
var MEMORY_COST_PACKAGE_MIN_VERSIONS = {
|
|
41
|
-
"@kynver-app/runtime": "0.1.83",
|
|
42
|
-
"@kynver-app/openclaw-agent-os": "0.1.43",
|
|
43
|
-
"@kynver-app/mcp-agent-os": "0.3.34"
|
|
44
|
-
};
|
|
45
|
-
var MEMORY_COST_MANAGED_PACKAGES = Object.keys(
|
|
46
|
-
MEMORY_COST_PACKAGE_MIN_VERSIONS
|
|
47
|
-
);
|
|
48
|
-
var DISPLAY_NAMES = {
|
|
49
|
-
"@kynver-app/runtime": "Kynver runtime",
|
|
50
|
-
"@kynver-app/openclaw-agent-os": "OpenClaw AgentOS plugin",
|
|
51
|
-
"@kynver-app/mcp-agent-os": "AgentOS MCP server"
|
|
52
|
-
};
|
|
53
|
-
var REPO_PACKAGE_JSON_RELATIVE = {
|
|
54
|
-
"@kynver-app/runtime": "packages/kynver-runtime/package.json",
|
|
55
|
-
"@kynver-app/openclaw-agent-os": "packages/kynver-openclaw-agent-os/package.json",
|
|
56
|
-
"@kynver-app/mcp-agent-os": "packages/kynver-mcp-agent-os/package.json"
|
|
57
|
-
};
|
|
58
|
-
function parseSemverParts(version) {
|
|
59
|
-
const core = version.trim().split("-")[0]?.split("+")[0];
|
|
60
|
-
if (!core) return null;
|
|
61
|
-
const parts = core.split(".");
|
|
62
|
-
if (parts.length < 1 || parts.length > 3) return null;
|
|
63
|
-
const nums = parts.map((p) => Number.parseInt(p, 10));
|
|
64
|
-
if (nums.some((n) => !Number.isFinite(n) || n < 0)) return null;
|
|
65
|
-
while (nums.length < 3) nums.push(0);
|
|
66
|
-
return [nums[0], nums[1], nums[2]];
|
|
67
|
-
}
|
|
68
|
-
function compareSemver(a, b) {
|
|
69
|
-
const pa = parseSemverParts(a);
|
|
70
|
-
const pb = parseSemverParts(b);
|
|
71
|
-
if (!pa || !pb) return 0;
|
|
72
|
-
for (let i = 0; i < 3; i += 1) {
|
|
73
|
-
if (pa[i] > pb[i]) return 1;
|
|
74
|
-
if (pa[i] < pb[i]) return -1;
|
|
75
|
-
}
|
|
76
|
-
return 0;
|
|
77
|
-
}
|
|
78
|
-
function semverAtLeast(version, minimum) {
|
|
79
|
-
return compareSemver(version, minimum) >= 0;
|
|
80
|
-
}
|
|
81
|
-
function maxSemver(versions) {
|
|
82
|
-
let best = null;
|
|
83
|
-
for (const version of versions) {
|
|
84
|
-
if (!best || compareSemver(version, best) > 0) best = version;
|
|
85
|
-
}
|
|
86
|
-
return best;
|
|
87
|
-
}
|
|
88
|
-
function readPackageJsonVersion(packageJsonPath) {
|
|
89
|
-
try {
|
|
90
|
-
const parsed = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
91
|
-
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
92
|
-
} catch {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function resolveRepoRoot(cwd, explicitRepoRoot) {
|
|
97
|
-
const candidates = [explicitRepoRoot, process.env.KYNVER_REPO, cwd].filter(
|
|
98
|
-
(value) => Boolean(value?.trim())
|
|
99
|
-
);
|
|
100
|
-
for (const candidate of candidates) {
|
|
101
|
-
const resolved = path.resolve(candidate);
|
|
102
|
-
if (existsSync2(path.join(resolved, "packages/kynver-runtime/package.json")) && existsSync2(path.join(resolved, "package.json"))) {
|
|
103
|
-
return resolved;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
function probeRepoPackageVersions(input = {}) {
|
|
109
|
-
const cwd = input.cwd ?? process.cwd();
|
|
110
|
-
const repoRoot = resolveRepoRoot(cwd, input.repoRoot);
|
|
111
|
-
if (!repoRoot) return {};
|
|
112
|
-
const out = {};
|
|
113
|
-
for (const packageName of MEMORY_COST_MANAGED_PACKAGES) {
|
|
114
|
-
const packageJsonPath = path.join(repoRoot, REPO_PACKAGE_JSON_RELATIVE[packageName]);
|
|
115
|
-
const version = readPackageJsonVersion(packageJsonPath);
|
|
116
|
-
if (!version) continue;
|
|
117
|
-
out[packageName] = { version, source: "repo", path: packageJsonPath };
|
|
118
|
-
}
|
|
119
|
-
return out;
|
|
120
|
-
}
|
|
121
|
-
function repoSourceCommands(packageName) {
|
|
122
|
-
if (packageName === "@kynver-app/runtime") {
|
|
123
|
-
return ["npm run kynver:build", "npm run kynver"];
|
|
124
|
-
}
|
|
125
|
-
return [`npm run build -w ${packageName}`];
|
|
126
|
-
}
|
|
127
|
-
function buildRemediation(input) {
|
|
128
|
-
const { packageName, minimumVersion, effectiveVersion, effectiveSource, repoVersion } = input;
|
|
129
|
-
const lines = [];
|
|
130
|
-
if (repoVersion && semverAtLeast(repoVersion, minimumVersion)) {
|
|
131
|
-
lines.push(
|
|
132
|
-
`Use the monorepo checkout (${repoVersion}) instead of a stale npm install: ${repoSourceCommands(packageName).join("; ")}.`
|
|
133
|
-
);
|
|
134
|
-
lines.push("Do not publish npm packages or wait on an operator release.");
|
|
135
|
-
return lines;
|
|
136
|
-
}
|
|
137
|
-
if (effectiveVersion) {
|
|
138
|
-
lines.push(
|
|
139
|
-
`Upgrade ${packageName} from ${effectiveVersion} to >= ${minimumVersion} (npm install -g ${packageName}@latest or align OpenClaw npm prefix).`
|
|
140
|
-
);
|
|
141
|
-
} else {
|
|
142
|
-
lines.push(`Install ${packageName} >= ${minimumVersion} before running memory-heavy AgentOS paths.`);
|
|
143
|
-
}
|
|
144
|
-
if (packageName === "@kynver-app/runtime") {
|
|
145
|
-
lines.push("Repo-source alternative: npm run kynver:build && npm run kynver");
|
|
146
|
-
}
|
|
147
|
-
if (effectiveSource === "installed" && repoVersion) {
|
|
148
|
-
lines.push(`Repo checkout reports ${repoVersion}; rebuild/link repo source if you develop from the monorepo.`);
|
|
149
|
-
}
|
|
150
|
-
return lines;
|
|
151
|
-
}
|
|
152
|
-
function pickEffectiveCandidate(candidates) {
|
|
153
|
-
if (candidates.length === 0) return { version: null, source: "unknown" };
|
|
154
|
-
const best = maxSemver(candidates.map((candidate) => candidate.version));
|
|
155
|
-
if (!best) return { version: null, source: "unknown" };
|
|
156
|
-
const winner = candidates.find((candidate) => candidate.version === best) ?? candidates[0];
|
|
157
|
-
return { version: winner.version, source: winner.source };
|
|
158
|
-
}
|
|
159
|
-
function evaluateMemoryCostPackageVersionGuard(input = {}) {
|
|
160
|
-
const normalize2 = (value, fallbackSource) => {
|
|
161
|
-
if (!value) return null;
|
|
162
|
-
if (typeof value === "string") return { version: value, source: fallbackSource };
|
|
163
|
-
return value;
|
|
164
|
-
};
|
|
165
|
-
const packages = MEMORY_COST_MANAGED_PACKAGES.map((packageName) => {
|
|
166
|
-
const minimumVersion = MEMORY_COST_PACKAGE_MIN_VERSIONS[packageName];
|
|
167
|
-
const candidates = [];
|
|
168
|
-
const installed = normalize2(input.installed?.[packageName], "installed");
|
|
169
|
-
const repo = normalize2(input.repo?.[packageName], "repo");
|
|
170
|
-
const self = normalize2(input.self?.[packageName], "self");
|
|
171
|
-
if (installed) candidates.push(installed);
|
|
172
|
-
if (repo) candidates.push(repo);
|
|
173
|
-
if (self) candidates.push(self);
|
|
174
|
-
const { version: effectiveVersion, source: effectiveSource } = pickEffectiveCandidate(candidates);
|
|
175
|
-
const repoVersion = repo?.version ?? null;
|
|
176
|
-
const ok2 = effectiveVersion ? semverAtLeast(effectiveVersion, minimumVersion) : false;
|
|
177
|
-
const remediation = ok2 ? [] : buildRemediation({
|
|
178
|
-
packageName,
|
|
179
|
-
minimumVersion,
|
|
180
|
-
effectiveVersion,
|
|
181
|
-
effectiveSource,
|
|
182
|
-
repoVersion
|
|
183
|
-
});
|
|
184
|
-
const summary2 = ok2 ? `${DISPLAY_NAMES[packageName]} ${effectiveVersion} meets memory-cost minimum ${minimumVersion} (${effectiveSource}).` : `${DISPLAY_NAMES[packageName]} is below memory-cost minimum ${minimumVersion}` + (effectiveVersion ? ` (effective ${effectiveVersion} via ${effectiveSource})` : " (no version detected)") + ".";
|
|
185
|
-
return {
|
|
186
|
-
packageName,
|
|
187
|
-
displayName: DISPLAY_NAMES[packageName],
|
|
188
|
-
minimumVersion,
|
|
189
|
-
effectiveVersion,
|
|
190
|
-
effectiveSource,
|
|
191
|
-
ok: ok2,
|
|
192
|
-
summary: summary2,
|
|
193
|
-
remediation
|
|
194
|
-
};
|
|
195
|
-
});
|
|
196
|
-
const violations = packages.filter((row) => !row.ok);
|
|
197
|
-
const ok = violations.length === 0;
|
|
198
|
-
const summary = ok ? "All managed AgentOS packages meet memory-cost minimum versions." : `Memory-cost package guard blocked ${violations.length} stale package(s): ${violations.map((row) => `${row.packageName} < ${row.minimumVersion}`).join("; ")}.`;
|
|
199
|
-
return { ok, summary, packages };
|
|
200
|
-
}
|
|
201
|
-
var MemoryCostPackageVersionGuardError = class extends Error {
|
|
202
|
-
result;
|
|
203
|
-
constructor(result) {
|
|
204
|
-
const lines = [
|
|
205
|
-
result.summary,
|
|
206
|
-
...result.packages.filter((row) => !row.ok).flatMap((row) => [`- ${row.summary}`, ...row.remediation.map((line) => ` \u2192 ${line}`)])
|
|
207
|
-
];
|
|
208
|
-
super(lines.join("\n"));
|
|
209
|
-
this.name = "MemoryCostPackageVersionGuardError";
|
|
210
|
-
this.result = result;
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
function assertMemoryCostPackageVersionGuard(input = {}) {
|
|
214
|
-
const result = evaluateMemoryCostPackageVersionGuard(input);
|
|
215
|
-
if (!result.ok) throw new MemoryCostPackageVersionGuardError(result);
|
|
216
|
-
return result;
|
|
217
|
-
}
|
|
218
|
-
function formatMemoryCostPackageGuardError(result) {
|
|
219
|
-
return new MemoryCostPackageVersionGuardError(result).message;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// src/installed-package-versions.ts
|
|
223
|
-
import { readFile } from "node:fs/promises";
|
|
224
|
-
import { homedir } from "node:os";
|
|
225
|
-
import path2 from "node:path";
|
|
226
|
-
var MANAGED_PACKAGES = [
|
|
227
|
-
"@kynver-app/runtime",
|
|
228
|
-
"@kynver-app/openclaw-agent-os",
|
|
229
|
-
"@kynver-app/mcp-agent-os"
|
|
230
|
-
];
|
|
231
|
-
function trim(value) {
|
|
232
|
-
const out = value?.trim();
|
|
233
|
-
return out ? out : null;
|
|
234
|
-
}
|
|
235
|
-
function unique(values) {
|
|
236
|
-
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
237
|
-
}
|
|
238
|
-
function moduleRoots() {
|
|
239
|
-
const home = homedir();
|
|
240
|
-
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path2.join(home, ".openclaw", "npm");
|
|
241
|
-
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path2.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path2.join(home, ".npm-global", "lib", "node_modules"));
|
|
242
|
-
return unique([
|
|
243
|
-
path2.join(openClawPrefix, "lib", "node_modules"),
|
|
244
|
-
path2.join(openClawPrefix, "node_modules"),
|
|
245
|
-
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path2.join(npmGlobalRoot, "lib", "node_modules")
|
|
246
|
-
]);
|
|
247
|
-
}
|
|
248
|
-
async function readVersion(packageJsonPath) {
|
|
249
|
-
try {
|
|
250
|
-
const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
251
|
-
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
252
|
-
} catch {
|
|
253
|
-
return null;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
257
|
-
const roots = moduleRoots();
|
|
258
|
-
const out = {};
|
|
259
|
-
for (const packageName of MANAGED_PACKAGES) {
|
|
260
|
-
for (const root of roots) {
|
|
261
|
-
const packageJsonPath = path2.join(root, packageName, "package.json");
|
|
262
|
-
const version = await readVersion(packageJsonPath);
|
|
263
|
-
if (!version) continue;
|
|
264
|
-
out[packageName] = { version, observedAt, path: packageJsonPath };
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return out;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// src/memory-cost-package-version-guard-enforce.ts
|
|
272
|
-
function installedVersionMap(observed) {
|
|
273
|
-
const out = {};
|
|
274
|
-
for (const [packageName, row] of Object.entries(observed)) {
|
|
275
|
-
if (!row?.version) continue;
|
|
276
|
-
out[packageName] = {
|
|
277
|
-
version: row.version,
|
|
278
|
-
source: "installed",
|
|
279
|
-
path: row.path
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
return out;
|
|
283
|
-
}
|
|
284
|
-
async function buildMemoryCostPackageGuardInput(input = {}) {
|
|
285
|
-
const [installed, repo] = await Promise.all([
|
|
286
|
-
collectInstalledPackageVersions(),
|
|
287
|
-
Promise.resolve(probeRepoPackageVersions({ cwd: input.cwd, repoRoot: input.repoRoot }))
|
|
288
|
-
]);
|
|
289
|
-
const self = {};
|
|
290
|
-
if (input.selfPackageName && input.selfVersion) {
|
|
291
|
-
self[input.selfPackageName] = { version: input.selfVersion, source: "self" };
|
|
292
|
-
} else {
|
|
293
|
-
self["@kynver-app/runtime"] = { version: PACKAGE_VERSION, source: "self" };
|
|
294
|
-
}
|
|
295
|
-
return {
|
|
296
|
-
installed: installedVersionMap(installed),
|
|
297
|
-
repo,
|
|
298
|
-
self
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
async function evaluateMemoryCostPackageGuardAtStartup(input = {}) {
|
|
302
|
-
const guardInput = await buildMemoryCostPackageGuardInput(input);
|
|
303
|
-
return evaluateMemoryCostPackageVersionGuard(guardInput);
|
|
304
|
-
}
|
|
305
|
-
async function enforceMemoryCostPackageGuardAtStartup(input = {}) {
|
|
306
|
-
const guardInput = await buildMemoryCostPackageGuardInput(input);
|
|
307
|
-
return assertMemoryCostPackageVersionGuard(guardInput);
|
|
308
|
-
}
|
|
309
|
-
function shouldEnforceMemoryCostPackageGuardCli(scope, action) {
|
|
310
|
-
if (!scope) return false;
|
|
311
|
-
if (scope === "daemon") return true;
|
|
312
|
-
if (scope === "worker") return true;
|
|
313
|
-
if (scope === "monitor") return true;
|
|
314
|
-
if (scope === "run" && (action === "dispatch" || action === "sweep" || action === "reconcile" || action === "unblock")) {
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
if (scope === "cron" && action === "tick") return true;
|
|
318
|
-
return false;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// src/config.ts
|
|
322
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "node:fs";
|
|
323
|
-
import { homedir as homedir5, totalmem } from "node:os";
|
|
324
|
-
import path10 from "node:path";
|
|
38
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
39
|
+
import path4 from "node:path";
|
|
325
40
|
|
|
326
41
|
// src/default-repo-discovery.ts
|
|
327
|
-
import { existsSync as
|
|
328
|
-
import { homedir as
|
|
329
|
-
import
|
|
42
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
43
|
+
import { homedir as homedir2 } from "node:os";
|
|
44
|
+
import path3 from "node:path";
|
|
330
45
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
331
46
|
|
|
332
47
|
// src/git.ts
|
|
333
48
|
import { spawnSync } from "node:child_process";
|
|
334
49
|
|
|
335
50
|
// src/util.ts
|
|
336
|
-
import { existsSync as
|
|
337
|
-
import
|
|
51
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
52
|
+
import path from "node:path";
|
|
338
53
|
function fail(message) {
|
|
339
54
|
console.error(message);
|
|
340
55
|
process.exit(1);
|
|
@@ -356,14 +71,14 @@ function safeJson(line) {
|
|
|
356
71
|
}
|
|
357
72
|
function readJson(file, fallback) {
|
|
358
73
|
try {
|
|
359
|
-
return JSON.parse(
|
|
74
|
+
return JSON.parse(readFileSync2(file, "utf8"));
|
|
360
75
|
} catch (error) {
|
|
361
76
|
if (arguments.length > 1) return fallback;
|
|
362
77
|
fail(`failed to read ${file}: ${error.message}`);
|
|
363
78
|
}
|
|
364
79
|
}
|
|
365
80
|
function writeJson(file, value) {
|
|
366
|
-
mkdirSync(
|
|
81
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
367
82
|
writeFileSync(file, `${JSON.stringify(value, null, 2)}
|
|
368
83
|
`);
|
|
369
84
|
}
|
|
@@ -394,12 +109,12 @@ function fileMtime(file) {
|
|
|
394
109
|
}
|
|
395
110
|
}
|
|
396
111
|
function tailFile(file, lines) {
|
|
397
|
-
if (!
|
|
398
|
-
const data =
|
|
112
|
+
if (!existsSync2(file)) return "";
|
|
113
|
+
const data = readFileSync2(file, "utf8");
|
|
399
114
|
return data.split("\n").slice(-lines).join("\n");
|
|
400
115
|
}
|
|
401
116
|
function readMaybeFile(file) {
|
|
402
|
-
return file ?
|
|
117
|
+
return file ? readFileSync2(path.resolve(file), "utf8") : "";
|
|
403
118
|
}
|
|
404
119
|
function sleepMs(ms) {
|
|
405
120
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
@@ -571,140 +286,449 @@ function computeGitAncestry(worktreePath, baseOrOptions = "origin/main") {
|
|
|
571
286
|
relation: "synced"
|
|
572
287
|
};
|
|
573
288
|
}
|
|
574
|
-
const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);
|
|
575
|
-
const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);
|
|
576
|
-
const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || void 0;
|
|
577
|
-
if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {
|
|
578
|
-
return {
|
|
579
|
-
checked: false,
|
|
580
|
-
base: baseLabel,
|
|
581
|
-
head: headSha,
|
|
582
|
-
baseHead: baseSha,
|
|
583
|
-
baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
|
|
584
|
-
headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
|
|
585
|
-
relation: "unknown",
|
|
586
|
-
...error ? { error } : {}
|
|
587
|
-
};
|
|
289
|
+
const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);
|
|
290
|
+
const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);
|
|
291
|
+
const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || void 0;
|
|
292
|
+
if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {
|
|
293
|
+
return {
|
|
294
|
+
checked: false,
|
|
295
|
+
base: baseLabel,
|
|
296
|
+
head: headSha,
|
|
297
|
+
baseHead: baseSha,
|
|
298
|
+
baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
|
|
299
|
+
headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
|
|
300
|
+
relation: "unknown",
|
|
301
|
+
...error ? { error } : {}
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const relation = baseIsAncestorOfHead.isAncestor ? "ahead" : headIsAncestorOfBase.isAncestor ? "merged" : "diverged";
|
|
305
|
+
return {
|
|
306
|
+
checked: true,
|
|
307
|
+
base: baseLabel,
|
|
308
|
+
head: headSha,
|
|
309
|
+
baseHead: baseSha,
|
|
310
|
+
baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
|
|
311
|
+
headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
|
|
312
|
+
relation,
|
|
313
|
+
...error ? { error } : {}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function unknownAncestry(base, error, head = null) {
|
|
317
|
+
return {
|
|
318
|
+
checked: false,
|
|
319
|
+
base,
|
|
320
|
+
head,
|
|
321
|
+
baseHead: null,
|
|
322
|
+
baseIsAncestorOfHead: null,
|
|
323
|
+
headIsAncestorOfBase: null,
|
|
324
|
+
relation: "unknown",
|
|
325
|
+
error
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/path-values.ts
|
|
330
|
+
import { homedir } from "node:os";
|
|
331
|
+
import path2 from "node:path";
|
|
332
|
+
function expandHomePath(value) {
|
|
333
|
+
if (value === "~") return homedir();
|
|
334
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
335
|
+
return path2.join(homedir(), value.slice(2));
|
|
336
|
+
}
|
|
337
|
+
return value;
|
|
338
|
+
}
|
|
339
|
+
function resolveUserPath(value) {
|
|
340
|
+
return path2.resolve(expandHomePath(value));
|
|
341
|
+
}
|
|
342
|
+
function redactHomePath(value) {
|
|
343
|
+
const expanded = expandHomePath(value);
|
|
344
|
+
const resolved = path2.resolve(expanded);
|
|
345
|
+
const home = path2.resolve(homedir());
|
|
346
|
+
if (resolved === home) return "~";
|
|
347
|
+
if (resolved.startsWith(`${home}${path2.sep}`)) {
|
|
348
|
+
return `~/${path2.relative(home, resolved).split(path2.sep).join("/")}`;
|
|
349
|
+
}
|
|
350
|
+
return resolved.replace(/^\/home\/[^/]+(?=\/|$)/, "~").replace(/^\/Users\/[^/]+(?=\/|$)/, "~");
|
|
351
|
+
}
|
|
352
|
+
function displayUserPath(value) {
|
|
353
|
+
return redactHomePath(value);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/default-repo-discovery.ts
|
|
357
|
+
var WELL_KNOWN_REPO_DIRS = [
|
|
358
|
+
"Kynver",
|
|
359
|
+
"repos/Kynver",
|
|
360
|
+
"repos/kynver-source-main",
|
|
361
|
+
"code/Kynver",
|
|
362
|
+
"projects/Kynver"
|
|
363
|
+
];
|
|
364
|
+
function readPackageName(repoRoot) {
|
|
365
|
+
const pkgPath = path3.join(repoRoot, "package.json");
|
|
366
|
+
if (!existsSync3(pkgPath)) return null;
|
|
367
|
+
try {
|
|
368
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
369
|
+
return typeof pkg.name === "string" ? pkg.name.trim() : null;
|
|
370
|
+
} catch {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function isKynverMonorepoRoot(repoRoot) {
|
|
375
|
+
return readPackageName(repoRoot) === "kynver";
|
|
376
|
+
}
|
|
377
|
+
function gitRepoRoot(startDir) {
|
|
378
|
+
const resolvedStart = path3.resolve(startDir);
|
|
379
|
+
if (!existsSync3(resolvedStart)) return null;
|
|
380
|
+
const probe = gitCapture(resolvedStart, ["rev-parse", "--show-toplevel"]);
|
|
381
|
+
if (probe.status !== 0) return null;
|
|
382
|
+
const root = probe.stdout.trim();
|
|
383
|
+
return root.length ? path3.resolve(root) : null;
|
|
384
|
+
}
|
|
385
|
+
function resolveRuntimePackageRoot(moduleUrl = import.meta.url) {
|
|
386
|
+
let dir = path3.dirname(fileURLToPath2(moduleUrl));
|
|
387
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
388
|
+
const pkgPath = path3.join(dir, "package.json");
|
|
389
|
+
if (existsSync3(pkgPath)) {
|
|
390
|
+
try {
|
|
391
|
+
const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
|
|
392
|
+
if (pkg.name === "@kynver-app/runtime") return dir;
|
|
393
|
+
} catch {
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const parent = path3.dirname(dir);
|
|
397
|
+
if (parent === dir) break;
|
|
398
|
+
dir = parent;
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
function pushCandidate(seen, out, repo, source) {
|
|
403
|
+
if (!repo) return;
|
|
404
|
+
const resolved = path3.resolve(repo);
|
|
405
|
+
if (seen.has(resolved)) return;
|
|
406
|
+
if (!isKynverMonorepoRoot(resolved)) return;
|
|
407
|
+
seen.add(resolved);
|
|
408
|
+
out.push({ repo: resolved, source });
|
|
409
|
+
}
|
|
410
|
+
function discoverDefaultRepoCandidates(opts) {
|
|
411
|
+
const cwd = opts?.cwd ?? process.cwd();
|
|
412
|
+
const seen = /* @__PURE__ */ new Set();
|
|
413
|
+
const candidates = [];
|
|
414
|
+
pushCandidate(seen, candidates, gitRepoRoot(cwd), "cwd_git");
|
|
415
|
+
const runtimePkgRoot = resolveRuntimePackageRoot(opts?.runtimeModuleUrl ?? import.meta.url);
|
|
416
|
+
if (runtimePkgRoot) {
|
|
417
|
+
pushCandidate(seen, candidates, gitRepoRoot(runtimePkgRoot), "runtime_checkout");
|
|
418
|
+
}
|
|
419
|
+
const home = homedir2();
|
|
420
|
+
for (const rel of WELL_KNOWN_REPO_DIRS) {
|
|
421
|
+
pushCandidate(seen, candidates, resolveUserPath(path3.join(home, rel)), "well_known_path");
|
|
422
|
+
}
|
|
423
|
+
return candidates;
|
|
424
|
+
}
|
|
425
|
+
function discoverDefaultRepo(opts) {
|
|
426
|
+
return discoverDefaultRepoCandidates(opts)[0] ?? null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/memory-cost-package-version-guard.ts
|
|
430
|
+
var MEMORY_COST_PACKAGE_MIN_VERSIONS = {
|
|
431
|
+
"@kynver-app/runtime": "0.1.83",
|
|
432
|
+
"@kynver-app/openclaw-agent-os": "0.1.43",
|
|
433
|
+
"@kynver-app/mcp-agent-os": "0.3.34"
|
|
434
|
+
};
|
|
435
|
+
var MEMORY_COST_MANAGED_PACKAGES = Object.keys(
|
|
436
|
+
MEMORY_COST_PACKAGE_MIN_VERSIONS
|
|
437
|
+
);
|
|
438
|
+
var DISPLAY_NAMES = {
|
|
439
|
+
"@kynver-app/runtime": "Kynver runtime",
|
|
440
|
+
"@kynver-app/openclaw-agent-os": "OpenClaw AgentOS plugin",
|
|
441
|
+
"@kynver-app/mcp-agent-os": "AgentOS MCP server"
|
|
442
|
+
};
|
|
443
|
+
var REPO_PACKAGE_JSON_RELATIVE = {
|
|
444
|
+
"@kynver-app/runtime": "packages/kynver-runtime/package.json",
|
|
445
|
+
"@kynver-app/openclaw-agent-os": "packages/kynver-openclaw-agent-os/package.json",
|
|
446
|
+
"@kynver-app/mcp-agent-os": "packages/kynver-mcp-agent-os/package.json"
|
|
447
|
+
};
|
|
448
|
+
function parseSemverParts(version) {
|
|
449
|
+
const core = version.trim().split("-")[0]?.split("+")[0];
|
|
450
|
+
if (!core) return null;
|
|
451
|
+
const parts = core.split(".");
|
|
452
|
+
if (parts.length < 1 || parts.length > 3) return null;
|
|
453
|
+
const nums = parts.map((p) => Number.parseInt(p, 10));
|
|
454
|
+
if (nums.some((n) => !Number.isFinite(n) || n < 0)) return null;
|
|
455
|
+
while (nums.length < 3) nums.push(0);
|
|
456
|
+
return [nums[0], nums[1], nums[2]];
|
|
457
|
+
}
|
|
458
|
+
function compareSemver(a, b) {
|
|
459
|
+
const pa = parseSemverParts(a);
|
|
460
|
+
const pb = parseSemverParts(b);
|
|
461
|
+
if (!pa || !pb) return 0;
|
|
462
|
+
for (let i = 0; i < 3; i += 1) {
|
|
463
|
+
if (pa[i] > pb[i]) return 1;
|
|
464
|
+
if (pa[i] < pb[i]) return -1;
|
|
465
|
+
}
|
|
466
|
+
return 0;
|
|
467
|
+
}
|
|
468
|
+
function semverAtLeast(version, minimum) {
|
|
469
|
+
return compareSemver(version, minimum) >= 0;
|
|
470
|
+
}
|
|
471
|
+
function maxSemver(versions) {
|
|
472
|
+
let best = null;
|
|
473
|
+
for (const version of versions) {
|
|
474
|
+
if (!best || compareSemver(version, best) > 0) best = version;
|
|
475
|
+
}
|
|
476
|
+
return best;
|
|
477
|
+
}
|
|
478
|
+
function readPackageJsonVersion(packageJsonPath) {
|
|
479
|
+
try {
|
|
480
|
+
const parsed = JSON.parse(readFileSync4(packageJsonPath, "utf8"));
|
|
481
|
+
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
482
|
+
} catch {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function resolveRepoRoot(cwd, explicitRepoRoot) {
|
|
487
|
+
const candidates = [explicitRepoRoot, process.env.KYNVER_REPO, cwd].filter(
|
|
488
|
+
(value) => Boolean(value?.trim())
|
|
489
|
+
);
|
|
490
|
+
for (const candidate of candidates) {
|
|
491
|
+
const resolved = path4.resolve(candidate);
|
|
492
|
+
if (existsSync4(path4.join(resolved, "packages/kynver-runtime/package.json")) && existsSync4(path4.join(resolved, "package.json"))) {
|
|
493
|
+
return resolved;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const discovered = discoverDefaultRepo({ cwd });
|
|
497
|
+
return discovered?.repo ?? null;
|
|
498
|
+
}
|
|
499
|
+
function probeRepoPackageVersions(input = {}) {
|
|
500
|
+
const cwd = input.cwd ?? process.cwd();
|
|
501
|
+
const repoRoot = resolveRepoRoot(cwd, input.repoRoot);
|
|
502
|
+
if (!repoRoot) return {};
|
|
503
|
+
const out = {};
|
|
504
|
+
for (const packageName of MEMORY_COST_MANAGED_PACKAGES) {
|
|
505
|
+
const packageJsonPath = path4.join(repoRoot, REPO_PACKAGE_JSON_RELATIVE[packageName]);
|
|
506
|
+
const version = readPackageJsonVersion(packageJsonPath);
|
|
507
|
+
if (!version) continue;
|
|
508
|
+
out[packageName] = { version, source: "repo", path: packageJsonPath };
|
|
509
|
+
}
|
|
510
|
+
return out;
|
|
511
|
+
}
|
|
512
|
+
function repoSourceCommands(packageName) {
|
|
513
|
+
if (packageName === "@kynver-app/runtime") {
|
|
514
|
+
return ["npm run kynver:build", "npm run kynver"];
|
|
515
|
+
}
|
|
516
|
+
return [`npm run build -w ${packageName}`];
|
|
517
|
+
}
|
|
518
|
+
function buildRemediation(input) {
|
|
519
|
+
const { packageName, minimumVersion, effectiveVersion, effectiveSource, repoVersion } = input;
|
|
520
|
+
const lines = [];
|
|
521
|
+
if (repoVersion && semverAtLeast(repoVersion, minimumVersion)) {
|
|
522
|
+
lines.push(
|
|
523
|
+
`Use the monorepo checkout (${repoVersion}) instead of a stale npm install: ${repoSourceCommands(packageName).join("; ")}.`
|
|
524
|
+
);
|
|
525
|
+
lines.push("Do not publish npm packages or wait on an operator release.");
|
|
526
|
+
return lines;
|
|
527
|
+
}
|
|
528
|
+
if (effectiveVersion) {
|
|
529
|
+
lines.push(
|
|
530
|
+
`Upgrade ${packageName} from ${effectiveVersion} to >= ${minimumVersion} (npm install -g ${packageName}@latest or align OpenClaw npm prefix).`
|
|
531
|
+
);
|
|
532
|
+
} else {
|
|
533
|
+
lines.push(`Install ${packageName} >= ${minimumVersion} before running memory-heavy AgentOS paths.`);
|
|
534
|
+
}
|
|
535
|
+
if (packageName === "@kynver-app/runtime") {
|
|
536
|
+
lines.push("Repo-source alternative: npm run kynver:build && npm run kynver");
|
|
537
|
+
}
|
|
538
|
+
if (effectiveSource === "installed" && repoVersion) {
|
|
539
|
+
lines.push(`Repo checkout reports ${repoVersion}; rebuild/link repo source if you develop from the monorepo.`);
|
|
588
540
|
}
|
|
589
|
-
|
|
590
|
-
return {
|
|
591
|
-
checked: true,
|
|
592
|
-
base: baseLabel,
|
|
593
|
-
head: headSha,
|
|
594
|
-
baseHead: baseSha,
|
|
595
|
-
baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
|
|
596
|
-
headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
|
|
597
|
-
relation,
|
|
598
|
-
...error ? { error } : {}
|
|
599
|
-
};
|
|
541
|
+
return lines;
|
|
600
542
|
}
|
|
601
|
-
function
|
|
602
|
-
return {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
543
|
+
function pickEffectiveCandidate(candidates) {
|
|
544
|
+
if (candidates.length === 0) return { version: null, source: "unknown" };
|
|
545
|
+
const best = maxSemver(candidates.map((candidate) => candidate.version));
|
|
546
|
+
if (!best) return { version: null, source: "unknown" };
|
|
547
|
+
const winner = candidates.find((candidate) => candidate.version === best) ?? candidates[0];
|
|
548
|
+
return { version: winner.version, source: winner.source };
|
|
549
|
+
}
|
|
550
|
+
function evaluateMemoryCostPackageVersionGuard(input = {}) {
|
|
551
|
+
const normalize2 = (value, fallbackSource) => {
|
|
552
|
+
if (!value) return null;
|
|
553
|
+
if (typeof value === "string") return { version: value, source: fallbackSource };
|
|
554
|
+
return value;
|
|
611
555
|
};
|
|
556
|
+
const packages = MEMORY_COST_MANAGED_PACKAGES.map((packageName) => {
|
|
557
|
+
const minimumVersion = MEMORY_COST_PACKAGE_MIN_VERSIONS[packageName];
|
|
558
|
+
const candidates = [];
|
|
559
|
+
const installed = normalize2(input.installed?.[packageName], "installed");
|
|
560
|
+
const repo = normalize2(input.repo?.[packageName], "repo");
|
|
561
|
+
const self = normalize2(input.self?.[packageName], "self");
|
|
562
|
+
if (installed) candidates.push(installed);
|
|
563
|
+
if (repo) candidates.push(repo);
|
|
564
|
+
if (self) candidates.push(self);
|
|
565
|
+
const { version: effectiveVersion, source: effectiveSource } = pickEffectiveCandidate(candidates);
|
|
566
|
+
const repoVersion = repo?.version ?? null;
|
|
567
|
+
const ok2 = effectiveVersion ? semverAtLeast(effectiveVersion, minimumVersion) : false;
|
|
568
|
+
const remediation = ok2 ? [] : buildRemediation({
|
|
569
|
+
packageName,
|
|
570
|
+
minimumVersion,
|
|
571
|
+
effectiveVersion,
|
|
572
|
+
effectiveSource,
|
|
573
|
+
repoVersion
|
|
574
|
+
});
|
|
575
|
+
const summary2 = ok2 ? `${DISPLAY_NAMES[packageName]} ${effectiveVersion} meets memory-cost minimum ${minimumVersion} (${effectiveSource}).` : `${DISPLAY_NAMES[packageName]} is below memory-cost minimum ${minimumVersion}` + (effectiveVersion ? ` (effective ${effectiveVersion} via ${effectiveSource})` : " (no version detected)") + ".";
|
|
576
|
+
return {
|
|
577
|
+
packageName,
|
|
578
|
+
displayName: DISPLAY_NAMES[packageName],
|
|
579
|
+
minimumVersion,
|
|
580
|
+
effectiveVersion,
|
|
581
|
+
effectiveSource,
|
|
582
|
+
ok: ok2,
|
|
583
|
+
summary: summary2,
|
|
584
|
+
remediation
|
|
585
|
+
};
|
|
586
|
+
});
|
|
587
|
+
const violations = packages.filter((row) => !row.ok);
|
|
588
|
+
const ok = violations.length === 0;
|
|
589
|
+
const summary = ok ? "All managed AgentOS packages meet memory-cost minimum versions." : `Memory-cost package guard blocked ${violations.length} stale package(s): ${violations.map((row) => `${row.packageName} < ${row.minimumVersion}`).join("; ")}.`;
|
|
590
|
+
return { ok, summary, packages };
|
|
612
591
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
592
|
+
var MemoryCostPackageVersionGuardError = class extends Error {
|
|
593
|
+
result;
|
|
594
|
+
constructor(result) {
|
|
595
|
+
const lines = [
|
|
596
|
+
result.summary,
|
|
597
|
+
...result.packages.filter((row) => !row.ok).flatMap((row) => [`- ${row.summary}`, ...row.remediation.map((line) => ` \u2192 ${line}`)])
|
|
598
|
+
];
|
|
599
|
+
super(lines.join("\n"));
|
|
600
|
+
this.name = "MemoryCostPackageVersionGuardError";
|
|
601
|
+
this.result = result;
|
|
621
602
|
}
|
|
622
|
-
|
|
603
|
+
};
|
|
604
|
+
function assertMemoryCostPackageVersionGuard(input = {}) {
|
|
605
|
+
const result = evaluateMemoryCostPackageVersionGuard(input);
|
|
606
|
+
if (!result.ok) throw new MemoryCostPackageVersionGuardError(result);
|
|
607
|
+
return result;
|
|
623
608
|
}
|
|
624
|
-
function
|
|
625
|
-
return
|
|
609
|
+
function formatMemoryCostPackageGuardError(result) {
|
|
610
|
+
return new MemoryCostPackageVersionGuardError(result).message;
|
|
626
611
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
612
|
+
|
|
613
|
+
// src/installed-package-versions.ts
|
|
614
|
+
import { readFile } from "node:fs/promises";
|
|
615
|
+
import { homedir as homedir3 } from "node:os";
|
|
616
|
+
import path5 from "node:path";
|
|
617
|
+
var MANAGED_PACKAGES = [
|
|
618
|
+
"@kynver-app/runtime",
|
|
619
|
+
"@kynver-app/openclaw-agent-os",
|
|
620
|
+
"@kynver-app/mcp-agent-os"
|
|
621
|
+
];
|
|
622
|
+
function trim(value) {
|
|
623
|
+
const out = value?.trim();
|
|
624
|
+
return out ? out : null;
|
|
636
625
|
}
|
|
637
|
-
function
|
|
638
|
-
return
|
|
626
|
+
function unique(values) {
|
|
627
|
+
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
639
628
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
629
|
+
function moduleRoots() {
|
|
630
|
+
const home = homedir3();
|
|
631
|
+
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path5.join(home, ".openclaw", "npm");
|
|
632
|
+
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path5.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path5.join(home, ".npm-global", "lib", "node_modules"));
|
|
633
|
+
return unique([
|
|
634
|
+
path5.join(openClawPrefix, "lib", "node_modules"),
|
|
635
|
+
path5.join(openClawPrefix, "node_modules"),
|
|
636
|
+
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path5.join(npmGlobalRoot, "lib", "node_modules")
|
|
637
|
+
]);
|
|
638
|
+
}
|
|
639
|
+
async function readVersion(packageJsonPath) {
|
|
646
640
|
try {
|
|
647
|
-
const
|
|
648
|
-
return typeof
|
|
641
|
+
const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
642
|
+
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
649
643
|
} catch {
|
|
650
644
|
return null;
|
|
651
645
|
}
|
|
652
646
|
}
|
|
653
|
-
function
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
const
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
647
|
+
function installedPackageJsonCandidates(packageName) {
|
|
648
|
+
const roots = moduleRoots();
|
|
649
|
+
const seen = /* @__PURE__ */ new Set();
|
|
650
|
+
const out = [];
|
|
651
|
+
for (const root of roots) {
|
|
652
|
+
const candidate = path5.join(root, packageName, "package.json");
|
|
653
|
+
if (seen.has(candidate)) continue;
|
|
654
|
+
seen.add(candidate);
|
|
655
|
+
out.push(candidate);
|
|
656
|
+
}
|
|
657
|
+
return out;
|
|
663
658
|
}
|
|
664
|
-
function
|
|
665
|
-
|
|
666
|
-
for (
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
659
|
+
async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
660
|
+
const out = {};
|
|
661
|
+
for (const packageName of MANAGED_PACKAGES) {
|
|
662
|
+
let best = null;
|
|
663
|
+
for (const packageJsonPath of installedPackageJsonCandidates(packageName)) {
|
|
664
|
+
const version = await readVersion(packageJsonPath);
|
|
665
|
+
if (!version) continue;
|
|
666
|
+
if (!best || compareSemver(version, best.version) > 0) {
|
|
667
|
+
best = { version, path: packageJsonPath };
|
|
673
668
|
}
|
|
674
669
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
670
|
+
if (best) {
|
|
671
|
+
out[packageName] = { version: best.version, observedAt, path: best.path };
|
|
672
|
+
}
|
|
678
673
|
}
|
|
679
|
-
return
|
|
680
|
-
}
|
|
681
|
-
function pushCandidate(seen, out, repo, source) {
|
|
682
|
-
if (!repo) return;
|
|
683
|
-
const resolved = path5.resolve(repo);
|
|
684
|
-
if (seen.has(resolved)) return;
|
|
685
|
-
if (!isKynverMonorepoRoot(resolved)) return;
|
|
686
|
-
seen.add(resolved);
|
|
687
|
-
out.push({ repo: resolved, source });
|
|
674
|
+
return out;
|
|
688
675
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
676
|
+
|
|
677
|
+
// src/memory-cost-package-version-guard-enforce.ts
|
|
678
|
+
function installedVersionMap(observed) {
|
|
679
|
+
const out = {};
|
|
680
|
+
for (const [packageName, row] of Object.entries(observed)) {
|
|
681
|
+
if (!row?.version) continue;
|
|
682
|
+
out[packageName] = {
|
|
683
|
+
version: row.version,
|
|
684
|
+
source: "installed",
|
|
685
|
+
path: row.path
|
|
686
|
+
};
|
|
697
687
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
688
|
+
return out;
|
|
689
|
+
}
|
|
690
|
+
async function buildMemoryCostPackageGuardInput(input = {}) {
|
|
691
|
+
const [installed, repo] = await Promise.all([
|
|
692
|
+
collectInstalledPackageVersions(),
|
|
693
|
+
Promise.resolve(probeRepoPackageVersions({ cwd: input.cwd, repoRoot: input.repoRoot }))
|
|
694
|
+
]);
|
|
695
|
+
const self = {};
|
|
696
|
+
const runtimeSelfVersion = input.selfPackageName === "@kynver-app/runtime" && input.selfVersion ? input.selfVersion : PACKAGE_VERSION;
|
|
697
|
+
self["@kynver-app/runtime"] = { version: runtimeSelfVersion, source: "self" };
|
|
698
|
+
if (input.selfPackageName && input.selfVersion && input.selfPackageName !== "@kynver-app/runtime") {
|
|
699
|
+
self[input.selfPackageName] = { version: input.selfVersion, source: "self" };
|
|
701
700
|
}
|
|
702
|
-
return
|
|
701
|
+
return {
|
|
702
|
+
installed: installedVersionMap(installed),
|
|
703
|
+
repo,
|
|
704
|
+
self
|
|
705
|
+
};
|
|
703
706
|
}
|
|
704
|
-
function
|
|
705
|
-
|
|
707
|
+
async function evaluateMemoryCostPackageGuardAtStartup(input = {}) {
|
|
708
|
+
const guardInput = await buildMemoryCostPackageGuardInput(input);
|
|
709
|
+
return evaluateMemoryCostPackageVersionGuard(guardInput);
|
|
710
|
+
}
|
|
711
|
+
async function enforceMemoryCostPackageGuardAtStartup(input = {}) {
|
|
712
|
+
const guardInput = await buildMemoryCostPackageGuardInput(input);
|
|
713
|
+
return assertMemoryCostPackageVersionGuard(guardInput);
|
|
714
|
+
}
|
|
715
|
+
function shouldEnforceMemoryCostPackageGuardCli(scope, action) {
|
|
716
|
+
if (!scope) return false;
|
|
717
|
+
if (scope === "daemon") return true;
|
|
718
|
+
if (scope === "worker") return true;
|
|
719
|
+
if (scope === "monitor") return true;
|
|
720
|
+
if (scope === "run" && (action === "dispatch" || action === "sweep" || action === "reconcile" || action === "unblock")) {
|
|
721
|
+
return true;
|
|
722
|
+
}
|
|
723
|
+
if (scope === "cron" && action === "tick") return true;
|
|
724
|
+
return false;
|
|
706
725
|
}
|
|
707
726
|
|
|
727
|
+
// src/config.ts
|
|
728
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync2, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
|
|
729
|
+
import { homedir as homedir5, totalmem } from "node:os";
|
|
730
|
+
import path10 from "node:path";
|
|
731
|
+
|
|
708
732
|
// src/box-identity.ts
|
|
709
733
|
function normalizeWorkerPoolBoxKind(raw) {
|
|
710
734
|
const kind = (raw ?? "").trim().toLowerCase();
|
|
@@ -779,6 +803,7 @@ function readMemAvailableBytes(meminfoText) {
|
|
|
779
803
|
|
|
780
804
|
// src/resource-gate.ts
|
|
781
805
|
import path9 from "node:path";
|
|
806
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
782
807
|
|
|
783
808
|
// src/disk-gate.ts
|
|
784
809
|
import { statfsSync as statfsSync2 } from "node:fs";
|
|
@@ -803,23 +828,23 @@ function isWslHost() {
|
|
|
803
828
|
function observeWslHostDisk(options = {}) {
|
|
804
829
|
const wsl = options.forceWsl === void 0 ? isWslHost() : options.forceWsl;
|
|
805
830
|
if (!wsl) return null;
|
|
806
|
-
const
|
|
831
|
+
const path71 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
|
|
807
832
|
const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;
|
|
808
833
|
const criticalBelowBytes = options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
|
|
809
834
|
const statfs = options.statfs ?? statfsSync;
|
|
810
835
|
let stats;
|
|
811
836
|
try {
|
|
812
|
-
stats = statfs(
|
|
837
|
+
stats = statfs(path71);
|
|
813
838
|
} catch (error) {
|
|
814
839
|
return {
|
|
815
840
|
ok: false,
|
|
816
|
-
path:
|
|
841
|
+
path: path71,
|
|
817
842
|
freeBytes: 0,
|
|
818
843
|
totalBytes: 0,
|
|
819
844
|
usedPercent: 100,
|
|
820
845
|
warnBelowBytes,
|
|
821
846
|
criticalBelowBytes,
|
|
822
|
-
reason: `Windows host disk probe failed at ${
|
|
847
|
+
reason: `Windows host disk probe failed at ${path71}: ${error.message}`,
|
|
823
848
|
probeError: error.message
|
|
824
849
|
};
|
|
825
850
|
}
|
|
@@ -833,11 +858,11 @@ function observeWslHostDisk(options = {}) {
|
|
|
833
858
|
let reason = null;
|
|
834
859
|
if (!ok) {
|
|
835
860
|
const tag = criticalFree ? "critical" : "warning";
|
|
836
|
-
reason = `Windows host disk ${
|
|
861
|
+
reason = `Windows host disk ${path71} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
|
|
837
862
|
}
|
|
838
863
|
return {
|
|
839
864
|
ok,
|
|
840
|
-
path:
|
|
865
|
+
path: path71,
|
|
841
866
|
freeBytes,
|
|
842
867
|
totalBytes,
|
|
843
868
|
usedPercent,
|
|
@@ -857,12 +882,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
|
857
882
|
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
858
883
|
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
859
884
|
function observeRunnerDiskGate(input = {}) {
|
|
860
|
-
const
|
|
885
|
+
const path71 = input.diskPath?.trim() || "/";
|
|
861
886
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
862
887
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
863
888
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
864
889
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
865
|
-
const stats = statfsSync2(
|
|
890
|
+
const stats = statfsSync2(path71);
|
|
866
891
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
867
892
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
868
893
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -885,7 +910,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
885
910
|
}
|
|
886
911
|
return {
|
|
887
912
|
ok,
|
|
888
|
-
path:
|
|
913
|
+
path: path71,
|
|
889
914
|
freeBytes,
|
|
890
915
|
totalBytes,
|
|
891
916
|
usedPercent,
|
|
@@ -2312,11 +2337,29 @@ function computeAutoMaxWorkers(totalMemBytes, opts = {}) {
|
|
|
2312
2337
|
function readAvailableMemBytes() {
|
|
2313
2338
|
return readMemAvailableBytes();
|
|
2314
2339
|
}
|
|
2340
|
+
function pidCommandLine(pid) {
|
|
2341
|
+
if (!pid || process.platform !== "linux") return null;
|
|
2342
|
+
try {
|
|
2343
|
+
return readFileSync9(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
|
|
2344
|
+
} catch {
|
|
2345
|
+
return null;
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
function workerProcessMatchesRecord(worker) {
|
|
2349
|
+
if (!worker.pid || process.platform !== "linux") return true;
|
|
2350
|
+
const cmdline = pidCommandLine(worker.pid);
|
|
2351
|
+
if (!cmdline) return false;
|
|
2352
|
+
const probes = [worker.worktreePath, worker.workerDir, worker.heartbeatPath].filter(
|
|
2353
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
2354
|
+
);
|
|
2355
|
+
return probes.some((probe) => cmdline.includes(probe));
|
|
2356
|
+
}
|
|
2315
2357
|
function isActiveHarnessWorker(worker) {
|
|
2316
2358
|
if (typeof worker.completionBlocker === "string" && worker.completionBlocker.trim()) {
|
|
2317
2359
|
return false;
|
|
2318
2360
|
}
|
|
2319
2361
|
const status = computeWorkerStatus(worker);
|
|
2362
|
+
if (status.alive && !workerProcessMatchesRecord(worker)) return false;
|
|
2320
2363
|
return status.alive && !status.finalResult && status.attention.state !== "done";
|
|
2321
2364
|
}
|
|
2322
2365
|
function countActiveWorkersForRun(run) {
|
|
@@ -2467,7 +2510,7 @@ var CREDENTIALS_FILE = path10.join(CONFIG_DIR, "credentials");
|
|
|
2467
2510
|
function loadUserConfig() {
|
|
2468
2511
|
if (!existsSync11(CONFIG_FILE)) return {};
|
|
2469
2512
|
try {
|
|
2470
|
-
return JSON.parse(
|
|
2513
|
+
return JSON.parse(readFileSync10(CONFIG_FILE, "utf8"));
|
|
2471
2514
|
} catch {
|
|
2472
2515
|
return {};
|
|
2473
2516
|
}
|
|
@@ -2544,7 +2587,7 @@ function resolveSetupWorkerConfig(existing, args, totalMemBytes = totalmem()) {
|
|
|
2544
2587
|
function loadCredentialsFile() {
|
|
2545
2588
|
if (!existsSync11(CREDENTIALS_FILE)) return {};
|
|
2546
2589
|
try {
|
|
2547
|
-
return JSON.parse(
|
|
2590
|
+
return JSON.parse(readFileSync10(CREDENTIALS_FILE, "utf8"));
|
|
2548
2591
|
} catch {
|
|
2549
2592
|
return {};
|
|
2550
2593
|
}
|
|
@@ -2821,15 +2864,30 @@ async function withTimeout(fn) {
|
|
|
2821
2864
|
clearTimeout(timeout);
|
|
2822
2865
|
}
|
|
2823
2866
|
}
|
|
2867
|
+
function callbackFetchError(error) {
|
|
2868
|
+
return {
|
|
2869
|
+
ok: false,
|
|
2870
|
+
status: 0,
|
|
2871
|
+
response: {
|
|
2872
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2873
|
+
timeoutMs: callbackTimeoutMs()
|
|
2874
|
+
}
|
|
2875
|
+
};
|
|
2876
|
+
}
|
|
2824
2877
|
async function postJson(url, secret, body) {
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2878
|
+
let res;
|
|
2879
|
+
try {
|
|
2880
|
+
res = await withTimeout(
|
|
2881
|
+
(signal) => fetch(url, {
|
|
2882
|
+
method: "POST",
|
|
2883
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
2884
|
+
body: JSON.stringify(body),
|
|
2885
|
+
signal
|
|
2886
|
+
})
|
|
2887
|
+
);
|
|
2888
|
+
} catch (error) {
|
|
2889
|
+
return callbackFetchError(error);
|
|
2890
|
+
}
|
|
2833
2891
|
let response = null;
|
|
2834
2892
|
try {
|
|
2835
2893
|
response = await res.json();
|
|
@@ -2847,13 +2905,18 @@ async function postJsonWithCredentialRefresh(url, secret, body, opts) {
|
|
|
2847
2905
|
return { ...retry, refreshedAuth: true };
|
|
2848
2906
|
}
|
|
2849
2907
|
async function getJson(url, secret) {
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2908
|
+
let res;
|
|
2909
|
+
try {
|
|
2910
|
+
res = await withTimeout(
|
|
2911
|
+
(signal) => fetch(url, {
|
|
2912
|
+
method: "GET",
|
|
2913
|
+
headers: buildHarnessCallbackHeaders(secret),
|
|
2914
|
+
signal
|
|
2915
|
+
})
|
|
2916
|
+
);
|
|
2917
|
+
} catch (error) {
|
|
2918
|
+
return callbackFetchError(error);
|
|
2919
|
+
}
|
|
2857
2920
|
let response = null;
|
|
2858
2921
|
try {
|
|
2859
2922
|
response = await res.json();
|
|
@@ -2863,41 +2926,6 @@ async function getJson(url, secret) {
|
|
|
2863
2926
|
return { ok: res.ok, status: res.status, response };
|
|
2864
2927
|
}
|
|
2865
2928
|
|
|
2866
|
-
// src/dispatch-lane-normalization.ts
|
|
2867
|
-
function trimLower(value) {
|
|
2868
|
-
return (value ?? "").trim().toLowerCase();
|
|
2869
|
-
}
|
|
2870
|
-
function roleLaneToDispatchLane(roleLane) {
|
|
2871
|
-
switch (trimLower(roleLane)) {
|
|
2872
|
-
case "implementer":
|
|
2873
|
-
case "repair_implementer":
|
|
2874
|
-
case "plan_author":
|
|
2875
|
-
case "runtime_verifier":
|
|
2876
|
-
return "implementation";
|
|
2877
|
-
case "plan_reviewer":
|
|
2878
|
-
case "report_reviewer":
|
|
2879
|
-
case "deep_reviewer":
|
|
2880
|
-
return "review";
|
|
2881
|
-
default:
|
|
2882
|
-
return null;
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
function normalizeDispatchNextLaneFilter(raw) {
|
|
2886
|
-
const key = trimLower(raw);
|
|
2887
|
-
if (!key) return void 0;
|
|
2888
|
-
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
2889
|
-
return key;
|
|
2890
|
-
}
|
|
2891
|
-
const mapped = roleLaneToDispatchLane(key);
|
|
2892
|
-
if (mapped) return mapped;
|
|
2893
|
-
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
2894
|
-
if (key === "land" || key === "merge") return "landing";
|
|
2895
|
-
return void 0;
|
|
2896
|
-
}
|
|
2897
|
-
function resolveDispatchNextLaneFilter(raw) {
|
|
2898
|
-
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
2899
|
-
}
|
|
2900
|
-
|
|
2901
2929
|
// src/worker-persona-catalog.ts
|
|
2902
2930
|
var WORKER_PERSONA_CATALOG = [
|
|
2903
2931
|
{
|
|
@@ -3012,6 +3040,41 @@ function workerPersonaLandingSlugs() {
|
|
|
3012
3040
|
);
|
|
3013
3041
|
}
|
|
3014
3042
|
|
|
3043
|
+
// src/dispatch-lane-normalization.ts
|
|
3044
|
+
function trimLower(value) {
|
|
3045
|
+
return (value ?? "").trim().toLowerCase();
|
|
3046
|
+
}
|
|
3047
|
+
function roleLaneToDispatchLane(roleLane) {
|
|
3048
|
+
switch (trimLower(roleLane)) {
|
|
3049
|
+
case "implementer":
|
|
3050
|
+
case "repair_implementer":
|
|
3051
|
+
case "plan_author":
|
|
3052
|
+
case "runtime_verifier":
|
|
3053
|
+
return "implementation";
|
|
3054
|
+
case "plan_reviewer":
|
|
3055
|
+
case "report_reviewer":
|
|
3056
|
+
case "deep_reviewer":
|
|
3057
|
+
return "review";
|
|
3058
|
+
default:
|
|
3059
|
+
return null;
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
function normalizeDispatchNextLaneFilter(raw) {
|
|
3063
|
+
const key = trimLower(raw);
|
|
3064
|
+
if (!key) return void 0;
|
|
3065
|
+
if (key === "implementation" || key === "review" || key === "landing" || key === "any") {
|
|
3066
|
+
return key;
|
|
3067
|
+
}
|
|
3068
|
+
const mapped = roleLaneToDispatchLane(key);
|
|
3069
|
+
if (mapped) return mapped;
|
|
3070
|
+
if (key === "implement" || key === "repair" || key === "coding") return "implementation";
|
|
3071
|
+
if (key === "land" || key === "merge") return "landing";
|
|
3072
|
+
return void 0;
|
|
3073
|
+
}
|
|
3074
|
+
function resolveDispatchNextLaneFilter(raw) {
|
|
3075
|
+
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3015
3078
|
// src/model-routing-task-enrich.ts
|
|
3016
3079
|
function taskString(task, key) {
|
|
3017
3080
|
const v = task[key];
|
|
@@ -3479,7 +3542,7 @@ function probeCursorOAuthBinding(nowIso = (/* @__PURE__ */ new Date()).toISOStri
|
|
|
3479
3542
|
}
|
|
3480
3543
|
|
|
3481
3544
|
// src/orchestration-providers/hermes-cli-adapter.ts
|
|
3482
|
-
import { existsSync as existsSync16, readFileSync as
|
|
3545
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
|
|
3483
3546
|
import { homedir as homedir10 } from "node:os";
|
|
3484
3547
|
import path15 from "node:path";
|
|
3485
3548
|
var PROFILE_ENV_KEYS = [
|
|
@@ -3495,7 +3558,7 @@ function hermesProfileEnvPath() {
|
|
|
3495
3558
|
}
|
|
3496
3559
|
function profileEnvKeyPresence(envPath) {
|
|
3497
3560
|
try {
|
|
3498
|
-
const text =
|
|
3561
|
+
const text = readFileSync11(envPath, "utf8");
|
|
3499
3562
|
const present = [];
|
|
3500
3563
|
for (const key of PROFILE_ENV_KEYS) {
|
|
3501
3564
|
const re = new RegExp(`^${key}=`, "m");
|
|
@@ -4438,14 +4501,15 @@ function buildPrompt(input) {
|
|
|
4438
4501
|
input.planId ? `Active planId: ${input.planId}${input.taskId ? ` \xB7 taskId: ${input.taskId}` : ""}` : "No planId on this worker \u2014 still emit progress when you touch plan-scoped work."
|
|
4439
4502
|
];
|
|
4440
4503
|
const mergeGateLines = compact ? [
|
|
4441
|
-
"Merge-gate cost control: do not use Vercel previews/builds for PR verification. Run `node scripts/agent-os-pr-merge-gate.mjs --pr <url> --agent-os-id <id>` (or `verify-pr-local.mjs --from-pr` + POST pr-merge-gate/refresh) before any GitHub Actions run; request merge-gate only via refresh then POST pr-merge-gate/request-run (one Actions run per PR head unless human approves extra)."
|
|
4504
|
+
"Merge-gate cost control: do not use Vercel previews/builds for PR verification. Run `node scripts/agent-os-pr-merge-gate.mjs --pr <url> --agent-os-id <id>` (or `verify-pr-local.mjs --from-pr` + POST pr-merge-gate/refresh) before any GitHub Actions run; request merge-gate only via refresh then POST pr-merge-gate/request-run (one Actions run per PR head unless human approves extra). Per-PR Vercel preview builds are off by default \u2014 production deploy runs via release batch after merge."
|
|
4442
4505
|
] : [
|
|
4443
4506
|
"GitHub Actions merge-gate cost control (Kynver/Hermes PRs):",
|
|
4444
4507
|
"- Prefer local cached package verification (`node scripts/verify-pr-local.mjs --emit-json`) before GitHub Actions. Do not use Vercel previews/builds as PR evidence.",
|
|
4445
4508
|
"- Do not push empty commits to re-trigger CI. One budgeted merge-gate Actions run per PR candidate (head SHA) unless a human approves extra.",
|
|
4446
4509
|
"- Record evidence: POST `/api/agent-os/by-id/<agentOsId>/pr-merge-gate/refresh` with prUrl + local payloads.",
|
|
4447
4510
|
"- Request the final Actions run only when local verification is green: POST `.../pr-merge-gate/request-run` (applies `merge-gate` label).",
|
|
4448
|
-
"- Empty failed Actions jobs (no runner/steps/logs) are infra/quota \u2014 do not enter repair loops; escalate to operator."
|
|
4511
|
+
"- Empty failed Actions jobs (no runner/steps/logs) are infra/quota \u2014 do not enter repair loops; escalate to operator.",
|
|
4512
|
+
"- After merge, landed PRs accumulate into a release batch; run batch verification then manual Vercel production deploy from Command Center (release train). PR landing completes with: verification complete, awaiting release batch/deploy."
|
|
4449
4513
|
];
|
|
4450
4514
|
const planArtifactLines = compact ? [
|
|
4451
4515
|
"Plan artifacts: when authoring/revising docs/superpowers/plans/, open a GitHub PR early and iterate from that PR branch; do not leave the canonical plan only in the harness worktree."
|
|
@@ -4468,7 +4532,7 @@ function buildPrompt(input) {
|
|
|
4468
4532
|
"Completion handoff (required): before you stop, ensure the harness records a final result \u2014 summarize outcome in your last message and append a heartbeat line with phase `complete`. If you leave uncommitted changes or committed work without a PR, the orchestrator blocks completion until a GitHub PR exists (or you discard/commit cleanly). One-off helper scripts must be removed (`kynver worker discard-disposable --path <file>`) or committed before completion \u2014 maintenance/board-drain workers are not exempt. Exiting with only dirty files and no PR routes to salvage review, not production review.",
|
|
4469
4533
|
"PR-ready handoff: for substantial implementation work, commit, push, and open a GitHub PR (draft OK) on your branch before finishing \u2014 or rely on the harness to run `gh pr create` at completion when `gh` is authenticated.",
|
|
4470
4534
|
"Expert review / production-review workers (Dalton/Lorentz, plan-review-task, scheduledJob reviewer children): do NOT open new implementation PRs \u2014 review the parent task's existing PR and record reviewVerdict in finalResult; landing-contract targetPrReconciliation does not apply.",
|
|
4471
|
-
"Worker resource guard: do not run full monorepo verification (`npm run typecheck`, `npm run build`, or equivalent) from this worker lane unless an operator explicitly requests it. Use targeted checks for touched paths and rely on CI/operator lanes for heavy gates.",
|
|
4535
|
+
"Worker resource guard: do not run full monorepo verification (`npm run typecheck`, `npm run build`, or equivalent) from this worker lane unless an operator explicitly requests it. Use targeted checks for touched paths and rely on CI/operator lanes for heavy gates. When heavy verification is required, route through `node scripts/verify-pr-local.mjs` or `kynver harness verify` \u2014 they acquire the global heavy-verification lease so parallel workers do not launch simultaneous typechecks.",
|
|
4472
4536
|
"npm publish boundary: do not run `npm publish`, do not republish `@kynver-app/*` packages, and do not block on an operator to publish. When you need newer runtime code than npm, use this repo checkout (`npm run kynver:build`, `npm run kynver`) and record evidence: packages/kynver-runtime/package.json version + git ref in your completion report.",
|
|
4473
4537
|
"If verification fails (including OOM), append a heartbeat line immediately with the last command, failure reason, dirty-file status, commit/PR handoff state, and next action so recovery does not require log spelunking.",
|
|
4474
4538
|
"Landing-wrapper cleanup on a git ref: use `node scripts/agent-os-land-pr-cleanup-verify.mjs --ref origin/main` (JSON, exit 0). Do not use `git show <ref>:scripts/agent-os-land-pr.mjs | rg \u2026` \u2014 ripgrep exit 1 when markers are absent is reported as a failed command in Telegram/status tooling.",
|
|
@@ -5344,8 +5408,8 @@ function dirtyPathsCoveredByDisposableRemoval(changedFiles, removed) {
|
|
|
5344
5408
|
if (removed.length === 0) return false;
|
|
5345
5409
|
const removedSet = new Set(removed.map((p) => normalizeRelativePath(p)));
|
|
5346
5410
|
return material.every((line) => {
|
|
5347
|
-
const
|
|
5348
|
-
return removedSet.has(
|
|
5411
|
+
const path71 = normalizeRelativePath(pathFromGitStatusLine(line));
|
|
5412
|
+
return removedSet.has(path71);
|
|
5349
5413
|
});
|
|
5350
5414
|
}
|
|
5351
5415
|
|
|
@@ -6653,7 +6717,7 @@ function collectRunActiveHarnessWorkers(runId) {
|
|
|
6653
6717
|
path24.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
6654
6718
|
void 0
|
|
6655
6719
|
);
|
|
6656
|
-
if (!worker?.taskId || !
|
|
6720
|
+
if (!worker?.taskId || !workerProcessMatchesRecord(worker)) continue;
|
|
6657
6721
|
out.push({
|
|
6658
6722
|
runId: run.id,
|
|
6659
6723
|
workerName: name,
|
|
@@ -6892,7 +6956,7 @@ function isTmpOnlyPath(filePath) {
|
|
|
6892
6956
|
// src/plan-persist/outbox-store.ts
|
|
6893
6957
|
import {
|
|
6894
6958
|
existsSync as existsSync23,
|
|
6895
|
-
readFileSync as
|
|
6959
|
+
readFileSync as readFileSync12,
|
|
6896
6960
|
renameSync,
|
|
6897
6961
|
readdirSync as readdirSync5,
|
|
6898
6962
|
writeFileSync as writeFileSync3,
|
|
@@ -6920,7 +6984,7 @@ function findOutboxByIdempotencyKey(key) {
|
|
|
6920
6984
|
function readOutboxItem(jsonPath) {
|
|
6921
6985
|
if (!existsSync23(jsonPath)) return null;
|
|
6922
6986
|
try {
|
|
6923
|
-
return JSON.parse(
|
|
6987
|
+
return JSON.parse(readFileSync12(jsonPath, "utf8"));
|
|
6924
6988
|
} catch {
|
|
6925
6989
|
return null;
|
|
6926
6990
|
}
|
|
@@ -6928,7 +6992,7 @@ function readOutboxItem(jsonPath) {
|
|
|
6928
6992
|
function readOutboxBody(item) {
|
|
6929
6993
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
6930
6994
|
const bodyFile = path26.join(outboxDir, item.bodyPath);
|
|
6931
|
-
return
|
|
6995
|
+
return readFileSync12(bodyFile, "utf8");
|
|
6932
6996
|
}
|
|
6933
6997
|
function writeOutboxItem(input, opts) {
|
|
6934
6998
|
const { outboxDir } = ensurePlanOutboxDirs();
|
|
@@ -7410,7 +7474,7 @@ async function dispatchRun(args) {
|
|
|
7410
7474
|
runnerPresence,
|
|
7411
7475
|
harnessBoardSnapshot: buildRunBoard(run.id),
|
|
7412
7476
|
...args.lane ? { lane: resolveDispatchNextLaneFilter(String(args.lane)) } : {},
|
|
7413
|
-
|
|
7477
|
+
...args.executor ? { executor: String(args.executor) } : {},
|
|
7414
7478
|
...args.diskPath ? { diskPath: String(args.diskPath) } : {},
|
|
7415
7479
|
...args.targetTaskId ? { targetTaskId: String(args.targetTaskId) } : {},
|
|
7416
7480
|
...!args.targetTaskId && args.targetTaskIds ? {
|
|
@@ -8238,7 +8302,7 @@ import { existsSync as existsSync29, mkdirSync as mkdirSync6 } from "node:fs";
|
|
|
8238
8302
|
import path37 from "node:path";
|
|
8239
8303
|
|
|
8240
8304
|
// src/run-list.ts
|
|
8241
|
-
import { existsSync as existsSync28, readFileSync as
|
|
8305
|
+
import { existsSync as existsSync28, readFileSync as readFileSync15 } from "node:fs";
|
|
8242
8306
|
import path36 from "node:path";
|
|
8243
8307
|
|
|
8244
8308
|
// src/stale-reconcile.ts
|
|
@@ -9009,7 +9073,7 @@ function reconcileRunsCli() {
|
|
|
9009
9073
|
function heartbeatByteLength(heartbeatPath) {
|
|
9010
9074
|
if (!heartbeatPath || !existsSync28(heartbeatPath)) return 0;
|
|
9011
9075
|
try {
|
|
9012
|
-
return
|
|
9076
|
+
return readFileSync15(heartbeatPath, "utf8").trim().length;
|
|
9013
9077
|
} catch {
|
|
9014
9078
|
return 0;
|
|
9015
9079
|
}
|
|
@@ -9519,11 +9583,11 @@ var LIVE_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
|
9519
9583
|
function collectPreservedLivePaths(actions, skips) {
|
|
9520
9584
|
const out = [];
|
|
9521
9585
|
const seen = /* @__PURE__ */ new Set();
|
|
9522
|
-
const push = (
|
|
9523
|
-
const key = `${
|
|
9586
|
+
const push = (path71, reason, detail) => {
|
|
9587
|
+
const key = `${path71}\0${reason}`;
|
|
9524
9588
|
if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;
|
|
9525
9589
|
seen.add(key);
|
|
9526
|
-
out.push({ path:
|
|
9590
|
+
out.push({ path: path71, reason, ...detail ? { detail } : {} });
|
|
9527
9591
|
};
|
|
9528
9592
|
for (const skip2 of skips) {
|
|
9529
9593
|
if (!LIVE_SKIP_REASONS.has(skip2.reason)) continue;
|
|
@@ -10874,7 +10938,7 @@ function isPipelineCleanupEnabled() {
|
|
|
10874
10938
|
}
|
|
10875
10939
|
|
|
10876
10940
|
// src/cli.ts
|
|
10877
|
-
import { mkdirSync as
|
|
10941
|
+
import { mkdirSync as mkdirSync10, realpathSync } from "node:fs";
|
|
10878
10942
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
10879
10943
|
|
|
10880
10944
|
// src/discard-disposable.ts
|
|
@@ -11062,12 +11126,12 @@ async function fireKynverCronJob(input) {
|
|
|
11062
11126
|
}
|
|
11063
11127
|
|
|
11064
11128
|
// src/cron/cron-lock.ts
|
|
11065
|
-
import { closeSync as closeSync6, existsSync as existsSync43, openSync as openSync6, readFileSync as
|
|
11129
|
+
import { closeSync as closeSync6, existsSync as existsSync43, openSync as openSync6, readFileSync as readFileSync16, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11066
11130
|
var STALE_LOCK_MS = 10 * 6e4;
|
|
11067
11131
|
function readLockInfo(lockPath) {
|
|
11068
11132
|
if (!existsSync43(lockPath)) return null;
|
|
11069
11133
|
try {
|
|
11070
|
-
const parsed = JSON.parse(
|
|
11134
|
+
const parsed = JSON.parse(readFileSync16(lockPath, "utf8"));
|
|
11071
11135
|
if (typeof parsed.pid === "number" && typeof parsed.at === "string") return parsed;
|
|
11072
11136
|
} catch {
|
|
11073
11137
|
return null;
|
|
@@ -11856,17 +11920,17 @@ async function runDaemon(args) {
|
|
|
11856
11920
|
idleStreak = 0;
|
|
11857
11921
|
}
|
|
11858
11922
|
const backoff = idleStreak >= MAX_IDLE_STREAK ? IDLE_INTERVAL_MS : intervalMs;
|
|
11859
|
-
sleepMs(backoff);
|
|
11923
|
+
await sleepMs(backoff);
|
|
11860
11924
|
} catch (error) {
|
|
11861
11925
|
console.error(JSON.stringify({ event: "daemon_tick_error", error: error.message }));
|
|
11862
|
-
sleepMs(intervalMs);
|
|
11926
|
+
await sleepMs(intervalMs);
|
|
11863
11927
|
}
|
|
11864
11928
|
}
|
|
11865
11929
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
11866
11930
|
}
|
|
11867
11931
|
|
|
11868
11932
|
// src/plan-progress.ts
|
|
11869
|
-
import
|
|
11933
|
+
import path61 from "node:path";
|
|
11870
11934
|
|
|
11871
11935
|
// src/bounded-build/constants.ts
|
|
11872
11936
|
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
@@ -11996,14 +12060,235 @@ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
|
11996
12060
|
}
|
|
11997
12061
|
|
|
11998
12062
|
// src/bounded-build/exec.ts
|
|
12063
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
12064
|
+
|
|
12065
|
+
// src/heavy-verification/slot.ts
|
|
12066
|
+
import {
|
|
12067
|
+
closeSync as closeSync7,
|
|
12068
|
+
existsSync as existsSync44,
|
|
12069
|
+
mkdirSync as mkdirSync8,
|
|
12070
|
+
openSync as openSync7,
|
|
12071
|
+
readdirSync as readdirSync15,
|
|
12072
|
+
readFileSync as readFileSync17,
|
|
12073
|
+
unlinkSync as unlinkSync4,
|
|
12074
|
+
writeFileSync as writeFileSync5
|
|
12075
|
+
} from "node:fs";
|
|
12076
|
+
import path59 from "node:path";
|
|
12077
|
+
|
|
12078
|
+
// src/heavy-verification/paths.ts
|
|
12079
|
+
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
12080
|
+
import path58 from "node:path";
|
|
12081
|
+
function resolveHeavyVerificationRoot() {
|
|
12082
|
+
return path58.join(resolveKynverStateRoot(), "heavy-verification");
|
|
12083
|
+
}
|
|
12084
|
+
function heavyVerificationSlotsDir() {
|
|
12085
|
+
return path58.join(resolveHeavyVerificationRoot(), "slots");
|
|
12086
|
+
}
|
|
12087
|
+
function ensureHeavyVerificationDirs() {
|
|
12088
|
+
const dir = heavyVerificationSlotsDir();
|
|
12089
|
+
mkdirSync7(dir, { recursive: true });
|
|
12090
|
+
return dir;
|
|
12091
|
+
}
|
|
12092
|
+
|
|
12093
|
+
// src/heavy-verification/slot.ts
|
|
12094
|
+
var DEFAULT_HEAVY_VERIFICATION_STALE_MS = 2 * 60 * 6e4;
|
|
12095
|
+
var DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT = 1;
|
|
12096
|
+
function positiveInt5(value, fallback) {
|
|
12097
|
+
const n = Number(value);
|
|
12098
|
+
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
12099
|
+
return Math.floor(n);
|
|
12100
|
+
}
|
|
12101
|
+
function isHeavyVerificationGateSkipped() {
|
|
12102
|
+
const v = process.env.KYNVER_HEAVY_VERIFICATION_SKIP?.trim().toLowerCase();
|
|
12103
|
+
return v === "1" || v === "true" || v === "yes";
|
|
12104
|
+
}
|
|
12105
|
+
function resolveHeavyVerificationMaxConcurrent() {
|
|
12106
|
+
const env = process.env.KYNVER_HEAVY_VERIFICATION_MAX_CONCURRENT;
|
|
12107
|
+
if (env) return positiveInt5(env, DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT);
|
|
12108
|
+
return DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT;
|
|
12109
|
+
}
|
|
12110
|
+
function indexedSlotId(index) {
|
|
12111
|
+
return `slot-${index}`;
|
|
12112
|
+
}
|
|
12113
|
+
function slotFilePath(slotId, slotsDir = heavyVerificationSlotsDir()) {
|
|
12114
|
+
return path59.join(slotsDir, `${slotId}.json`);
|
|
12115
|
+
}
|
|
12116
|
+
function readSlotRecord(filePath) {
|
|
12117
|
+
if (!existsSync44(filePath)) return null;
|
|
12118
|
+
try {
|
|
12119
|
+
const parsed = JSON.parse(readFileSync17(filePath, "utf8"));
|
|
12120
|
+
if (typeof parsed.slotId === "string" && typeof parsed.pid === "number" && typeof parsed.acquiredAt === "string" && typeof parsed.command === "string") {
|
|
12121
|
+
return parsed;
|
|
12122
|
+
}
|
|
12123
|
+
} catch {
|
|
12124
|
+
return null;
|
|
12125
|
+
}
|
|
12126
|
+
return null;
|
|
12127
|
+
}
|
|
12128
|
+
function slotIsStale(record3, staleMs = DEFAULT_HEAVY_VERIFICATION_STALE_MS) {
|
|
12129
|
+
if (!record3) return true;
|
|
12130
|
+
if (!isPidAlive(record3.pid)) return true;
|
|
12131
|
+
const atMs = Date.parse(record3.acquiredAt);
|
|
12132
|
+
if (Number.isNaN(atMs)) return true;
|
|
12133
|
+
return Date.now() - atMs > staleMs;
|
|
12134
|
+
}
|
|
12135
|
+
function reclaimStaleSlot(filePath, staleMs) {
|
|
12136
|
+
const record3 = readSlotRecord(filePath);
|
|
12137
|
+
if (!slotIsStale(record3, staleMs)) return;
|
|
12138
|
+
try {
|
|
12139
|
+
unlinkSync4(filePath);
|
|
12140
|
+
} catch {
|
|
12141
|
+
}
|
|
12142
|
+
}
|
|
12143
|
+
function ensureSlotsDir(slotsDir) {
|
|
12144
|
+
mkdirSync8(slotsDir, { recursive: true });
|
|
12145
|
+
return slotsDir;
|
|
12146
|
+
}
|
|
12147
|
+
function reclaimStaleHeavyVerificationSlots(opts = {}) {
|
|
12148
|
+
const slotsDir = ensureSlotsDir(opts.slotsDir ?? ensureHeavyVerificationDirs());
|
|
12149
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12150
|
+
let reclaimed = 0;
|
|
12151
|
+
for (const name of readdirSync15(slotsDir)) {
|
|
12152
|
+
if (!name.endsWith(".json")) continue;
|
|
12153
|
+
const filePath = path59.join(slotsDir, name);
|
|
12154
|
+
const before = existsSync44(filePath);
|
|
12155
|
+
reclaimStaleSlot(filePath, staleMs);
|
|
12156
|
+
if (before && !existsSync44(filePath)) reclaimed += 1;
|
|
12157
|
+
}
|
|
12158
|
+
return reclaimed;
|
|
12159
|
+
}
|
|
12160
|
+
function listActiveHeavyVerificationSlots(opts = {}) {
|
|
12161
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
12162
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12163
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12164
|
+
const active = [];
|
|
12165
|
+
for (const name of readdirSync15(slotsDir)) {
|
|
12166
|
+
if (!name.endsWith(".json")) continue;
|
|
12167
|
+
const record3 = readSlotRecord(path59.join(slotsDir, name));
|
|
12168
|
+
if (record3 && !slotIsStale(record3, staleMs)) active.push(record3);
|
|
12169
|
+
}
|
|
12170
|
+
return active;
|
|
12171
|
+
}
|
|
12172
|
+
function countActiveHeavyVerificationSlots(opts = {}) {
|
|
12173
|
+
return listActiveHeavyVerificationSlots(opts).length;
|
|
12174
|
+
}
|
|
12175
|
+
function tryAcquireHeavyVerificationSlot(command, opts = {}) {
|
|
12176
|
+
if (isHeavyVerificationGateSkipped()) {
|
|
12177
|
+
return {
|
|
12178
|
+
admitted: true,
|
|
12179
|
+
slotId: null,
|
|
12180
|
+
activeSlots: 0,
|
|
12181
|
+
maxSlots: resolveHeavyVerificationMaxConcurrent(),
|
|
12182
|
+
reason: null
|
|
12183
|
+
};
|
|
12184
|
+
}
|
|
12185
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
12186
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12187
|
+
const maxSlots = opts.maxSlots ?? resolveHeavyVerificationMaxConcurrent();
|
|
12188
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12189
|
+
for (let index = 0; index < maxSlots; index += 1) {
|
|
12190
|
+
const slotId = indexedSlotId(index);
|
|
12191
|
+
const filePath = slotFilePath(slotId, slotsDir);
|
|
12192
|
+
const existing = readSlotRecord(filePath);
|
|
12193
|
+
if (existing && slotIsStale(existing, staleMs)) {
|
|
12194
|
+
try {
|
|
12195
|
+
unlinkSync4(filePath);
|
|
12196
|
+
} catch {
|
|
12197
|
+
}
|
|
12198
|
+
} else if (existing && !slotIsStale(existing, staleMs)) {
|
|
12199
|
+
continue;
|
|
12200
|
+
}
|
|
12201
|
+
const record3 = {
|
|
12202
|
+
slotId,
|
|
12203
|
+
pid: process.pid,
|
|
12204
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12205
|
+
command
|
|
12206
|
+
};
|
|
12207
|
+
try {
|
|
12208
|
+
const fd = openSync7(filePath, "wx");
|
|
12209
|
+
writeFileSync5(fd, JSON.stringify(record3, null, 2), "utf8");
|
|
12210
|
+
closeSync7(fd);
|
|
12211
|
+
const activeSlots2 = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12212
|
+
return {
|
|
12213
|
+
admitted: true,
|
|
12214
|
+
slotId,
|
|
12215
|
+
activeSlots: activeSlots2,
|
|
12216
|
+
maxSlots,
|
|
12217
|
+
reason: null
|
|
12218
|
+
};
|
|
12219
|
+
} catch (err) {
|
|
12220
|
+
if (err.code === "EEXIST") {
|
|
12221
|
+
continue;
|
|
12222
|
+
}
|
|
12223
|
+
throw err;
|
|
12224
|
+
}
|
|
12225
|
+
}
|
|
12226
|
+
const activeSlots = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12227
|
+
return {
|
|
12228
|
+
admitted: false,
|
|
12229
|
+
slotId: null,
|
|
12230
|
+
activeSlots,
|
|
12231
|
+
maxSlots,
|
|
12232
|
+
reason: `heavy verification at capacity (${activeSlots}/${maxSlots} slots)`
|
|
12233
|
+
};
|
|
12234
|
+
}
|
|
12235
|
+
function releaseHeavyVerificationSlot(slotId, opts = {}) {
|
|
12236
|
+
if (!slotId) return;
|
|
12237
|
+
const filePath = slotFilePath(slotId, opts.slotsDir ?? heavyVerificationSlotsDir());
|
|
12238
|
+
try {
|
|
12239
|
+
unlinkSync4(filePath);
|
|
12240
|
+
} catch {
|
|
12241
|
+
}
|
|
12242
|
+
}
|
|
12243
|
+
function assessHeavyVerificationGate(command, opts = {}) {
|
|
12244
|
+
if (isHeavyVerificationGateSkipped()) {
|
|
12245
|
+
return {
|
|
12246
|
+
admitted: true,
|
|
12247
|
+
slotId: null,
|
|
12248
|
+
activeSlots: 0,
|
|
12249
|
+
maxSlots: resolveHeavyVerificationMaxConcurrent(),
|
|
12250
|
+
reason: null
|
|
12251
|
+
};
|
|
12252
|
+
}
|
|
12253
|
+
const slotsDir = opts.slotsDir ?? ensureHeavyVerificationDirs();
|
|
12254
|
+
const staleMs = opts.staleMs ?? DEFAULT_HEAVY_VERIFICATION_STALE_MS;
|
|
12255
|
+
const maxSlots = opts.maxSlots ?? resolveHeavyVerificationMaxConcurrent();
|
|
12256
|
+
reclaimStaleHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12257
|
+
const activeSlots = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12258
|
+
const admitted = activeSlots < maxSlots;
|
|
12259
|
+
return {
|
|
12260
|
+
admitted,
|
|
12261
|
+
slotId: null,
|
|
12262
|
+
activeSlots,
|
|
12263
|
+
maxSlots,
|
|
12264
|
+
reason: admitted ? null : `heavy verification at capacity (${activeSlots}/${maxSlots} slots); waiting for ${command}`
|
|
12265
|
+
};
|
|
12266
|
+
}
|
|
12267
|
+
|
|
12268
|
+
// src/heavy-verification/gate.ts
|
|
11999
12269
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
12270
|
+
function sleepMs3(ms) {
|
|
12271
|
+
if (ms <= 0) return;
|
|
12272
|
+
spawnSync8(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
12273
|
+
stdio: "ignore"
|
|
12274
|
+
});
|
|
12275
|
+
}
|
|
12276
|
+
function waitForHeavyVerificationSlot(command, timeoutMs, pollMs = 2e3, opts = {}) {
|
|
12277
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
12278
|
+
let verdict = tryAcquireHeavyVerificationSlot(command, opts);
|
|
12279
|
+
while (!verdict.admitted && Date.now() < deadline) {
|
|
12280
|
+
sleepMs3(Math.min(pollMs, deadline - Date.now()));
|
|
12281
|
+
verdict = tryAcquireHeavyVerificationSlot(command, opts);
|
|
12282
|
+
}
|
|
12283
|
+
return verdict;
|
|
12284
|
+
}
|
|
12000
12285
|
|
|
12001
12286
|
// src/harness-worktree-build-guard.ts
|
|
12002
|
-
import
|
|
12287
|
+
import path60 from "node:path";
|
|
12003
12288
|
function isPathUnderHarnessWorktree(cwd) {
|
|
12004
12289
|
const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
|
|
12005
|
-
const rel =
|
|
12006
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
12290
|
+
const rel = path60.relative(worktreesDir, path60.resolve(cwd));
|
|
12291
|
+
return rel.length > 0 && !rel.startsWith("..") && !path60.isAbsolute(rel);
|
|
12007
12292
|
}
|
|
12008
12293
|
function assessHarnessWorktreeBuildGuard(cwd) {
|
|
12009
12294
|
if (!isPathUnderHarnessWorktree(cwd)) return { ok: true };
|
|
@@ -12027,7 +12312,7 @@ function envArgv(env) {
|
|
|
12027
12312
|
return out;
|
|
12028
12313
|
}
|
|
12029
12314
|
function runSpawn(argv, opts) {
|
|
12030
|
-
const res =
|
|
12315
|
+
const res = spawnSync9(argv[0], argv.slice(1), {
|
|
12031
12316
|
cwd: opts.cwd,
|
|
12032
12317
|
env: opts.env,
|
|
12033
12318
|
encoding: "utf8",
|
|
@@ -12043,8 +12328,25 @@ function runSpawn(argv, opts) {
|
|
|
12043
12328
|
}
|
|
12044
12329
|
function runBoundedBuildCheck(input) {
|
|
12045
12330
|
const waitMs = input.waitForAdmissionMs ?? 6e5;
|
|
12331
|
+
const verificationGate = waitMs > 0 ? waitForHeavyVerificationSlot(input.command, waitMs) : tryAcquireOrAssessVerificationGate(input.command);
|
|
12332
|
+
if (!verificationGate.admitted) {
|
|
12333
|
+
return {
|
|
12334
|
+
ok: false,
|
|
12335
|
+
exitCode: 1,
|
|
12336
|
+
stdout: "",
|
|
12337
|
+
stderr: verificationGate.reason ?? "heavy verification gate denied",
|
|
12338
|
+
admitted: false,
|
|
12339
|
+
wrappedWithSystemd: false,
|
|
12340
|
+
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
12341
|
+
admission: assessBuildAdmission(),
|
|
12342
|
+
verificationGate,
|
|
12343
|
+
command: input.command
|
|
12344
|
+
};
|
|
12345
|
+
}
|
|
12346
|
+
const slotId = verificationGate.slotId;
|
|
12046
12347
|
const admission = waitMs > 0 ? waitForBuildAdmission(waitMs) : assessBuildAdmission();
|
|
12047
12348
|
if (!admission.admitted) {
|
|
12349
|
+
releaseHeavyVerificationSlot(slotId);
|
|
12048
12350
|
return {
|
|
12049
12351
|
ok: false,
|
|
12050
12352
|
exitCode: 1,
|
|
@@ -12054,11 +12356,13 @@ function runBoundedBuildCheck(input) {
|
|
|
12054
12356
|
wrappedWithSystemd: false,
|
|
12055
12357
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
12056
12358
|
admission,
|
|
12359
|
+
verificationGate,
|
|
12057
12360
|
command: input.command
|
|
12058
12361
|
};
|
|
12059
12362
|
}
|
|
12060
12363
|
const worktreeGuard = assessHarnessWorktreeBuildGuard(input.cwd);
|
|
12061
12364
|
if (!worktreeGuard.ok) {
|
|
12365
|
+
releaseHeavyVerificationSlot(slotId);
|
|
12062
12366
|
return {
|
|
12063
12367
|
ok: false,
|
|
12064
12368
|
exitCode: 1,
|
|
@@ -12068,6 +12372,7 @@ function runBoundedBuildCheck(input) {
|
|
|
12068
12372
|
wrappedWithSystemd: false,
|
|
12069
12373
|
nodeOptionsFlag: formatNodeOptionsFlag(),
|
|
12070
12374
|
admission,
|
|
12375
|
+
verificationGate,
|
|
12071
12376
|
command: input.command
|
|
12072
12377
|
};
|
|
12073
12378
|
}
|
|
@@ -12100,12 +12405,19 @@ function runBoundedBuildCheck(input) {
|
|
|
12100
12405
|
wrappedWithSystemd: useSystemd,
|
|
12101
12406
|
nodeOptionsFlag,
|
|
12102
12407
|
admission,
|
|
12408
|
+
verificationGate,
|
|
12103
12409
|
command: input.command
|
|
12104
12410
|
};
|
|
12105
12411
|
} finally {
|
|
12106
12412
|
registerBuildEnd();
|
|
12413
|
+
releaseHeavyVerificationSlot(slotId);
|
|
12107
12414
|
}
|
|
12108
12415
|
}
|
|
12416
|
+
function tryAcquireOrAssessVerificationGate(command) {
|
|
12417
|
+
const acquired = waitForHeavyVerificationSlot(command, 0);
|
|
12418
|
+
if (acquired.admitted) return acquired;
|
|
12419
|
+
return { ...assessHeavyVerificationGate(command), slotId: null };
|
|
12420
|
+
}
|
|
12109
12421
|
|
|
12110
12422
|
// src/harness-verify.ts
|
|
12111
12423
|
var DEFAULT_HARNESS_VERIFY_COMMANDS = ["npm run typecheck", "npm run test"];
|
|
@@ -12188,7 +12500,7 @@ async function emitPlanProgress(args) {
|
|
|
12188
12500
|
}
|
|
12189
12501
|
function verifyPlanLocal(args) {
|
|
12190
12502
|
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
12191
|
-
const cwd =
|
|
12503
|
+
const cwd = path61.resolve(worktree);
|
|
12192
12504
|
const summary = runHarnessVerifyCommands(cwd);
|
|
12193
12505
|
const emitJson = args.json === true || args.json === "true";
|
|
12194
12506
|
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
@@ -12237,9 +12549,9 @@ async function verifyPlan(args) {
|
|
|
12237
12549
|
}
|
|
12238
12550
|
|
|
12239
12551
|
// src/harness-verify-cli.ts
|
|
12240
|
-
import
|
|
12552
|
+
import path62 from "node:path";
|
|
12241
12553
|
function runHarnessVerifyCli(args) {
|
|
12242
|
-
const cwd =
|
|
12554
|
+
const cwd = path62.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
12243
12555
|
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
12244
12556
|
const commands = [];
|
|
12245
12557
|
const rawCmd = args.command;
|
|
@@ -12267,6 +12579,7 @@ function runHarnessVerifyCli(args) {
|
|
|
12267
12579
|
wrappedWithSystemd: s.result.wrappedWithSystemd,
|
|
12268
12580
|
nodeOptionsFlag: s.result.nodeOptionsFlag,
|
|
12269
12581
|
admission: s.result.admission,
|
|
12582
|
+
verificationGate: s.result.verificationGate,
|
|
12270
12583
|
stderr: s.result.stderr.slice(0, 4e3)
|
|
12271
12584
|
}))
|
|
12272
12585
|
};
|
|
@@ -12283,7 +12596,7 @@ function runHarnessVerifyCli(args) {
|
|
|
12283
12596
|
}
|
|
12284
12597
|
|
|
12285
12598
|
// src/plan-persist-cli.ts
|
|
12286
|
-
import { readFileSync as
|
|
12599
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
12287
12600
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
12288
12601
|
var FAILURE_KINDS = [
|
|
12289
12602
|
"approval_guard",
|
|
@@ -12295,7 +12608,7 @@ var FAILURE_KINDS = [
|
|
|
12295
12608
|
function readBodyArg(args) {
|
|
12296
12609
|
const bodyFile = args.bodyFile ? String(args.bodyFile) : void 0;
|
|
12297
12610
|
if (bodyFile) {
|
|
12298
|
-
return { body:
|
|
12611
|
+
return { body: readFileSync18(bodyFile, "utf8"), bodyPathHint: bodyFile };
|
|
12299
12612
|
}
|
|
12300
12613
|
const inline = args.body ? String(args.body) : void 0;
|
|
12301
12614
|
if (inline) return { body: inline };
|
|
@@ -12675,7 +12988,7 @@ ${text.slice(0, 800)}`,
|
|
|
12675
12988
|
}
|
|
12676
12989
|
|
|
12677
12990
|
// src/monitor/monitor.service.ts
|
|
12678
|
-
import
|
|
12991
|
+
import path64 from "node:path";
|
|
12679
12992
|
|
|
12680
12993
|
// src/monitor/monitor.classify.ts
|
|
12681
12994
|
function classifyWorkerHealth(input) {
|
|
@@ -12727,19 +13040,19 @@ function classifyWorkerHealth(input) {
|
|
|
12727
13040
|
}
|
|
12728
13041
|
|
|
12729
13042
|
// src/monitor/monitor.store.ts
|
|
12730
|
-
import { existsSync as
|
|
12731
|
-
import
|
|
13043
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync9, readdirSync as readdirSync16, unlinkSync as unlinkSync5 } from "node:fs";
|
|
13044
|
+
import path63 from "node:path";
|
|
12732
13045
|
function monitorsDir() {
|
|
12733
13046
|
const { harnessRoot } = getHarnessPaths();
|
|
12734
|
-
const dir =
|
|
12735
|
-
|
|
13047
|
+
const dir = path63.join(harnessRoot, "monitors");
|
|
13048
|
+
mkdirSync9(dir, { recursive: true });
|
|
12736
13049
|
return dir;
|
|
12737
13050
|
}
|
|
12738
13051
|
function monitorIdFor(runId, workerName) {
|
|
12739
13052
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
12740
13053
|
}
|
|
12741
13054
|
function monitorPath(monitorId) {
|
|
12742
|
-
return
|
|
13055
|
+
return path63.join(monitorsDir(), `${monitorId}.json`);
|
|
12743
13056
|
}
|
|
12744
13057
|
function loadMonitorSession(monitorId) {
|
|
12745
13058
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -12749,18 +13062,18 @@ function saveMonitorSession(session) {
|
|
|
12749
13062
|
}
|
|
12750
13063
|
function deleteMonitorSession(monitorId) {
|
|
12751
13064
|
const file = monitorPath(monitorId);
|
|
12752
|
-
if (!
|
|
12753
|
-
|
|
13065
|
+
if (!existsSync45(file)) return false;
|
|
13066
|
+
unlinkSync5(file);
|
|
12754
13067
|
return true;
|
|
12755
13068
|
}
|
|
12756
13069
|
function listMonitorSessions() {
|
|
12757
13070
|
const dir = monitorsDir();
|
|
12758
|
-
if (!
|
|
13071
|
+
if (!existsSync45(dir)) return [];
|
|
12759
13072
|
const entries = [];
|
|
12760
|
-
for (const name of
|
|
13073
|
+
for (const name of readdirSync16(dir)) {
|
|
12761
13074
|
if (!name.endsWith(".json")) continue;
|
|
12762
13075
|
const session = readJson(
|
|
12763
|
-
|
|
13076
|
+
path63.join(dir, name),
|
|
12764
13077
|
void 0
|
|
12765
13078
|
);
|
|
12766
13079
|
if (!session?.monitorId) continue;
|
|
@@ -12851,7 +13164,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
12851
13164
|
// src/monitor/monitor.service.ts
|
|
12852
13165
|
function workerRecord2(runId, name) {
|
|
12853
13166
|
return readJson(
|
|
12854
|
-
|
|
13167
|
+
path64.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
12855
13168
|
void 0
|
|
12856
13169
|
);
|
|
12857
13170
|
}
|
|
@@ -13057,21 +13370,21 @@ async function runMonitorLoop(args) {
|
|
|
13057
13370
|
|
|
13058
13371
|
// src/monitor/monitor-spawn.ts
|
|
13059
13372
|
import { spawn as spawn6 } from "node:child_process";
|
|
13060
|
-
import { closeSync as
|
|
13061
|
-
import
|
|
13373
|
+
import { closeSync as closeSync8, existsSync as existsSync46, openSync as openSync8 } from "node:fs";
|
|
13374
|
+
import path65 from "node:path";
|
|
13062
13375
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
13063
13376
|
function resolveDefaultCliPath2() {
|
|
13064
|
-
return
|
|
13377
|
+
return path65.join(fileURLToPath4(new URL(".", import.meta.url)), "cli.js");
|
|
13065
13378
|
}
|
|
13066
13379
|
function spawnMonitorSidecar(opts) {
|
|
13067
13380
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
13068
|
-
if (!
|
|
13381
|
+
if (!existsSync46(cliPath)) return void 0;
|
|
13069
13382
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
13070
13383
|
const { harnessRoot } = getHarnessPaths();
|
|
13071
|
-
const logPath =
|
|
13384
|
+
const logPath = path65.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
13072
13385
|
let logFd;
|
|
13073
13386
|
try {
|
|
13074
|
-
logFd =
|
|
13387
|
+
logFd = openSync8(logPath, "a");
|
|
13075
13388
|
} catch {
|
|
13076
13389
|
logFd = void 0;
|
|
13077
13390
|
}
|
|
@@ -13111,7 +13424,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
13111
13424
|
env: process.env
|
|
13112
13425
|
})
|
|
13113
13426
|
);
|
|
13114
|
-
if (logFd !== void 0)
|
|
13427
|
+
if (logFd !== void 0) closeSync8(logFd);
|
|
13115
13428
|
child.unref();
|
|
13116
13429
|
const session = {
|
|
13117
13430
|
monitorId,
|
|
@@ -13128,7 +13441,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
13128
13441
|
} catch {
|
|
13129
13442
|
if (logFd !== void 0) {
|
|
13130
13443
|
try {
|
|
13131
|
-
|
|
13444
|
+
closeSync8(logFd);
|
|
13132
13445
|
} catch {
|
|
13133
13446
|
}
|
|
13134
13447
|
}
|
|
@@ -13188,7 +13501,7 @@ async function monitorTickCli(args) {
|
|
|
13188
13501
|
}
|
|
13189
13502
|
|
|
13190
13503
|
// src/post-restart-unblock.ts
|
|
13191
|
-
import
|
|
13504
|
+
import path66 from "node:path";
|
|
13192
13505
|
function skip(runId, worker, taskId, agentOsId, leaseOwner, reason) {
|
|
13193
13506
|
return { runId, worker, taskId, agentOsId, leaseOwner, action: "skipped", reason };
|
|
13194
13507
|
}
|
|
@@ -13201,7 +13514,7 @@ async function postRestartUnblock(args) {
|
|
|
13201
13514
|
const errors = [];
|
|
13202
13515
|
for (const run of listRunRecords()) {
|
|
13203
13516
|
for (const name of Object.keys(run.workers ?? {})) {
|
|
13204
|
-
const workerPath =
|
|
13517
|
+
const workerPath = path66.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
|
|
13205
13518
|
const worker = readJson(workerPath, void 0);
|
|
13206
13519
|
if (!worker) {
|
|
13207
13520
|
skipped.push(skip(run.id, name, "", "", "", "worker.json missing"));
|
|
@@ -13313,9 +13626,9 @@ async function postRestartUnblockCli(args) {
|
|
|
13313
13626
|
}
|
|
13314
13627
|
|
|
13315
13628
|
// src/default-repo-cli.ts
|
|
13316
|
-
import
|
|
13629
|
+
import path67 from "node:path";
|
|
13317
13630
|
import { homedir as homedir15 } from "node:os";
|
|
13318
|
-
var CONFIG_FILE2 =
|
|
13631
|
+
var CONFIG_FILE2 = path67.join(homedir15(), ".kynver", "config.json");
|
|
13319
13632
|
function ensureDefaultRepo(opts) {
|
|
13320
13633
|
const existing = loadUserConfig();
|
|
13321
13634
|
const resolved = resolveDefaultRepo({ ...opts, config: existing });
|
|
@@ -13396,16 +13709,16 @@ function summarizeResolvedDefaultRepo(resolved) {
|
|
|
13396
13709
|
}
|
|
13397
13710
|
|
|
13398
13711
|
// src/doctor/runtime-takeover.ts
|
|
13399
|
-
import
|
|
13712
|
+
import path69 from "node:path";
|
|
13400
13713
|
|
|
13401
13714
|
// src/doctor/runtime-takeover.probes.ts
|
|
13402
|
-
import { accessSync, constants, existsSync as
|
|
13715
|
+
import { accessSync, constants, existsSync as existsSync47, readFileSync as readFileSync19 } from "node:fs";
|
|
13403
13716
|
import { homedir as homedir16 } from "node:os";
|
|
13404
|
-
import
|
|
13405
|
-
import { spawnSync as
|
|
13717
|
+
import path68 from "node:path";
|
|
13718
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
13406
13719
|
function captureCommand(bin, args) {
|
|
13407
13720
|
try {
|
|
13408
|
-
const res =
|
|
13721
|
+
const res = spawnSync10(bin, args, { encoding: "utf8" });
|
|
13409
13722
|
const stdout = (res.stdout || "").trim();
|
|
13410
13723
|
const stderr = (res.stderr || "").trim();
|
|
13411
13724
|
const ok = res.status === 0;
|
|
@@ -13430,7 +13743,7 @@ function tokenPrefix(token) {
|
|
|
13430
13743
|
return trimmed.length <= 12 ? `${trimmed}\u2026` : `${trimmed.slice(0, 12)}\u2026`;
|
|
13431
13744
|
}
|
|
13432
13745
|
function isWritable(target) {
|
|
13433
|
-
if (!
|
|
13746
|
+
if (!existsSync47(target)) return false;
|
|
13434
13747
|
try {
|
|
13435
13748
|
accessSync(target, constants.W_OK);
|
|
13436
13749
|
return true;
|
|
@@ -13443,15 +13756,15 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
13443
13756
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
13444
13757
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
13445
13758
|
loadConfig: () => loadUserConfig(),
|
|
13446
|
-
configFilePath: () =>
|
|
13447
|
-
credentialsFilePath: () =>
|
|
13759
|
+
configFilePath: () => path68.join(homedir16(), ".kynver", "config.json"),
|
|
13760
|
+
credentialsFilePath: () => path68.join(homedir16(), ".kynver", "credentials"),
|
|
13448
13761
|
readCredentials: () => {
|
|
13449
|
-
const credPath =
|
|
13450
|
-
if (!
|
|
13762
|
+
const credPath = path68.join(homedir16(), ".kynver", "credentials");
|
|
13763
|
+
if (!existsSync47(credPath)) {
|
|
13451
13764
|
return { hasApiKey: false };
|
|
13452
13765
|
}
|
|
13453
13766
|
try {
|
|
13454
|
-
const parsed = JSON.parse(
|
|
13767
|
+
const parsed = JSON.parse(readFileSync19(credPath, "utf8"));
|
|
13455
13768
|
return {
|
|
13456
13769
|
hasApiKey: Boolean(parsed.apiKey?.trim()),
|
|
13457
13770
|
runnerTokenPrefix: tokenPrefix(parsed.runnerToken),
|
|
@@ -13481,11 +13794,9 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
13481
13794
|
})()
|
|
13482
13795
|
}),
|
|
13483
13796
|
harnessRoot: () => resolveHarnessRoot(),
|
|
13484
|
-
legacyOpenclawHarnessRoot: () =>
|
|
13485
|
-
pathExists: (target) =>
|
|
13486
|
-
pathWritable: (target) => isWritable(target)
|
|
13487
|
-
vercelVersion: () => captureCommand("vercel", ["--version"]),
|
|
13488
|
-
vercelWhoami: () => captureCommand("vercel", ["whoami"])
|
|
13797
|
+
legacyOpenclawHarnessRoot: () => path68.join(homedir16(), ".openclaw", "harness"),
|
|
13798
|
+
pathExists: (target) => existsSync47(target),
|
|
13799
|
+
pathWritable: (target) => isWritable(target)
|
|
13489
13800
|
};
|
|
13490
13801
|
|
|
13491
13802
|
// src/doctor/runtime-takeover-scheduler.ts
|
|
@@ -13852,37 +14163,46 @@ function assessRunnerToken(probes) {
|
|
|
13852
14163
|
];
|
|
13853
14164
|
return { id: "runner_token", label: "Runner token readiness", checks };
|
|
13854
14165
|
}
|
|
13855
|
-
function
|
|
13856
|
-
const
|
|
13857
|
-
const
|
|
13858
|
-
const
|
|
14166
|
+
function assessVercelDeployEvidence(probes) {
|
|
14167
|
+
const globalCli = probes.commandOnPath("vercel");
|
|
14168
|
+
const cliInstalled = globalCli.ok;
|
|
14169
|
+
const githubToken = Boolean(
|
|
14170
|
+
process.env.GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim()
|
|
14171
|
+
);
|
|
14172
|
+
const vercelToken = Boolean(process.env.VERCEL_TOKEN?.trim());
|
|
13859
14173
|
return {
|
|
13860
|
-
id: "
|
|
13861
|
-
label: "Vercel
|
|
14174
|
+
id: "vercel_deploy_evidence",
|
|
14175
|
+
label: "Vercel deploy evidence",
|
|
13862
14176
|
checks: [
|
|
13863
14177
|
check2({
|
|
13864
|
-
id: "
|
|
13865
|
-
label: "Vercel CLI installed",
|
|
13866
|
-
status:
|
|
13867
|
-
summary:
|
|
13868
|
-
remediation:
|
|
13869
|
-
details: {
|
|
14178
|
+
id: "vercel_global_cli_absent",
|
|
14179
|
+
label: "Global Vercel CLI not installed",
|
|
14180
|
+
status: cliInstalled ? "warn" : "pass",
|
|
14181
|
+
summary: cliInstalled ? `Global Vercel CLI found (${globalCli.stdout || "on PATH"}) \u2014 uninstall after operator approval` : "No global Vercel CLI on PATH",
|
|
14182
|
+
remediation: cliInstalled ? "Uninstall global Vercel CLI (`npm uninstall -g vercel`) \u2014 use GitHub commit status or scoped VERCEL_TOKEN + REST API instead." : void 0,
|
|
14183
|
+
details: { path: cliInstalled ? globalCli.stdout || null : null }
|
|
14184
|
+
}),
|
|
14185
|
+
check2({
|
|
14186
|
+
id: "github_token_for_vercel_status",
|
|
14187
|
+
label: "GitHub token for Vercel status",
|
|
14188
|
+
status: githubToken ? "pass" : "warn",
|
|
14189
|
+
summary: githubToken ? "GITHUB_TOKEN/GH_TOKEN present for GitHub Vercel StatusContext evidence" : "No GITHUB_TOKEN \u2014 merge-gate Vercel evidence requires GitHub commit status API",
|
|
14190
|
+
remediation: githubToken ? void 0 : "Export GITHUB_TOKEN (or GH_TOKEN) for PR head commit status lookups."
|
|
13870
14191
|
}),
|
|
13871
14192
|
check2({
|
|
13872
|
-
id: "
|
|
13873
|
-
label: "Vercel
|
|
13874
|
-
status:
|
|
13875
|
-
summary:
|
|
13876
|
-
remediation:
|
|
13877
|
-
details: { account: whoami.ok ? whoami.stdout : null }
|
|
14193
|
+
id: "vercel_api_token_optional",
|
|
14194
|
+
label: "Vercel API token (optional fallback)",
|
|
14195
|
+
status: vercelToken ? "pass" : "warn",
|
|
14196
|
+
summary: vercelToken ? "VERCEL_TOKEN configured for optional REST API deployment lookup" : "VERCEL_TOKEN unset \u2014 GitHub status is the default path; API fallback disabled",
|
|
14197
|
+
remediation: vercelToken ? void 0 : "Set ephemeral/scoped VERCEL_TOKEN only when GitHub status is insufficient; avoid persistent ~/.vercel auth on runner hosts."
|
|
13878
14198
|
})
|
|
13879
14199
|
]
|
|
13880
14200
|
};
|
|
13881
14201
|
}
|
|
13882
14202
|
function assessHarnessDirs(probes) {
|
|
13883
14203
|
const harnessRoot = probes.harnessRoot();
|
|
13884
|
-
const runsDir =
|
|
13885
|
-
const worktreesDir =
|
|
14204
|
+
const runsDir = path69.join(harnessRoot, "runs");
|
|
14205
|
+
const worktreesDir = path69.join(harnessRoot, "worktrees");
|
|
13886
14206
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
13887
14207
|
const displayRunsDir = redactHomePath(runsDir);
|
|
13888
14208
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -14013,7 +14333,7 @@ function assessRuntimeTakeoverReadiness(probes = defaultRuntimeTakeoverProbes) {
|
|
|
14013
14333
|
assessCliPackage(probes),
|
|
14014
14334
|
assessUserConfig(probes),
|
|
14015
14335
|
assessRunnerToken(probes),
|
|
14016
|
-
|
|
14336
|
+
assessVercelDeployEvidence(probes),
|
|
14017
14337
|
assessHarnessDirs(probes),
|
|
14018
14338
|
assessCallbackAuth(probes),
|
|
14019
14339
|
assessOpenclawHotspots(probes)
|
|
@@ -14146,9 +14466,9 @@ function applySchedulerCutoverAttestation(config) {
|
|
|
14146
14466
|
}
|
|
14147
14467
|
|
|
14148
14468
|
// src/scheduler-cutover-cli.ts
|
|
14149
|
-
import
|
|
14469
|
+
import path70 from "node:path";
|
|
14150
14470
|
import { homedir as homedir17 } from "node:os";
|
|
14151
|
-
var CONFIG_FILE3 =
|
|
14471
|
+
var CONFIG_FILE3 = path70.join(homedir17(), ".kynver", "config.json");
|
|
14152
14472
|
function runSchedulerCutoverCheckCli(json = false) {
|
|
14153
14473
|
const config = loadUserConfig();
|
|
14154
14474
|
const report = assessSchedulerCutover(config);
|
|
@@ -14360,10 +14680,22 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
14360
14680
|
if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
|
|
14361
14681
|
const args = parseArgs(rest);
|
|
14362
14682
|
const { runsDir, worktreesDir } = getPaths();
|
|
14363
|
-
|
|
14364
|
-
|
|
14683
|
+
mkdirSync10(runsDir, { recursive: true });
|
|
14684
|
+
mkdirSync10(worktreesDir, { recursive: true });
|
|
14365
14685
|
if (shouldEnforceMemoryCostPackageGuardCli(scope, action)) {
|
|
14366
|
-
|
|
14686
|
+
let repoRoot;
|
|
14687
|
+
const runId = args.run ? String(args.run).trim() : "";
|
|
14688
|
+
if (runId) {
|
|
14689
|
+
try {
|
|
14690
|
+
repoRoot = loadRun(runId).repo;
|
|
14691
|
+
} catch {
|
|
14692
|
+
repoRoot = void 0;
|
|
14693
|
+
}
|
|
14694
|
+
}
|
|
14695
|
+
await enforceMemoryCostPackageGuardAtStartup({
|
|
14696
|
+
repoRoot,
|
|
14697
|
+
cwd: repoRoot
|
|
14698
|
+
});
|
|
14367
14699
|
}
|
|
14368
14700
|
if (scope === "login") return void await runLogin(args);
|
|
14369
14701
|
if (scope === "runner" && action === "credential") return void await mintRunnerCredential(args);
|
|
@@ -14435,6 +14767,76 @@ if (isCliEntry) {
|
|
|
14435
14767
|
});
|
|
14436
14768
|
}
|
|
14437
14769
|
|
|
14770
|
+
// src/vercel/vercel-api.ts
|
|
14771
|
+
var VERCEL_API = "https://api.vercel.com";
|
|
14772
|
+
function resolveToken(explicit) {
|
|
14773
|
+
const trimmed = explicit?.trim();
|
|
14774
|
+
if (trimmed) return trimmed;
|
|
14775
|
+
return process.env.VERCEL_TOKEN?.trim() || null;
|
|
14776
|
+
}
|
|
14777
|
+
function mapReadyState(state) {
|
|
14778
|
+
return (state ?? "").trim().toUpperCase();
|
|
14779
|
+
}
|
|
14780
|
+
function previewUrlFromDeployment(url) {
|
|
14781
|
+
if (typeof url !== "string" || !url.trim()) return null;
|
|
14782
|
+
const trimmed = url.trim();
|
|
14783
|
+
return trimmed.startsWith("http") ? trimmed : `https://${trimmed}`;
|
|
14784
|
+
}
|
|
14785
|
+
async function fetchVercelDeploymentStatus(deploymentIdOrUrl, options = {}) {
|
|
14786
|
+
const target = deploymentIdOrUrl.trim();
|
|
14787
|
+
if (!target) {
|
|
14788
|
+
return { ok: false, readyState: null, previewUrl: null, error: "missing deployment id or URL" };
|
|
14789
|
+
}
|
|
14790
|
+
const token = resolveToken(options.token);
|
|
14791
|
+
if (!token) {
|
|
14792
|
+
return {
|
|
14793
|
+
ok: false,
|
|
14794
|
+
readyState: null,
|
|
14795
|
+
previewUrl: null,
|
|
14796
|
+
error: "VERCEL_TOKEN not configured"
|
|
14797
|
+
};
|
|
14798
|
+
}
|
|
14799
|
+
const teamId = options.teamId?.trim() || process.env.VERCEL_TEAM_ID?.trim();
|
|
14800
|
+
const teamQuery = teamId ? `?teamId=${encodeURIComponent(teamId)}` : "";
|
|
14801
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
14802
|
+
try {
|
|
14803
|
+
const res = await fetchImpl(`${VERCEL_API}/v13/deployments/${encodeURIComponent(target)}${teamQuery}`, {
|
|
14804
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
14805
|
+
});
|
|
14806
|
+
if (!res.ok) {
|
|
14807
|
+
const body = await res.text();
|
|
14808
|
+
return {
|
|
14809
|
+
ok: false,
|
|
14810
|
+
readyState: null,
|
|
14811
|
+
previewUrl: null,
|
|
14812
|
+
error: `Vercel API ${res.status}: ${body.slice(0, 200)}`
|
|
14813
|
+
};
|
|
14814
|
+
}
|
|
14815
|
+
const data = await res.json();
|
|
14816
|
+
const readyState = mapReadyState(data.readyState ?? data.state);
|
|
14817
|
+
return {
|
|
14818
|
+
ok: true,
|
|
14819
|
+
readyState: readyState || null,
|
|
14820
|
+
previewUrl: previewUrlFromDeployment(data.url),
|
|
14821
|
+
error: null
|
|
14822
|
+
};
|
|
14823
|
+
} catch (err) {
|
|
14824
|
+
return {
|
|
14825
|
+
ok: false,
|
|
14826
|
+
readyState: null,
|
|
14827
|
+
previewUrl: null,
|
|
14828
|
+
error: err instanceof Error ? err.message : "Vercel API fetch failed"
|
|
14829
|
+
};
|
|
14830
|
+
}
|
|
14831
|
+
}
|
|
14832
|
+
function mapVercelReadyStateToEvidenceStatus(readyState, githubPending) {
|
|
14833
|
+
const state = mapReadyState(readyState);
|
|
14834
|
+
if (state === "READY") return "ready";
|
|
14835
|
+
if (state === "ERROR" || state === "CANCELED") return "error";
|
|
14836
|
+
if (state === "BUILDING" || state === "QUEUED" || state === "INITIALIZING") return "building";
|
|
14837
|
+
return githubPending ? "building" : "error";
|
|
14838
|
+
}
|
|
14839
|
+
|
|
14438
14840
|
// src/vercel/vercel-url.ts
|
|
14439
14841
|
var VERCEL_HOST_RE = /(^|\.)vercel\.app$/i;
|
|
14440
14842
|
var DPL_ID_RE = /^dpl_[a-z0-9]+$/i;
|
|
@@ -14565,8 +14967,6 @@ function pickVercelStatusContext(statuses) {
|
|
|
14565
14967
|
}
|
|
14566
14968
|
|
|
14567
14969
|
// src/vercel/vercel-evidence.ts
|
|
14568
|
-
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
14569
|
-
var DEFAULT_INSPECT_WAIT_SECONDS = 120;
|
|
14570
14970
|
function mapGitHubStateToEvidence(state) {
|
|
14571
14971
|
if (state === "success") return "ready";
|
|
14572
14972
|
if (state === "pending") return "building";
|
|
@@ -14589,7 +14989,7 @@ function resolveVercelInspectTarget(rawUrl) {
|
|
|
14589
14989
|
return {
|
|
14590
14990
|
target: null,
|
|
14591
14991
|
classified,
|
|
14592
|
-
reason: classified.deploymentId ? "dashboard deployment id is not
|
|
14992
|
+
reason: classified.deploymentId ? "dashboard deployment id is not API-inspectable; trust GitHub Vercel status" : "dashboard URL is not valid for Vercel API lookup"
|
|
14593
14993
|
};
|
|
14594
14994
|
}
|
|
14595
14995
|
return { target: null, classified, reason: "unrecognized Vercel URL" };
|
|
@@ -14620,55 +15020,16 @@ function evidenceFromGitHubVercelStatus(statuses, options = {}) {
|
|
|
14620
15020
|
summary: evidenceSummary([
|
|
14621
15021
|
`GitHub ${row.context}=${row.state}`,
|
|
14622
15022
|
row.description ?? "",
|
|
14623
|
-
row.dashboardUrl ? "dashboard target_url (
|
|
15023
|
+
row.dashboardUrl ? "dashboard target_url (API lookup skipped)" : ""
|
|
14624
15024
|
]),
|
|
14625
15025
|
observedAt,
|
|
14626
15026
|
inspectSkipped: true,
|
|
14627
|
-
inspectReason: row.dashboardUrl && row.state === "success" ? "trusted_github_status_dashboard_url" : row.dashboardUrl ? "
|
|
15027
|
+
inspectReason: row.dashboardUrl && row.state === "success" ? "trusted_github_status_dashboard_url" : row.dashboardUrl ? "dashboard_url_not_api_inspectable" : "github_status_only",
|
|
14628
15028
|
githubState: row.state,
|
|
14629
15029
|
vercelContext: row.context
|
|
14630
15030
|
};
|
|
14631
15031
|
}
|
|
14632
|
-
function
|
|
14633
|
-
if (!isInspectableVercelTarget(target)) {
|
|
14634
|
-
return {
|
|
14635
|
-
ok: false,
|
|
14636
|
-
exitCode: 1,
|
|
14637
|
-
stdout: "",
|
|
14638
|
-
stderr: "",
|
|
14639
|
-
error: "refusing vercel inspect on non-inspectable target (dashboard URLs use GitHub status)"
|
|
14640
|
-
};
|
|
14641
|
-
}
|
|
14642
|
-
const args = ["inspect", target, "--wait", String(waitSeconds)];
|
|
14643
|
-
const result = spawnSync10("vercel", args, {
|
|
14644
|
-
encoding: "utf8",
|
|
14645
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
14646
|
-
});
|
|
14647
|
-
if (result.error) {
|
|
14648
|
-
return {
|
|
14649
|
-
ok: false,
|
|
14650
|
-
exitCode: result.status,
|
|
14651
|
-
stdout: "",
|
|
14652
|
-
stderr: "",
|
|
14653
|
-
error: result.error.message
|
|
14654
|
-
};
|
|
14655
|
-
}
|
|
14656
|
-
return {
|
|
14657
|
-
ok: result.status === 0,
|
|
14658
|
-
exitCode: result.status ?? 1,
|
|
14659
|
-
stdout: (result.stdout ?? "").trim(),
|
|
14660
|
-
stderr: (result.stderr ?? "").trim(),
|
|
14661
|
-
error: null
|
|
14662
|
-
};
|
|
14663
|
-
}
|
|
14664
|
-
function parseInspectReady(stdout, stderr) {
|
|
14665
|
-
const blob = `${stdout}
|
|
14666
|
-
${stderr}`.toLowerCase();
|
|
14667
|
-
if (/\b(status|state)\s*[:=]\s*(ready|completed)\b/.test(blob)) return true;
|
|
14668
|
-
if (/\bready\b/.test(blob) && !/\bnot ready\b/.test(blob)) return true;
|
|
14669
|
-
return false;
|
|
14670
|
-
}
|
|
14671
|
-
function collectVercelEvidence(input) {
|
|
15032
|
+
async function collectVercelEvidence(input) {
|
|
14672
15033
|
const observedAt = input.observedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
14673
15034
|
const base = evidenceFromGitHubVercelStatus(input.statuses ?? [], { observedAt });
|
|
14674
15035
|
const row = pickVercelStatusContext(input.statuses ?? []);
|
|
@@ -14684,7 +15045,7 @@ function collectVercelEvidence(input) {
|
|
|
14684
15045
|
return {
|
|
14685
15046
|
...base,
|
|
14686
15047
|
inspectSkipped: true,
|
|
14687
|
-
inspectReason: "
|
|
15048
|
+
inspectReason: "api_lookup_disabled"
|
|
14688
15049
|
};
|
|
14689
15050
|
}
|
|
14690
15051
|
const { target, reason } = resolveVercelInspectTarget(row.targetUrl);
|
|
@@ -14692,39 +15053,37 @@ function collectVercelEvidence(input) {
|
|
|
14692
15053
|
return {
|
|
14693
15054
|
...base,
|
|
14694
15055
|
inspectSkipped: true,
|
|
14695
|
-
inspectReason: reason ?? "
|
|
15056
|
+
inspectReason: reason ?? "not_api_inspectable",
|
|
14696
15057
|
summary: evidenceSummary([
|
|
14697
15058
|
base.summary ?? "",
|
|
14698
|
-
reason ?? "skipped
|
|
15059
|
+
reason ?? "skipped Vercel API lookup"
|
|
14699
15060
|
])
|
|
14700
15061
|
};
|
|
14701
15062
|
}
|
|
14702
|
-
const
|
|
14703
|
-
const
|
|
14704
|
-
const inspected = runInspect(target, waitSeconds);
|
|
15063
|
+
const runLookup = input.runInspect ?? fetchVercelDeploymentStatus;
|
|
15064
|
+
const lookedUp = await runLookup(target);
|
|
14705
15065
|
const observed = (/* @__PURE__ */ new Date()).toISOString();
|
|
14706
|
-
if (
|
|
15066
|
+
if (!lookedUp.ok && lookedUp.error?.includes("VERCEL_TOKEN")) {
|
|
14707
15067
|
return {
|
|
14708
15068
|
status: "unavailable",
|
|
14709
15069
|
previewUrl: base.previewUrl,
|
|
14710
15070
|
deploymentUrl: base.deploymentUrl,
|
|
14711
|
-
summary: "
|
|
15071
|
+
summary: "VERCEL_TOKEN not configured for API fallback",
|
|
14712
15072
|
observedAt: observed,
|
|
14713
15073
|
inspectSkipped: true,
|
|
14714
|
-
inspectReason: "
|
|
15074
|
+
inspectReason: "vercel_token_missing",
|
|
14715
15075
|
githubState: row.state,
|
|
14716
15076
|
vercelContext: row.context
|
|
14717
15077
|
};
|
|
14718
15078
|
}
|
|
14719
|
-
if (!
|
|
14720
|
-
const detail = [inspected.stderr, inspected.stdout, inspected.error].filter(Boolean).join("\n").trim().slice(0, 500);
|
|
15079
|
+
if (!lookedUp.ok) {
|
|
14721
15080
|
return {
|
|
14722
15081
|
status: row.state === "pending" ? "building" : "error",
|
|
14723
15082
|
previewUrl: base.previewUrl,
|
|
14724
15083
|
deploymentUrl: target.startsWith("http") ? target : base.deploymentUrl,
|
|
14725
15084
|
summary: evidenceSummary([
|
|
14726
|
-
`
|
|
14727
|
-
|
|
15085
|
+
`Vercel API lookup ${target} failed`,
|
|
15086
|
+
lookedUp.error ?? ""
|
|
14728
15087
|
]),
|
|
14729
15088
|
observedAt: observed,
|
|
14730
15089
|
inspectSkipped: false,
|
|
@@ -14733,12 +15092,19 @@ function collectVercelEvidence(input) {
|
|
|
14733
15092
|
vercelContext: row.context
|
|
14734
15093
|
};
|
|
14735
15094
|
}
|
|
14736
|
-
const
|
|
15095
|
+
const mapped = mapVercelReadyStateToEvidenceStatus(
|
|
15096
|
+
lookedUp.readyState,
|
|
15097
|
+
row.state === "pending"
|
|
15098
|
+
);
|
|
15099
|
+
const previewUrl = lookedUp.previewUrl ?? (target.startsWith("http") ? target : base.previewUrl);
|
|
14737
15100
|
return {
|
|
14738
|
-
status:
|
|
14739
|
-
previewUrl
|
|
14740
|
-
deploymentUrl:
|
|
14741
|
-
summary:
|
|
15101
|
+
status: mapped,
|
|
15102
|
+
previewUrl,
|
|
15103
|
+
deploymentUrl: previewUrl ?? base.deploymentUrl,
|
|
15104
|
+
summary: evidenceSummary([
|
|
15105
|
+
`Vercel API ${target}=${lookedUp.readyState ?? "unknown"}`,
|
|
15106
|
+
mapped === "ready" ? "preview ready" : ""
|
|
15107
|
+
]),
|
|
14742
15108
|
observedAt: observed,
|
|
14743
15109
|
inspectSkipped: false,
|
|
14744
15110
|
inspectReason: null,
|
|
@@ -14750,6 +15116,7 @@ export {
|
|
|
14750
15116
|
CODEX_DEFAULT_MODEL,
|
|
14751
15117
|
DEFAULT_DISPATCH_LEASE_MS,
|
|
14752
15118
|
DEFAULT_HARNESS_VERIFY_COMMANDS,
|
|
15119
|
+
DEFAULT_HEAVY_VERIFICATION_MAX_CONCURRENT,
|
|
14753
15120
|
DEFAULT_MAX_ACTIONS_PER_SWEEP,
|
|
14754
15121
|
DEFAULT_NODE_MODULES_AGE_MS,
|
|
14755
15122
|
DEFAULT_RUN_DIRECTORIES_AGE_MS,
|
|
@@ -14778,6 +15145,7 @@ export {
|
|
|
14778
15145
|
assessAutoCompleteEligibility,
|
|
14779
15146
|
assessBuildAdmission,
|
|
14780
15147
|
assessExitedWorkerSalvage,
|
|
15148
|
+
assessHeavyVerificationGate,
|
|
14781
15149
|
assessOrphanWorktreeSafety,
|
|
14782
15150
|
assessPrHandoffRequirement,
|
|
14783
15151
|
assessWorkerLanding,
|
|
@@ -14811,6 +15179,7 @@ export {
|
|
|
14811
15179
|
completeWorker,
|
|
14812
15180
|
computeAttention,
|
|
14813
15181
|
computeWorkerStatus,
|
|
15182
|
+
countActiveHeavyVerificationSlots,
|
|
14814
15183
|
createRun,
|
|
14815
15184
|
defaultBoxId,
|
|
14816
15185
|
deriveRunStatus,
|
|
@@ -14864,6 +15233,7 @@ export {
|
|
|
14864
15233
|
isForbiddenWorkerEnvKey,
|
|
14865
15234
|
isGeneratedHarnessPath,
|
|
14866
15235
|
isHarnessRunMetadataPath,
|
|
15236
|
+
isHeavyVerificationGateSkipped,
|
|
14867
15237
|
isInspectableVercelTarget,
|
|
14868
15238
|
isKnownWorkerPersonaSlug,
|
|
14869
15239
|
isKynverMonorepoRoot,
|
|
@@ -14878,6 +15248,7 @@ export {
|
|
|
14878
15248
|
isWslHost,
|
|
14879
15249
|
joinHarnessNotice,
|
|
14880
15250
|
landingContractAttentionReason,
|
|
15251
|
+
listActiveHeavyVerificationSlots,
|
|
14881
15252
|
listForbiddenWorkerEnvKeys,
|
|
14882
15253
|
listMonitors,
|
|
14883
15254
|
listOrchestrationProviderCapabilities,
|
|
@@ -14917,12 +15288,14 @@ export {
|
|
|
14917
15288
|
providerCapableForRisk,
|
|
14918
15289
|
readMemAvailableBytes,
|
|
14919
15290
|
readProductionDbKeysFromEnvFile,
|
|
15291
|
+
reclaimStaleHeavyVerificationSlots,
|
|
14920
15292
|
reconcileRunsCli,
|
|
14921
15293
|
reconcileStaleWorkers,
|
|
14922
15294
|
reconcileWorkerMetadata,
|
|
14923
15295
|
reconcileWorkerMetadataCli,
|
|
14924
15296
|
redactHarness,
|
|
14925
15297
|
redactProviderErrorText,
|
|
15298
|
+
releaseHeavyVerificationSlot,
|
|
14926
15299
|
remediateDefaultRepo,
|
|
14927
15300
|
repairMissingRunMetadata,
|
|
14928
15301
|
repairNestedRunsPath,
|
|
@@ -14934,6 +15307,7 @@ export {
|
|
|
14934
15307
|
resolveConfiguredWorkerProvider,
|
|
14935
15308
|
resolveDefaultRepo,
|
|
14936
15309
|
resolveHarnessRoot,
|
|
15310
|
+
resolveHeavyVerificationMaxConcurrent,
|
|
14937
15311
|
resolveOpenAiCodexRetryBudget,
|
|
14938
15312
|
resolveOrchestrationPolicyMode,
|
|
14939
15313
|
resolveOrchestrationRouting,
|
|
@@ -14971,12 +15345,14 @@ export {
|
|
|
14971
15345
|
tailWorker,
|
|
14972
15346
|
taskAllowsClaudeWorker,
|
|
14973
15347
|
terminalFinalResultFromHeartbeat,
|
|
15348
|
+
tryAcquireHeavyVerificationSlot,
|
|
14974
15349
|
usage,
|
|
14975
15350
|
validateOwnedPaths,
|
|
14976
15351
|
validateRepo,
|
|
14977
15352
|
validateRunId,
|
|
14978
15353
|
validateTailLines,
|
|
14979
15354
|
validateWorkerName,
|
|
15355
|
+
waitForHeavyVerificationSlot,
|
|
14980
15356
|
workerDirHasActiveRetentionSignals,
|
|
14981
15357
|
workerPersonaLandingSlugs,
|
|
14982
15358
|
workerPersonaReviewSlugs,
|