@kynver-app/runtime 0.1.108 → 0.1.116
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/bootstrap.d.ts +1 -0
- package/dist/cleanup-git-rev-cache.d.ts +5 -0
- package/dist/cleanup-git-status-cache.d.ts +5 -0
- package/dist/cleanup-guards.d.ts +2 -0
- package/dist/cleanup-index-status.d.ts +8 -1
- package/dist/cleanup-run-liveness.d.ts +8 -1
- package/dist/cli.js +1929 -468
- package/dist/cli.js.map +4 -4
- package/dist/daemon-heartbeat.d.ts +20 -0
- package/dist/daemon-keeper.d.ts +21 -0
- package/dist/daemon-platform-guard.d.ts +2 -0
- package/dist/device-login.d.ts +8 -0
- package/dist/index.js +2636 -1151
- package/dist/index.js.map +4 -4
- package/dist/landing/cli-auth.d.ts +5 -1
- package/dist/landing/land-pr.d.ts +8 -0
- package/dist/provider-evidence/collect.d.ts +18 -0
- package/dist/provider-evidence/exec.d.ts +5 -0
- package/dist/provider-evidence/index.d.ts +7 -0
- package/dist/provider-evidence/recipes-github.d.ts +4 -0
- package/dist/provider-evidence/recipes-vercel.d.ts +2 -0
- package/dist/provider-evidence/registry.d.ts +6 -0
- package/dist/provider-evidence/types.d.ts +48 -0
- package/dist/provider-evidence/wanted-store.d.ts +5 -0
- package/dist/providers/codex.d.ts +7 -2
- package/dist/providers/hermes-codex.d.ts +5 -2
- package/dist/server/cleanup.js +560 -164
- package/dist/server/cleanup.js.map +4 -4
- package/dist/server/default-repo.js +298 -68
- package/dist/server/default-repo.js.map +4 -4
- package/dist/server/memory-cost-enforce.js +11 -1
- package/dist/server/memory-cost-enforce.js.map +3 -3
- package/dist/server/monitor.js +356 -128
- package/dist/server/monitor.js.map +4 -4
- package/dist/server/worker-policy.js +304 -49
- package/dist/server/worker-policy.js.map +4 -4
- package/dist/status.d.ts +18 -0
- package/dist/worker-ops.d.ts +4 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// src/default-repo-discovery.ts
|
|
13
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
14
|
-
import { homedir as homedir2 } from "node:os";
|
|
15
|
-
import path3 from "node:path";
|
|
16
|
-
import { fileURLToPath } from "node:url";
|
|
17
|
-
|
|
18
|
-
// src/git.ts
|
|
19
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
20
11
|
|
|
21
12
|
// src/util.ts
|
|
22
13
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -125,42 +116,13 @@ function latestIso(values) {
|
|
|
125
116
|
function secsAgo(ms) {
|
|
126
117
|
return Math.max(0, Math.round((Date.now() - ms) / 1e3));
|
|
127
118
|
}
|
|
119
|
+
var init_util = __esm({
|
|
120
|
+
"src/util.ts"() {
|
|
121
|
+
"use strict";
|
|
122
|
+
}
|
|
123
|
+
});
|
|
128
124
|
|
|
129
125
|
// src/worker-env.ts
|
|
130
|
-
var FORBIDDEN_WORKER_ENV_KEYS = [
|
|
131
|
-
"ANTHROPIC_API_KEY",
|
|
132
|
-
"ANALYST_API_KEY",
|
|
133
|
-
"RECRUITER_API_KEY",
|
|
134
|
-
"AUTH_SECRET",
|
|
135
|
-
"NEXTAUTH_SECRET",
|
|
136
|
-
"DATABASE_URL",
|
|
137
|
-
"PRODUCTION_DATABASE_URL",
|
|
138
|
-
"KYNVER_PRODUCTION_DATABASE_URL",
|
|
139
|
-
"REDIS_URL",
|
|
140
|
-
"GOOGLE_CLIENT_SECRET",
|
|
141
|
-
"GITHUB_CLIENT_SECRET",
|
|
142
|
-
"KYNVER_API_KEY",
|
|
143
|
-
"KYNVER_SERVICE_SECRET",
|
|
144
|
-
"KYNVER_RUNTIME_SECRET",
|
|
145
|
-
"KYNVER_CRON_SECRET",
|
|
146
|
-
"OPENCLAW_CRON_SECRET",
|
|
147
|
-
"QSTASH_TOKEN",
|
|
148
|
-
"QSTASH_CURRENT_SIGNING_KEY",
|
|
149
|
-
"QSTASH_NEXT_SIGNING_KEY",
|
|
150
|
-
"TOOL_SECRETS_KEK",
|
|
151
|
-
"TOOL_EXECUTOR_DISPATCH_SECRET",
|
|
152
|
-
"CLOUDFLARE_API_TOKEN",
|
|
153
|
-
"STRIPE_SECRET_KEY",
|
|
154
|
-
"STRIPE_WEBHOOK_SECRET",
|
|
155
|
-
"STRIPE_IDENTITY_WEBHOOK_SECRET",
|
|
156
|
-
"VOYAGE_API_KEY",
|
|
157
|
-
"PERPLEXITY_API_KEY",
|
|
158
|
-
"FRED_API_KEY",
|
|
159
|
-
"FMP_API_KEY",
|
|
160
|
-
"CURSOR_API_KEY"
|
|
161
|
-
];
|
|
162
|
-
var FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
|
|
163
|
-
var FORBIDDEN_SUFFIXES = ["_SECRET", "_API_KEY"];
|
|
164
126
|
function isForbiddenWorkerEnvKey(key) {
|
|
165
127
|
if (FORBIDDEN_KEY_SET.has(key)) return true;
|
|
166
128
|
return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));
|
|
@@ -172,10 +134,55 @@ function scrubWorkerEnv(env) {
|
|
|
172
134
|
}
|
|
173
135
|
return next;
|
|
174
136
|
}
|
|
137
|
+
var FORBIDDEN_WORKER_ENV_KEYS, FORBIDDEN_KEY_SET, FORBIDDEN_SUFFIXES;
|
|
138
|
+
var init_worker_env = __esm({
|
|
139
|
+
"src/worker-env.ts"() {
|
|
140
|
+
"use strict";
|
|
141
|
+
FORBIDDEN_WORKER_ENV_KEYS = [
|
|
142
|
+
"ANTHROPIC_API_KEY",
|
|
143
|
+
"ANALYST_API_KEY",
|
|
144
|
+
"RECRUITER_API_KEY",
|
|
145
|
+
"AUTH_SECRET",
|
|
146
|
+
"NEXTAUTH_SECRET",
|
|
147
|
+
"DATABASE_URL",
|
|
148
|
+
"PRODUCTION_DATABASE_URL",
|
|
149
|
+
"KYNVER_PRODUCTION_DATABASE_URL",
|
|
150
|
+
"REDIS_URL",
|
|
151
|
+
"GOOGLE_CLIENT_SECRET",
|
|
152
|
+
"GITHUB_CLIENT_SECRET",
|
|
153
|
+
"KYNVER_API_KEY",
|
|
154
|
+
"KYNVER_SERVICE_SECRET",
|
|
155
|
+
"KYNVER_RUNTIME_SECRET",
|
|
156
|
+
"KYNVER_CRON_SECRET",
|
|
157
|
+
"OPENCLAW_CRON_SECRET",
|
|
158
|
+
"QSTASH_TOKEN",
|
|
159
|
+
"QSTASH_CURRENT_SIGNING_KEY",
|
|
160
|
+
"QSTASH_NEXT_SIGNING_KEY",
|
|
161
|
+
"TOOL_SECRETS_KEK",
|
|
162
|
+
"TOOL_EXECUTOR_DISPATCH_SECRET",
|
|
163
|
+
"CLOUDFLARE_API_TOKEN",
|
|
164
|
+
"STRIPE_SECRET_KEY",
|
|
165
|
+
"STRIPE_WEBHOOK_SECRET",
|
|
166
|
+
"STRIPE_IDENTITY_WEBHOOK_SECRET",
|
|
167
|
+
"VOYAGE_API_KEY",
|
|
168
|
+
"PERPLEXITY_API_KEY",
|
|
169
|
+
"FRED_API_KEY",
|
|
170
|
+
"FMP_API_KEY",
|
|
171
|
+
"CURSOR_API_KEY"
|
|
172
|
+
];
|
|
173
|
+
FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
|
|
174
|
+
FORBIDDEN_SUFFIXES = ["_SECRET", "_API_KEY"];
|
|
175
|
+
}
|
|
176
|
+
});
|
|
175
177
|
|
|
176
178
|
// src/git.ts
|
|
179
|
+
import { spawnSync } from "node:child_process";
|
|
177
180
|
function git(cwd, args, options = {}) {
|
|
178
|
-
const res = spawnSync(
|
|
181
|
+
const res = spawnSync(
|
|
182
|
+
"git",
|
|
183
|
+
args,
|
|
184
|
+
hiddenSpawnOptions({ cwd, encoding: "utf8" })
|
|
185
|
+
);
|
|
179
186
|
if (res.status !== 0 && !options.allowFailure) {
|
|
180
187
|
const message = `git ${args.join(" ")} failed: ${res.stderr || res.stdout}`;
|
|
181
188
|
if (options.throwError) throw new Error(message);
|
|
@@ -191,7 +198,11 @@ function gitStatusShort(worktreePath) {
|
|
|
191
198
|
}
|
|
192
199
|
function gitCapture(cwd, args) {
|
|
193
200
|
try {
|
|
194
|
-
const res = spawnSync(
|
|
201
|
+
const res = spawnSync(
|
|
202
|
+
"git",
|
|
203
|
+
args,
|
|
204
|
+
hiddenSpawnOptions({ cwd, encoding: "utf8" })
|
|
205
|
+
);
|
|
195
206
|
return {
|
|
196
207
|
status: res.status,
|
|
197
208
|
stdout: res.stdout || "",
|
|
@@ -289,6 +300,13 @@ function unknownAncestry(base, error, head = null) {
|
|
|
289
300
|
error
|
|
290
301
|
};
|
|
291
302
|
}
|
|
303
|
+
var init_git = __esm({
|
|
304
|
+
"src/git.ts"() {
|
|
305
|
+
"use strict";
|
|
306
|
+
init_util();
|
|
307
|
+
init_worker_env();
|
|
308
|
+
}
|
|
309
|
+
});
|
|
292
310
|
|
|
293
311
|
// src/path-values.ts
|
|
294
312
|
import { homedir } from "node:os";
|
|
@@ -318,15 +336,17 @@ function redactHomePath(value) {
|
|
|
318
336
|
function displayUserPath(value) {
|
|
319
337
|
return redactHomePath(value);
|
|
320
338
|
}
|
|
339
|
+
var init_path_values = __esm({
|
|
340
|
+
"src/path-values.ts"() {
|
|
341
|
+
"use strict";
|
|
342
|
+
}
|
|
343
|
+
});
|
|
321
344
|
|
|
322
345
|
// src/default-repo-discovery.ts
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
"code/Kynver",
|
|
328
|
-
"projects/Kynver"
|
|
329
|
-
];
|
|
346
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
347
|
+
import { homedir as homedir2 } from "node:os";
|
|
348
|
+
import path3 from "node:path";
|
|
349
|
+
import { fileURLToPath } from "node:url";
|
|
330
350
|
function readPackageName(repoRoot) {
|
|
331
351
|
const pkgPath = path3.join(repoRoot, "package.json");
|
|
332
352
|
if (!existsSync2(pkgPath)) return null;
|
|
@@ -391,6 +411,21 @@ function discoverDefaultRepoCandidates(opts) {
|
|
|
391
411
|
function discoverDefaultRepo(opts) {
|
|
392
412
|
return discoverDefaultRepoCandidates(opts)[0] ?? null;
|
|
393
413
|
}
|
|
414
|
+
var WELL_KNOWN_REPO_DIRS;
|
|
415
|
+
var init_default_repo_discovery = __esm({
|
|
416
|
+
"src/default-repo-discovery.ts"() {
|
|
417
|
+
"use strict";
|
|
418
|
+
init_git();
|
|
419
|
+
init_path_values();
|
|
420
|
+
WELL_KNOWN_REPO_DIRS = [
|
|
421
|
+
"Kynver",
|
|
422
|
+
"repos/Kynver",
|
|
423
|
+
"repos/kynver-source-main",
|
|
424
|
+
"code/Kynver",
|
|
425
|
+
"projects/Kynver"
|
|
426
|
+
];
|
|
427
|
+
}
|
|
428
|
+
});
|
|
394
429
|
|
|
395
430
|
// src/box-identity.ts
|
|
396
431
|
function normalizeWorkerPoolBoxKind(raw) {
|
|
@@ -440,9 +475,11 @@ function resolveBoxIdentity(env = process.env, config = {}) {
|
|
|
440
475
|
function resolveBoxKindFromConfig(config = {}, env = process.env) {
|
|
441
476
|
return resolveBoxIdentity(env, config).boxKind;
|
|
442
477
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
478
|
+
var init_box_identity = __esm({
|
|
479
|
+
"src/box-identity.ts"() {
|
|
480
|
+
"use strict";
|
|
481
|
+
}
|
|
482
|
+
});
|
|
446
483
|
|
|
447
484
|
// src/bounded-build/meminfo.ts
|
|
448
485
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
@@ -463,18 +500,14 @@ function readMemAvailableBytes(meminfoText) {
|
|
|
463
500
|
}
|
|
464
501
|
return os.freemem();
|
|
465
502
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
import { statfsSync as statfsSync2 } from "node:fs";
|
|
503
|
+
var init_meminfo = __esm({
|
|
504
|
+
"src/bounded-build/meminfo.ts"() {
|
|
505
|
+
"use strict";
|
|
506
|
+
}
|
|
507
|
+
});
|
|
472
508
|
|
|
473
509
|
// src/wsl-host.ts
|
|
474
510
|
import { existsSync as existsSync3, readFileSync as readFileSync4, statfsSync } from "node:fs";
|
|
475
|
-
var DEFAULT_WSL_HOST_WARN_FREE_BYTES = 25 * 1024 * 1024 * 1024;
|
|
476
|
-
var DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES = 12 * 1024 * 1024 * 1024;
|
|
477
|
-
var DEFAULT_WSL_HOST_MOUNT = "/mnt/c";
|
|
478
511
|
function isWslHost() {
|
|
479
512
|
if (process.platform !== "linux") return false;
|
|
480
513
|
for (const probe of ["/proc/sys/kernel/osrelease", "/proc/version"]) {
|
|
@@ -490,23 +523,23 @@ function isWslHost() {
|
|
|
490
523
|
function observeWslHostDisk(options = {}) {
|
|
491
524
|
const wsl = options.forceWsl === void 0 ? isWslHost() : options.forceWsl;
|
|
492
525
|
if (!wsl) return null;
|
|
493
|
-
const
|
|
526
|
+
const path73 = options.wslHostMount?.trim() || process.env.KYNVER_WSL_HOST_MOUNT?.trim() || DEFAULT_WSL_HOST_MOUNT;
|
|
494
527
|
const warnBelowBytes = options.wslHostFreeWarnBytes ?? DEFAULT_WSL_HOST_WARN_FREE_BYTES;
|
|
495
528
|
const criticalBelowBytes = options.wslHostFreeCriticalBytes ?? DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
|
|
496
529
|
const statfs = options.statfs ?? statfsSync;
|
|
497
530
|
let stats;
|
|
498
531
|
try {
|
|
499
|
-
stats = statfs(
|
|
532
|
+
stats = statfs(path73);
|
|
500
533
|
} catch (error) {
|
|
501
534
|
return {
|
|
502
535
|
ok: false,
|
|
503
|
-
path:
|
|
536
|
+
path: path73,
|
|
504
537
|
freeBytes: 0,
|
|
505
538
|
totalBytes: 0,
|
|
506
539
|
usedPercent: 100,
|
|
507
540
|
warnBelowBytes,
|
|
508
541
|
criticalBelowBytes,
|
|
509
|
-
reason: `Windows host disk probe failed at ${
|
|
542
|
+
reason: `Windows host disk probe failed at ${path73}: ${error.message}`,
|
|
510
543
|
probeError: error.message
|
|
511
544
|
};
|
|
512
545
|
}
|
|
@@ -520,11 +553,11 @@ function observeWslHostDisk(options = {}) {
|
|
|
520
553
|
let reason = null;
|
|
521
554
|
if (!ok) {
|
|
522
555
|
const tag = criticalFree ? "critical" : "warning";
|
|
523
|
-
reason = `Windows host disk ${
|
|
556
|
+
reason = `Windows host disk ${path73} at ${tag}: ${freeGiB} GiB free (<${(criticalFree ? criticalBelowBytes : warnBelowBytes) / 1024 / 1024 / 1024} GiB); WSL VHDX cannot grow safely. ${summarizeWslRecoverySteps()}`;
|
|
524
557
|
}
|
|
525
558
|
return {
|
|
526
559
|
ok,
|
|
527
|
-
path:
|
|
560
|
+
path: path73,
|
|
528
561
|
freeBytes,
|
|
529
562
|
totalBytes,
|
|
530
563
|
usedPercent,
|
|
@@ -537,19 +570,25 @@ function observeWslHostDisk(options = {}) {
|
|
|
537
570
|
function summarizeWslRecoverySteps() {
|
|
538
571
|
return "Recovery: 1) free Windows C: (empty Recycle Bin / Storage Sense / clear %TEMP%); 2) shut down WSL (`wsl --shutdown`) then compact the VHDX (`Optimize-VHD` or `diskpart compact vdisk`); 3) clear local node_modules / .next / harness worktrees before restarting workers. Full runbook: docs/runbooks/wsl-disk-pressure.md.";
|
|
539
572
|
}
|
|
573
|
+
var DEFAULT_WSL_HOST_WARN_FREE_BYTES, DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES, DEFAULT_WSL_HOST_MOUNT;
|
|
574
|
+
var init_wsl_host = __esm({
|
|
575
|
+
"src/wsl-host.ts"() {
|
|
576
|
+
"use strict";
|
|
577
|
+
DEFAULT_WSL_HOST_WARN_FREE_BYTES = 25 * 1024 * 1024 * 1024;
|
|
578
|
+
DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES = 12 * 1024 * 1024 * 1024;
|
|
579
|
+
DEFAULT_WSL_HOST_MOUNT = "/mnt/c";
|
|
580
|
+
}
|
|
581
|
+
});
|
|
540
582
|
|
|
541
583
|
// src/disk-gate.ts
|
|
542
|
-
|
|
543
|
-
var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
544
|
-
var DEFAULT_MAX_USED_PERCENT = 80;
|
|
545
|
-
var DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
584
|
+
import { statfsSync as statfsSync2 } from "node:fs";
|
|
546
585
|
function observeRunnerDiskGate(input = {}) {
|
|
547
|
-
const
|
|
586
|
+
const path73 = input.diskPath?.trim() || "/";
|
|
548
587
|
const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
|
|
549
588
|
const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
|
|
550
589
|
const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
|
|
551
590
|
const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
|
|
552
|
-
const stats = statfsSync2(
|
|
591
|
+
const stats = statfsSync2(path73);
|
|
553
592
|
const freeBytes = Number(stats.bavail) * Number(stats.bsize);
|
|
554
593
|
const totalBytes = Number(stats.blocks) * Number(stats.bsize);
|
|
555
594
|
const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
|
|
@@ -572,7 +611,7 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
572
611
|
}
|
|
573
612
|
return {
|
|
574
613
|
ok,
|
|
575
|
-
path:
|
|
614
|
+
path: path73,
|
|
576
615
|
freeBytes,
|
|
577
616
|
totalBytes,
|
|
578
617
|
usedPercent,
|
|
@@ -584,17 +623,22 @@ function observeRunnerDiskGate(input = {}) {
|
|
|
584
623
|
wslHost
|
|
585
624
|
};
|
|
586
625
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
626
|
+
var DEFAULT_WARN_FREE_BYTES, DEFAULT_CRITICAL_FREE_BYTES, DEFAULT_MAX_USED_PERCENT, DEFAULT_HARD_MAX_USED_PERCENT;
|
|
627
|
+
var init_disk_gate = __esm({
|
|
628
|
+
"src/disk-gate.ts"() {
|
|
629
|
+
"use strict";
|
|
630
|
+
init_wsl_host();
|
|
631
|
+
DEFAULT_WARN_FREE_BYTES = 30 * 1024 * 1024 * 1024;
|
|
632
|
+
DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
|
|
633
|
+
DEFAULT_MAX_USED_PERCENT = 80;
|
|
634
|
+
DEFAULT_HARD_MAX_USED_PERCENT = 90;
|
|
635
|
+
}
|
|
636
|
+
});
|
|
591
637
|
|
|
592
638
|
// src/paths.ts
|
|
593
639
|
import { existsSync as existsSync4 } from "node:fs";
|
|
594
640
|
import { homedir as homedir3 } from "node:os";
|
|
595
641
|
import path4 from "node:path";
|
|
596
|
-
var LEGACY_ROOT = path4.join(homedir3(), ".openclaw", "harness");
|
|
597
|
-
var HARNESS_LAYOUT_DIR_NAMES = /* @__PURE__ */ new Set(["runs", "worktrees"]);
|
|
598
642
|
function normalizeHarnessRoot(root) {
|
|
599
643
|
let resolved = path4.resolve(resolveUserPath(root.trim()));
|
|
600
644
|
while (HARNESS_LAYOUT_DIR_NAMES.has(path4.basename(resolved))) {
|
|
@@ -629,8 +673,21 @@ function getHarnessPaths() {
|
|
|
629
673
|
function runDir(runsDir, id) {
|
|
630
674
|
return path4.join(runsDir, safeSlug(id));
|
|
631
675
|
}
|
|
676
|
+
var LEGACY_ROOT, HARNESS_LAYOUT_DIR_NAMES;
|
|
677
|
+
var init_paths = __esm({
|
|
678
|
+
"src/paths.ts"() {
|
|
679
|
+
"use strict";
|
|
680
|
+
init_config();
|
|
681
|
+
init_path_values();
|
|
682
|
+
init_util();
|
|
683
|
+
LEGACY_ROOT = path4.join(homedir3(), ".openclaw", "harness");
|
|
684
|
+
HARNESS_LAYOUT_DIR_NAMES = /* @__PURE__ */ new Set(["runs", "worktrees"]);
|
|
685
|
+
}
|
|
686
|
+
});
|
|
632
687
|
|
|
633
688
|
// src/run-store.ts
|
|
689
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
|
|
690
|
+
import path5 from "node:path";
|
|
634
691
|
function getPaths() {
|
|
635
692
|
return getHarnessPaths();
|
|
636
693
|
}
|
|
@@ -688,6 +745,13 @@ function runDirectory(id) {
|
|
|
688
745
|
function runDirectoryAt(harnessRoot, id) {
|
|
689
746
|
return runDir(harnessRunsDir(harnessRoot), safeSlug(id));
|
|
690
747
|
}
|
|
748
|
+
var init_run_store = __esm({
|
|
749
|
+
"src/run-store.ts"() {
|
|
750
|
+
"use strict";
|
|
751
|
+
init_paths();
|
|
752
|
+
init_util();
|
|
753
|
+
}
|
|
754
|
+
});
|
|
691
755
|
|
|
692
756
|
// src/run-worker-index.ts
|
|
693
757
|
import { existsSync as existsSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
@@ -705,12 +769,13 @@ function listRunWorkerNames(run) {
|
|
|
705
769
|
}
|
|
706
770
|
return [...names];
|
|
707
771
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
772
|
+
var init_run_worker_index = __esm({
|
|
773
|
+
"src/run-worker-index.ts"() {
|
|
774
|
+
"use strict";
|
|
775
|
+
init_run_store();
|
|
776
|
+
init_util();
|
|
777
|
+
}
|
|
778
|
+
});
|
|
714
779
|
|
|
715
780
|
// src/heartbeat-final-result.ts
|
|
716
781
|
function tryParseJsonObject(text) {
|
|
@@ -761,9 +826,14 @@ function terminalFinalResultFromHeartbeatRow(row) {
|
|
|
761
826
|
if (embedded) return embedded;
|
|
762
827
|
return summary;
|
|
763
828
|
}
|
|
829
|
+
var init_heartbeat_final_result = __esm({
|
|
830
|
+
"src/heartbeat-final-result.ts"() {
|
|
831
|
+
"use strict";
|
|
832
|
+
}
|
|
833
|
+
});
|
|
764
834
|
|
|
765
835
|
// src/heartbeat.ts
|
|
766
|
-
|
|
836
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
767
837
|
function isTerminalHeartbeatPhase(phase) {
|
|
768
838
|
return phase === "complete";
|
|
769
839
|
}
|
|
@@ -826,29 +896,17 @@ function parseHeartbeat(file) {
|
|
|
826
896
|
}
|
|
827
897
|
return result;
|
|
828
898
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
899
|
+
var HEARTBEAT_FUTURE_SKEW_MS;
|
|
900
|
+
var init_heartbeat = __esm({
|
|
901
|
+
"src/heartbeat.ts"() {
|
|
902
|
+
"use strict";
|
|
903
|
+
init_heartbeat_final_result();
|
|
904
|
+
init_util();
|
|
905
|
+
HEARTBEAT_FUTURE_SKEW_MS = 6e4;
|
|
906
|
+
}
|
|
907
|
+
});
|
|
832
908
|
|
|
833
909
|
// src/repo-search.ts
|
|
834
|
-
var RG_BINARIES = /* @__PURE__ */ new Set(["rg", "ripgrep", "grep"]);
|
|
835
|
-
var RG_OPTS_WITH_VALUE = /* @__PURE__ */ new Set([
|
|
836
|
-
"-e",
|
|
837
|
-
"--regexp",
|
|
838
|
-
"-f",
|
|
839
|
-
"--file",
|
|
840
|
-
"-m",
|
|
841
|
-
"--max-count",
|
|
842
|
-
"-A",
|
|
843
|
-
"--after-context",
|
|
844
|
-
"-B",
|
|
845
|
-
"--before-context",
|
|
846
|
-
"-C",
|
|
847
|
-
"--context",
|
|
848
|
-
"-g",
|
|
849
|
-
"--glob",
|
|
850
|
-
"--iglob"
|
|
851
|
-
]);
|
|
852
910
|
function binaryName(token) {
|
|
853
911
|
if (!token) return null;
|
|
854
912
|
const base = token.split("/").pop() ?? token;
|
|
@@ -1047,11 +1105,32 @@ function diagnoseRepoSearchFailure(input) {
|
|
|
1047
1105
|
}
|
|
1048
1106
|
return null;
|
|
1049
1107
|
}
|
|
1108
|
+
var RG_BINARIES, RG_OPTS_WITH_VALUE;
|
|
1109
|
+
var init_repo_search = __esm({
|
|
1110
|
+
"src/repo-search.ts"() {
|
|
1111
|
+
"use strict";
|
|
1112
|
+
RG_BINARIES = /* @__PURE__ */ new Set(["rg", "ripgrep", "grep"]);
|
|
1113
|
+
RG_OPTS_WITH_VALUE = /* @__PURE__ */ new Set([
|
|
1114
|
+
"-e",
|
|
1115
|
+
"--regexp",
|
|
1116
|
+
"-f",
|
|
1117
|
+
"--file",
|
|
1118
|
+
"-m",
|
|
1119
|
+
"--max-count",
|
|
1120
|
+
"-A",
|
|
1121
|
+
"--after-context",
|
|
1122
|
+
"-B",
|
|
1123
|
+
"--before-context",
|
|
1124
|
+
"-C",
|
|
1125
|
+
"--context",
|
|
1126
|
+
"-g",
|
|
1127
|
+
"--glob",
|
|
1128
|
+
"--iglob"
|
|
1129
|
+
]);
|
|
1130
|
+
}
|
|
1131
|
+
});
|
|
1050
1132
|
|
|
1051
1133
|
// src/shell-command-outcome.ts
|
|
1052
|
-
var NPM_AUDIT_RE = /\bnpm\s+audit\b/i;
|
|
1053
|
-
var RG_CMD_RE = /\b(rg|ripgrep)\b/i;
|
|
1054
|
-
var RG_REAL_ERROR_RE = /\b(error|invalid|unknown|panic|not found)\b/i;
|
|
1055
1134
|
function tidy(text, max = 200) {
|
|
1056
1135
|
const one = text.replace(/\s+/g, " ").trim();
|
|
1057
1136
|
return one.length > max ? `${one.slice(0, max - 1)}\u2026` : one;
|
|
@@ -1255,8 +1334,19 @@ function classifyShellCommandOutcome(input) {
|
|
|
1255
1334
|
summary: `command failed (exit ${input.exitCode}): ${tail}`
|
|
1256
1335
|
};
|
|
1257
1336
|
}
|
|
1337
|
+
var NPM_AUDIT_RE, RG_CMD_RE, RG_REAL_ERROR_RE;
|
|
1338
|
+
var init_shell_command_outcome = __esm({
|
|
1339
|
+
"src/shell-command-outcome.ts"() {
|
|
1340
|
+
"use strict";
|
|
1341
|
+
init_repo_search();
|
|
1342
|
+
NPM_AUDIT_RE = /\bnpm\s+audit\b/i;
|
|
1343
|
+
RG_CMD_RE = /\b(rg|ripgrep)\b/i;
|
|
1344
|
+
RG_REAL_ERROR_RE = /\b(error|invalid|unknown|panic|not found)\b/i;
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1258
1347
|
|
|
1259
1348
|
// src/stream.ts
|
|
1349
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
|
|
1260
1350
|
function eventTimestampIso(event) {
|
|
1261
1351
|
const tsMs = event.timestamp_ms;
|
|
1262
1352
|
return event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : void 0);
|
|
@@ -1422,38 +1512,15 @@ function summarizeEvent(event) {
|
|
|
1422
1512
|
}
|
|
1423
1513
|
return void 0;
|
|
1424
1514
|
}
|
|
1515
|
+
var init_stream = __esm({
|
|
1516
|
+
"src/stream.ts"() {
|
|
1517
|
+
"use strict";
|
|
1518
|
+
init_shell_command_outcome();
|
|
1519
|
+
init_util();
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1425
1522
|
|
|
1426
1523
|
// src/exit-classify.ts
|
|
1427
|
-
var FAILURE_PATTERNS = [
|
|
1428
|
-
{
|
|
1429
|
-
test: /\b(?:invalid|unknown|unsupported|unrecognized)\b[^.\n]*\bmodel\b/i,
|
|
1430
|
-
label: "provider rejected the requested model"
|
|
1431
|
-
},
|
|
1432
|
-
{
|
|
1433
|
-
test: /\bmodel\b[^.\n]*\b(?:not\s+(?:found|supported|available|recognized|valid)|is\s+not\s+valid|does\s+not\s+exist)/i,
|
|
1434
|
-
label: "provider rejected the requested model"
|
|
1435
|
-
},
|
|
1436
|
-
{
|
|
1437
|
-
test: /\b(?:did you mean|available models|choose (?:a|one of)|supported models)\b/i,
|
|
1438
|
-
label: "provider rejected the requested model"
|
|
1439
|
-
},
|
|
1440
|
-
{
|
|
1441
|
-
test: /model preflight failed/i,
|
|
1442
|
-
label: "model/provider preflight failed"
|
|
1443
|
-
},
|
|
1444
|
-
{
|
|
1445
|
-
test: /\b(?:command not found|ENOENT|is the .*CLI on PATH|executable not found|no such file or directory)\b/i,
|
|
1446
|
-
label: "provider CLI is missing or not on PATH"
|
|
1447
|
-
},
|
|
1448
|
-
{
|
|
1449
|
-
test: /\bfailed to spawn\b/i,
|
|
1450
|
-
label: "provider failed to spawn the worker process"
|
|
1451
|
-
},
|
|
1452
|
-
{
|
|
1453
|
-
test: /\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\b/i,
|
|
1454
|
-
label: "provider authentication failed"
|
|
1455
|
-
}
|
|
1456
|
-
];
|
|
1457
1524
|
function tidy2(errorText, max = 240) {
|
|
1458
1525
|
const oneLine2 = errorText.replace(/\s+/g, " ").trim();
|
|
1459
1526
|
return oneLine2.length > max ? `${oneLine2.slice(0, max - 1)}\u2026` : oneLine2;
|
|
@@ -1468,6 +1535,42 @@ function classifyExitFailure(errorText) {
|
|
|
1468
1535
|
}
|
|
1469
1536
|
return null;
|
|
1470
1537
|
}
|
|
1538
|
+
var FAILURE_PATTERNS;
|
|
1539
|
+
var init_exit_classify = __esm({
|
|
1540
|
+
"src/exit-classify.ts"() {
|
|
1541
|
+
"use strict";
|
|
1542
|
+
FAILURE_PATTERNS = [
|
|
1543
|
+
{
|
|
1544
|
+
test: /\b(?:invalid|unknown|unsupported|unrecognized)\b[^.\n]*\bmodel\b/i,
|
|
1545
|
+
label: "provider rejected the requested model"
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
test: /\bmodel\b[^.\n]*\b(?:not\s+(?:found|supported|available|recognized|valid)|is\s+not\s+valid|does\s+not\s+exist)/i,
|
|
1549
|
+
label: "provider rejected the requested model"
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
test: /\b(?:did you mean|available models|choose (?:a|one of)|supported models)\b/i,
|
|
1553
|
+
label: "provider rejected the requested model"
|
|
1554
|
+
},
|
|
1555
|
+
{
|
|
1556
|
+
test: /model preflight failed/i,
|
|
1557
|
+
label: "model/provider preflight failed"
|
|
1558
|
+
},
|
|
1559
|
+
{
|
|
1560
|
+
test: /\b(?:command not found|ENOENT|is the .*CLI on PATH|executable not found|no such file or directory)\b/i,
|
|
1561
|
+
label: "provider CLI is missing or not on PATH"
|
|
1562
|
+
},
|
|
1563
|
+
{
|
|
1564
|
+
test: /\bfailed to spawn\b/i,
|
|
1565
|
+
label: "provider failed to spawn the worker process"
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
test: /\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\b/i,
|
|
1569
|
+
label: "provider authentication failed"
|
|
1570
|
+
}
|
|
1571
|
+
];
|
|
1572
|
+
}
|
|
1573
|
+
});
|
|
1471
1574
|
|
|
1472
1575
|
// src/exited-salvage.ts
|
|
1473
1576
|
function trimOrNull(value) {
|
|
@@ -1526,6 +1629,11 @@ function assessExitedWorkerSalvage(input) {
|
|
|
1526
1629
|
attentionReason: buildAttentionReason(kind, uncommittedCount, headCommit)
|
|
1527
1630
|
};
|
|
1528
1631
|
}
|
|
1632
|
+
var init_exited_salvage = __esm({
|
|
1633
|
+
"src/exited-salvage.ts"() {
|
|
1634
|
+
"use strict";
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1529
1637
|
|
|
1530
1638
|
// src/landing-gate.ts
|
|
1531
1639
|
function trimOrNull2(value) {
|
|
@@ -1571,6 +1679,11 @@ function landingAttentionReason(verdict) {
|
|
|
1571
1679
|
if (!verdict.blocked) return void 0;
|
|
1572
1680
|
return verdict.detail ?? verdict.reason ?? "dirty_worktree_no_pr";
|
|
1573
1681
|
}
|
|
1682
|
+
var init_landing_gate = __esm({
|
|
1683
|
+
"src/landing-gate.ts"() {
|
|
1684
|
+
"use strict";
|
|
1685
|
+
}
|
|
1686
|
+
});
|
|
1574
1687
|
|
|
1575
1688
|
// src/worker-final-result-embed.ts
|
|
1576
1689
|
function tryParseJsonObject2(text) {
|
|
@@ -1620,6 +1733,11 @@ function extractEmbeddedWorkerFinalResultRecord(value) {
|
|
|
1620
1733
|
}
|
|
1621
1734
|
return best;
|
|
1622
1735
|
}
|
|
1736
|
+
var init_worker_final_result_embed = __esm({
|
|
1737
|
+
"src/worker-final-result-embed.ts"() {
|
|
1738
|
+
"use strict";
|
|
1739
|
+
}
|
|
1740
|
+
});
|
|
1623
1741
|
|
|
1624
1742
|
// src/landing-contract-gate.ts
|
|
1625
1743
|
function trimOrNull3(value) {
|
|
@@ -1779,10 +1897,14 @@ function landingContractAttentionReason(verdict) {
|
|
|
1779
1897
|
if (!verdict.blocked) return void 0;
|
|
1780
1898
|
return verdict.detail ?? verdict.reason;
|
|
1781
1899
|
}
|
|
1900
|
+
var init_landing_contract_gate = __esm({
|
|
1901
|
+
"src/landing-contract-gate.ts"() {
|
|
1902
|
+
"use strict";
|
|
1903
|
+
init_worker_final_result_embed();
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1782
1906
|
|
|
1783
1907
|
// src/status.ts
|
|
1784
|
-
var NO_START_MS = 18e4;
|
|
1785
|
-
var STALE_MS = 6e5;
|
|
1786
1908
|
function computeAttention(input) {
|
|
1787
1909
|
const now = Date.now();
|
|
1788
1910
|
if (input.completionBlocker && !isSkippedTerminalCompletionBlocker(input.completionBlocker)) {
|
|
@@ -1974,7 +2096,15 @@ function computeWorkerStatus(worker, options = {}) {
|
|
|
1974
2096
|
changedFiles,
|
|
1975
2097
|
gitAncestry,
|
|
1976
2098
|
instructionPolicyFingerprint: worker.instructionPolicyFingerprint ?? null,
|
|
1977
|
-
instructionPolicyEvidence: worker.instructionPolicyEvidence ?? null
|
|
2099
|
+
instructionPolicyEvidence: worker.instructionPolicyEvidence ?? null,
|
|
2100
|
+
model: worker.model ?? worker.orchestrationAudit?.model ?? null,
|
|
2101
|
+
provider: worker.orchestrationAudit?.provider ?? null,
|
|
2102
|
+
boxKind: worker.boxKind ?? null,
|
|
2103
|
+
boxId: worker.boxId ?? null,
|
|
2104
|
+
runtimeId: worker.runtimeId ?? null,
|
|
2105
|
+
personaSlug: worker.personaSlug ?? null,
|
|
2106
|
+
dispatched: worker.dispatched ?? null,
|
|
2107
|
+
localOnly: worker.localOnly ?? null
|
|
1978
2108
|
};
|
|
1979
2109
|
}
|
|
1980
2110
|
function isFinishedWorkerStatus(status) {
|
|
@@ -1996,8 +2126,26 @@ function deriveRunStatus(fallback, workers) {
|
|
|
1996
2126
|
if (workers.some((w) => w.status === "running")) return "running";
|
|
1997
2127
|
return fallback;
|
|
1998
2128
|
}
|
|
2129
|
+
var NO_START_MS, STALE_MS;
|
|
2130
|
+
var init_status = __esm({
|
|
2131
|
+
"src/status.ts"() {
|
|
2132
|
+
"use strict";
|
|
2133
|
+
init_heartbeat();
|
|
2134
|
+
init_stream();
|
|
2135
|
+
init_exit_classify();
|
|
2136
|
+
init_exited_salvage();
|
|
2137
|
+
init_git();
|
|
2138
|
+
init_landing_gate();
|
|
2139
|
+
init_landing_contract_gate();
|
|
2140
|
+
init_worker_final_result_embed();
|
|
2141
|
+
init_util();
|
|
2142
|
+
NO_START_MS = 18e4;
|
|
2143
|
+
STALE_MS = 6e5;
|
|
2144
|
+
}
|
|
2145
|
+
});
|
|
1999
2146
|
|
|
2000
2147
|
// src/harness-worker-active.ts
|
|
2148
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
2001
2149
|
function pidCommandLine(pid) {
|
|
2002
2150
|
if (!pid || process.platform !== "linux") return null;
|
|
2003
2151
|
try {
|
|
@@ -2023,12 +2171,16 @@ function isActiveHarnessWorker(worker) {
|
|
|
2023
2171
|
if (status.alive && !workerProcessMatchesRecord(worker)) return false;
|
|
2024
2172
|
return status.alive && !status.finalResult && status.attention.state !== "done";
|
|
2025
2173
|
}
|
|
2174
|
+
var init_harness_worker_active = __esm({
|
|
2175
|
+
"src/harness-worker-active.ts"() {
|
|
2176
|
+
"use strict";
|
|
2177
|
+
init_status();
|
|
2178
|
+
}
|
|
2179
|
+
});
|
|
2026
2180
|
|
|
2027
2181
|
// src/resource-gate.ts
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
var DEFAULT_MEM_UTILIZATION = 0.85;
|
|
2031
|
-
var AUTO_MAX_WORKERS_CEILING = 64;
|
|
2182
|
+
import os2 from "node:os";
|
|
2183
|
+
import path7 from "node:path";
|
|
2032
2184
|
function positiveInt(value, fallback) {
|
|
2033
2185
|
const n = Number(value);
|
|
2034
2186
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
@@ -2134,6 +2286,25 @@ function observeRunnerResourceGate(input) {
|
|
|
2134
2286
|
...diskGate ? { diskGate } : {}
|
|
2135
2287
|
};
|
|
2136
2288
|
}
|
|
2289
|
+
var DEFAULT_PER_WORKER_MEM_BYTES, DEFAULT_MEM_RESERVE_BYTES, DEFAULT_MEM_UTILIZATION, AUTO_MAX_WORKERS_CEILING;
|
|
2290
|
+
var init_resource_gate = __esm({
|
|
2291
|
+
"src/resource-gate.ts"() {
|
|
2292
|
+
"use strict";
|
|
2293
|
+
init_meminfo();
|
|
2294
|
+
init_config();
|
|
2295
|
+
init_box_identity();
|
|
2296
|
+
init_worker_cap_source();
|
|
2297
|
+
init_disk_gate();
|
|
2298
|
+
init_run_store();
|
|
2299
|
+
init_run_worker_index();
|
|
2300
|
+
init_harness_worker_active();
|
|
2301
|
+
init_util();
|
|
2302
|
+
DEFAULT_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;
|
|
2303
|
+
DEFAULT_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;
|
|
2304
|
+
DEFAULT_MEM_UTILIZATION = 0.85;
|
|
2305
|
+
AUTO_MAX_WORKERS_CEILING = 64;
|
|
2306
|
+
}
|
|
2307
|
+
});
|
|
2137
2308
|
|
|
2138
2309
|
// src/worker-cap-source.ts
|
|
2139
2310
|
function positiveInt2(value, fallback) {
|
|
@@ -2205,12 +2376,113 @@ function recommendSetupWorkerCap(input = {}) {
|
|
|
2205
2376
|
diskFreeBytes: input.diskFreeBytes ?? null
|
|
2206
2377
|
};
|
|
2207
2378
|
}
|
|
2379
|
+
var init_worker_cap_source = __esm({
|
|
2380
|
+
"src/worker-cap-source.ts"() {
|
|
2381
|
+
"use strict";
|
|
2382
|
+
init_resource_gate();
|
|
2383
|
+
}
|
|
2384
|
+
});
|
|
2208
2385
|
|
|
2209
|
-
// src/
|
|
2386
|
+
// src/device-login.ts
|
|
2387
|
+
var device_login_exports = {};
|
|
2388
|
+
__export(device_login_exports, {
|
|
2389
|
+
runDeviceLogin: () => runDeviceLogin
|
|
2390
|
+
});
|
|
2210
2391
|
import os3 from "node:os";
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2392
|
+
function resolveDeviceBaseUrl(args) {
|
|
2393
|
+
const raw = (typeof args.apiBaseUrl === "string" ? args.apiBaseUrl : void 0) || (typeof args.baseUrl === "string" ? args.baseUrl : void 0) || process.env.KYNVER_API_URL || loadUserConfig().apiBaseUrl;
|
|
2394
|
+
return raw ? trimTrailingSlash(String(raw)) : void 0;
|
|
2395
|
+
}
|
|
2396
|
+
async function sleep(ms) {
|
|
2397
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
2398
|
+
}
|
|
2399
|
+
async function runDeviceLogin(args) {
|
|
2400
|
+
const base = resolveDeviceBaseUrl(args);
|
|
2401
|
+
if (!base) {
|
|
2402
|
+
console.error(
|
|
2403
|
+
"kynver login (device flow) requires a Kynver URL \u2014 pass --api-base-url https://your-kynver-site, set KYNVER_API_URL, or run `kynver setup` first."
|
|
2404
|
+
);
|
|
2405
|
+
return { ok: false };
|
|
2406
|
+
}
|
|
2407
|
+
const clientName = `${os3.hostname()} (${os3.platform()})`;
|
|
2408
|
+
let start;
|
|
2409
|
+
try {
|
|
2410
|
+
const res = await fetch(`${base}/api/auth/device/code`, {
|
|
2411
|
+
method: "POST",
|
|
2412
|
+
headers: { "Content-Type": "application/json" },
|
|
2413
|
+
body: JSON.stringify({ clientName })
|
|
2414
|
+
});
|
|
2415
|
+
if (!res.ok) {
|
|
2416
|
+
console.error(`Could not start device authorization (${res.status}).`);
|
|
2417
|
+
return { ok: false };
|
|
2418
|
+
}
|
|
2419
|
+
start = await res.json();
|
|
2420
|
+
} catch (err) {
|
|
2421
|
+
console.error(`Could not reach ${base}: ${err.message}`);
|
|
2422
|
+
return { ok: false };
|
|
2423
|
+
}
|
|
2424
|
+
const verifyUrl = start.verification_uri_complete || start.verification_uri;
|
|
2425
|
+
console.log("");
|
|
2426
|
+
console.log(" Authorize this machine:");
|
|
2427
|
+
console.log(` 1. Open: ${verifyUrl}`);
|
|
2428
|
+
console.log(` 2. Confirm the code: ${start.user_code}`);
|
|
2429
|
+
console.log("");
|
|
2430
|
+
console.log(" Waiting for approval\u2026");
|
|
2431
|
+
const deadline = Date.now() + start.expires_in * 1e3;
|
|
2432
|
+
let intervalMs = Math.max(1, start.interval) * 1e3;
|
|
2433
|
+
while (Date.now() < deadline) {
|
|
2434
|
+
await sleep(intervalMs);
|
|
2435
|
+
let body;
|
|
2436
|
+
try {
|
|
2437
|
+
const res = await fetch(`${base}/api/auth/device/token`, {
|
|
2438
|
+
method: "POST",
|
|
2439
|
+
headers: { "Content-Type": "application/json" },
|
|
2440
|
+
body: JSON.stringify({ device_code: start.device_code })
|
|
2441
|
+
});
|
|
2442
|
+
body = await res.json().catch(() => ({}));
|
|
2443
|
+
} catch {
|
|
2444
|
+
continue;
|
|
2445
|
+
}
|
|
2446
|
+
switch (body.status) {
|
|
2447
|
+
case "approved":
|
|
2448
|
+
if (body.api_key) {
|
|
2449
|
+
saveApiKey(body.api_key);
|
|
2450
|
+
console.log(" Approved \u2014 this machine is now linked to your Kynver account.");
|
|
2451
|
+
return { ok: true, apiKey: body.api_key };
|
|
2452
|
+
}
|
|
2453
|
+
return { ok: false };
|
|
2454
|
+
case "slow_down":
|
|
2455
|
+
intervalMs += 2e3;
|
|
2456
|
+
break;
|
|
2457
|
+
case "authorization_pending":
|
|
2458
|
+
if (typeof body.interval === "number") intervalMs = Math.max(intervalMs, body.interval * 1e3);
|
|
2459
|
+
break;
|
|
2460
|
+
case "access_denied":
|
|
2461
|
+
console.error(" Request was denied in the browser.");
|
|
2462
|
+
return { ok: false };
|
|
2463
|
+
case "expired_token":
|
|
2464
|
+
console.error(" The code expired before it was approved. Run `kynver login` again.");
|
|
2465
|
+
return { ok: false };
|
|
2466
|
+
default:
|
|
2467
|
+
break;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
console.error(" Timed out waiting for approval. Run `kynver login` again.");
|
|
2471
|
+
return { ok: false };
|
|
2472
|
+
}
|
|
2473
|
+
var init_device_login = __esm({
|
|
2474
|
+
"src/device-login.ts"() {
|
|
2475
|
+
"use strict";
|
|
2476
|
+
init_config();
|
|
2477
|
+
init_util();
|
|
2478
|
+
}
|
|
2479
|
+
});
|
|
2480
|
+
|
|
2481
|
+
// src/config.ts
|
|
2482
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2483
|
+
import { homedir as homedir4, totalmem } from "node:os";
|
|
2484
|
+
import path8 from "node:path";
|
|
2485
|
+
import os4 from "node:os";
|
|
2214
2486
|
function loadUserConfig() {
|
|
2215
2487
|
if (!existsSync9(CONFIG_FILE)) return {};
|
|
2216
2488
|
try {
|
|
@@ -2249,8 +2521,6 @@ function inferSetupFields(existing, args) {
|
|
|
2249
2521
|
...typeof args.agentOsSlug === "string" ? { agentOsSlug: args.agentOsSlug } : existing.agentOsSlug ? { agentOsSlug: existing.agentOsSlug } : {}
|
|
2250
2522
|
};
|
|
2251
2523
|
}
|
|
2252
|
-
var SETUP_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;
|
|
2253
|
-
var SETUP_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;
|
|
2254
2524
|
function resolveSetupWorkerConfig(existing, args, totalMemBytes = totalmem()) {
|
|
2255
2525
|
const maxWorkersRaw = typeof args.maxWorkers === "string" ? args.maxWorkers : typeof args.maxConcurrentWorkers === "string" ? args.maxConcurrentWorkers : void 0;
|
|
2256
2526
|
const explicitBoxKindArg = typeof args.boxKind === "string" ? args.boxKind : typeof args["box-kind"] === "string" ? String(args["box-kind"]) : void 0;
|
|
@@ -2471,7 +2741,7 @@ async function runSetup(args) {
|
|
|
2471
2741
|
diskPath: typeof args.diskPath === "string" ? args.diskPath : "/"
|
|
2472
2742
|
});
|
|
2473
2743
|
const capRecommendation = recommendSetupWorkerCap({
|
|
2474
|
-
totalMemBytes:
|
|
2744
|
+
totalMemBytes: os4.totalmem(),
|
|
2475
2745
|
diskPath: diskGate.path,
|
|
2476
2746
|
diskGateOk: diskGate.ok,
|
|
2477
2747
|
diskFreeBytes: diskGate.freeBytes,
|
|
@@ -2520,10 +2790,104 @@ async function runSetup(args) {
|
|
|
2520
2790
|
}
|
|
2521
2791
|
async function runLogin(args) {
|
|
2522
2792
|
const apiKey = typeof args.apiKey === "string" ? args.apiKey : process.env.KYNVER_API_KEY;
|
|
2523
|
-
if (
|
|
2524
|
-
|
|
2793
|
+
if (apiKey) {
|
|
2794
|
+
saveApiKey(apiKey);
|
|
2795
|
+
console.log(JSON.stringify({ ok: true, credentialsPath: displayUserPath(CREDENTIALS_FILE) }, null, 2));
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2798
|
+
const { runDeviceLogin: runDeviceLogin2 } = await Promise.resolve().then(() => (init_device_login(), device_login_exports));
|
|
2799
|
+
const result = await runDeviceLogin2(args);
|
|
2800
|
+
if (!result.ok) process.exit(1);
|
|
2525
2801
|
console.log(JSON.stringify({ ok: true, credentialsPath: displayUserPath(CREDENTIALS_FILE) }, null, 2));
|
|
2526
2802
|
}
|
|
2803
|
+
var CONFIG_DIR, CONFIG_FILE, CREDENTIALS_FILE, SETUP_PER_WORKER_MEM_BYTES, SETUP_MEM_RESERVE_BYTES;
|
|
2804
|
+
var init_config = __esm({
|
|
2805
|
+
"src/config.ts"() {
|
|
2806
|
+
"use strict";
|
|
2807
|
+
init_default_repo_discovery();
|
|
2808
|
+
init_path_values();
|
|
2809
|
+
init_util();
|
|
2810
|
+
init_box_identity();
|
|
2811
|
+
init_worker_cap_source();
|
|
2812
|
+
init_disk_gate();
|
|
2813
|
+
CONFIG_DIR = path8.join(homedir4(), ".kynver");
|
|
2814
|
+
CONFIG_FILE = path8.join(CONFIG_DIR, "config.json");
|
|
2815
|
+
CREDENTIALS_FILE = path8.join(CONFIG_DIR, "credentials");
|
|
2816
|
+
SETUP_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;
|
|
2817
|
+
SETUP_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;
|
|
2818
|
+
}
|
|
2819
|
+
});
|
|
2820
|
+
|
|
2821
|
+
// src/cli.ts
|
|
2822
|
+
init_config();
|
|
2823
|
+
import { mkdirSync as mkdirSync11, realpathSync } from "node:fs";
|
|
2824
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
2825
|
+
|
|
2826
|
+
// src/bootstrap.ts
|
|
2827
|
+
init_config();
|
|
2828
|
+
init_util();
|
|
2829
|
+
init_device_login();
|
|
2830
|
+
import os5 from "node:os";
|
|
2831
|
+
function resolveBootstrapBaseUrl(args) {
|
|
2832
|
+
const raw = (typeof args.apiBaseUrl === "string" ? args.apiBaseUrl : void 0) || (typeof args.baseUrl === "string" ? args.baseUrl : void 0) || process.env.KYNVER_API_URL || loadUserConfig().apiBaseUrl;
|
|
2833
|
+
return raw ? trimTrailingSlash(String(raw)) : void 0;
|
|
2834
|
+
}
|
|
2835
|
+
async function fetchPrimaryAgentOs(base, apiKey) {
|
|
2836
|
+
const res = await fetch(`${base}/api/agent-os`, {
|
|
2837
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2838
|
+
});
|
|
2839
|
+
if (!res.ok) return null;
|
|
2840
|
+
const body = await res.json().catch(() => null);
|
|
2841
|
+
if (!body?.primarySlug) return null;
|
|
2842
|
+
const match = body.items?.find((it) => it.slug === body.primarySlug);
|
|
2843
|
+
if (match?.id && match.slug) return { id: match.id, slug: match.slug };
|
|
2844
|
+
return { id: "", slug: body.primarySlug };
|
|
2845
|
+
}
|
|
2846
|
+
async function runBootstrap(args) {
|
|
2847
|
+
const base = resolveBootstrapBaseUrl(args);
|
|
2848
|
+
if (!base) {
|
|
2849
|
+
console.error(
|
|
2850
|
+
"kynver bootstrap requires a Kynver URL \u2014 pass --api-base-url https://your-kynver-site or set KYNVER_API_URL."
|
|
2851
|
+
);
|
|
2852
|
+
process.exit(1);
|
|
2853
|
+
}
|
|
2854
|
+
if (!loadApiKey()) {
|
|
2855
|
+
if (typeof args.apiKey === "string") {
|
|
2856
|
+
saveApiKey(args.apiKey);
|
|
2857
|
+
} else {
|
|
2858
|
+
const login = await runDeviceLogin({ ...args, apiBaseUrl: base });
|
|
2859
|
+
if (!login.ok) process.exit(1);
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
const apiKey = loadApiKey();
|
|
2863
|
+
if (!apiKey) {
|
|
2864
|
+
console.error("No API key after login \u2014 aborting.");
|
|
2865
|
+
process.exit(1);
|
|
2866
|
+
}
|
|
2867
|
+
const primary = await fetchPrimaryAgentOs(base, apiKey);
|
|
2868
|
+
if (!primary) {
|
|
2869
|
+
console.error(
|
|
2870
|
+
"Could not resolve your AgentOS workspace from the account. Confirm this account has AgentOS access, then retry."
|
|
2871
|
+
);
|
|
2872
|
+
process.exit(1);
|
|
2873
|
+
}
|
|
2874
|
+
const setupArgs = {
|
|
2875
|
+
...args,
|
|
2876
|
+
apiBaseUrl: base,
|
|
2877
|
+
agentOsSlug: primary.slug,
|
|
2878
|
+
...primary.id ? { agentOsId: primary.id } : {},
|
|
2879
|
+
// Best-effort repo discovery unless the caller pinned one.
|
|
2880
|
+
...typeof args.repo === "string" ? {} : { discoverRepo: true }
|
|
2881
|
+
};
|
|
2882
|
+
await runSetup(setupArgs);
|
|
2883
|
+
console.log("");
|
|
2884
|
+
console.log(` Bootstrap complete \u2014 ${os5.hostname()} is linked to workspace "${primary.slug}".`);
|
|
2885
|
+
console.log(" Next: run autonomous work with `kynver daemon --run <RUN_ID> --agent-os-id <AOS_ID> --execute`");
|
|
2886
|
+
console.log(" (create a run first with `kynver run create --repo /path/to/repo`).");
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2889
|
+
// src/dispatch.ts
|
|
2890
|
+
init_config();
|
|
2527
2891
|
|
|
2528
2892
|
// src/callback-headers.ts
|
|
2529
2893
|
function buildHarnessCallbackHeaders(secret) {
|
|
@@ -2547,6 +2911,7 @@ function buildHarnessCallbackHeaders(secret) {
|
|
|
2547
2911
|
}
|
|
2548
2912
|
|
|
2549
2913
|
// src/callbacks.ts
|
|
2914
|
+
init_config();
|
|
2550
2915
|
function callbackTimeoutMs() {
|
|
2551
2916
|
const parsed = Number(process.env.KYNVER_CALLBACK_TIMEOUT_MS);
|
|
2552
2917
|
if (Number.isFinite(parsed) && parsed > 0) return Math.floor(parsed);
|
|
@@ -2760,6 +3125,12 @@ function resolveDispatchNextLaneFilter(raw) {
|
|
|
2760
3125
|
return normalizeDispatchNextLaneFilter(raw) ?? "any";
|
|
2761
3126
|
}
|
|
2762
3127
|
|
|
3128
|
+
// src/dispatch.ts
|
|
3129
|
+
init_disk_gate();
|
|
3130
|
+
init_resource_gate();
|
|
3131
|
+
init_run_store();
|
|
3132
|
+
init_run_store();
|
|
3133
|
+
|
|
2763
3134
|
// src/model-routing-task-enrich.ts
|
|
2764
3135
|
function taskString(task, key) {
|
|
2765
3136
|
const v = task[key];
|
|
@@ -2809,6 +3180,9 @@ function enrichTaskForModelRouting(task) {
|
|
|
2809
3180
|
return { ...task, roleLane };
|
|
2810
3181
|
}
|
|
2811
3182
|
|
|
3183
|
+
// src/model-routing.ts
|
|
3184
|
+
init_config();
|
|
3185
|
+
|
|
2812
3186
|
// src/worker-provider-policy.ts
|
|
2813
3187
|
var DEFAULT_WORKER_PROVIDER = "cursor";
|
|
2814
3188
|
var CLAUDE_FAMILY = /* @__PURE__ */ new Set(["claude", "opus", "anthropic"]);
|
|
@@ -3472,6 +3846,8 @@ function resolveOrchestrationRouting(input) {
|
|
|
3472
3846
|
}
|
|
3473
3847
|
|
|
3474
3848
|
// src/providers/claude.ts
|
|
3849
|
+
init_worker_env();
|
|
3850
|
+
init_util();
|
|
3475
3851
|
import { closeSync, openSync } from "node:fs";
|
|
3476
3852
|
import { spawn } from "node:child_process";
|
|
3477
3853
|
|
|
@@ -3609,13 +3985,17 @@ var claudeProvider = {
|
|
|
3609
3985
|
};
|
|
3610
3986
|
|
|
3611
3987
|
// src/providers/codex.ts
|
|
3988
|
+
init_worker_env();
|
|
3989
|
+
init_util();
|
|
3612
3990
|
import { closeSync as closeSync3, existsSync as existsSync15, openSync as openSync3 } from "node:fs";
|
|
3613
3991
|
import { spawn as spawn3 } from "node:child_process";
|
|
3614
3992
|
|
|
3615
3993
|
// src/providers/hermes-codex.ts
|
|
3994
|
+
init_worker_env();
|
|
3995
|
+
init_util();
|
|
3616
3996
|
import { closeSync as closeSync2, openSync as openSync2 } from "node:fs";
|
|
3617
3997
|
import { spawn as spawn2 } from "node:child_process";
|
|
3618
|
-
var HERMES_OPENAI_CODEX_DEFAULT_MODEL = "gpt-5.4";
|
|
3998
|
+
var HERMES_OPENAI_CODEX_DEFAULT_MODEL = process.env.KYNVER_CODEX_DEFAULT_MODEL?.trim() || "gpt-5.4";
|
|
3619
3999
|
function hermesWorkerEnv() {
|
|
3620
4000
|
return scrubWorkerEnv({
|
|
3621
4001
|
...process.env,
|
|
@@ -3683,7 +4063,10 @@ var hermesCodexProvider = {
|
|
|
3683
4063
|
};
|
|
3684
4064
|
|
|
3685
4065
|
// src/providers/codex.ts
|
|
3686
|
-
|
|
4066
|
+
function resolveCodexDefaultModel() {
|
|
4067
|
+
return process.env.KYNVER_CODEX_DEFAULT_MODEL?.trim() || "gpt-5.4";
|
|
4068
|
+
}
|
|
4069
|
+
var CODEX_DEFAULT_MODEL = resolveCodexDefaultModel();
|
|
3687
4070
|
function resolveCodexBin() {
|
|
3688
4071
|
return process.env.KYNVER_CODEX_BIN?.trim() || process.env.CODEX_BIN?.trim() || "codex";
|
|
3689
4072
|
}
|
|
@@ -3935,7 +4318,11 @@ function readHarnessRetryLimits() {
|
|
|
3935
4318
|
}
|
|
3936
4319
|
|
|
3937
4320
|
// src/lease-renewal.ts
|
|
4321
|
+
init_config();
|
|
3938
4322
|
import path14 from "node:path";
|
|
4323
|
+
init_run_store();
|
|
4324
|
+
init_status();
|
|
4325
|
+
init_util();
|
|
3939
4326
|
|
|
3940
4327
|
// src/harness-lease-owner.ts
|
|
3941
4328
|
var HARNESS_LEASE_PREFIX = "kynver-harness:";
|
|
@@ -3971,12 +4358,14 @@ function resolveHarnessLeaseOwnerForRenewal(input) {
|
|
|
3971
4358
|
}
|
|
3972
4359
|
|
|
3973
4360
|
// src/runner-identity.ts
|
|
3974
|
-
import
|
|
4361
|
+
import os7 from "node:os";
|
|
3975
4362
|
|
|
3976
4363
|
// src/box-resource-snapshot-shared.ts
|
|
3977
|
-
|
|
4364
|
+
init_box_identity();
|
|
4365
|
+
init_box_identity();
|
|
4366
|
+
import os6 from "node:os";
|
|
3978
4367
|
function defaultBoxId(boxKind, hostLabel) {
|
|
3979
|
-
const host = (hostLabel ??
|
|
4368
|
+
const host = (hostLabel ?? os6.hostname()).trim().toLowerCase().replace(/\s+/g, "-") || "unknown-host";
|
|
3980
4369
|
return `${boxKind}:${host}`;
|
|
3981
4370
|
}
|
|
3982
4371
|
|
|
@@ -3987,10 +4376,10 @@ function trimOrNull5(value) {
|
|
|
3987
4376
|
}
|
|
3988
4377
|
function resolveRunnerPresencePayload(input = {}) {
|
|
3989
4378
|
const env = input.env ?? process.env;
|
|
3990
|
-
const runnerId = trimOrNull5(env.KYNVER_RUNTIME_ID) ?? trimOrNull5(env.OPENCLAW_RUNTIME_ID) ?? trimOrNull5(env.HOSTNAME) ??
|
|
4379
|
+
const runnerId = trimOrNull5(env.KYNVER_RUNTIME_ID) ?? trimOrNull5(env.OPENCLAW_RUNTIME_ID) ?? trimOrNull5(env.HOSTNAME) ?? os7.hostname();
|
|
3991
4380
|
return {
|
|
3992
4381
|
runnerId,
|
|
3993
|
-
hostname: trimOrNull5(env.HOSTNAME) ??
|
|
4382
|
+
hostname: trimOrNull5(env.HOSTNAME) ?? os7.hostname(),
|
|
3994
4383
|
profile: trimOrNull5(env.KYNVER_RUNNER_PROFILE) ?? trimOrNull5(env.OPENCLAW_RUNNER_PROFILE),
|
|
3995
4384
|
harnessRepo: trimOrNull5(env.KYNVER_HARNESS_REPO) ?? trimOrNull5(env.KYNVER_DEFAULT_REPO),
|
|
3996
4385
|
runId: input.runId ?? null
|
|
@@ -4075,6 +4464,9 @@ function hasLiveWorkerForTask(runId, taskId) {
|
|
|
4075
4464
|
}
|
|
4076
4465
|
|
|
4077
4466
|
// src/supervisor.ts
|
|
4467
|
+
init_git();
|
|
4468
|
+
init_run_store();
|
|
4469
|
+
init_run_store();
|
|
4078
4470
|
import { existsSync as existsSync19, mkdirSync as mkdirSync4 } from "node:fs";
|
|
4079
4471
|
import path21 from "node:path";
|
|
4080
4472
|
|
|
@@ -4224,10 +4616,18 @@ function buildPrompt(input) {
|
|
|
4224
4616
|
].join("\n");
|
|
4225
4617
|
}
|
|
4226
4618
|
|
|
4619
|
+
// src/supervisor.ts
|
|
4620
|
+
init_util();
|
|
4621
|
+
|
|
4622
|
+
// src/providers/registry.ts
|
|
4623
|
+
init_config();
|
|
4624
|
+
|
|
4227
4625
|
// src/providers/cursor.ts
|
|
4626
|
+
init_util();
|
|
4627
|
+
init_worker_env();
|
|
4228
4628
|
import { closeSync as closeSync4, existsSync as existsSync17, mkdirSync as mkdirSync3, openSync as openSync4, statSync as statSync4, unlinkSync } from "node:fs";
|
|
4229
4629
|
import { spawn as spawn4 } from "node:child_process";
|
|
4230
|
-
import
|
|
4630
|
+
import os8 from "node:os";
|
|
4231
4631
|
import path16 from "node:path";
|
|
4232
4632
|
|
|
4233
4633
|
// src/providers/cursor-windows.ts
|
|
@@ -4338,7 +4738,7 @@ function positiveIntEnv(name, fallback) {
|
|
|
4338
4738
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : fallback;
|
|
4339
4739
|
}
|
|
4340
4740
|
function cursorStartLockPath() {
|
|
4341
|
-
const root = process.env.KYNVER_CURSOR_START_LOCK_DIR?.trim() || path16.join(
|
|
4741
|
+
const root = process.env.KYNVER_CURSOR_START_LOCK_DIR?.trim() || path16.join(os8.homedir(), ".kynver", "locks");
|
|
4342
4742
|
mkdirSync3(root, { recursive: true });
|
|
4343
4743
|
return path16.join(root, "cursor-agent-start.lock");
|
|
4344
4744
|
}
|
|
@@ -4464,12 +4864,14 @@ function resolveWorkerProvider(name) {
|
|
|
4464
4864
|
}
|
|
4465
4865
|
|
|
4466
4866
|
// src/auto-complete.ts
|
|
4867
|
+
init_util();
|
|
4467
4868
|
import { spawn as spawn5 } from "node:child_process";
|
|
4468
4869
|
import { existsSync as existsSync18, openSync as openSync5, closeSync as closeSync5 } from "node:fs";
|
|
4469
4870
|
import path20 from "node:path";
|
|
4470
4871
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4471
4872
|
|
|
4472
4873
|
// src/completion-ack.ts
|
|
4874
|
+
init_run_store();
|
|
4473
4875
|
function hasCompletionAck(worker) {
|
|
4474
4876
|
return Boolean(worker.completionReportedAt?.trim());
|
|
4475
4877
|
}
|
|
@@ -4497,7 +4899,12 @@ function hasTerminalCompletionAck(worker) {
|
|
|
4497
4899
|
return hasCompletionAck(worker) && !shouldReplayHarnessCompletion(worker);
|
|
4498
4900
|
}
|
|
4499
4901
|
|
|
4902
|
+
// src/auto-complete.ts
|
|
4903
|
+
init_run_store();
|
|
4904
|
+
init_status();
|
|
4905
|
+
|
|
4500
4906
|
// src/worker-ops.ts
|
|
4907
|
+
init_config();
|
|
4501
4908
|
import path19 from "node:path";
|
|
4502
4909
|
|
|
4503
4910
|
// src/completion-response.ts
|
|
@@ -4539,6 +4946,10 @@ function completionPostSucceeded(summary) {
|
|
|
4539
4946
|
return summary.taskAdvanced;
|
|
4540
4947
|
}
|
|
4541
4948
|
|
|
4949
|
+
// src/worker-ops.ts
|
|
4950
|
+
init_run_store();
|
|
4951
|
+
init_exited_salvage();
|
|
4952
|
+
|
|
4542
4953
|
// src/harness-expert-review.ts
|
|
4543
4954
|
var EXPERT_LANE_REVIEW_REF = "expert-lane-pr-review:";
|
|
4544
4955
|
var PLAN_REVIEW_EXECUTOR_REF = "plan-review-task";
|
|
@@ -4706,6 +5117,7 @@ function normalizeOwnerRepo(value) {
|
|
|
4706
5117
|
}
|
|
4707
5118
|
|
|
4708
5119
|
// src/pr-handoff/pr-handoff-gh.ts
|
|
5120
|
+
init_git();
|
|
4709
5121
|
function capture(bin, cwd, args) {
|
|
4710
5122
|
try {
|
|
4711
5123
|
const res = spawnSync3(bin, args, { cwd, encoding: "utf8" });
|
|
@@ -5076,6 +5488,10 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
|
|
|
5076
5488
|
};
|
|
5077
5489
|
}
|
|
5078
5490
|
|
|
5491
|
+
// src/worker-ops.ts
|
|
5492
|
+
init_status();
|
|
5493
|
+
init_stream();
|
|
5494
|
+
|
|
5079
5495
|
// src/material-worktree-changes.ts
|
|
5080
5496
|
function materialWorktreeChanges(changedFiles) {
|
|
5081
5497
|
return changedFiles.filter((line) => {
|
|
@@ -5118,8 +5534,8 @@ function dirtyPathsCoveredByDisposableRemoval(changedFiles, removed) {
|
|
|
5118
5534
|
if (removed.length === 0) return false;
|
|
5119
5535
|
const removedSet = new Set(removed.map((p) => normalizeRelativePath(p)));
|
|
5120
5536
|
return material.every((line) => {
|
|
5121
|
-
const
|
|
5122
|
-
return removedSet.has(
|
|
5537
|
+
const path73 = normalizeRelativePath(pathFromGitStatusLine(line));
|
|
5538
|
+
return removedSet.has(path73);
|
|
5123
5539
|
});
|
|
5124
5540
|
}
|
|
5125
5541
|
|
|
@@ -5204,6 +5620,9 @@ function assessWorktreeCompletionHandoff(input) {
|
|
|
5204
5620
|
}
|
|
5205
5621
|
|
|
5206
5622
|
// src/worker-lifecycle.ts
|
|
5623
|
+
init_run_store();
|
|
5624
|
+
init_status();
|
|
5625
|
+
init_util();
|
|
5207
5626
|
import path17 from "node:path";
|
|
5208
5627
|
var TASK_LEFT_RUNNING = /* @__PURE__ */ new Set([
|
|
5209
5628
|
"awaiting_review",
|
|
@@ -5295,7 +5714,11 @@ function syncCompletionAcknowledgedFromOperatorTick(runId, operatorTick) {
|
|
|
5295
5714
|
return synced;
|
|
5296
5715
|
}
|
|
5297
5716
|
|
|
5717
|
+
// src/worker-ops.ts
|
|
5718
|
+
init_util();
|
|
5719
|
+
|
|
5298
5720
|
// src/validate.ts
|
|
5721
|
+
init_util();
|
|
5299
5722
|
import path18 from "node:path";
|
|
5300
5723
|
var RUN_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
|
|
5301
5724
|
var WORKER_NAME_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
|
|
@@ -5648,32 +6071,98 @@ function workerStatus(args) {
|
|
|
5648
6071
|
writeJson(path19.join(worker.workerDir, "last-status.json"), status);
|
|
5649
6072
|
console.log(JSON.stringify(status, null, 2));
|
|
5650
6073
|
}
|
|
6074
|
+
function buildWorkerListDrilldownCommands(runId) {
|
|
6075
|
+
return {
|
|
6076
|
+
full: `kynver worker list --run ${runId} --full`,
|
|
6077
|
+
blocked: `kynver worker list --run ${runId} --blocked`,
|
|
6078
|
+
running: `kynver worker list --run ${runId} --running`,
|
|
6079
|
+
task: `kynver worker list --run ${runId} --task <task-id>`,
|
|
6080
|
+
worker: `kynver worker list --run ${runId} --worker <worker>`,
|
|
6081
|
+
runFull: `kynver run status --run ${runId} --full`,
|
|
6082
|
+
workerFull: `kynver worker status --run ${runId} --name <worker>`,
|
|
6083
|
+
workerTail: `kynver worker tail --run ${runId} --name <worker> --lines 80`
|
|
6084
|
+
};
|
|
6085
|
+
}
|
|
6086
|
+
function asOptionalArg(value) {
|
|
6087
|
+
if (typeof value !== "string") return void 0;
|
|
6088
|
+
const trimmed = value.trim();
|
|
6089
|
+
return trimmed.length ? trimmed : void 0;
|
|
6090
|
+
}
|
|
6091
|
+
function activeWorkerFilters(args) {
|
|
6092
|
+
const filters = {};
|
|
6093
|
+
if (args.blocked === true || args.blocked === "true") filters.blocked = true;
|
|
6094
|
+
if (args.running === true || args.running === "true") filters.running = true;
|
|
6095
|
+
const task = asOptionalArg(args.task ?? args.taskId);
|
|
6096
|
+
if (task) filters.task = task;
|
|
6097
|
+
const worker = asOptionalArg(args.worker ?? args.name);
|
|
6098
|
+
if (worker) filters.worker = worker;
|
|
6099
|
+
const status = asOptionalArg(args.status);
|
|
6100
|
+
if (status) filters.status = status;
|
|
6101
|
+
return filters;
|
|
6102
|
+
}
|
|
6103
|
+
function workerMatchesFilters(worker, filters) {
|
|
6104
|
+
if (filters.blocked) {
|
|
6105
|
+
const attention = typeof worker.attention === "string" ? worker.attention : "";
|
|
6106
|
+
const status = typeof worker.status === "string" ? worker.status : "";
|
|
6107
|
+
if (!(attention === "blocked" || attention === "needs_attention" || attention === "stale" || status === "blocked")) {
|
|
6108
|
+
return false;
|
|
6109
|
+
}
|
|
6110
|
+
}
|
|
6111
|
+
if (filters.running) {
|
|
6112
|
+
if (!(worker.status === "running" && worker.attention !== "blocked" && worker.attention !== "needs_attention")) {
|
|
6113
|
+
return false;
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
6116
|
+
if (typeof filters.task === "string" && worker.taskId !== filters.task) return false;
|
|
6117
|
+
if (typeof filters.worker === "string" && worker.worker !== filters.worker) return false;
|
|
6118
|
+
if (typeof filters.status === "string" && worker.status !== filters.status) return false;
|
|
6119
|
+
return true;
|
|
6120
|
+
}
|
|
6121
|
+
function applyWorkerFilters(board, args) {
|
|
6122
|
+
const filters = activeWorkerFilters(args);
|
|
6123
|
+
if (Object.keys(filters).length === 0) return board;
|
|
6124
|
+
const workers = board.workers.filter((worker) => workerMatchesFilters(worker, filters));
|
|
6125
|
+
const filtered = {
|
|
6126
|
+
...board,
|
|
6127
|
+
workerCount: workers.length,
|
|
6128
|
+
needsAttention: workers.filter((w) => w.attention && w.attention !== "ok" && w.attention !== "done").map((w) => w.worker),
|
|
6129
|
+
workers,
|
|
6130
|
+
activeFilters: filters
|
|
6131
|
+
};
|
|
6132
|
+
if (board.summary) {
|
|
6133
|
+
filtered.summary = {
|
|
6134
|
+
statusCounts: countBy(workers, "status"),
|
|
6135
|
+
attentionCounts: countBy(workers, "attention"),
|
|
6136
|
+
lifecycleCounts: countBy(workers, "lifecycleStage")
|
|
6137
|
+
};
|
|
6138
|
+
}
|
|
6139
|
+
if (board.controller) filtered.controller = buildControllerSummary(workers);
|
|
6140
|
+
return filtered;
|
|
6141
|
+
}
|
|
5651
6142
|
function workerList(args) {
|
|
5652
6143
|
const runId = resolveRunTargetArg(args);
|
|
5653
|
-
const explicitCompact = args.compact === true || args.compact === "true";
|
|
5654
6144
|
const explicitFull = args.full === true || args.full === "true";
|
|
5655
|
-
const
|
|
5656
|
-
const
|
|
5657
|
-
const compact = explicitCompact || !explicitFull && workerCount > 100;
|
|
5658
|
-
const board = compact ? buildCompactRunBoard(runId) : buildRunBoard(runId);
|
|
5659
|
-
const autoCompact = compact && !explicitCompact;
|
|
5660
|
-
const outputWorkers = autoCompact ? board.workers.filter((worker) => worker.attention && worker.attention !== "done" && worker.attention !== "ok") : board.workers;
|
|
6145
|
+
const board = applyWorkerFilters(explicitFull ? buildRunBoard(runId) : buildCompactRunBoard(runId), args);
|
|
6146
|
+
const outputWorkers = board.workers;
|
|
5661
6147
|
console.log(
|
|
5662
6148
|
JSON.stringify(
|
|
5663
6149
|
{
|
|
5664
6150
|
runId: board.runId,
|
|
5665
6151
|
status: board.status,
|
|
6152
|
+
projection: explicitFull ? "full" : "compact",
|
|
5666
6153
|
workerCount: board.workerCount,
|
|
5667
|
-
...
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
6154
|
+
...board.activeFilters ? { activeFilters: board.activeFilters } : {},
|
|
6155
|
+
...!explicitFull ? {
|
|
6156
|
+
resultContract: {
|
|
6157
|
+
projection: "compact",
|
|
6158
|
+
rawWorkerPayloadsOmitted: true,
|
|
6159
|
+
deepDetailAvailableVia: ["--full", "worker status", "worker tail", "run status --full"]
|
|
6160
|
+
},
|
|
6161
|
+
drilldownCommands: buildWorkerListDrilldownCommands(runId)
|
|
5673
6162
|
} : {},
|
|
5674
6163
|
needsAttention: board.needsAttention,
|
|
5675
|
-
...
|
|
5676
|
-
...
|
|
6164
|
+
..."summary" in board ? { summary: board.summary } : {},
|
|
6165
|
+
..."controller" in board ? { controller: board.controller } : {},
|
|
5677
6166
|
workers: outputWorkers
|
|
5678
6167
|
},
|
|
5679
6168
|
null,
|
|
@@ -5941,9 +6430,33 @@ async function publishHarnessBoardSnapshot(args, source) {
|
|
|
5941
6430
|
authRefreshFailure: res.authRefreshFailure
|
|
5942
6431
|
};
|
|
5943
6432
|
}
|
|
6433
|
+
function buildRunStatusDrilldownCommands(runId) {
|
|
6434
|
+
return {
|
|
6435
|
+
full: `kynver run status --run ${runId} --full`,
|
|
6436
|
+
blocked: `kynver status --run ${runId} --blocked`,
|
|
6437
|
+
running: `kynver status --run ${runId} --running`,
|
|
6438
|
+
task: `kynver status --run ${runId} --task <task-id>`,
|
|
6439
|
+
worker: `kynver status --run ${runId} --worker <worker>`,
|
|
6440
|
+
workersFull: `kynver worker list --run ${runId} --full`,
|
|
6441
|
+
workerFull: `kynver worker status --run ${runId} --name <worker>`,
|
|
6442
|
+
workerTail: `kynver worker tail --run ${runId} --name <worker> --lines 80`,
|
|
6443
|
+
monitorTick: `kynver monitor status --run ${runId} --tick`
|
|
6444
|
+
};
|
|
6445
|
+
}
|
|
5944
6446
|
function runStatus(args) {
|
|
5945
|
-
const
|
|
5946
|
-
const
|
|
6447
|
+
const runId = resolveRunTargetArg(args);
|
|
6448
|
+
const explicitFull = args.full === true || args.full === "true";
|
|
6449
|
+
const board = applyWorkerFilters(explicitFull ? buildRunBoard(runId) : buildCompactRunBoard(runId), args);
|
|
6450
|
+
board.projection = explicitFull ? "full" : "compact";
|
|
6451
|
+
if (!explicitFull) {
|
|
6452
|
+
board.resultContract = {
|
|
6453
|
+
projection: "compact",
|
|
6454
|
+
rawWorkerPayloadsOmitted: true,
|
|
6455
|
+
omittedWorkerFields: ["finalResult", "changedFiles", "gitAncestry", "completionResponse", "stdout/stderr tails"],
|
|
6456
|
+
deepDetailAvailableVia: ["--full", "worker status", "worker tail", "monitor status --tick"]
|
|
6457
|
+
};
|
|
6458
|
+
board.drilldownCommands = buildRunStatusDrilldownCommands(runId);
|
|
6459
|
+
}
|
|
5947
6460
|
console.log(JSON.stringify(board, null, 2));
|
|
5948
6461
|
}
|
|
5949
6462
|
function tailWorker(args) {
|
|
@@ -5978,6 +6491,7 @@ function stopWorker(args) {
|
|
|
5978
6491
|
}
|
|
5979
6492
|
|
|
5980
6493
|
// src/auto-complete.ts
|
|
6494
|
+
init_util();
|
|
5981
6495
|
var DEFAULT_POLL_MS = 5e3;
|
|
5982
6496
|
var DEFAULT_MAX_TOTAL_MS = 6 * 60 * 60 * 1e3;
|
|
5983
6497
|
var DEFAULT_COMPLETE_ATTEMPTS = 3;
|
|
@@ -6162,6 +6676,7 @@ function spawnCompletionSidecar(opts) {
|
|
|
6162
6676
|
}
|
|
6163
6677
|
|
|
6164
6678
|
// src/repair-target-worktree.ts
|
|
6679
|
+
init_git();
|
|
6165
6680
|
function addWorktreeForRepairBranch(repo, worktreePath, branch) {
|
|
6166
6681
|
git(repo, ["fetch", "origin", branch, "--prune"], { allowFailure: true });
|
|
6167
6682
|
const remoteRef = `origin/${branch}`;
|
|
@@ -6175,6 +6690,8 @@ function addWorktreeForRepairBranch(repo, worktreePath, branch) {
|
|
|
6175
6690
|
}
|
|
6176
6691
|
|
|
6177
6692
|
// src/supervisor.ts
|
|
6693
|
+
init_box_identity();
|
|
6694
|
+
init_config();
|
|
6178
6695
|
function spawnWorkerProcess(run, opts) {
|
|
6179
6696
|
const rawName = typeof opts.name === "string" ? opts.name.trim() : "";
|
|
6180
6697
|
if (!rawName || rawName === "undefined" || rawName === "null") {
|
|
@@ -6268,6 +6785,10 @@ function spawnWorkerProcess(run, opts) {
|
|
|
6268
6785
|
else process.env.KYNVER_HARNESS_AGENT_OS_ID = prevHarnessAgentOsId;
|
|
6269
6786
|
}
|
|
6270
6787
|
const model = resolveModelFallback(started.model, launchModel, provider.defaultModel);
|
|
6788
|
+
const config = loadUserConfig();
|
|
6789
|
+
const boxIdentity = resolveBoxIdentity(process.env, config);
|
|
6790
|
+
const runtimeId = resolveRunnerPresencePayload().runnerId;
|
|
6791
|
+
const boxId = defaultBoxId(boxIdentity.boxKind);
|
|
6271
6792
|
const worker = {
|
|
6272
6793
|
name,
|
|
6273
6794
|
runId: run.id,
|
|
@@ -6303,6 +6824,9 @@ function spawnWorkerProcess(run, opts) {
|
|
|
6303
6824
|
...opts.taskPrUrl ? { taskPrUrl: String(opts.taskPrUrl) } : {},
|
|
6304
6825
|
...opts.repairTargetPrUrl ? { repairTargetPrUrl: String(opts.repairTargetPrUrl) } : {},
|
|
6305
6826
|
...opts.repairTargetBranch ? { repairTargetBranch: String(opts.repairTargetBranch) } : {},
|
|
6827
|
+
boxKind: boxIdentity.boxKind,
|
|
6828
|
+
boxId,
|
|
6829
|
+
runtimeId,
|
|
6306
6830
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6307
6831
|
};
|
|
6308
6832
|
saveWorker(run.id, worker);
|
|
@@ -6401,6 +6925,9 @@ async function startWorker(args) {
|
|
|
6401
6925
|
}
|
|
6402
6926
|
|
|
6403
6927
|
// src/active-harness-workers.ts
|
|
6928
|
+
init_run_store();
|
|
6929
|
+
init_harness_worker_active();
|
|
6930
|
+
init_util();
|
|
6404
6931
|
import path22 from "node:path";
|
|
6405
6932
|
function workerWriteSetFields(worker) {
|
|
6406
6933
|
const ownedPaths = Array.isArray(worker.ownedPaths) ? worker.ownedPaths.filter((p) => typeof p === "string") : [];
|
|
@@ -6433,6 +6960,9 @@ function collectRunActiveHarnessWorkers(runId) {
|
|
|
6433
6960
|
return out;
|
|
6434
6961
|
}
|
|
6435
6962
|
|
|
6963
|
+
// src/dispatch.ts
|
|
6964
|
+
init_util();
|
|
6965
|
+
|
|
6436
6966
|
// src/plan-persist/body-hash.ts
|
|
6437
6967
|
import { createHash as createHash2 } from "node:crypto";
|
|
6438
6968
|
function hashPlanBody(body) {
|
|
@@ -6446,6 +6976,9 @@ function hashSummary(summary) {
|
|
|
6446
6976
|
return createHash2("sha256").update(trimmed, "utf8").digest("hex");
|
|
6447
6977
|
}
|
|
6448
6978
|
|
|
6979
|
+
// src/plan-persist/agentos-api.ts
|
|
6980
|
+
init_config();
|
|
6981
|
+
|
|
6449
6982
|
// src/plan-persist/errors.ts
|
|
6450
6983
|
var PlanPersistError = class extends Error {
|
|
6451
6984
|
kind;
|
|
@@ -7081,6 +7614,10 @@ var READY_MERGE_STATES = /* @__PURE__ */ new Set(["CLEAN", "HAS_HOOKS"]);
|
|
|
7081
7614
|
function repoArgs(repo) {
|
|
7082
7615
|
return repo?.trim() ? ["--repo", repo.trim()] : [];
|
|
7083
7616
|
}
|
|
7617
|
+
function repoFromPrUrl(prUrl) {
|
|
7618
|
+
const m = /github\.com\/([^/]+)\/([^/]+)\/pull\/\d+/i.exec(prUrl.trim());
|
|
7619
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
7620
|
+
}
|
|
7084
7621
|
function ghJson(exec, cwd, args) {
|
|
7085
7622
|
const res = exec.gh(cwd, args);
|
|
7086
7623
|
if (res.status !== 0) {
|
|
@@ -7106,11 +7643,11 @@ function classifyChecks(statusCheckRollup) {
|
|
|
7106
7643
|
continue;
|
|
7107
7644
|
}
|
|
7108
7645
|
if (state && SUCCESSFUL_CHECK_CONCLUSIONS.has(state)) continue;
|
|
7109
|
-
if (state && state !== "PENDING") {
|
|
7646
|
+
if (state && state !== "PENDING" && state !== "EXPECTED") {
|
|
7110
7647
|
failed.push(`${checkName(check3)}=${state}`);
|
|
7111
7648
|
continue;
|
|
7112
7649
|
}
|
|
7113
|
-
if (state === "PENDING") {
|
|
7650
|
+
if (state === "PENDING" || state === "EXPECTED") {
|
|
7114
7651
|
pending.push(`${checkName(check3)}=${state}`);
|
|
7115
7652
|
continue;
|
|
7116
7653
|
}
|
|
@@ -7136,14 +7673,21 @@ var STRUCTURED_SECTION_RE = /^##\s*(test\s*plan|verification|test\s*evidence|ver
|
|
|
7136
7673
|
var LOCAL_VERIFICATION_RE = /typecheck|npm run (test|build|typecheck)|vitest|tsc\b|verify-pr-local|local verify|local-verify|tests? (pass|green)|build green|node --test/i;
|
|
7137
7674
|
var DOCS_TITLE_RE = /^docs[(:]/i;
|
|
7138
7675
|
var DOCS_BODY_RE = /docs[- ]only|documentation only|no[- ]code change|no code changes|low[- ]risk|plan tracker only|markdown only/i;
|
|
7139
|
-
function
|
|
7140
|
-
const title = typeof
|
|
7141
|
-
const body = typeof
|
|
7676
|
+
function runtimeVerificationEvidenceSufficient(input) {
|
|
7677
|
+
const title = typeof input.title === "string" ? input.title.trim() : "";
|
|
7678
|
+
const body = typeof input.body === "string" ? input.body.trim() : "";
|
|
7142
7679
|
const docsLowRisk = DOCS_TITLE_RE.test(title) || DOCS_BODY_RE.test(body);
|
|
7143
7680
|
const structuredSection = STRUCTURED_SECTION_RE.test(body);
|
|
7144
7681
|
const localVerification = LOCAL_VERIFICATION_RE.test(body);
|
|
7145
|
-
|
|
7146
|
-
|
|
7682
|
+
return docsLowRisk || structuredSection || localVerification || input.vercelCheckSuccess === true;
|
|
7683
|
+
}
|
|
7684
|
+
function assertVerificationEvidence(pr) {
|
|
7685
|
+
const sufficient = runtimeVerificationEvidenceSufficient({
|
|
7686
|
+
title: pr.title,
|
|
7687
|
+
body: pr.body,
|
|
7688
|
+
vercelCheckSuccess: vercelCheckSuccess(pr.statusCheckRollup)
|
|
7689
|
+
});
|
|
7690
|
+
if (sufficient) return;
|
|
7147
7691
|
throw new Error(
|
|
7148
7692
|
`PR #${pr.number} lacks landing verification evidence \u2014 add ## Test plan / ## Verification with local commands, Vercel preview, or docs/no-code rationale`
|
|
7149
7693
|
);
|
|
@@ -7244,6 +7788,14 @@ async function executeLandPrMerge(input) {
|
|
|
7244
7788
|
"mergeCommit"
|
|
7245
7789
|
].join(",")
|
|
7246
7790
|
]);
|
|
7791
|
+
if (before.state === "MERGED" || before.mergedAt) {
|
|
7792
|
+
return {
|
|
7793
|
+
prUrl: before.url || prTarget,
|
|
7794
|
+
outcome: "skipped",
|
|
7795
|
+
mergeCommit: before.mergeCommit?.oid ?? null,
|
|
7796
|
+
reason: `PR #${before.number} is already merged \u2014 land_pr no-op (redelivery)`
|
|
7797
|
+
};
|
|
7798
|
+
}
|
|
7247
7799
|
const notReadyReason = landingReadinessError(before);
|
|
7248
7800
|
if (notReadyReason) {
|
|
7249
7801
|
if (input.skipNotReady) {
|
|
@@ -7275,40 +7827,56 @@ async function executeLandPrMerge(input) {
|
|
|
7275
7827
|
"--squash"
|
|
7276
7828
|
]);
|
|
7277
7829
|
if (mergeRes.status !== 0) {
|
|
7830
|
+
const raced = viewMergedState(exec, cwd, target, input.repo);
|
|
7831
|
+
if (raced) {
|
|
7832
|
+
return {
|
|
7833
|
+
prUrl: raced.url || before.url || prTarget,
|
|
7834
|
+
outcome: "skipped",
|
|
7835
|
+
mergeCommit: raced.mergeCommit?.oid ?? null,
|
|
7836
|
+
reason: `PR #${before.number} is already merged \u2014 merged by another lane during land_pr (race)`
|
|
7837
|
+
};
|
|
7838
|
+
}
|
|
7278
7839
|
return {
|
|
7279
7840
|
prUrl: before.url || prTarget,
|
|
7280
7841
|
outcome: "blocked",
|
|
7281
7842
|
reason: mergeRes.stderr || mergeRes.stdout || "gh pr merge failed"
|
|
7282
7843
|
};
|
|
7283
7844
|
}
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
return {
|
|
7294
|
-
prUrl: after.url || before.url || prTarget,
|
|
7295
|
-
outcome: "blocked",
|
|
7296
|
-
reason: `PR #${after.number} did not verify as merged after gh pr merge`
|
|
7297
|
-
};
|
|
7845
|
+
let after = viewMergedState(exec, cwd, target, input.repo);
|
|
7846
|
+
if (!after) {
|
|
7847
|
+
after = viewMergedState(exec, cwd, target, input.repo);
|
|
7848
|
+
}
|
|
7849
|
+
try {
|
|
7850
|
+
const repo = resolveRepo(exec, cwd, input.repo);
|
|
7851
|
+
deleteRemoteBranch(exec, cwd, repo, before.headRefName);
|
|
7852
|
+
removeBranchWorktrees(cwd, before.headRefName);
|
|
7853
|
+
} catch {
|
|
7298
7854
|
}
|
|
7299
|
-
const repo = resolveRepo(exec, cwd, input.repo);
|
|
7300
|
-
deleteRemoteBranch(exec, cwd, repo, before.headRefName);
|
|
7301
|
-
removeBranchWorktrees(cwd, before.headRefName);
|
|
7302
|
-
const mergeCommit = after.mergeCommit?.oid ?? null;
|
|
7303
7855
|
return {
|
|
7304
|
-
prUrl: after
|
|
7856
|
+
prUrl: after?.url || before.url || prTarget,
|
|
7305
7857
|
outcome: "merged",
|
|
7306
|
-
mergeCommit,
|
|
7307
|
-
reason: `Daemon land_pr merged PR #${
|
|
7858
|
+
mergeCommit: after?.mergeCommit?.oid ?? null,
|
|
7859
|
+
reason: `Daemon land_pr merged PR #${before.number}${after ? "" : " (post-merge view unavailable \u2014 merge verified by gh exit 0)"}`
|
|
7308
7860
|
};
|
|
7309
7861
|
}
|
|
7862
|
+
function viewMergedState(exec, cwd, target, repo) {
|
|
7863
|
+
try {
|
|
7864
|
+
const view = ghJson(exec, cwd, [
|
|
7865
|
+
"pr",
|
|
7866
|
+
"view",
|
|
7867
|
+
target,
|
|
7868
|
+
...repoArgs(repo),
|
|
7869
|
+
"--json",
|
|
7870
|
+
"number,url,mergedAt,mergeCommit,state"
|
|
7871
|
+
]);
|
|
7872
|
+
return view.state === "MERGED" || view.mergedAt ? view : null;
|
|
7873
|
+
} catch {
|
|
7874
|
+
return null;
|
|
7875
|
+
}
|
|
7876
|
+
}
|
|
7310
7877
|
|
|
7311
7878
|
// src/landing/land-pr-completion-post.ts
|
|
7879
|
+
init_config();
|
|
7312
7880
|
async function postLandPrHarnessCompletion(input) {
|
|
7313
7881
|
const secret = await resolveCallbackSecretWithMint(input.secret, input.agentOsId, {
|
|
7314
7882
|
baseUrl: input.baseUrl
|
|
@@ -7593,12 +8161,25 @@ async function dispatchRun(args) {
|
|
|
7593
8161
|
async function runLandPrClaimed(decision) {
|
|
7594
8162
|
const task = decision.task;
|
|
7595
8163
|
const taskId = String(task.id);
|
|
8164
|
+
if (exactTargetMode && !exactTargetIds.has(taskId)) {
|
|
8165
|
+
return abortClaimedSpawn(
|
|
8166
|
+
task,
|
|
8167
|
+
"exact_target_mismatch: dispatch-next returned a different task than requested",
|
|
8168
|
+
{
|
|
8169
|
+
requestedTargetTaskIds: [...exactTargetIds]
|
|
8170
|
+
}
|
|
8171
|
+
);
|
|
8172
|
+
}
|
|
7596
8173
|
const prUrl = task.prUrl ? String(task.prUrl) : "";
|
|
7597
8174
|
if (!prUrl) {
|
|
7598
8175
|
return abortClaimedSpawn(task, "land_pr task missing prUrl");
|
|
7599
8176
|
}
|
|
7600
8177
|
try {
|
|
7601
|
-
const report = await executeLandPrMerge({
|
|
8178
|
+
const report = await executeLandPrMerge({
|
|
8179
|
+
prUrl,
|
|
8180
|
+
repo: repoFromPrUrl(prUrl),
|
|
8181
|
+
cwd: run.repo
|
|
8182
|
+
});
|
|
7602
8183
|
const post = await postLandPrHarnessCompletion({
|
|
7603
8184
|
baseUrl: base,
|
|
7604
8185
|
secret,
|
|
@@ -7625,6 +8206,27 @@ async function dispatchRun(args) {
|
|
|
7625
8206
|
return abortClaimedSpawn(task, error.message);
|
|
7626
8207
|
}
|
|
7627
8208
|
}
|
|
8209
|
+
async function releaseDuplicateLocalClaim(task) {
|
|
8210
|
+
const error = "duplicate_dispatch_prevented: live local worker already owns this task";
|
|
8211
|
+
const release = await releaseDispatchClaimAfterSpawnFailure({
|
|
8212
|
+
baseUrl: base,
|
|
8213
|
+
secret,
|
|
8214
|
+
agentOsId,
|
|
8215
|
+
taskId: String(task.id),
|
|
8216
|
+
leaseOwner,
|
|
8217
|
+
failureDetail: error
|
|
8218
|
+
});
|
|
8219
|
+
outcomes.push({
|
|
8220
|
+
taskId: task.id,
|
|
8221
|
+
started: false,
|
|
8222
|
+
error,
|
|
8223
|
+
alreadyRunning: true,
|
|
8224
|
+
nonFatal: true,
|
|
8225
|
+
released: release.released,
|
|
8226
|
+
releaseResponse: release.releaseResponse
|
|
8227
|
+
});
|
|
8228
|
+
return false;
|
|
8229
|
+
}
|
|
7628
8230
|
async function spawnClaimed(decision) {
|
|
7629
8231
|
const task = decision.task;
|
|
7630
8232
|
const harnessContext = readHarnessWorkerContext(decision);
|
|
@@ -7646,10 +8248,7 @@ async function dispatchRun(args) {
|
|
|
7646
8248
|
);
|
|
7647
8249
|
}
|
|
7648
8250
|
if (hasLiveWorkerForTask(run.id, taskId)) {
|
|
7649
|
-
return
|
|
7650
|
-
task,
|
|
7651
|
-
"duplicate_dispatch_prevented: live local worker already owns this task"
|
|
7652
|
-
);
|
|
8251
|
+
return releaseDuplicateLocalClaim(task);
|
|
7653
8252
|
}
|
|
7654
8253
|
const attempt = Number(task.attempt) || 1;
|
|
7655
8254
|
if (attempt > retryLimits.maxTaskAttempts) {
|
|
@@ -7819,11 +8418,12 @@ async function dispatchRun(args) {
|
|
|
7819
8418
|
diskGate: result.diskGate,
|
|
7820
8419
|
resourceGate: result.resourceGate
|
|
7821
8420
|
};
|
|
8421
|
+
const fatalOutcome = (outcome) => !outcome.started && outcome.nonFatal !== true;
|
|
7822
8422
|
if (pipeline) {
|
|
7823
|
-
return { ok: !outcomes.some(
|
|
8423
|
+
return { ok: !outcomes.some(fatalOutcome), ...summary };
|
|
7824
8424
|
}
|
|
7825
8425
|
console.log(JSON.stringify(summary, null, 2));
|
|
7826
|
-
if (outcomes.some(
|
|
8426
|
+
if (outcomes.some(fatalOutcome)) process.exit(1);
|
|
7827
8427
|
} catch (error) {
|
|
7828
8428
|
if (pipeline) return { ok: false, error: error.message };
|
|
7829
8429
|
console.error(`run dispatch failed: ${error.message}`);
|
|
@@ -7831,8 +8431,15 @@ async function dispatchRun(args) {
|
|
|
7831
8431
|
}
|
|
7832
8432
|
}
|
|
7833
8433
|
|
|
8434
|
+
// src/cli.ts
|
|
8435
|
+
init_run_store();
|
|
8436
|
+
|
|
7834
8437
|
// src/sweep.ts
|
|
8438
|
+
init_config();
|
|
7835
8439
|
import path26 from "node:path";
|
|
8440
|
+
init_run_store();
|
|
8441
|
+
init_status();
|
|
8442
|
+
init_util();
|
|
7836
8443
|
async function sweepRun(args) {
|
|
7837
8444
|
const pipeline = args.pipeline === true || args.pipeline === "true";
|
|
7838
8445
|
try {
|
|
@@ -7893,10 +8500,14 @@ async function sweepRun(args) {
|
|
|
7893
8500
|
}
|
|
7894
8501
|
|
|
7895
8502
|
// src/worktree.ts
|
|
8503
|
+
init_git();
|
|
8504
|
+
init_run_store();
|
|
7896
8505
|
import { existsSync as existsSync25, mkdirSync as mkdirSync6 } from "node:fs";
|
|
7897
8506
|
import path35 from "node:path";
|
|
7898
8507
|
|
|
7899
8508
|
// src/run-list.ts
|
|
8509
|
+
init_run_store();
|
|
8510
|
+
init_run_worker_index();
|
|
7900
8511
|
import { existsSync as existsSync24, readFileSync as readFileSync11 } from "node:fs";
|
|
7901
8512
|
import path34 from "node:path";
|
|
7902
8513
|
|
|
@@ -7904,6 +8515,10 @@ import path34 from "node:path";
|
|
|
7904
8515
|
import path33 from "node:path";
|
|
7905
8516
|
|
|
7906
8517
|
// src/finalize.ts
|
|
8518
|
+
init_run_store();
|
|
8519
|
+
init_run_worker_index();
|
|
8520
|
+
init_status();
|
|
8521
|
+
init_util();
|
|
7907
8522
|
import path27 from "node:path";
|
|
7908
8523
|
var ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
7909
8524
|
"running",
|
|
@@ -7961,11 +8576,21 @@ function finalizeStaleRuns() {
|
|
|
7961
8576
|
return finalized;
|
|
7962
8577
|
}
|
|
7963
8578
|
|
|
8579
|
+
// src/stale-reconcile.ts
|
|
8580
|
+
init_run_store();
|
|
8581
|
+
init_run_worker_index();
|
|
8582
|
+
init_status();
|
|
8583
|
+
init_util();
|
|
8584
|
+
|
|
7964
8585
|
// src/worker-metadata-reconcile.ts
|
|
8586
|
+
init_heartbeat();
|
|
8587
|
+
init_stream();
|
|
7965
8588
|
import { existsSync as existsSync23, lstatSync, readdirSync as readdirSync7, readlinkSync, renameSync as renameSync2, rmSync } from "node:fs";
|
|
7966
8589
|
import path31 from "node:path";
|
|
7967
8590
|
|
|
7968
8591
|
// src/worker-metadata-paths.ts
|
|
8592
|
+
init_paths();
|
|
8593
|
+
init_util();
|
|
7969
8594
|
import path28 from "node:path";
|
|
7970
8595
|
var NESTED_RUNS = `${path28.sep}runs${path28.sep}runs${path28.sep}`;
|
|
7971
8596
|
function hasNestedRunsSegment(filePath) {
|
|
@@ -8013,6 +8638,9 @@ import { existsSync as existsSync22, readdirSync as readdirSync6, statSync as st
|
|
|
8013
8638
|
import path30 from "node:path";
|
|
8014
8639
|
|
|
8015
8640
|
// src/default-repo.ts
|
|
8641
|
+
init_config();
|
|
8642
|
+
init_default_repo_discovery();
|
|
8643
|
+
init_path_values();
|
|
8016
8644
|
import path29 from "node:path";
|
|
8017
8645
|
function expandConfiguredRepo(value) {
|
|
8018
8646
|
return path29.resolve(resolveUserPath(value.trim()));
|
|
@@ -8063,6 +8691,10 @@ function formatResolvedDefaultRepo(resolved) {
|
|
|
8063
8691
|
}
|
|
8064
8692
|
|
|
8065
8693
|
// src/run-metadata-retention.ts
|
|
8694
|
+
init_heartbeat();
|
|
8695
|
+
init_paths();
|
|
8696
|
+
init_run_store();
|
|
8697
|
+
init_util();
|
|
8066
8698
|
var RUN_METADATA_ACTIVE_SIGNAL_MS = 15 * 60 * 1e3;
|
|
8067
8699
|
function isHarnessRunMetadataPath(targetPath, harnessRoot) {
|
|
8068
8700
|
const resolved = path30.resolve(targetPath);
|
|
@@ -8203,6 +8835,8 @@ function collectFilesystemLiveRunKeys(harnessRoot, now = Date.now()) {
|
|
|
8203
8835
|
}
|
|
8204
8836
|
|
|
8205
8837
|
// src/worker-metadata-reconcile.ts
|
|
8838
|
+
init_run_store();
|
|
8839
|
+
init_util();
|
|
8206
8840
|
function materializeSymlinkedRunDir(harnessRoot, runId) {
|
|
8207
8841
|
const canonical = canonicalRunDir(harnessRoot, runId);
|
|
8208
8842
|
let stat;
|
|
@@ -8485,6 +9119,12 @@ function reconcileWorkerMetadata() {
|
|
|
8485
9119
|
}
|
|
8486
9120
|
|
|
8487
9121
|
// src/local-pr-attention-reconcile.ts
|
|
9122
|
+
init_heartbeat();
|
|
9123
|
+
init_worker_final_result_embed();
|
|
9124
|
+
init_status();
|
|
9125
|
+
init_run_store();
|
|
9126
|
+
init_run_worker_index();
|
|
9127
|
+
init_util();
|
|
8488
9128
|
import { execFileSync } from "node:child_process";
|
|
8489
9129
|
import path32 from "node:path";
|
|
8490
9130
|
function normalizePrUrl3(url) {
|
|
@@ -8811,6 +9451,8 @@ function reconcileRunsCli() {
|
|
|
8811
9451
|
}
|
|
8812
9452
|
|
|
8813
9453
|
// src/run-list.ts
|
|
9454
|
+
init_status();
|
|
9455
|
+
init_util();
|
|
8814
9456
|
function heartbeatByteLength(heartbeatPath) {
|
|
8815
9457
|
if (!heartbeatPath || !existsSync24(heartbeatPath)) return 0;
|
|
8816
9458
|
try {
|
|
@@ -8926,6 +9568,7 @@ function listRunsCli() {
|
|
|
8926
9568
|
}
|
|
8927
9569
|
|
|
8928
9570
|
// src/worktree.ts
|
|
9571
|
+
init_util();
|
|
8929
9572
|
function resolveCreateRunRepo(args) {
|
|
8930
9573
|
const explicit = typeof args.repo === "string" ? args.repo.trim() : "";
|
|
8931
9574
|
if (explicit) return explicit;
|
|
@@ -8965,6 +9608,8 @@ function failExists(message) {
|
|
|
8965
9608
|
}
|
|
8966
9609
|
|
|
8967
9610
|
// src/discard-disposable.ts
|
|
9611
|
+
init_run_store();
|
|
9612
|
+
init_status();
|
|
8968
9613
|
import { existsSync as existsSync26, rmSync as rmSync2 } from "node:fs";
|
|
8969
9614
|
import path36 from "node:path";
|
|
8970
9615
|
function normalizeRelativePath2(value) {
|
|
@@ -9018,8 +9663,14 @@ function discardDisposableCli(args) {
|
|
|
9018
9663
|
if (!result.ok) process.exit(1);
|
|
9019
9664
|
}
|
|
9020
9665
|
|
|
9666
|
+
// src/daemon.ts
|
|
9667
|
+
init_config();
|
|
9668
|
+
|
|
9021
9669
|
// src/daemon-box-identity.ts
|
|
9022
|
-
|
|
9670
|
+
init_config();
|
|
9671
|
+
init_box_identity();
|
|
9672
|
+
init_worker_cap_source();
|
|
9673
|
+
import os9 from "node:os";
|
|
9023
9674
|
function emitDaemonIdentityMessage(level, message) {
|
|
9024
9675
|
console.error(JSON.stringify({ event: "daemon_identity", level, message }));
|
|
9025
9676
|
}
|
|
@@ -9027,7 +9678,7 @@ function validateDaemonInstallIdentity(config = loadUserConfig(), env = process.
|
|
|
9027
9678
|
const box = resolveBoxIdentity(env, config);
|
|
9028
9679
|
const cap = resolveWorkerCap({
|
|
9029
9680
|
config,
|
|
9030
|
-
totalMemBytes:
|
|
9681
|
+
totalMemBytes: os9.totalmem(),
|
|
9031
9682
|
env
|
|
9032
9683
|
});
|
|
9033
9684
|
const warnings = [...box.warnings];
|
|
@@ -9057,11 +9708,71 @@ function validateDaemonInstallIdentity(config = loadUserConfig(), env = process.
|
|
|
9057
9708
|
};
|
|
9058
9709
|
}
|
|
9059
9710
|
|
|
9060
|
-
// src/
|
|
9061
|
-
import {
|
|
9711
|
+
// src/daemon-heartbeat.ts
|
|
9712
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync12, renameSync as renameSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
9062
9713
|
import { homedir as homedir11 } from "node:os";
|
|
9063
9714
|
import path37 from "node:path";
|
|
9064
|
-
function
|
|
9715
|
+
function daemonHeartbeatPath(agentOsId) {
|
|
9716
|
+
const safe = agentOsId.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
9717
|
+
return path37.join(homedir11(), ".kynver", `daemon-heartbeat-${safe}.json`);
|
|
9718
|
+
}
|
|
9719
|
+
function writeDaemonHeartbeat(input) {
|
|
9720
|
+
try {
|
|
9721
|
+
const file = daemonHeartbeatPath(input.agentOsId);
|
|
9722
|
+
mkdirSync7(path37.dirname(file), { recursive: true });
|
|
9723
|
+
const beat = {
|
|
9724
|
+
observedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
9725
|
+
pid: process.pid,
|
|
9726
|
+
runId: input.runId,
|
|
9727
|
+
agentOsId: input.agentOsId
|
|
9728
|
+
};
|
|
9729
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
9730
|
+
writeFileSync4(tmp, JSON.stringify(beat), "utf8");
|
|
9731
|
+
renameSync3(tmp, file);
|
|
9732
|
+
} catch {
|
|
9733
|
+
}
|
|
9734
|
+
}
|
|
9735
|
+
function readDaemonHeartbeat(agentOsId) {
|
|
9736
|
+
try {
|
|
9737
|
+
const raw = readFileSync12(daemonHeartbeatPath(agentOsId), "utf8");
|
|
9738
|
+
const parsed = JSON.parse(raw);
|
|
9739
|
+
if (typeof parsed?.observedAt !== "string") return null;
|
|
9740
|
+
return parsed;
|
|
9741
|
+
} catch {
|
|
9742
|
+
return null;
|
|
9743
|
+
}
|
|
9744
|
+
}
|
|
9745
|
+
function isDaemonHeartbeatStale(beat, stallMs, nowMs = Date.now()) {
|
|
9746
|
+
if (!beat) return false;
|
|
9747
|
+
const observed = Date.parse(beat.observedAt);
|
|
9748
|
+
if (Number.isNaN(observed)) return true;
|
|
9749
|
+
return nowMs - observed > stallMs;
|
|
9750
|
+
}
|
|
9751
|
+
|
|
9752
|
+
// src/daemon-platform-guard.ts
|
|
9753
|
+
function envFlag(name) {
|
|
9754
|
+
const raw = process.env[name]?.trim().toLowerCase();
|
|
9755
|
+
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
9756
|
+
}
|
|
9757
|
+
function assertNativeDaemonAllowed() {
|
|
9758
|
+
if (process.platform !== "win32") return;
|
|
9759
|
+
if (envFlag("KYNVER_DAEMON_ALLOW_NATIVE_WINDOWS")) return;
|
|
9760
|
+
console.error(
|
|
9761
|
+
JSON.stringify({
|
|
9762
|
+
event: "daemon_start_blocked",
|
|
9763
|
+
reason: "native_windows_console_flash",
|
|
9764
|
+
remedy: "Run the daemon inside WSL: .\\scripts\\start-tier2-wsl.ps1 \u2014 or set KYNVER_DAEMON_ALLOW_NATIVE_WINDOWS=1 to override (flashes visible consoles)."
|
|
9765
|
+
})
|
|
9766
|
+
);
|
|
9767
|
+
process.exit(1);
|
|
9768
|
+
}
|
|
9769
|
+
|
|
9770
|
+
// src/cron/cron-env.ts
|
|
9771
|
+
init_config();
|
|
9772
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
9773
|
+
import { homedir as homedir12 } from "node:os";
|
|
9774
|
+
import path38 from "node:path";
|
|
9775
|
+
function envFlag2(name, defaultValue) {
|
|
9065
9776
|
const raw = process.env[name]?.trim().toLowerCase();
|
|
9066
9777
|
if (!raw) return defaultValue;
|
|
9067
9778
|
if (raw === "0" || raw === "false" || raw === "no" || raw === "off") return false;
|
|
@@ -9076,7 +9787,7 @@ function envInt(name, fallback, min = 1) {
|
|
|
9076
9787
|
function defaultKynverCronStorePath() {
|
|
9077
9788
|
const explicit = process.env.KYNVER_CRON_STORE_PATH?.trim() || process.env.OPENCLAW_CRON_STORE_PATH?.trim();
|
|
9078
9789
|
if (explicit) return explicit;
|
|
9079
|
-
return
|
|
9790
|
+
return path38.join(homedir12(), ".kynver", "agent-os-cron.json");
|
|
9080
9791
|
}
|
|
9081
9792
|
function defaultKynverCronStatePath(storePath = defaultKynverCronStorePath()) {
|
|
9082
9793
|
const explicit = process.env.KYNVER_CRON_TICK_STATE_PATH?.trim();
|
|
@@ -9097,14 +9808,14 @@ function resolveKynverCronEnv() {
|
|
|
9097
9808
|
const secret = resolveKynverCronSecret();
|
|
9098
9809
|
const credsReady = Boolean(fireBaseUrl && secret);
|
|
9099
9810
|
const storeExists = existsSync27(storePath);
|
|
9100
|
-
const defaultEnabled = credsReady && (storeExists ||
|
|
9811
|
+
const defaultEnabled = credsReady && (storeExists || envFlag2("KYNVER_CRON_TICK_FORCE", false));
|
|
9101
9812
|
return {
|
|
9102
9813
|
storePath,
|
|
9103
9814
|
statePath,
|
|
9104
9815
|
lockPath: `${statePath}.lock`,
|
|
9105
9816
|
fireBaseUrl,
|
|
9106
9817
|
secret,
|
|
9107
|
-
tickEnabled:
|
|
9818
|
+
tickEnabled: envFlag2("KYNVER_CRON_TICK_ENABLED", defaultEnabled),
|
|
9108
9819
|
tickIntervalMs: envInt("KYNVER_CRON_TICK_INTERVAL_MS", 6e4, 5e3),
|
|
9109
9820
|
missedRunPolicy: process.env.KYNVER_CRON_MISSED_RUN_POLICY?.trim().toLowerCase() === "skip" ? "skip" : "catch_up",
|
|
9110
9821
|
maxCatchUpPerTick: envInt("KYNVER_CRON_MAX_CATCH_UP_PER_TICK", 3, 0),
|
|
@@ -9149,12 +9860,13 @@ async function fireKynverCronJob(input) {
|
|
|
9149
9860
|
}
|
|
9150
9861
|
|
|
9151
9862
|
// src/cron/cron-lock.ts
|
|
9152
|
-
|
|
9863
|
+
init_util();
|
|
9864
|
+
import { closeSync as closeSync6, existsSync as existsSync28, openSync as openSync6, readFileSync as readFileSync13, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9153
9865
|
var STALE_LOCK_MS = 10 * 6e4;
|
|
9154
9866
|
function readLockInfo(lockPath) {
|
|
9155
9867
|
if (!existsSync28(lockPath)) return null;
|
|
9156
9868
|
try {
|
|
9157
|
-
const parsed = JSON.parse(
|
|
9869
|
+
const parsed = JSON.parse(readFileSync13(lockPath, "utf8"));
|
|
9158
9870
|
if (typeof parsed.pid === "number" && typeof parsed.at === "string") return parsed;
|
|
9159
9871
|
} catch {
|
|
9160
9872
|
return null;
|
|
@@ -9185,7 +9897,7 @@ function tryAcquireCronTickLock(lockPath) {
|
|
|
9185
9897
|
}
|
|
9186
9898
|
try {
|
|
9187
9899
|
const fd = openSync6(lockPath, "wx");
|
|
9188
|
-
|
|
9900
|
+
writeFileSync5(
|
|
9189
9901
|
fd,
|
|
9190
9902
|
JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
9191
9903
|
"utf8"
|
|
@@ -9318,7 +10030,7 @@ async function loadCronJobs(storePath = defaultKynverCronStorePath()) {
|
|
|
9318
10030
|
// src/cron/cron-tick-state.ts
|
|
9319
10031
|
import { randomBytes } from "node:crypto";
|
|
9320
10032
|
import { promises as fs2 } from "node:fs";
|
|
9321
|
-
import
|
|
10033
|
+
import path39 from "node:path";
|
|
9322
10034
|
var EMPTY = { version: 1, jobs: {} };
|
|
9323
10035
|
async function readFileIfExists2(filePath) {
|
|
9324
10036
|
try {
|
|
@@ -9345,7 +10057,7 @@ async function loadCronTickState(statePath) {
|
|
|
9345
10057
|
return parseCronTickState(raw);
|
|
9346
10058
|
}
|
|
9347
10059
|
async function writeStateAtomic(statePath, state) {
|
|
9348
|
-
await fs2.mkdir(
|
|
10060
|
+
await fs2.mkdir(path39.dirname(statePath), { recursive: true });
|
|
9349
10061
|
const suffix = randomBytes(6).toString("hex");
|
|
9350
10062
|
const tmp = `${statePath}.tmp-${process.pid}-${Date.now()}-${suffix}`;
|
|
9351
10063
|
await fs2.writeFile(tmp, `${JSON.stringify(state, null, 2)}
|
|
@@ -9521,8 +10233,12 @@ async function runKynverCronTick(opts = {}) {
|
|
|
9521
10233
|
}
|
|
9522
10234
|
}
|
|
9523
10235
|
|
|
10236
|
+
// src/daemon.ts
|
|
10237
|
+
init_util();
|
|
10238
|
+
|
|
9524
10239
|
// src/pipeline-tick.ts
|
|
9525
|
-
import
|
|
10240
|
+
import path58 from "node:path";
|
|
10241
|
+
init_config();
|
|
9526
10242
|
|
|
9527
10243
|
// src/pipeline-dispatch.ts
|
|
9528
10244
|
var RESERVED_REVIEW_STARTS = 1;
|
|
@@ -9652,11 +10368,16 @@ function resolvePipelineMaxStarts(resourceGate, operatorTick) {
|
|
|
9652
10368
|
};
|
|
9653
10369
|
}
|
|
9654
10370
|
|
|
10371
|
+
// src/pipeline-tick.ts
|
|
10372
|
+
init_resource_gate();
|
|
10373
|
+
|
|
9655
10374
|
// src/box-resource-snapshot.ts
|
|
9656
|
-
|
|
10375
|
+
init_config();
|
|
10376
|
+
init_box_identity();
|
|
10377
|
+
import os10 from "node:os";
|
|
9657
10378
|
function buildBoxResourceSnapshotFromGate(gate, input = {}) {
|
|
9658
10379
|
const boxKind = (input.boxKind ?? resolveBoxKindFromConfig(loadUserConfig())).trim().toLowerCase() || "forge";
|
|
9659
|
-
const hostLabel = input.hostLabel ??
|
|
10380
|
+
const hostLabel = input.hostLabel ?? os10.hostname();
|
|
9660
10381
|
const boxId = input.boxId ?? defaultBoxId(boxKind, hostLabel);
|
|
9661
10382
|
return {
|
|
9662
10383
|
boxId,
|
|
@@ -9677,10 +10398,20 @@ function buildBoxResourceSnapshotFromGate(gate, input = {}) {
|
|
|
9677
10398
|
};
|
|
9678
10399
|
}
|
|
9679
10400
|
|
|
10401
|
+
// src/pipeline-tick.ts
|
|
10402
|
+
init_run_store();
|
|
10403
|
+
init_exited_salvage();
|
|
10404
|
+
init_status();
|
|
10405
|
+
init_util();
|
|
10406
|
+
|
|
9680
10407
|
// src/plan-progress-daemon-sync.ts
|
|
9681
|
-
|
|
10408
|
+
init_status();
|
|
10409
|
+
init_run_store();
|
|
10410
|
+
init_util();
|
|
10411
|
+
import path40 from "node:path";
|
|
9682
10412
|
|
|
9683
10413
|
// src/plan-progress-sync.ts
|
|
10414
|
+
init_config();
|
|
9684
10415
|
async function syncPlanProgress(args) {
|
|
9685
10416
|
const base = resolveBaseUrl(args.baseUrl);
|
|
9686
10417
|
const secret = await resolveCallbackSecretWithMint(args.secret, args.agentOsId, { baseUrl: base });
|
|
@@ -9702,7 +10433,7 @@ async function syncActiveWorkerPlanProgress(runId, args) {
|
|
|
9702
10433
|
const outcomes = [];
|
|
9703
10434
|
for (const name of Object.keys(run.workers || {})) {
|
|
9704
10435
|
const worker = readJson(
|
|
9705
|
-
|
|
10436
|
+
path40.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
9706
10437
|
void 0
|
|
9707
10438
|
);
|
|
9708
10439
|
if (!worker?.dispatched || !worker.taskId) continue;
|
|
@@ -9730,6 +10461,8 @@ async function syncActiveWorkerPlanProgress(runId, args) {
|
|
|
9730
10461
|
}
|
|
9731
10462
|
|
|
9732
10463
|
// src/workspace-runtime-config.ts
|
|
10464
|
+
init_config();
|
|
10465
|
+
init_box_identity();
|
|
9733
10466
|
function shouldApplyWorkspaceRuntimePreferences(env = process.env) {
|
|
9734
10467
|
const config = loadUserConfig();
|
|
9735
10468
|
return resolveBoxKindFromConfig(config, env) !== "forge";
|
|
@@ -9758,11 +10491,21 @@ async function fetchWorkspaceRuntimePreferences(agentOsId, args) {
|
|
|
9758
10491
|
}
|
|
9759
10492
|
}
|
|
9760
10493
|
|
|
10494
|
+
// src/pipeline-tick.ts
|
|
10495
|
+
init_config();
|
|
10496
|
+
init_box_identity();
|
|
10497
|
+
|
|
9761
10498
|
// src/cleanup.ts
|
|
9762
|
-
|
|
10499
|
+
init_paths();
|
|
10500
|
+
import path54 from "node:path";
|
|
9763
10501
|
|
|
9764
10502
|
// src/cleanup-guards.ts
|
|
9765
|
-
|
|
10503
|
+
init_landing_gate();
|
|
10504
|
+
import path41 from "node:path";
|
|
10505
|
+
|
|
10506
|
+
// src/cleanup-index-status.ts
|
|
10507
|
+
init_git();
|
|
10508
|
+
init_status();
|
|
9766
10509
|
|
|
9767
10510
|
// src/cleanup-build-cache-paths.ts
|
|
9768
10511
|
var HARNESS_BUILD_CACHE_RELATIVE_PATHS = [
|
|
@@ -9791,23 +10534,6 @@ function materialWorktreeChanges2(changedFiles) {
|
|
|
9791
10534
|
});
|
|
9792
10535
|
}
|
|
9793
10536
|
|
|
9794
|
-
// src/cleanup-index-status.ts
|
|
9795
|
-
function indexedWorktreeStatus(entry) {
|
|
9796
|
-
if (!entry.status) {
|
|
9797
|
-
entry.status = computeWorkerStatus(entry.worker, {
|
|
9798
|
-
base: entry.run.base,
|
|
9799
|
-
baseCommit: entry.run.baseCommit
|
|
9800
|
-
});
|
|
9801
|
-
}
|
|
9802
|
-
return entry.status;
|
|
9803
|
-
}
|
|
9804
|
-
function indexedWorktreeHasMaterialChanges(entry) {
|
|
9805
|
-
if (entry.status) {
|
|
9806
|
-
return materialWorktreeChanges2(entry.status.changedFiles).length > 0;
|
|
9807
|
-
}
|
|
9808
|
-
return materialWorktreeChanges2(gitStatusShort(entry.worktreePath)).length > 0;
|
|
9809
|
-
}
|
|
9810
|
-
|
|
9811
10537
|
// src/cleanup-worktree-salvage.ts
|
|
9812
10538
|
function prUrlFromFinalResult(finalResult) {
|
|
9813
10539
|
if (typeof finalResult === "string") {
|
|
@@ -9834,7 +10560,93 @@ function isPrOrUnmergedWork(status) {
|
|
|
9834
10560
|
return false;
|
|
9835
10561
|
}
|
|
9836
10562
|
|
|
10563
|
+
// src/cleanup-index-status.ts
|
|
10564
|
+
init_util();
|
|
10565
|
+
function indexedWorktreeStatus(entry) {
|
|
10566
|
+
if (!entry.status) {
|
|
10567
|
+
entry.status = computeWorkerStatus(entry.worker, {
|
|
10568
|
+
base: entry.run.base,
|
|
10569
|
+
baseCommit: entry.run.baseCommit
|
|
10570
|
+
});
|
|
10571
|
+
}
|
|
10572
|
+
return entry.status;
|
|
10573
|
+
}
|
|
10574
|
+
function indexedWorktreeHasMaterialChanges(entry, gitStatusCache) {
|
|
10575
|
+
if (entry.status) {
|
|
10576
|
+
return materialWorktreeChanges2(entry.status.changedFiles).length > 0;
|
|
10577
|
+
}
|
|
10578
|
+
const porcelain = gitStatusCache ? gitStatusCache.porcelain(entry.worktreePath) : gitStatusShort(entry.worktreePath);
|
|
10579
|
+
return materialWorktreeChanges2(porcelain).length > 0;
|
|
10580
|
+
}
|
|
10581
|
+
function finalResultFromWorkerJson(entry) {
|
|
10582
|
+
const snapshot = entry.worker.completionSnapshot?.finalResult;
|
|
10583
|
+
if (snapshot !== void 0 && snapshot !== null) return snapshot;
|
|
10584
|
+
if (entry.worker.taskPrUrl) {
|
|
10585
|
+
return { prUrl: entry.worker.taskPrUrl };
|
|
10586
|
+
}
|
|
10587
|
+
return null;
|
|
10588
|
+
}
|
|
10589
|
+
function resolveWorktreeGuardStatus(entry, ctx) {
|
|
10590
|
+
if (entry.status) return entry.status;
|
|
10591
|
+
const worker = entry.worker;
|
|
10592
|
+
const completionAcknowledged = typeof worker.completionReportedAt === "string" && worker.completionReportedAt.trim().length > 0;
|
|
10593
|
+
const workerJsonTerminal = Boolean(worker.status && ["done", "exited", "blocked", "failed", "abandoned"].includes(worker.status)) || completionAcknowledged;
|
|
10594
|
+
const finalResult = finalResultFromWorkerJson(entry);
|
|
10595
|
+
if (workerJsonTerminal && !isPidAlive(worker.pid)) {
|
|
10596
|
+
const changedFiles = ctx?.gitStatusCache ? ctx.gitStatusCache.porcelain(entry.worktreePath) : gitStatusShort(entry.worktreePath);
|
|
10597
|
+
const baseLabel = entry.run.baseCommit?.trim() || entry.run.base?.trim() || "origin/main";
|
|
10598
|
+
const ahead = ctx?.gitRevCache?.countAheadOfMain(entry.worktreePath, baseLabel);
|
|
10599
|
+
const gitAncestry = ahead === 0 ? {
|
|
10600
|
+
checked: true,
|
|
10601
|
+
base: baseLabel,
|
|
10602
|
+
relation: "synced"
|
|
10603
|
+
} : computeGitAncestry(entry.worktreePath, {
|
|
10604
|
+
base: entry.run.base,
|
|
10605
|
+
baseCommit: entry.run.baseCommit
|
|
10606
|
+
});
|
|
10607
|
+
const status = {
|
|
10608
|
+
runId: entry.runId,
|
|
10609
|
+
worker: entry.workerName,
|
|
10610
|
+
pid: worker.pid,
|
|
10611
|
+
alive: false,
|
|
10612
|
+
status: worker.status ?? (completionAcknowledged ? "done" : "exited"),
|
|
10613
|
+
attention: { state: completionAcknowledged ? "done" : "stale" },
|
|
10614
|
+
branch: worker.branch,
|
|
10615
|
+
worktreePath: entry.worktreePath,
|
|
10616
|
+
ownedPaths: worker.ownedPaths,
|
|
10617
|
+
stdoutBytes: 0,
|
|
10618
|
+
stderrBytes: 0,
|
|
10619
|
+
heartbeatBytes: 0,
|
|
10620
|
+
firstEventAt: null,
|
|
10621
|
+
lastEventAt: null,
|
|
10622
|
+
lastActivityAt: worker.completionReportedAt ?? null,
|
|
10623
|
+
currentTool: null,
|
|
10624
|
+
heartbeatCount: 0,
|
|
10625
|
+
lastHeartbeatAt: null,
|
|
10626
|
+
lastHeartbeatPhase: null,
|
|
10627
|
+
lastHeartbeatSummary: null,
|
|
10628
|
+
heartbeatBlocker: null,
|
|
10629
|
+
changedFiles,
|
|
10630
|
+
gitAncestry,
|
|
10631
|
+
finalResult,
|
|
10632
|
+
completionBlocker: typeof worker.completionBlocker === "string" ? worker.completionBlocker.trim() || null : null,
|
|
10633
|
+
prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? prUrlFromFinalResult(finalResult)
|
|
10634
|
+
};
|
|
10635
|
+
entry.status = status;
|
|
10636
|
+
return status;
|
|
10637
|
+
}
|
|
10638
|
+
return indexedWorktreeStatus(entry);
|
|
10639
|
+
}
|
|
10640
|
+
|
|
10641
|
+
// src/cleanup-guards.ts
|
|
10642
|
+
init_status();
|
|
10643
|
+
|
|
10644
|
+
// src/cleanup-run-liveness.ts
|
|
10645
|
+
init_status();
|
|
10646
|
+
|
|
9837
10647
|
// src/cleanup-completion-blocker.ts
|
|
10648
|
+
init_landing_gate();
|
|
10649
|
+
init_status();
|
|
9838
10650
|
function completionBlockerBlocksWorktreeRemoval(indexed, status) {
|
|
9839
10651
|
const blocker = typeof indexed.worker.completionBlocker === "string" ? indexed.worker.completionBlocker.trim() : "";
|
|
9840
10652
|
if (!blocker) return false;
|
|
@@ -9854,13 +10666,29 @@ function completionBlockerBlocksWorktreeRemoval(indexed, status) {
|
|
|
9854
10666
|
}
|
|
9855
10667
|
|
|
9856
10668
|
// src/cleanup-run-liveness.ts
|
|
10669
|
+
init_util();
|
|
10670
|
+
var TERMINAL_WORKER_JSON_STATUSES = /* @__PURE__ */ new Set([
|
|
10671
|
+
"done",
|
|
10672
|
+
"exited",
|
|
10673
|
+
"blocked",
|
|
10674
|
+
"failed",
|
|
10675
|
+
"abandoned"
|
|
10676
|
+
]);
|
|
9857
10677
|
function deriveRunTerminal(indexed, ctx) {
|
|
9858
10678
|
if (ctx) return ctx.runTerminalCache.derive(indexed.run);
|
|
9859
10679
|
return deriveTerminalRunStatus(indexed.run);
|
|
9860
10680
|
}
|
|
9861
10681
|
function isWorkerProcessLive(indexed) {
|
|
9862
10682
|
if (isPidAlive(indexed.worker.pid)) return true;
|
|
9863
|
-
if (
|
|
10683
|
+
if (typeof indexed.worker.completionReportedAt === "string" && indexed.worker.completionReportedAt.trim().length > 0) {
|
|
10684
|
+
return false;
|
|
10685
|
+
}
|
|
10686
|
+
const workerStatus2 = indexed.worker.status;
|
|
10687
|
+
if (workerStatus2 && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus2)) return false;
|
|
10688
|
+
if (!indexed.worker.pid) {
|
|
10689
|
+
if (workerStatus2 !== "running") return false;
|
|
10690
|
+
return indexedWorktreeStatus(indexed).alive;
|
|
10691
|
+
}
|
|
9864
10692
|
return false;
|
|
9865
10693
|
}
|
|
9866
10694
|
function isRunStaleActive(indexed, ctx) {
|
|
@@ -9869,6 +10697,10 @@ function isRunStaleActive(indexed, ctx) {
|
|
|
9869
10697
|
}
|
|
9870
10698
|
function runBlocksWorktreeRemoval(indexed, ctx) {
|
|
9871
10699
|
if (isWorkerProcessLive(indexed)) return true;
|
|
10700
|
+
const workerStatus2 = indexed.worker.status;
|
|
10701
|
+
if (workerStatus2 && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus2) && !indexed.worker.completionBlocker) {
|
|
10702
|
+
return false;
|
|
10703
|
+
}
|
|
9872
10704
|
const status = indexedWorktreeStatus(indexed);
|
|
9873
10705
|
if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return true;
|
|
9874
10706
|
if (isFinishedWorkerStatus(status)) return false;
|
|
@@ -9887,7 +10719,7 @@ function effectiveWorktreeAgeMs(input) {
|
|
|
9887
10719
|
if (input.liveness && isRunStaleActive(indexed, input.liveness)) {
|
|
9888
10720
|
return terminalWorktreesAgeMs;
|
|
9889
10721
|
}
|
|
9890
|
-
if (input.liveness && isFinishedWorkerStatus(
|
|
10722
|
+
if (input.liveness && isFinishedWorkerStatus(resolveWorktreeGuardStatus(indexed, input.liveness)) && !isWorkerProcessLive(indexed)) {
|
|
9891
10723
|
return terminalWorktreesAgeMs;
|
|
9892
10724
|
}
|
|
9893
10725
|
return worktreesAgeMs;
|
|
@@ -9901,8 +10733,13 @@ function skipWorktreeRemoval(input) {
|
|
|
9901
10733
|
const ageThresholdMs = effectiveWorktreeAgeMs(input);
|
|
9902
10734
|
if (worktreesAgeMs <= 0 && !includeOrphans && ageThresholdMs <= 0) return "worktrees_disabled";
|
|
9903
10735
|
if (ageThresholdMs > 0 && ageMs < ageThresholdMs) return "below_age_threshold";
|
|
9904
|
-
const status = indexedWorktreeStatus(indexed);
|
|
9905
10736
|
if (isWorkerProcessLive(indexed)) return "active_worker";
|
|
10737
|
+
if (indexedWorktreeHasMaterialChanges(indexed, input.liveness?.gitStatusCache)) {
|
|
10738
|
+
return "dirty_worktree";
|
|
10739
|
+
}
|
|
10740
|
+
const ahead = input.liveness?.gitRevCache?.countAheadOfMain(input.worktreePath);
|
|
10741
|
+
if (ahead !== null && ahead !== void 0 && ahead > 0) return "pr_or_unmerged_commits";
|
|
10742
|
+
const status = resolveWorktreeGuardStatus(indexed, input.liveness);
|
|
9906
10743
|
if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return "completion_blocked";
|
|
9907
10744
|
if (runBlocksWorktreeRemoval(indexed, input.liveness)) return "run_still_active";
|
|
9908
10745
|
if (!isFinishedWorkerStatus(status)) return "run_still_active";
|
|
@@ -9931,9 +10768,11 @@ function skipWorktreeRemoval(input) {
|
|
|
9931
10768
|
function skipDependencyCacheRemoval(input) {
|
|
9932
10769
|
const { indexed, nodeModulesAgeMs, ageMs, worktreePath, activeWorktreePaths, diskPressure } = input;
|
|
9933
10770
|
if (!diskPressure && ageMs < nodeModulesAgeMs) return "below_age_threshold";
|
|
9934
|
-
if (activeWorktreePaths.has(
|
|
10771
|
+
if (activeWorktreePaths.has(path41.resolve(worktreePath))) return "active_worker";
|
|
9935
10772
|
if (indexed && isWorkerProcessLive(indexed)) return "active_worker";
|
|
9936
|
-
if (indexed && indexedWorktreeHasMaterialChanges(indexed))
|
|
10773
|
+
if (indexed && indexedWorktreeHasMaterialChanges(indexed, input.gitStatusCache)) {
|
|
10774
|
+
return "dirty_worktree";
|
|
10775
|
+
}
|
|
9937
10776
|
return null;
|
|
9938
10777
|
}
|
|
9939
10778
|
function skipBuildCacheRemoval(input) {
|
|
@@ -9958,11 +10797,11 @@ var LIVE_SKIP_REASONS = /* @__PURE__ */ new Set([
|
|
|
9958
10797
|
function collectPreservedLivePaths(actions, skips) {
|
|
9959
10798
|
const out = [];
|
|
9960
10799
|
const seen = /* @__PURE__ */ new Set();
|
|
9961
|
-
const push = (
|
|
9962
|
-
const key = `${
|
|
10800
|
+
const push = (path73, reason, detail) => {
|
|
10801
|
+
const key = `${path73}\0${reason}`;
|
|
9963
10802
|
if (seen.has(key) || out.length >= MAX_PRESERVED_LIVE_PATH_SAMPLES) return;
|
|
9964
10803
|
seen.add(key);
|
|
9965
|
-
out.push({ path:
|
|
10804
|
+
out.push({ path: path73, reason, ...detail ? { detail } : {} });
|
|
9966
10805
|
};
|
|
9967
10806
|
for (const skip2 of skips) {
|
|
9968
10807
|
if (!LIVE_SKIP_REASONS.has(skip2.reason)) continue;
|
|
@@ -9978,11 +10817,14 @@ function collectPreservedLivePaths(actions, skips) {
|
|
|
9978
10817
|
|
|
9979
10818
|
// src/cleanup-run-directory.ts
|
|
9980
10819
|
import { existsSync as existsSync30, readdirSync as readdirSync9, statSync as statSync7 } from "node:fs";
|
|
9981
|
-
import
|
|
10820
|
+
import path43 from "node:path";
|
|
9982
10821
|
|
|
9983
10822
|
// src/cleanup-active-worktrees.ts
|
|
10823
|
+
init_run_store();
|
|
10824
|
+
init_paths();
|
|
9984
10825
|
import { existsSync as existsSync29, readdirSync as readdirSync8, statSync as statSync6 } from "node:fs";
|
|
9985
|
-
import
|
|
10826
|
+
import path42 from "node:path";
|
|
10827
|
+
init_util();
|
|
9986
10828
|
function workerHasRecentHarnessActivity(worker, now) {
|
|
9987
10829
|
const paths = [worker.heartbeatPath, worker.stdoutPath, worker.stderrPath];
|
|
9988
10830
|
for (const target of paths) {
|
|
@@ -10008,11 +10850,11 @@ function collectActiveWorktreeGuards(harnessRoots, now = Date.now()) {
|
|
|
10008
10850
|
let runHasLive = false;
|
|
10009
10851
|
for (const name of Object.keys(run.workers || {})) {
|
|
10010
10852
|
const worker = readJson(
|
|
10011
|
-
|
|
10853
|
+
path42.join(runDirectoryAt(harnessRoot, run.id), "workers", safeSlug(name), "worker.json"),
|
|
10012
10854
|
void 0
|
|
10013
10855
|
);
|
|
10014
10856
|
if (!worker?.worktreePath) continue;
|
|
10015
|
-
const worktreePath =
|
|
10857
|
+
const worktreePath = path42.resolve(worker.worktreePath);
|
|
10016
10858
|
if (!isActiveHarnessWorker2(worker, now)) continue;
|
|
10017
10859
|
runHasLive = true;
|
|
10018
10860
|
activeWorktreePaths.add(worktreePath);
|
|
@@ -10031,6 +10873,7 @@ function isWorktreeOnLiveRun(worktreePath, harnessRoot, runId, liveRunKeys) {
|
|
|
10031
10873
|
}
|
|
10032
10874
|
|
|
10033
10875
|
// src/cleanup-run-directory.ts
|
|
10876
|
+
init_util();
|
|
10034
10877
|
function pathAgeMs(target, now) {
|
|
10035
10878
|
try {
|
|
10036
10879
|
const mtime = statSync7(target).mtimeMs;
|
|
@@ -10040,7 +10883,7 @@ function pathAgeMs(target, now) {
|
|
|
10040
10883
|
}
|
|
10041
10884
|
}
|
|
10042
10885
|
function loadRunStatus(harnessRoot, runId) {
|
|
10043
|
-
const runPath =
|
|
10886
|
+
const runPath = path43.join(harnessRoot, "runs", runId, "run.json");
|
|
10044
10887
|
if (!existsSync30(runPath)) return null;
|
|
10045
10888
|
return readJson(runPath, null);
|
|
10046
10889
|
}
|
|
@@ -10078,7 +10921,7 @@ function scanStaleRunDirectoryCandidates(opts) {
|
|
|
10078
10921
|
if (!runEntry.isDirectory()) continue;
|
|
10079
10922
|
const runId = runEntry.name;
|
|
10080
10923
|
if (opts.runIdFilter && runId !== opts.runIdFilter) continue;
|
|
10081
|
-
const runPath =
|
|
10924
|
+
const runPath = path43.join(opts.worktreesDir, runId);
|
|
10082
10925
|
if (!runDirectoryIsEmpty(runPath)) continue;
|
|
10083
10926
|
candidates.push({
|
|
10084
10927
|
kind: "remove_run_directory",
|
|
@@ -10093,12 +10936,13 @@ function scanStaleRunDirectoryCandidates(opts) {
|
|
|
10093
10936
|
}
|
|
10094
10937
|
|
|
10095
10938
|
// src/cleanup-execute.ts
|
|
10939
|
+
init_git();
|
|
10096
10940
|
import { existsSync as existsSync33, rmSync as rmSync4 } from "node:fs";
|
|
10097
10941
|
|
|
10098
10942
|
// src/cleanup-dir-size.ts
|
|
10099
10943
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
10100
10944
|
import { existsSync as existsSync31, readdirSync as readdirSync10, statSync as statSync8 } from "node:fs";
|
|
10101
|
-
import
|
|
10945
|
+
import path44 from "node:path";
|
|
10102
10946
|
var DEFAULT_DU_TIMEOUT_MS = 2500;
|
|
10103
10947
|
function directorySizeBytesDu(root, timeoutMs = DEFAULT_DU_TIMEOUT_MS) {
|
|
10104
10948
|
if (!existsSync31(root)) return 0;
|
|
@@ -10132,7 +10976,7 @@ function directorySizeBytes(root, maxEntries = 5e4) {
|
|
|
10132
10976
|
}
|
|
10133
10977
|
for (const name of entries) {
|
|
10134
10978
|
if (seen++ > maxEntries) return null;
|
|
10135
|
-
const full =
|
|
10979
|
+
const full = path44.join(current, name);
|
|
10136
10980
|
let st;
|
|
10137
10981
|
try {
|
|
10138
10982
|
st = statSync8(full);
|
|
@@ -10148,6 +10992,7 @@ function directorySizeBytes(root, maxEntries = 5e4) {
|
|
|
10148
10992
|
|
|
10149
10993
|
// src/cleanup-remove-path.ts
|
|
10150
10994
|
import { existsSync as existsSync32, rmSync as rmSync3 } from "node:fs";
|
|
10995
|
+
init_paths();
|
|
10151
10996
|
|
|
10152
10997
|
// src/cleanup-path-ownership.ts
|
|
10153
10998
|
import { lstatSync as lstatSync2, readdirSync as readdirSync11 } from "node:fs";
|
|
@@ -10183,20 +11028,20 @@ function pathHasForeignOwnedEntry(targetPath, maxEntries = 32) {
|
|
|
10183
11028
|
|
|
10184
11029
|
// src/cleanup-privileged-remove.ts
|
|
10185
11030
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
10186
|
-
import
|
|
11031
|
+
import path46 from "node:path";
|
|
10187
11032
|
|
|
10188
11033
|
// src/cleanup-harness-path-validate.ts
|
|
10189
|
-
import
|
|
11034
|
+
import path45 from "node:path";
|
|
10190
11035
|
function isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, cacheDirName) {
|
|
10191
|
-
const resolved =
|
|
10192
|
-
const suffix = `${
|
|
11036
|
+
const resolved = path45.resolve(targetPath);
|
|
11037
|
+
const suffix = `${path45.sep}${cacheDirName}`;
|
|
10193
11038
|
const cachePath = resolved.endsWith(suffix) ? resolved : null;
|
|
10194
11039
|
if (!cachePath) return "path_outside_harness";
|
|
10195
|
-
const rel =
|
|
10196
|
-
if (rel.startsWith("..") ||
|
|
10197
|
-
const parts = rel.split(
|
|
11040
|
+
const rel = path45.relative(worktreesDir, cachePath);
|
|
11041
|
+
if (rel.startsWith("..") || path45.isAbsolute(rel)) return "path_outside_harness";
|
|
11042
|
+
const parts = rel.split(path45.sep);
|
|
10198
11043
|
if (parts.length < 3 || parts[parts.length - 1] !== cacheDirName) return "path_outside_harness";
|
|
10199
|
-
if (!resolved.startsWith(
|
|
11044
|
+
if (!resolved.startsWith(path45.resolve(harnessRoot))) return "path_outside_harness";
|
|
10200
11045
|
return null;
|
|
10201
11046
|
}
|
|
10202
11047
|
function isHarnessNodeModulesPath(targetPath, harnessRoot, worktreesDir) {
|
|
@@ -10206,16 +11051,16 @@ function isHarnessNextCachePath(targetPath, harnessRoot, worktreesDir) {
|
|
|
10206
11051
|
return isHarnessDependencyCachePath(targetPath, harnessRoot, worktreesDir, ".next");
|
|
10207
11052
|
}
|
|
10208
11053
|
function isHarnessBuildCachePath(targetPath, harnessRoot, worktreesDir) {
|
|
10209
|
-
const resolved =
|
|
10210
|
-
const relToWt =
|
|
10211
|
-
if (relToWt.startsWith("..") ||
|
|
10212
|
-
const parts = relToWt.split(
|
|
11054
|
+
const resolved = path45.resolve(targetPath);
|
|
11055
|
+
const relToWt = path45.relative(worktreesDir, resolved);
|
|
11056
|
+
if (relToWt.startsWith("..") || path45.isAbsolute(relToWt)) return "path_outside_harness";
|
|
11057
|
+
const parts = relToWt.split(path45.sep);
|
|
10213
11058
|
if (parts.length < 3) return "path_outside_harness";
|
|
10214
|
-
if (!resolved.startsWith(
|
|
11059
|
+
if (!resolved.startsWith(path45.resolve(harnessRoot))) return "path_outside_harness";
|
|
10215
11060
|
return null;
|
|
10216
11061
|
}
|
|
10217
11062
|
function isHarnessGeneratedCachePath(targetPath, harnessRoot, worktreesDir) {
|
|
10218
|
-
const resolved =
|
|
11063
|
+
const resolved = path45.resolve(targetPath);
|
|
10219
11064
|
return isHarnessNodeModulesPath(resolved, harnessRoot, worktreesDir) === null || isHarnessNextCachePath(resolved, harnessRoot, worktreesDir) === null || isHarnessBuildCachePath(resolved, harnessRoot, worktreesDir) === null;
|
|
10220
11065
|
}
|
|
10221
11066
|
|
|
@@ -10249,12 +11094,12 @@ function tryPrivilegedReclaimHarnessCache(targetPath, harnessRoot, worktreesDir)
|
|
|
10249
11094
|
"chown",
|
|
10250
11095
|
"-R",
|
|
10251
11096
|
`${effectiveUid}:${effectiveGid}`,
|
|
10252
|
-
|
|
11097
|
+
path46.resolve(targetPath)
|
|
10253
11098
|
]);
|
|
10254
11099
|
if (chown.ok) {
|
|
10255
11100
|
return { ok: true, method: "chown_then_rm" };
|
|
10256
11101
|
}
|
|
10257
|
-
const rm = runSudoNonInteractive(["rm", "-rf",
|
|
11102
|
+
const rm = runSudoNonInteractive(["rm", "-rf", path46.resolve(targetPath)]);
|
|
10258
11103
|
if (rm.ok) {
|
|
10259
11104
|
return { ok: true, method: "sudo_rm" };
|
|
10260
11105
|
}
|
|
@@ -10456,7 +11301,7 @@ function removeWorktree(candidate, execute) {
|
|
|
10456
11301
|
|
|
10457
11302
|
// src/cleanup-scan.ts
|
|
10458
11303
|
import { existsSync as existsSync34, readdirSync as readdirSync12, statSync as statSync9 } from "node:fs";
|
|
10459
|
-
import
|
|
11304
|
+
import path47 from "node:path";
|
|
10460
11305
|
function pathAgeMs2(target, now) {
|
|
10461
11306
|
try {
|
|
10462
11307
|
const mtime = statSync9(target).mtimeMs;
|
|
@@ -10466,16 +11311,16 @@ function pathAgeMs2(target, now) {
|
|
|
10466
11311
|
}
|
|
10467
11312
|
}
|
|
10468
11313
|
function isPathInside(child, parent) {
|
|
10469
|
-
const rel =
|
|
10470
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
11314
|
+
const rel = path47.relative(parent, child);
|
|
11315
|
+
return rel === "" || !rel.startsWith("..") && !path47.isAbsolute(rel);
|
|
10471
11316
|
}
|
|
10472
11317
|
function collectBuildCacheForWorktree(worktreePath, opts, seen, meta) {
|
|
10473
11318
|
const out = [];
|
|
10474
11319
|
for (const rel of HARNESS_BUILD_CACHE_RELATIVE_PATHS) {
|
|
10475
11320
|
if (rel === ".next") continue;
|
|
10476
|
-
const target =
|
|
11321
|
+
const target = path47.join(worktreePath, rel);
|
|
10477
11322
|
if (!existsSync34(target)) continue;
|
|
10478
|
-
const resolved =
|
|
11323
|
+
const resolved = path47.resolve(target);
|
|
10479
11324
|
if (seen.has(resolved)) continue;
|
|
10480
11325
|
if (!isPathInside(resolved, opts.harnessRoot)) continue;
|
|
10481
11326
|
seen.add(resolved);
|
|
@@ -10507,10 +11352,10 @@ function scanBuildCacheCandidates(opts) {
|
|
|
10507
11352
|
if (!opts.includeOrphans || !existsSync34(opts.worktreesDir)) return candidates;
|
|
10508
11353
|
for (const runEntry of readdirSync12(opts.worktreesDir, { withFileTypes: true })) {
|
|
10509
11354
|
if (!runEntry.isDirectory()) continue;
|
|
10510
|
-
const runPath =
|
|
11355
|
+
const runPath = path47.join(opts.worktreesDir, runEntry.name);
|
|
10511
11356
|
for (const workerEntry of readdirSync12(runPath, { withFileTypes: true })) {
|
|
10512
11357
|
if (!workerEntry.isDirectory()) continue;
|
|
10513
|
-
const worktreePath =
|
|
11358
|
+
const worktreePath = path47.join(runPath, workerEntry.name);
|
|
10514
11359
|
candidates.push(
|
|
10515
11360
|
...collectBuildCacheForWorktree(worktreePath, opts, seen, {
|
|
10516
11361
|
runId: runEntry.name,
|
|
@@ -10548,12 +11393,12 @@ function scanWorktreeCandidates(opts) {
|
|
|
10548
11393
|
if (!orphanEnabled || !existsSync34(opts.worktreesDir)) return candidates;
|
|
10549
11394
|
const indexedPaths = /* @__PURE__ */ new Set();
|
|
10550
11395
|
for (const entry of opts.index.values()) {
|
|
10551
|
-
indexedPaths.add(
|
|
11396
|
+
indexedPaths.add(path47.resolve(entry.worktreePath));
|
|
10552
11397
|
}
|
|
10553
11398
|
for (const runEntry of readdirSync12(opts.worktreesDir, { withFileTypes: true })) {
|
|
10554
11399
|
if (!runEntry.isDirectory()) continue;
|
|
10555
11400
|
if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;
|
|
10556
|
-
const runPath =
|
|
11401
|
+
const runPath = path47.join(opts.worktreesDir, runEntry.name);
|
|
10557
11402
|
let workerEntries;
|
|
10558
11403
|
try {
|
|
10559
11404
|
workerEntries = readdirSync12(runPath, { withFileTypes: true });
|
|
@@ -10562,7 +11407,7 @@ function scanWorktreeCandidates(opts) {
|
|
|
10562
11407
|
}
|
|
10563
11408
|
for (const workerEntry of workerEntries) {
|
|
10564
11409
|
if (!workerEntry.isDirectory()) continue;
|
|
10565
|
-
const worktreePath =
|
|
11410
|
+
const worktreePath = path47.resolve(path47.join(runPath, workerEntry.name));
|
|
10566
11411
|
if (seen.has(worktreePath)) continue;
|
|
10567
11412
|
if (indexedPaths.has(worktreePath)) continue;
|
|
10568
11413
|
if (!isPathInside(worktreePath, opts.harnessRoot)) continue;
|
|
@@ -10582,7 +11427,7 @@ function scanWorktreeCandidates(opts) {
|
|
|
10582
11427
|
|
|
10583
11428
|
// src/cleanup-dependency-scan.ts
|
|
10584
11429
|
import { existsSync as existsSync35, readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
|
|
10585
|
-
import
|
|
11430
|
+
import path48 from "node:path";
|
|
10586
11431
|
var DEPENDENCY_CACHE_DIRS = [
|
|
10587
11432
|
{ dirName: "node_modules", kind: "remove_node_modules" },
|
|
10588
11433
|
{ dirName: ".next", kind: "remove_next_cache" }
|
|
@@ -10596,12 +11441,12 @@ function pathAgeMs3(target, now) {
|
|
|
10596
11441
|
}
|
|
10597
11442
|
}
|
|
10598
11443
|
function isPathInside2(child, parent) {
|
|
10599
|
-
const rel =
|
|
10600
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
11444
|
+
const rel = path48.relative(parent, child);
|
|
11445
|
+
return rel === "" || !rel.startsWith("..") && !path48.isAbsolute(rel);
|
|
10601
11446
|
}
|
|
10602
11447
|
function pushCandidate2(candidates, seen, opts, targetPath, kind, meta) {
|
|
10603
11448
|
if (!existsSync35(targetPath)) return;
|
|
10604
|
-
const resolved =
|
|
11449
|
+
const resolved = path48.resolve(targetPath);
|
|
10605
11450
|
if (seen.has(resolved)) return;
|
|
10606
11451
|
if (!isPathInside2(resolved, opts.harnessRoot)) return;
|
|
10607
11452
|
seen.add(resolved);
|
|
@@ -10618,7 +11463,7 @@ function pushCandidate2(candidates, seen, opts, targetPath, kind, meta) {
|
|
|
10618
11463
|
}
|
|
10619
11464
|
function scanWorktreeDependencyCaches(candidates, seen, opts, worktreePath, meta) {
|
|
10620
11465
|
for (const entry of DEPENDENCY_CACHE_DIRS) {
|
|
10621
|
-
pushCandidate2(candidates, seen, opts,
|
|
11466
|
+
pushCandidate2(candidates, seen, opts, path48.join(worktreePath, entry.dirName), entry.kind, meta);
|
|
10622
11467
|
}
|
|
10623
11468
|
}
|
|
10624
11469
|
function scanDependencyCacheCandidates(opts) {
|
|
@@ -10636,7 +11481,7 @@ function scanDependencyCacheCandidates(opts) {
|
|
|
10636
11481
|
for (const runEntry of readdirSync13(opts.worktreesDir, { withFileTypes: true })) {
|
|
10637
11482
|
if (!runEntry.isDirectory()) continue;
|
|
10638
11483
|
if (opts.runIdFilter && runEntry.name !== opts.runIdFilter) continue;
|
|
10639
|
-
const runPath =
|
|
11484
|
+
const runPath = path48.join(opts.worktreesDir, runEntry.name);
|
|
10640
11485
|
let workerEntries;
|
|
10641
11486
|
try {
|
|
10642
11487
|
workerEntries = readdirSync13(runPath, { withFileTypes: true });
|
|
@@ -10645,7 +11490,7 @@ function scanDependencyCacheCandidates(opts) {
|
|
|
10645
11490
|
}
|
|
10646
11491
|
for (const workerEntry of workerEntries) {
|
|
10647
11492
|
if (!workerEntry.isDirectory()) continue;
|
|
10648
|
-
const worktreePath =
|
|
11493
|
+
const worktreePath = path48.join(runPath, workerEntry.name);
|
|
10649
11494
|
scanWorktreeDependencyCaches(candidates, seen, opts, worktreePath, {
|
|
10650
11495
|
runId: runEntry.name,
|
|
10651
11496
|
worker: workerEntry.name
|
|
@@ -10656,8 +11501,9 @@ function scanDependencyCacheCandidates(opts) {
|
|
|
10656
11501
|
}
|
|
10657
11502
|
|
|
10658
11503
|
// src/cleanup-duplicate-worktrees.ts
|
|
11504
|
+
init_git();
|
|
10659
11505
|
import { existsSync as existsSync36, statSync as statSync11 } from "node:fs";
|
|
10660
|
-
import
|
|
11506
|
+
import path49 from "node:path";
|
|
10661
11507
|
function pathAgeMs4(target, now) {
|
|
10662
11508
|
try {
|
|
10663
11509
|
const mtime = statSync11(target).mtimeMs;
|
|
@@ -10687,8 +11533,8 @@ function parseWorktreePorcelain(output) {
|
|
|
10687
11533
|
return records;
|
|
10688
11534
|
}
|
|
10689
11535
|
function isUnderWorktreesDir(worktreePath, worktreesDir) {
|
|
10690
|
-
const rel =
|
|
10691
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
11536
|
+
const rel = path49.relative(path49.resolve(worktreesDir), path49.resolve(worktreePath));
|
|
11537
|
+
return rel !== "" && !rel.startsWith("..") && !path49.isAbsolute(rel);
|
|
10692
11538
|
}
|
|
10693
11539
|
function isCleanWorktree(worktreePath, repoRoot) {
|
|
10694
11540
|
try {
|
|
@@ -10704,11 +11550,11 @@ function scanDuplicateWorktreeCandidates(opts) {
|
|
|
10704
11550
|
if (!opts.includeOrphans || !existsSync36(opts.worktreesDir)) return [];
|
|
10705
11551
|
const repos = /* @__PURE__ */ new Set();
|
|
10706
11552
|
for (const entry of opts.index.values()) {
|
|
10707
|
-
if (entry.run.repo) repos.add(
|
|
11553
|
+
if (entry.run.repo) repos.add(path49.resolve(entry.run.repo));
|
|
10708
11554
|
}
|
|
10709
11555
|
const indexedPaths = /* @__PURE__ */ new Set();
|
|
10710
11556
|
for (const entry of opts.index.values()) {
|
|
10711
|
-
indexedPaths.add(
|
|
11557
|
+
indexedPaths.add(path49.resolve(entry.worktreePath));
|
|
10712
11558
|
}
|
|
10713
11559
|
const candidates = [];
|
|
10714
11560
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -10721,15 +11567,15 @@ function scanDuplicateWorktreeCandidates(opts) {
|
|
|
10721
11567
|
}
|
|
10722
11568
|
const worktrees = parseWorktreePorcelain(porcelain);
|
|
10723
11569
|
for (const wt of worktrees) {
|
|
10724
|
-
const resolved =
|
|
10725
|
-
if (resolved ===
|
|
11570
|
+
const resolved = path49.resolve(wt.path);
|
|
11571
|
+
if (resolved === path49.resolve(repoRoot)) continue;
|
|
10726
11572
|
if (!isUnderWorktreesDir(resolved, opts.worktreesDir)) continue;
|
|
10727
11573
|
if (indexedPaths.has(resolved)) continue;
|
|
10728
11574
|
if (seen.has(resolved)) continue;
|
|
10729
11575
|
if (!existsSync36(resolved)) continue;
|
|
10730
11576
|
if (!isCleanWorktree(resolved, repoRoot)) continue;
|
|
10731
|
-
const rel =
|
|
10732
|
-
const parts = rel.split(
|
|
11577
|
+
const rel = path49.relative(opts.worktreesDir, resolved);
|
|
11578
|
+
const parts = rel.split(path49.sep);
|
|
10733
11579
|
const runId = parts[0];
|
|
10734
11580
|
const worker = parts[1] ?? "unknown";
|
|
10735
11581
|
seen.add(resolved);
|
|
@@ -10748,12 +11594,14 @@ function scanDuplicateWorktreeCandidates(opts) {
|
|
|
10748
11594
|
}
|
|
10749
11595
|
|
|
10750
11596
|
// src/cleanup-worktree-index.ts
|
|
10751
|
-
|
|
11597
|
+
init_run_store();
|
|
11598
|
+
init_util();
|
|
11599
|
+
import path50 from "node:path";
|
|
10752
11600
|
function buildWorktreeIndexAt(harnessRoot) {
|
|
10753
11601
|
const index = /* @__PURE__ */ new Map();
|
|
10754
11602
|
for (const run of listRunRecordsForHarnessRoot(harnessRoot)) {
|
|
10755
11603
|
for (const name of Object.keys(run.workers || {})) {
|
|
10756
|
-
const workerPath =
|
|
11604
|
+
const workerPath = path50.join(
|
|
10757
11605
|
runDirectoryAt(harnessRoot, run.id),
|
|
10758
11606
|
"workers",
|
|
10759
11607
|
safeSlug(name),
|
|
@@ -10761,9 +11609,9 @@ function buildWorktreeIndexAt(harnessRoot) {
|
|
|
10761
11609
|
);
|
|
10762
11610
|
const worker = readJson(workerPath, void 0);
|
|
10763
11611
|
if (!worker?.worktreePath) continue;
|
|
10764
|
-
index.set(
|
|
11612
|
+
index.set(path50.resolve(worker.worktreePath), {
|
|
10765
11613
|
harnessRoot,
|
|
10766
|
-
worktreePath:
|
|
11614
|
+
worktreePath: path50.resolve(worker.worktreePath),
|
|
10767
11615
|
runId: run.id,
|
|
10768
11616
|
workerName: name,
|
|
10769
11617
|
run,
|
|
@@ -10775,7 +11623,7 @@ function buildWorktreeIndexAt(harnessRoot) {
|
|
|
10775
11623
|
}
|
|
10776
11624
|
|
|
10777
11625
|
// src/cleanup-retention-config.ts
|
|
10778
|
-
function
|
|
11626
|
+
function envFlag3(name) {
|
|
10779
11627
|
const v = process.env[name];
|
|
10780
11628
|
return v === "1" || v === "true" || v === "yes";
|
|
10781
11629
|
}
|
|
@@ -10786,17 +11634,17 @@ function envMs(name, fallback) {
|
|
|
10786
11634
|
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
10787
11635
|
}
|
|
10788
11636
|
function resolveHarnessRetention(options = {}) {
|
|
10789
|
-
const execute = options.execute === true || options.execute !== false &&
|
|
10790
|
-
const finalizeStaleRuns2 = options.finalizeStaleRuns !== false && !
|
|
11637
|
+
const execute = options.execute === true || options.execute !== false && envFlag3("KYNVER_CLEANUP_EXECUTE");
|
|
11638
|
+
const finalizeStaleRuns2 = options.finalizeStaleRuns !== false && !envFlag3("KYNVER_CLEANUP_SKIP_FINALIZE");
|
|
10791
11639
|
const nodeModulesAgeMs = options.nodeModulesAgeMs ?? envMs("KYNVER_CLEANUP_NODE_MODULES_AGE_MS", DEFAULT_NODE_MODULES_AGE_MS);
|
|
10792
11640
|
const worktreesAgeMs = options.worktreesAgeMs ?? envMs("KYNVER_CLEANUP_WORKTREES_AGE_MS", 0);
|
|
10793
11641
|
const terminalWorktreesAgeMs = options.terminalWorktreesAgeMs ?? envMs("KYNVER_CLEANUP_TERMINAL_WORKTREES_AGE_MS", DEFAULT_TERMINAL_WORKTREES_AGE_MS);
|
|
10794
11642
|
const runDirectoriesAgeMs = options.runDirectoriesAgeMs ?? envMs("KYNVER_CLEANUP_RUN_DIRECTORIES_AGE_MS", DEFAULT_RUN_DIRECTORIES_AGE_MS);
|
|
10795
11643
|
const maxActionsPerSweep = options.maxActionsPerSweep ?? envMs("KYNVER_CLEANUP_MAX_ACTIONS_PER_SWEEP", DEFAULT_MAX_ACTIONS_PER_SWEEP);
|
|
10796
|
-
const includeOrphans = options.includeOrphans === true ||
|
|
10797
|
-
const scopeAll =
|
|
11644
|
+
const includeOrphans = options.includeOrphans === true || envFlag3("KYNVER_CLEANUP_INCLUDE_ORPHANS");
|
|
11645
|
+
const scopeAll = envFlag3("KYNVER_CLEANUP_SCOPE_ALL") || process.env.KYNVER_CLEANUP_SCOPE === "all";
|
|
10798
11646
|
const runIdFilter = scopeAll ? options.runIdFilter : options.runIdFilter ?? (process.env.KYNVER_CLEANUP_RUN_ID || void 0);
|
|
10799
|
-
const accountBytes = options.accountBytes !== false && !
|
|
11647
|
+
const accountBytes = options.accountBytes !== false && !envFlag3("KYNVER_CLEANUP_SKIP_BYTE_ACCOUNTING");
|
|
10800
11648
|
const storageCapEnv = envMs("KYNVER_CLEANUP_STORAGE_ENTRY_CAP", 2e3);
|
|
10801
11649
|
const storagePerRunEntryCap = options.storagePerRunEntryCap !== void 0 ? options.storagePerRunEntryCap : accountBytes ? storageCapEnv > 0 ? storageCapEnv : null : null;
|
|
10802
11650
|
const byteCapEnv = envMs("KYNVER_CLEANUP_BYTE_ENTRY_CAP", 2e3);
|
|
@@ -10832,15 +11680,16 @@ function resolvePipelineHarnessRetention(runId) {
|
|
|
10832
11680
|
}
|
|
10833
11681
|
|
|
10834
11682
|
// src/cleanup-orphan-safety.ts
|
|
11683
|
+
init_git();
|
|
10835
11684
|
import { existsSync as existsSync37, statSync as statSync12 } from "node:fs";
|
|
10836
|
-
import
|
|
11685
|
+
import path51 from "node:path";
|
|
10837
11686
|
var DEFAULT_HEARTBEAT_FRESH_MS = 30 * 60 * 1e3;
|
|
10838
11687
|
function assessOrphanWorktreeSafety(input) {
|
|
10839
11688
|
const now = input.now ?? Date.now();
|
|
10840
11689
|
const heartbeatFreshMs = input.heartbeatFreshMs ?? DEFAULT_HEARTBEAT_FRESH_MS;
|
|
10841
11690
|
if (!existsSync37(input.worktreePath)) return null;
|
|
10842
11691
|
if (input.runId && input.workerName) {
|
|
10843
|
-
const heartbeatPath =
|
|
11692
|
+
const heartbeatPath = path51.join(
|
|
10844
11693
|
input.harnessRoot,
|
|
10845
11694
|
"runs",
|
|
10846
11695
|
input.runId,
|
|
@@ -10854,7 +11703,7 @@ function assessOrphanWorktreeSafety(input) {
|
|
|
10854
11703
|
} catch {
|
|
10855
11704
|
}
|
|
10856
11705
|
}
|
|
10857
|
-
const gitDir =
|
|
11706
|
+
const gitDir = path51.join(input.worktreePath, ".git");
|
|
10858
11707
|
if (!existsSync37(gitDir)) return null;
|
|
10859
11708
|
const porcelain = gitCapture(input.worktreePath, ["status", "--porcelain"]);
|
|
10860
11709
|
if (porcelain.status !== 0) return "pr_or_unmerged_commits";
|
|
@@ -10884,8 +11733,9 @@ function assessOrphanWorktreeSafety(input) {
|
|
|
10884
11733
|
}
|
|
10885
11734
|
|
|
10886
11735
|
// src/harness-storage-snapshot.ts
|
|
11736
|
+
init_paths();
|
|
10887
11737
|
import { existsSync as existsSync38, readdirSync as readdirSync14, statSync as statSync13 } from "node:fs";
|
|
10888
|
-
import
|
|
11738
|
+
import path52 from "node:path";
|
|
10889
11739
|
function harnessStorageSnapshot(opts = {}) {
|
|
10890
11740
|
const harnessRoot = normalizeHarnessRoot(opts.harnessRoot ?? resolveHarnessRoot());
|
|
10891
11741
|
const worktreesDir = harnessWorktreesDir(harnessRoot);
|
|
@@ -10923,7 +11773,7 @@ function harnessStorageSnapshot(opts = {}) {
|
|
|
10923
11773
|
for (const runEntry of entries) {
|
|
10924
11774
|
if (!runEntry.isDirectory()) continue;
|
|
10925
11775
|
runCount += 1;
|
|
10926
|
-
const runPath =
|
|
11776
|
+
const runPath = path52.join(worktreesDir, runEntry.name);
|
|
10927
11777
|
try {
|
|
10928
11778
|
const st = statSync13(runPath);
|
|
10929
11779
|
oldestMs = oldestMs === null ? st.mtimeMs : Math.min(oldestMs, st.mtimeMs);
|
|
@@ -10958,12 +11808,13 @@ function harnessStorageSnapshot(opts = {}) {
|
|
|
10958
11808
|
}
|
|
10959
11809
|
|
|
10960
11810
|
// src/cleanup-harness-roots.ts
|
|
11811
|
+
init_paths();
|
|
10961
11812
|
import { existsSync as existsSync39 } from "node:fs";
|
|
10962
|
-
import { homedir as
|
|
10963
|
-
import
|
|
11813
|
+
import { homedir as homedir13 } from "node:os";
|
|
11814
|
+
import path53 from "node:path";
|
|
10964
11815
|
var WELL_KNOWN_HARNESS_SCAN_ROOTS = [
|
|
10965
11816
|
"/var/tmp/kynver-harness",
|
|
10966
|
-
|
|
11817
|
+
path53.join(homedir13(), ".openclaw", "harness")
|
|
10967
11818
|
];
|
|
10968
11819
|
function addRoot(seen, roots, candidate) {
|
|
10969
11820
|
if (!candidate?.trim()) return;
|
|
@@ -10985,7 +11836,7 @@ function resolveHarnessScanRoots(options = {}) {
|
|
|
10985
11836
|
for (const candidate of extra ?? []) addRoot(seen, roots, candidate);
|
|
10986
11837
|
if (shouldScanWellKnownRoots(options)) {
|
|
10987
11838
|
for (const candidate of WELL_KNOWN_HARNESS_SCAN_ROOTS) {
|
|
10988
|
-
const resolved =
|
|
11839
|
+
const resolved = path53.resolve(candidate);
|
|
10989
11840
|
if (!seen.has(resolved) && existsSync39(resolved)) addRoot(seen, roots, resolved);
|
|
10990
11841
|
}
|
|
10991
11842
|
}
|
|
@@ -10993,7 +11844,8 @@ function resolveHarnessScanRoots(options = {}) {
|
|
|
10993
11844
|
}
|
|
10994
11845
|
|
|
10995
11846
|
// src/cleanup-disk-pressure.ts
|
|
10996
|
-
|
|
11847
|
+
init_disk_gate();
|
|
11848
|
+
function envFlag4(name) {
|
|
10997
11849
|
const v = process.env[name];
|
|
10998
11850
|
return v === "1" || v === "true" || v === "yes";
|
|
10999
11851
|
}
|
|
@@ -11016,7 +11868,7 @@ function observeCleanupDiskPressure(input = {}) {
|
|
|
11016
11868
|
}
|
|
11017
11869
|
function applyDiskPressureToRetention(retention, pressure) {
|
|
11018
11870
|
if (!pressure.pressured) return retention;
|
|
11019
|
-
const executeOnPressure = retention.execute || !
|
|
11871
|
+
const executeOnPressure = retention.execute || !envFlag4("KYNVER_CLEANUP_DRY_RUN_ON_PRESSURE");
|
|
11020
11872
|
return {
|
|
11021
11873
|
...retention,
|
|
11022
11874
|
execute: executeOnPressure,
|
|
@@ -11041,6 +11893,39 @@ function emitCleanupProgress(phase, detail) {
|
|
|
11041
11893
|
console.error(`[kynver cleanup] ${phase}${suffix}`);
|
|
11042
11894
|
}
|
|
11043
11895
|
|
|
11896
|
+
// src/cleanup-git-rev-cache.ts
|
|
11897
|
+
init_git();
|
|
11898
|
+
var CleanupGitRevCache = class {
|
|
11899
|
+
aheadOfMain = /* @__PURE__ */ new Map();
|
|
11900
|
+
countAheadOfMain(worktreePath, base = "origin/main") {
|
|
11901
|
+
const key = `${worktreePath}\0${base}`;
|
|
11902
|
+
if (this.aheadOfMain.has(key)) return this.aheadOfMain.get(key) ?? null;
|
|
11903
|
+
const result = gitCapture(worktreePath, ["rev-list", "--count", `${base}..HEAD`]);
|
|
11904
|
+
if (result.status !== 0) {
|
|
11905
|
+
this.aheadOfMain.set(key, null);
|
|
11906
|
+
return null;
|
|
11907
|
+
}
|
|
11908
|
+
const count = Number(result.stdout.trim());
|
|
11909
|
+
const parsed = Number.isFinite(count) ? count : null;
|
|
11910
|
+
this.aheadOfMain.set(key, parsed);
|
|
11911
|
+
return parsed;
|
|
11912
|
+
}
|
|
11913
|
+
};
|
|
11914
|
+
|
|
11915
|
+
// src/cleanup-git-status-cache.ts
|
|
11916
|
+
init_git();
|
|
11917
|
+
var CleanupGitStatusCache = class {
|
|
11918
|
+
cache = /* @__PURE__ */ new Map();
|
|
11919
|
+
porcelain(worktreePath) {
|
|
11920
|
+
const resolved = worktreePath;
|
|
11921
|
+
const cached = this.cache.get(resolved);
|
|
11922
|
+
if (cached !== void 0) return cached;
|
|
11923
|
+
const lines = gitStatusShort(resolved);
|
|
11924
|
+
this.cache.set(resolved, lines);
|
|
11925
|
+
return lines;
|
|
11926
|
+
}
|
|
11927
|
+
};
|
|
11928
|
+
|
|
11044
11929
|
// src/cleanup-run-terminal-cache.ts
|
|
11045
11930
|
var CleanupRunTerminalCache = class {
|
|
11046
11931
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -11140,9 +12025,9 @@ function mergeWorktreeIndexes(scanRoots) {
|
|
|
11140
12025
|
}
|
|
11141
12026
|
function worktreePathForCandidate(candidate, worktreesDir) {
|
|
11142
12027
|
if (candidate.runId && candidate.worker) {
|
|
11143
|
-
return
|
|
12028
|
+
return path54.join(worktreesDir, candidate.runId, candidate.worker);
|
|
11144
12029
|
}
|
|
11145
|
-
return
|
|
12030
|
+
return path54.resolve(candidate.path, "..");
|
|
11146
12031
|
}
|
|
11147
12032
|
function runHarnessCleanup(options = {}) {
|
|
11148
12033
|
let retention = resolveHarnessRetention(options);
|
|
@@ -11158,7 +12043,11 @@ function runHarnessCleanup(options = {}) {
|
|
|
11158
12043
|
emitCleanupProgress("index", "building worktree index");
|
|
11159
12044
|
const index = mergeWorktreeIndexes(paths.scanRoots);
|
|
11160
12045
|
emitCleanupProgress("index", `${index.size} indexed worktree(s)`);
|
|
11161
|
-
const liveness = {
|
|
12046
|
+
const liveness = {
|
|
12047
|
+
runTerminalCache: new CleanupRunTerminalCache(),
|
|
12048
|
+
gitStatusCache: new CleanupGitStatusCache(),
|
|
12049
|
+
gitRevCache: new CleanupGitRevCache()
|
|
12050
|
+
};
|
|
11162
12051
|
const skips = [];
|
|
11163
12052
|
const actions = [];
|
|
11164
12053
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
@@ -11167,7 +12056,7 @@ function runHarnessCleanup(options = {}) {
|
|
|
11167
12056
|
for (const harnessRoot of paths.scanRoots) {
|
|
11168
12057
|
if (atSweepCap()) break;
|
|
11169
12058
|
emitCleanupProgress("root", harnessRoot);
|
|
11170
|
-
const worktreesDir =
|
|
12059
|
+
const worktreesDir = path54.join(harnessRoot, "worktrees");
|
|
11171
12060
|
const scanOpts = {
|
|
11172
12061
|
harnessRoot,
|
|
11173
12062
|
worktreesDir,
|
|
@@ -11178,9 +12067,16 @@ function runHarnessCleanup(options = {}) {
|
|
|
11178
12067
|
index,
|
|
11179
12068
|
now: paths.now
|
|
11180
12069
|
};
|
|
11181
|
-
|
|
12070
|
+
const dependencyCandidates = scanDependencyCacheCandidates(scanOpts);
|
|
12071
|
+
emitCleanupProgress("dependency", `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}`);
|
|
12072
|
+
let dependencyProcessed = 0;
|
|
12073
|
+
for (const raw of dependencyCandidates) {
|
|
11182
12074
|
if (atSweepCap()) break;
|
|
11183
|
-
|
|
12075
|
+
dependencyProcessed += 1;
|
|
12076
|
+
if (dependencyProcessed % 50 === 0) {
|
|
12077
|
+
emitCleanupProgress("dependency", `${dependencyProcessed}/${dependencyCandidates.length} evaluated`);
|
|
12078
|
+
}
|
|
12079
|
+
const resolved = path54.resolve(raw.path);
|
|
11184
12080
|
if (processedPaths.has(resolved)) continue;
|
|
11185
12081
|
processedPaths.add(resolved);
|
|
11186
12082
|
const candidate = { ...raw, path: resolved };
|
|
@@ -11191,7 +12087,7 @@ function runHarnessCleanup(options = {}) {
|
|
|
11191
12087
|
continue;
|
|
11192
12088
|
}
|
|
11193
12089
|
const worktreePath = worktreePathForCandidate(candidate, worktreesDir);
|
|
11194
|
-
const indexed = index.get(
|
|
12090
|
+
const indexed = index.get(path54.resolve(worktreePath)) ?? null;
|
|
11195
12091
|
const guardReason = skipDependencyCacheRemoval({
|
|
11196
12092
|
indexed,
|
|
11197
12093
|
includeOrphans: true,
|
|
@@ -11199,7 +12095,8 @@ function runHarnessCleanup(options = {}) {
|
|
|
11199
12095
|
ageMs: candidate.ageMs,
|
|
11200
12096
|
worktreePath,
|
|
11201
12097
|
activeWorktreePaths: activeGuards.activeWorktreePaths,
|
|
11202
|
-
diskPressure: retention.diskPressure
|
|
12098
|
+
diskPressure: retention.diskPressure,
|
|
12099
|
+
gitStatusCache: liveness.gitStatusCache
|
|
11203
12100
|
});
|
|
11204
12101
|
if (guardReason) {
|
|
11205
12102
|
recordSkip(skips, candidate.path, guardReason);
|
|
@@ -11215,7 +12112,7 @@ function runHarnessCleanup(options = {}) {
|
|
|
11215
12112
|
}
|
|
11216
12113
|
for (const raw of scanBuildCacheCandidates(scanOpts)) {
|
|
11217
12114
|
if (atSweepCap()) break;
|
|
11218
|
-
const resolved =
|
|
12115
|
+
const resolved = path54.resolve(raw.path);
|
|
11219
12116
|
if (processedPaths.has(resolved)) continue;
|
|
11220
12117
|
processedPaths.add(resolved);
|
|
11221
12118
|
const candidate = { ...raw, path: resolved };
|
|
@@ -11226,7 +12123,7 @@ function runHarnessCleanup(options = {}) {
|
|
|
11226
12123
|
continue;
|
|
11227
12124
|
}
|
|
11228
12125
|
const worktreePath = worktreePathForCandidate(candidate, worktreesDir);
|
|
11229
|
-
const indexed = index.get(
|
|
12126
|
+
const indexed = index.get(path54.resolve(worktreePath)) ?? null;
|
|
11230
12127
|
const guardReason = skipBuildCacheRemoval({
|
|
11231
12128
|
indexed,
|
|
11232
12129
|
includeOrphans: true,
|
|
@@ -11234,7 +12131,8 @@ function runHarnessCleanup(options = {}) {
|
|
|
11234
12131
|
ageMs: candidate.ageMs,
|
|
11235
12132
|
worktreePath,
|
|
11236
12133
|
activeWorktreePaths: activeGuards.activeWorktreePaths,
|
|
11237
|
-
diskPressure: retention.diskPressure
|
|
12134
|
+
diskPressure: retention.diskPressure,
|
|
12135
|
+
gitStatusCache: liveness.gitStatusCache
|
|
11238
12136
|
});
|
|
11239
12137
|
if (guardReason) {
|
|
11240
12138
|
recordSkip(skips, candidate.path, guardReason);
|
|
@@ -11254,13 +12152,18 @@ function runHarnessCleanup(options = {}) {
|
|
|
11254
12152
|
];
|
|
11255
12153
|
emitCleanupProgress("worktrees", `${worktreeCandidates.length} candidate(s) at ${harnessRoot}`);
|
|
11256
12154
|
const worktreeSeen = /* @__PURE__ */ new Set();
|
|
12155
|
+
let worktreeProcessed = 0;
|
|
11257
12156
|
for (const raw of worktreeCandidates) {
|
|
11258
12157
|
if (atSweepCap()) break;
|
|
11259
|
-
|
|
12158
|
+
worktreeProcessed += 1;
|
|
12159
|
+
if (worktreeProcessed % 50 === 0) {
|
|
12160
|
+
emitCleanupProgress("worktrees", `${worktreeProcessed}/${worktreeCandidates.length} evaluated`);
|
|
12161
|
+
}
|
|
12162
|
+
const resolved = path54.resolve(raw.path);
|
|
11260
12163
|
if (worktreeSeen.has(resolved)) continue;
|
|
11261
12164
|
worktreeSeen.add(resolved);
|
|
11262
12165
|
const candidate = { ...raw, path: resolved };
|
|
11263
|
-
const indexed = index.get(
|
|
12166
|
+
const indexed = index.get(path54.resolve(candidate.path)) ?? null;
|
|
11264
12167
|
const orphanSafety = indexed ? null : assessOrphanWorktreeSafety({
|
|
11265
12168
|
worktreePath: candidate.path,
|
|
11266
12169
|
harnessRoot,
|
|
@@ -11270,7 +12173,7 @@ function runHarnessCleanup(options = {}) {
|
|
|
11270
12173
|
});
|
|
11271
12174
|
const guardSkip = skipWorktreeRemoval({
|
|
11272
12175
|
indexed,
|
|
11273
|
-
worktreePath:
|
|
12176
|
+
worktreePath: path54.resolve(candidate.path),
|
|
11274
12177
|
includeOrphans: retention.includeOrphans,
|
|
11275
12178
|
worktreesAgeMs: retention.worktreesAgeMs,
|
|
11276
12179
|
terminalWorktreesAgeMs: retention.terminalWorktreesAgeMs,
|
|
@@ -11302,11 +12205,11 @@ function runHarnessCleanup(options = {}) {
|
|
|
11302
12205
|
now: paths.now
|
|
11303
12206
|
})) {
|
|
11304
12207
|
if (atSweepCap()) break;
|
|
11305
|
-
const resolved =
|
|
12208
|
+
const resolved = path54.resolve(raw.path);
|
|
11306
12209
|
if (processedPaths.has(resolved)) continue;
|
|
11307
12210
|
processedPaths.add(resolved);
|
|
11308
12211
|
const candidate = { ...raw, path: resolved };
|
|
11309
|
-
const runId = candidate.runId ??
|
|
12212
|
+
const runId = candidate.runId ?? path54.basename(resolved);
|
|
11310
12213
|
const dirSkip = skipRunDirectoryRemoval({
|
|
11311
12214
|
harnessRoot,
|
|
11312
12215
|
runId,
|
|
@@ -11441,12 +12344,13 @@ function isPipelineCleanupEnabled() {
|
|
|
11441
12344
|
|
|
11442
12345
|
// src/installed-package-versions.ts
|
|
11443
12346
|
import { readFile } from "node:fs/promises";
|
|
11444
|
-
import { homedir as
|
|
11445
|
-
import
|
|
12347
|
+
import { homedir as homedir14 } from "node:os";
|
|
12348
|
+
import path56 from "node:path";
|
|
11446
12349
|
|
|
11447
12350
|
// src/memory-cost-package-version-guard.ts
|
|
11448
|
-
|
|
11449
|
-
import
|
|
12351
|
+
init_default_repo_discovery();
|
|
12352
|
+
import { existsSync as existsSync40, readFileSync as readFileSync14 } from "node:fs";
|
|
12353
|
+
import path55 from "node:path";
|
|
11450
12354
|
var MEMORY_COST_PACKAGE_MIN_VERSIONS = {
|
|
11451
12355
|
"@kynver-app/runtime": "0.1.83",
|
|
11452
12356
|
"@kynver-app/openclaw-agent-os": "0.1.43",
|
|
@@ -11497,7 +12401,7 @@ function maxSemver(versions) {
|
|
|
11497
12401
|
}
|
|
11498
12402
|
function readPackageJsonVersion(packageJsonPath) {
|
|
11499
12403
|
try {
|
|
11500
|
-
const parsed = JSON.parse(
|
|
12404
|
+
const parsed = JSON.parse(readFileSync14(packageJsonPath, "utf8"));
|
|
11501
12405
|
return typeof parsed.version === "string" && parsed.version.trim() ? parsed.version.trim() : null;
|
|
11502
12406
|
} catch {
|
|
11503
12407
|
return null;
|
|
@@ -11508,8 +12412,8 @@ function resolveRepoRoot(cwd, explicitRepoRoot) {
|
|
|
11508
12412
|
(value) => Boolean(value?.trim())
|
|
11509
12413
|
);
|
|
11510
12414
|
for (const candidate of candidates) {
|
|
11511
|
-
const resolved =
|
|
11512
|
-
if (existsSync40(
|
|
12415
|
+
const resolved = path55.resolve(candidate);
|
|
12416
|
+
if (existsSync40(path55.join(resolved, "packages/kynver-runtime/package.json")) && existsSync40(path55.join(resolved, "package.json"))) {
|
|
11513
12417
|
return resolved;
|
|
11514
12418
|
}
|
|
11515
12419
|
}
|
|
@@ -11522,7 +12426,7 @@ function probeRepoPackageVersions(input = {}) {
|
|
|
11522
12426
|
if (!repoRoot) return {};
|
|
11523
12427
|
const out = {};
|
|
11524
12428
|
for (const packageName of MEMORY_COST_MANAGED_PACKAGES) {
|
|
11525
|
-
const packageJsonPath =
|
|
12429
|
+
const packageJsonPath = path55.join(repoRoot, REPO_PACKAGE_JSON_RELATIVE[packageName]);
|
|
11526
12430
|
const version = readPackageJsonVersion(packageJsonPath);
|
|
11527
12431
|
if (!version) continue;
|
|
11528
12432
|
out[packageName] = { version, source: "repo", path: packageJsonPath };
|
|
@@ -11641,13 +12545,13 @@ function unique(values) {
|
|
|
11641
12545
|
return [...new Set(values.filter((value) => Boolean(value)))];
|
|
11642
12546
|
}
|
|
11643
12547
|
function moduleRoots() {
|
|
11644
|
-
const home =
|
|
11645
|
-
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ??
|
|
11646
|
-
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ?
|
|
12548
|
+
const home = homedir14();
|
|
12549
|
+
const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path56.join(home, ".openclaw", "npm");
|
|
12550
|
+
const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path56.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path56.join(home, ".npm-global", "lib", "node_modules"));
|
|
11647
12551
|
return unique([
|
|
11648
|
-
|
|
11649
|
-
|
|
11650
|
-
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot :
|
|
12552
|
+
path56.join(openClawPrefix, "lib", "node_modules"),
|
|
12553
|
+
path56.join(openClawPrefix, "node_modules"),
|
|
12554
|
+
npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path56.join(npmGlobalRoot, "lib", "node_modules")
|
|
11651
12555
|
]);
|
|
11652
12556
|
}
|
|
11653
12557
|
async function readVersion(packageJsonPath) {
|
|
@@ -11663,7 +12567,7 @@ function installedPackageJsonCandidates(packageName) {
|
|
|
11663
12567
|
const seen = /* @__PURE__ */ new Set();
|
|
11664
12568
|
const out = [];
|
|
11665
12569
|
for (const root of roots) {
|
|
11666
|
-
const candidate =
|
|
12570
|
+
const candidate = path56.join(root, packageName, "package.json");
|
|
11667
12571
|
if (seen.has(candidate)) continue;
|
|
11668
12572
|
seen.add(candidate);
|
|
11669
12573
|
out.push(candidate);
|
|
@@ -11688,13 +12592,355 @@ async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new
|
|
|
11688
12592
|
return out;
|
|
11689
12593
|
}
|
|
11690
12594
|
|
|
12595
|
+
// src/provider-evidence/exec.ts
|
|
12596
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
12597
|
+
var DEFAULT_CLI_TIMEOUT_MS = 1e4;
|
|
12598
|
+
var MAX_CLI_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
12599
|
+
var defaultCliRunner = (cmd, args, opts) => {
|
|
12600
|
+
try {
|
|
12601
|
+
const result = spawnSync7(cmd, args, {
|
|
12602
|
+
encoding: "utf8",
|
|
12603
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
12604
|
+
timeout: opts?.timeoutMs ?? DEFAULT_CLI_TIMEOUT_MS,
|
|
12605
|
+
maxBuffer: MAX_CLI_BUFFER_BYTES
|
|
12606
|
+
});
|
|
12607
|
+
return {
|
|
12608
|
+
ok: result.status === 0,
|
|
12609
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
12610
|
+
stderr: typeof result.stderr === "string" ? result.stderr : ""
|
|
12611
|
+
};
|
|
12612
|
+
} catch (err) {
|
|
12613
|
+
return { ok: false, stdout: "", stderr: err instanceof Error ? err.message : String(err) };
|
|
12614
|
+
}
|
|
12615
|
+
};
|
|
12616
|
+
function runCliJson(run, cmd, args) {
|
|
12617
|
+
const result = run(cmd, args);
|
|
12618
|
+
if (!result.ok || !result.stdout.trim()) return null;
|
|
12619
|
+
try {
|
|
12620
|
+
return JSON.parse(result.stdout);
|
|
12621
|
+
} catch {
|
|
12622
|
+
return null;
|
|
12623
|
+
}
|
|
12624
|
+
}
|
|
12625
|
+
|
|
12626
|
+
// src/provider-evidence/types.ts
|
|
12627
|
+
function providerEvidenceKey(provider, kind, subject) {
|
|
12628
|
+
return `${provider} ${kind} ${subject}`;
|
|
12629
|
+
}
|
|
12630
|
+
function parseCommitEvidenceSubject(subject) {
|
|
12631
|
+
const at = subject.lastIndexOf("@");
|
|
12632
|
+
if (at <= 0 || at === subject.length - 1) return null;
|
|
12633
|
+
const repo = subject.slice(0, at);
|
|
12634
|
+
const sha = subject.slice(at + 1);
|
|
12635
|
+
if (!/^[^/\s]+\/[^/\s]+$/.test(repo) || !/^[0-9a-f]{7,40}$/i.test(sha)) return null;
|
|
12636
|
+
return { repo, sha };
|
|
12637
|
+
}
|
|
12638
|
+
function parsePrUrlSubject(subject) {
|
|
12639
|
+
const m = subject.trim().match(/[/:]([^/]+\/[^/]+)\/(?:pull|pulls|merge_requests|pull-requests)\/(\d+)/i);
|
|
12640
|
+
if (!m) return null;
|
|
12641
|
+
const number = Number(m[2]);
|
|
12642
|
+
if (!Number.isFinite(number) || number <= 0) return null;
|
|
12643
|
+
return { repo: m[1], number };
|
|
12644
|
+
}
|
|
12645
|
+
|
|
12646
|
+
// src/provider-evidence/recipes-github.ts
|
|
12647
|
+
var MAX_BODY_CHARS = 8e3;
|
|
12648
|
+
var MAX_STATUS_ROWS = 30;
|
|
12649
|
+
var MAX_CHECK_RUNS = 100;
|
|
12650
|
+
var MAX_CHANGED_FILES = 400;
|
|
12651
|
+
function githubCliAvailable(run) {
|
|
12652
|
+
if (process.env.GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim()) return true;
|
|
12653
|
+
return run("gh", ["auth", "token"]).ok;
|
|
12654
|
+
}
|
|
12655
|
+
function asRecord4(value) {
|
|
12656
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
12657
|
+
}
|
|
12658
|
+
function pickStatusRows(value) {
|
|
12659
|
+
if (!Array.isArray(value)) return [];
|
|
12660
|
+
return value.map((raw) => asRecord4(raw)).filter((row) => row !== null).slice(0, MAX_STATUS_ROWS).map((row) => ({
|
|
12661
|
+
context: row.context ?? null,
|
|
12662
|
+
state: row.state ?? null,
|
|
12663
|
+
target_url: row.target_url ?? null,
|
|
12664
|
+
description: row.description ?? null
|
|
12665
|
+
}));
|
|
12666
|
+
}
|
|
12667
|
+
function fetchCombinedStatus(run, repo, sha) {
|
|
12668
|
+
const status = runCliJson(run, "gh", [
|
|
12669
|
+
"api",
|
|
12670
|
+
`repos/${repo}/commits/${sha}/status`
|
|
12671
|
+
]);
|
|
12672
|
+
if (!status) return null;
|
|
12673
|
+
return { state: status.state ?? null, statuses: pickStatusRows(status.statuses) };
|
|
12674
|
+
}
|
|
12675
|
+
var githubPrSnapshotRecipe = {
|
|
12676
|
+
provider: "github",
|
|
12677
|
+
kind: "pr_snapshot",
|
|
12678
|
+
version: "1",
|
|
12679
|
+
isAvailable: githubCliAvailable,
|
|
12680
|
+
collect(subject, run) {
|
|
12681
|
+
const parsed = parsePrUrlSubject(subject);
|
|
12682
|
+
if (!parsed) return null;
|
|
12683
|
+
const pull = runCliJson(run, "gh", [
|
|
12684
|
+
"api",
|
|
12685
|
+
`repos/${parsed.repo}/pulls/${parsed.number}`
|
|
12686
|
+
]);
|
|
12687
|
+
if (!pull) return null;
|
|
12688
|
+
const head = asRecord4(pull.head);
|
|
12689
|
+
const headSha = typeof head?.sha === "string" ? head.sha : null;
|
|
12690
|
+
const user = asRecord4(pull.user);
|
|
12691
|
+
const headRepoOwner = asRecord4(asRecord4(head?.repo)?.owner);
|
|
12692
|
+
const body = typeof pull.body === "string" ? pull.body.slice(0, MAX_BODY_CHARS) : null;
|
|
12693
|
+
let checkRuns = [];
|
|
12694
|
+
let combinedStatus = {
|
|
12695
|
+
state: null,
|
|
12696
|
+
statuses: []
|
|
12697
|
+
};
|
|
12698
|
+
if (headSha) {
|
|
12699
|
+
const runs = runCliJson(run, "gh", [
|
|
12700
|
+
"api",
|
|
12701
|
+
`repos/${parsed.repo}/commits/${headSha}/check-runs?per_page=100`
|
|
12702
|
+
]);
|
|
12703
|
+
if (Array.isArray(runs?.check_runs)) {
|
|
12704
|
+
checkRuns = runs.check_runs.map((raw) => asRecord4(raw)).filter((row) => row !== null).slice(0, MAX_CHECK_RUNS).map((row) => ({
|
|
12705
|
+
name: row.name ?? null,
|
|
12706
|
+
status: row.status ?? null,
|
|
12707
|
+
conclusion: row.conclusion ?? null
|
|
12708
|
+
}));
|
|
12709
|
+
}
|
|
12710
|
+
combinedStatus = fetchCombinedStatus(run, parsed.repo, headSha) ?? combinedStatus;
|
|
12711
|
+
}
|
|
12712
|
+
const filesResult = run("gh", [
|
|
12713
|
+
"api",
|
|
12714
|
+
"--paginate",
|
|
12715
|
+
`repos/${parsed.repo}/pulls/${parsed.number}/files?per_page=100`,
|
|
12716
|
+
"--jq",
|
|
12717
|
+
".[].filename"
|
|
12718
|
+
]);
|
|
12719
|
+
const changedFiles = filesResult.ok ? filesResult.stdout.split("\n").map((line) => line.trim()).filter(Boolean).slice(0, MAX_CHANGED_FILES) : [];
|
|
12720
|
+
return {
|
|
12721
|
+
pull: {
|
|
12722
|
+
html_url: pull.html_url ?? null,
|
|
12723
|
+
title: pull.title ?? null,
|
|
12724
|
+
body,
|
|
12725
|
+
user: { login: user?.login ?? null },
|
|
12726
|
+
state: pull.state ?? null,
|
|
12727
|
+
draft: pull.draft ?? null,
|
|
12728
|
+
merged: pull.merged ?? null,
|
|
12729
|
+
merged_at: pull.merged_at ?? null,
|
|
12730
|
+
merge_commit_sha: pull.merge_commit_sha ?? null,
|
|
12731
|
+
mergeable: pull.mergeable ?? null,
|
|
12732
|
+
mergeable_state: pull.mergeable_state ?? null,
|
|
12733
|
+
head: {
|
|
12734
|
+
sha: headSha,
|
|
12735
|
+
ref: head?.ref ?? null,
|
|
12736
|
+
repo: { owner: { login: headRepoOwner?.login ?? null } }
|
|
12737
|
+
}
|
|
12738
|
+
},
|
|
12739
|
+
checkRuns,
|
|
12740
|
+
combinedStatus,
|
|
12741
|
+
changedFiles
|
|
12742
|
+
};
|
|
12743
|
+
}
|
|
12744
|
+
};
|
|
12745
|
+
var githubCommitStatusRecipe = {
|
|
12746
|
+
provider: "github",
|
|
12747
|
+
kind: "commit_status",
|
|
12748
|
+
version: "1",
|
|
12749
|
+
isAvailable: githubCliAvailable,
|
|
12750
|
+
collect(subject, run) {
|
|
12751
|
+
const parsed = parseCommitEvidenceSubject(subject);
|
|
12752
|
+
if (!parsed) return null;
|
|
12753
|
+
return fetchCombinedStatus(run, parsed.repo, parsed.sha);
|
|
12754
|
+
}
|
|
12755
|
+
};
|
|
12756
|
+
var githubBranchReachabilityRecipe = {
|
|
12757
|
+
provider: "github",
|
|
12758
|
+
kind: "branch_reachability",
|
|
12759
|
+
version: "1",
|
|
12760
|
+
isAvailable: githubCliAvailable,
|
|
12761
|
+
collect(subject, run) {
|
|
12762
|
+
const parsed = parseCommitEvidenceSubject(subject);
|
|
12763
|
+
if (!parsed) return null;
|
|
12764
|
+
const repoMeta = runCliJson(run, "gh", [
|
|
12765
|
+
"api",
|
|
12766
|
+
`repos/${parsed.repo}`
|
|
12767
|
+
]);
|
|
12768
|
+
const defaultBranch = typeof repoMeta?.default_branch === "string" && repoMeta.default_branch.trim() ? repoMeta.default_branch.trim() : null;
|
|
12769
|
+
if (!defaultBranch) return null;
|
|
12770
|
+
const compare = runCliJson(run, "gh", [
|
|
12771
|
+
"api",
|
|
12772
|
+
`repos/${parsed.repo}/compare/${encodeURIComponent(defaultBranch)}...${parsed.sha}`
|
|
12773
|
+
]);
|
|
12774
|
+
if (!compare) return null;
|
|
12775
|
+
const compareStatus = typeof compare.status === "string" ? compare.status : null;
|
|
12776
|
+
return {
|
|
12777
|
+
defaultBranch,
|
|
12778
|
+
compareStatus,
|
|
12779
|
+
reachable: compareStatus === "identical" || compareStatus === "behind"
|
|
12780
|
+
};
|
|
12781
|
+
}
|
|
12782
|
+
};
|
|
12783
|
+
|
|
12784
|
+
// src/provider-evidence/recipes-vercel.ts
|
|
12785
|
+
var MAX_DEPLOYMENT_ROWS = 5;
|
|
12786
|
+
var STATE_PATTERN = /\b(READY|ERROR|BUILDING|QUEUED|CANCELED|INITIALIZING)\b/i;
|
|
12787
|
+
var URL_PATTERN = /https:\/\/[^\s]+/;
|
|
12788
|
+
var vercelDeploymentStatusRecipe = {
|
|
12789
|
+
provider: "vercel",
|
|
12790
|
+
kind: "deployment_status",
|
|
12791
|
+
version: "1",
|
|
12792
|
+
isAvailable(run) {
|
|
12793
|
+
return run("vercel", ["whoami"]).ok;
|
|
12794
|
+
},
|
|
12795
|
+
collect(subject, run) {
|
|
12796
|
+
const parsed = parseCommitEvidenceSubject(subject);
|
|
12797
|
+
if (!parsed) return null;
|
|
12798
|
+
const result = run("vercel", [
|
|
12799
|
+
"list",
|
|
12800
|
+
"--prod",
|
|
12801
|
+
"--meta",
|
|
12802
|
+
`githubCommitSha=${parsed.sha}`
|
|
12803
|
+
]);
|
|
12804
|
+
if (!result.ok) return null;
|
|
12805
|
+
const deployments = [];
|
|
12806
|
+
for (const line of result.stdout.split("\n")) {
|
|
12807
|
+
const url = line.match(URL_PATTERN)?.[0];
|
|
12808
|
+
if (!url) continue;
|
|
12809
|
+
const state = line.match(STATE_PATTERN)?.[1]?.toUpperCase() ?? null;
|
|
12810
|
+
deployments.push({ url, state });
|
|
12811
|
+
if (deployments.length >= MAX_DEPLOYMENT_ROWS) break;
|
|
12812
|
+
}
|
|
12813
|
+
return { found: deployments.length > 0, deployments };
|
|
12814
|
+
}
|
|
12815
|
+
};
|
|
12816
|
+
|
|
12817
|
+
// src/provider-evidence/registry.ts
|
|
12818
|
+
var _recipes = [];
|
|
12819
|
+
function registerEvidenceCollector(recipe) {
|
|
12820
|
+
if (_recipes.some((r) => r.provider === recipe.provider && r.kind === recipe.kind)) return;
|
|
12821
|
+
_recipes.push(recipe);
|
|
12822
|
+
}
|
|
12823
|
+
function getEvidenceCollector(provider, kind) {
|
|
12824
|
+
return _recipes.find((r) => r.provider === provider && r.kind === kind) ?? null;
|
|
12825
|
+
}
|
|
12826
|
+
function registerDefaultEvidenceCollectors() {
|
|
12827
|
+
registerEvidenceCollector(githubPrSnapshotRecipe);
|
|
12828
|
+
registerEvidenceCollector(githubCommitStatusRecipe);
|
|
12829
|
+
registerEvidenceCollector(githubBranchReachabilityRecipe);
|
|
12830
|
+
registerEvidenceCollector(vercelDeploymentStatusRecipe);
|
|
12831
|
+
}
|
|
12832
|
+
|
|
12833
|
+
// src/provider-evidence/collect.ts
|
|
12834
|
+
var DEFAULT_MAX_SUBJECTS_PER_TICK = 8;
|
|
12835
|
+
var DEFAULT_DEADLINE_MS = 25e3;
|
|
12836
|
+
function collectProviderEvidence(wanted, opts = {}) {
|
|
12837
|
+
registerDefaultEvidenceCollectors();
|
|
12838
|
+
const run = opts.run ?? defaultCliRunner;
|
|
12839
|
+
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
12840
|
+
const maxSubjects = opts.maxSubjects ?? DEFAULT_MAX_SUBJECTS_PER_TICK;
|
|
12841
|
+
const deadline = Date.now() + (opts.deadlineMs ?? DEFAULT_DEADLINE_MS);
|
|
12842
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12843
|
+
const deduped = wanted.filter((w) => {
|
|
12844
|
+
const key = providerEvidenceKey(w.provider, w.kind, w.subject);
|
|
12845
|
+
if (seen.has(key)) return false;
|
|
12846
|
+
seen.add(key);
|
|
12847
|
+
return true;
|
|
12848
|
+
});
|
|
12849
|
+
const offset = deduped.length > 0 ? Math.floor(now().getTime() / 6e4) % deduped.length : 0;
|
|
12850
|
+
const rotated = deduped.map((_, i) => deduped[(offset + i) % deduped.length]);
|
|
12851
|
+
const window = rotated.slice(0, maxSubjects);
|
|
12852
|
+
const summary = {
|
|
12853
|
+
attempted: 0,
|
|
12854
|
+
collected: 0,
|
|
12855
|
+
items: [],
|
|
12856
|
+
skipped: []
|
|
12857
|
+
};
|
|
12858
|
+
const availability = /* @__PURE__ */ new Map();
|
|
12859
|
+
for (const item of window) {
|
|
12860
|
+
if (Date.now() > deadline) {
|
|
12861
|
+
summary.skipped.push({ ...item, reason: "budget_exhausted" });
|
|
12862
|
+
continue;
|
|
12863
|
+
}
|
|
12864
|
+
const recipe = getEvidenceCollector(item.provider, item.kind);
|
|
12865
|
+
if (!recipe) {
|
|
12866
|
+
summary.skipped.push({ ...item, reason: "no_recipe" });
|
|
12867
|
+
continue;
|
|
12868
|
+
}
|
|
12869
|
+
const availKey = `${recipe.provider} ${recipe.kind}`;
|
|
12870
|
+
let available = availability.get(availKey);
|
|
12871
|
+
if (available === void 0) {
|
|
12872
|
+
available = recipe.isAvailable(run);
|
|
12873
|
+
availability.set(availKey, available);
|
|
12874
|
+
}
|
|
12875
|
+
if (!available) {
|
|
12876
|
+
summary.skipped.push({ ...item, reason: "provider_unavailable" });
|
|
12877
|
+
continue;
|
|
12878
|
+
}
|
|
12879
|
+
summary.attempted += 1;
|
|
12880
|
+
const payload = recipe.collect(item.subject, run);
|
|
12881
|
+
if (payload === null || payload === void 0) {
|
|
12882
|
+
summary.skipped.push({ ...item, reason: "collect_failed" });
|
|
12883
|
+
continue;
|
|
12884
|
+
}
|
|
12885
|
+
summary.collected += 1;
|
|
12886
|
+
summary.items.push({
|
|
12887
|
+
provider: item.provider,
|
|
12888
|
+
kind: item.kind,
|
|
12889
|
+
subject: item.subject,
|
|
12890
|
+
payload,
|
|
12891
|
+
observedAt: now().toISOString(),
|
|
12892
|
+
collectorVersion: recipe.version
|
|
12893
|
+
});
|
|
12894
|
+
}
|
|
12895
|
+
return summary;
|
|
12896
|
+
}
|
|
12897
|
+
|
|
12898
|
+
// src/provider-evidence/wanted-store.ts
|
|
12899
|
+
init_run_store();
|
|
12900
|
+
init_util();
|
|
12901
|
+
import path57 from "node:path";
|
|
12902
|
+
var WANTED_FILE = "provider-evidence-wanted.json";
|
|
12903
|
+
function wantedFilePath(runId) {
|
|
12904
|
+
return path57.join(runDirectory(runId), WANTED_FILE);
|
|
12905
|
+
}
|
|
12906
|
+
function parseWantedItems(value) {
|
|
12907
|
+
if (!Array.isArray(value)) return [];
|
|
12908
|
+
const out = [];
|
|
12909
|
+
for (const raw of value) {
|
|
12910
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
12911
|
+
const row = raw;
|
|
12912
|
+
const provider = typeof row.provider === "string" ? row.provider.trim() : "";
|
|
12913
|
+
const kind = typeof row.kind === "string" ? row.kind.trim() : "";
|
|
12914
|
+
const subject = typeof row.subject === "string" ? row.subject.trim() : "";
|
|
12915
|
+
if (!provider || !kind || !subject) continue;
|
|
12916
|
+
out.push({ provider, kind, subject });
|
|
12917
|
+
}
|
|
12918
|
+
return out;
|
|
12919
|
+
}
|
|
12920
|
+
function loadPersistedProviderEvidenceWanted(runId) {
|
|
12921
|
+
const persisted = readJson(wantedFilePath(runId), null);
|
|
12922
|
+
return parseWantedItems(persisted?.wanted);
|
|
12923
|
+
}
|
|
12924
|
+
function persistProviderEvidenceWanted(runId, wanted) {
|
|
12925
|
+
writeJson(wantedFilePath(runId), {
|
|
12926
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12927
|
+
wanted
|
|
12928
|
+
});
|
|
12929
|
+
}
|
|
12930
|
+
function extractProviderEvidenceWanted(tickResponse) {
|
|
12931
|
+
if (!tickResponse || typeof tickResponse !== "object" || Array.isArray(tickResponse)) return null;
|
|
12932
|
+
const wanted = tickResponse.providerEvidenceWanted;
|
|
12933
|
+
if (!Array.isArray(wanted)) return null;
|
|
12934
|
+
return parseWantedItems(wanted);
|
|
12935
|
+
}
|
|
12936
|
+
|
|
11691
12937
|
// src/pipeline-tick.ts
|
|
11692
12938
|
async function completeFinishedWorkers(runId, args) {
|
|
11693
12939
|
const run = loadRun(runId);
|
|
11694
12940
|
const outcomes = [];
|
|
11695
12941
|
for (const name of Object.keys(run.workers || {})) {
|
|
11696
12942
|
const worker = readJson(
|
|
11697
|
-
|
|
12943
|
+
path58.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
|
|
11698
12944
|
void 0
|
|
11699
12945
|
);
|
|
11700
12946
|
if (!worker?.taskId || worker.localOnly) continue;
|
|
@@ -11727,6 +12973,13 @@ async function postOperatorTick(agentOsId, runId, resourceGate, args, harnessCle
|
|
|
11727
12973
|
const url = `${base}/api/agent-os/by-id/${encodeURIComponent(agentOsId)}/operator/tick`;
|
|
11728
12974
|
const packageVersions = await collectInstalledPackageVersions();
|
|
11729
12975
|
const activeHarnessWorkers = collectRunActiveHarnessWorkers(runId);
|
|
12976
|
+
let evidenceCollection = null;
|
|
12977
|
+
try {
|
|
12978
|
+
const evidenceWanted = loadPersistedProviderEvidenceWanted(runId);
|
|
12979
|
+
evidenceCollection = evidenceWanted.length > 0 ? collectProviderEvidence(evidenceWanted) : null;
|
|
12980
|
+
} catch {
|
|
12981
|
+
evidenceCollection = null;
|
|
12982
|
+
}
|
|
11730
12983
|
const res = await postJson(url, secret, {
|
|
11731
12984
|
agentOsId,
|
|
11732
12985
|
runId,
|
|
@@ -11741,9 +12994,27 @@ async function postOperatorTick(agentOsId, runId, resourceGate, args, harnessCle
|
|
|
11741
12994
|
...harnessCleanup ? { harnessCleanup } : {},
|
|
11742
12995
|
runnerPresence: resolveRunnerPresencePayload({ runId }),
|
|
11743
12996
|
activeHarnessWorkers,
|
|
11744
|
-
...
|
|
12997
|
+
...evidenceCollection && evidenceCollection.items.length > 0 ? { providerEvidence: evidenceCollection.items } : {}
|
|
11745
12998
|
});
|
|
11746
|
-
|
|
12999
|
+
const nextWanted = extractProviderEvidenceWanted(res.response);
|
|
13000
|
+
if (nextWanted) {
|
|
13001
|
+
try {
|
|
13002
|
+
persistProviderEvidenceWanted(runId, nextWanted);
|
|
13003
|
+
} catch {
|
|
13004
|
+
}
|
|
13005
|
+
}
|
|
13006
|
+
return {
|
|
13007
|
+
ok: res.ok,
|
|
13008
|
+
httpStatus: res.status,
|
|
13009
|
+
response: res.response,
|
|
13010
|
+
...evidenceCollection ? {
|
|
13011
|
+
providerEvidence: {
|
|
13012
|
+
attempted: evidenceCollection.attempted,
|
|
13013
|
+
collected: evidenceCollection.collected,
|
|
13014
|
+
skipped: evidenceCollection.skipped.length
|
|
13015
|
+
}
|
|
13016
|
+
} : {}
|
|
13017
|
+
};
|
|
11747
13018
|
}
|
|
11748
13019
|
async function runPipelineTick(args) {
|
|
11749
13020
|
const runId = String(required(String(args.run || ""), "--run"));
|
|
@@ -11851,6 +13122,7 @@ async function awaitDaemonBackoff(ms, isStopping) {
|
|
|
11851
13122
|
}
|
|
11852
13123
|
}
|
|
11853
13124
|
async function runDaemon(args) {
|
|
13125
|
+
assertNativeDaemonAllowed();
|
|
11854
13126
|
const runId = String(required(String(args.run || ""), "--run"));
|
|
11855
13127
|
const agentOsId = String(required(String(args.agentOsId || loadUserConfig().agentOsId || ""), "--agent-os-id"));
|
|
11856
13128
|
const execute = args.execute !== false && args.execute !== "false";
|
|
@@ -11890,6 +13162,7 @@ async function runDaemon(args) {
|
|
|
11890
13162
|
const cronEnv = resolveKynverCronEnv();
|
|
11891
13163
|
while (!stopping) {
|
|
11892
13164
|
try {
|
|
13165
|
+
writeDaemonHeartbeat({ agentOsId, runId });
|
|
11893
13166
|
if (cronEnv.tickEnabled) {
|
|
11894
13167
|
const cronTick = await runKynverCronTick({
|
|
11895
13168
|
env: cronEnv,
|
|
@@ -11916,8 +13189,140 @@ async function runDaemon(args) {
|
|
|
11916
13189
|
console.error(JSON.stringify({ event: "daemon_stop", runId, agentOsId }));
|
|
11917
13190
|
}
|
|
11918
13191
|
|
|
13192
|
+
// src/daemon-keeper.ts
|
|
13193
|
+
init_config();
|
|
13194
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
13195
|
+
init_util();
|
|
13196
|
+
var DEFAULT_STALL_MS = 15 * 6e4;
|
|
13197
|
+
var STARTUP_GRACE_MS = 2 * 6e4;
|
|
13198
|
+
var KILL_GRACE_MS = 1e4;
|
|
13199
|
+
var BACKOFF_BASE_MS = 5e3;
|
|
13200
|
+
var BACKOFF_CAP_MS = 5 * 6e4;
|
|
13201
|
+
var HEALTHY_RESET_MS = 30 * 6e4;
|
|
13202
|
+
var POLL_MS = 5e3;
|
|
13203
|
+
function resolveKeeperStallMs(flag, env = process.env) {
|
|
13204
|
+
const fromFlag = typeof flag === "string" ? Number.parseInt(flag, 10) : NaN;
|
|
13205
|
+
if (Number.isFinite(fromFlag) && fromFlag > 0) return fromFlag;
|
|
13206
|
+
const fromEnv = Number.parseInt(env.KYNVER_DAEMON_STALL_MS ?? "", 10);
|
|
13207
|
+
if (Number.isFinite(fromEnv) && fromEnv > 0) return fromEnv;
|
|
13208
|
+
return DEFAULT_STALL_MS;
|
|
13209
|
+
}
|
|
13210
|
+
function shouldRunDaemonKeeper(args, env = process.env) {
|
|
13211
|
+
if (args.keeperChild === true || args.keeperChild === "true") return false;
|
|
13212
|
+
if (args.noSupervise === true || args.noSupervise === "true") return false;
|
|
13213
|
+
if (args.supervised === "false") return false;
|
|
13214
|
+
const envFlag5 = (env.KYNVER_DAEMON_SUPERVISED ?? "").trim().toLowerCase();
|
|
13215
|
+
if (envFlag5 === "0" || envFlag5 === "false" || envFlag5 === "no" || envFlag5 === "off") {
|
|
13216
|
+
return false;
|
|
13217
|
+
}
|
|
13218
|
+
return true;
|
|
13219
|
+
}
|
|
13220
|
+
function nextKeeperBackoffMs(consecutiveFailures, base = BACKOFF_BASE_MS, cap = BACKOFF_CAP_MS) {
|
|
13221
|
+
const exp = Math.min(Math.max(consecutiveFailures, 1) - 1, 10);
|
|
13222
|
+
return Math.min(base * 2 ** exp, cap);
|
|
13223
|
+
}
|
|
13224
|
+
function keeperRunWasHealthy(startedAtMs, endedAtMs, healthyMs = HEALTHY_RESET_MS) {
|
|
13225
|
+
return endedAtMs - startedAtMs >= healthyMs;
|
|
13226
|
+
}
|
|
13227
|
+
function keeperLog(event, detail = {}) {
|
|
13228
|
+
console.error(JSON.stringify({ event: `daemon_keeper_${event}`, ...detail }));
|
|
13229
|
+
}
|
|
13230
|
+
function buildKeeperChildArgv(argv) {
|
|
13231
|
+
const out = [];
|
|
13232
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
13233
|
+
const arg = argv[i];
|
|
13234
|
+
if (arg === "--supervised" || arg === "--no-supervise" || arg === "--keeper-child") continue;
|
|
13235
|
+
if (arg === "--stall-ms") {
|
|
13236
|
+
if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) i += 1;
|
|
13237
|
+
continue;
|
|
13238
|
+
}
|
|
13239
|
+
if (arg.startsWith("--stall-ms=") || arg.startsWith("--supervised=")) continue;
|
|
13240
|
+
out.push(arg);
|
|
13241
|
+
}
|
|
13242
|
+
out.push("--keeper-child");
|
|
13243
|
+
return out;
|
|
13244
|
+
}
|
|
13245
|
+
async function runDaemonKeeper(args, rawArgv = process.argv.slice(2)) {
|
|
13246
|
+
const agentOsId = String(
|
|
13247
|
+
required(String(args.agentOsId || loadUserConfig().agentOsId || ""), "--agent-os-id")
|
|
13248
|
+
);
|
|
13249
|
+
const stallMs = resolveKeeperStallMs(args.stallMs);
|
|
13250
|
+
const childArgv = buildKeeperChildArgv(rawArgv);
|
|
13251
|
+
const cliEntry = process.argv[1];
|
|
13252
|
+
let stopping = false;
|
|
13253
|
+
let child = null;
|
|
13254
|
+
let consecutiveFailures = 0;
|
|
13255
|
+
const stop = (signal) => {
|
|
13256
|
+
stopping = true;
|
|
13257
|
+
keeperLog("stop", { signal });
|
|
13258
|
+
if (child?.pid) child.kill(signal);
|
|
13259
|
+
};
|
|
13260
|
+
process.on("SIGINT", () => stop("SIGINT"));
|
|
13261
|
+
process.on("SIGTERM", () => stop("SIGTERM"));
|
|
13262
|
+
keeperLog("start", { agentOsId, stallMs, childArgv });
|
|
13263
|
+
while (!stopping) {
|
|
13264
|
+
const startedAt = Date.now();
|
|
13265
|
+
let exited = false;
|
|
13266
|
+
let exitCode = null;
|
|
13267
|
+
let exitSignal = null;
|
|
13268
|
+
child = spawn6(process.execPath, [cliEntry, ...childArgv], {
|
|
13269
|
+
stdio: "inherit",
|
|
13270
|
+
env: process.env
|
|
13271
|
+
});
|
|
13272
|
+
keeperLog("child_spawned", { pid: child.pid ?? null });
|
|
13273
|
+
child.on("exit", (code, signal) => {
|
|
13274
|
+
exited = true;
|
|
13275
|
+
exitCode = code;
|
|
13276
|
+
exitSignal = signal;
|
|
13277
|
+
});
|
|
13278
|
+
while (!exited && !stopping) {
|
|
13279
|
+
await sleepMsAsync(POLL_MS);
|
|
13280
|
+
if (exited || stopping) break;
|
|
13281
|
+
if (Date.now() - startedAt < STARTUP_GRACE_MS) continue;
|
|
13282
|
+
const beat = readDaemonHeartbeat(agentOsId);
|
|
13283
|
+
const ownBeat = beat && beat.pid === child.pid ? beat : null;
|
|
13284
|
+
if (ownBeat && isDaemonHeartbeatStale(ownBeat, stallMs)) {
|
|
13285
|
+
keeperLog("stall_detected", {
|
|
13286
|
+
pid: child.pid ?? null,
|
|
13287
|
+
lastBeatAt: ownBeat.observedAt,
|
|
13288
|
+
stallMs
|
|
13289
|
+
});
|
|
13290
|
+
child.kill("SIGTERM");
|
|
13291
|
+
await sleepMsAsync(KILL_GRACE_MS);
|
|
13292
|
+
if (!exited) child.kill("SIGKILL");
|
|
13293
|
+
break;
|
|
13294
|
+
}
|
|
13295
|
+
if (!ownBeat && Date.now() - startedAt > stallMs + STARTUP_GRACE_MS) {
|
|
13296
|
+
keeperLog("no_heartbeat_detected", { pid: child.pid ?? null, stallMs });
|
|
13297
|
+
child.kill("SIGTERM");
|
|
13298
|
+
await sleepMsAsync(KILL_GRACE_MS);
|
|
13299
|
+
if (!exited) child.kill("SIGKILL");
|
|
13300
|
+
break;
|
|
13301
|
+
}
|
|
13302
|
+
}
|
|
13303
|
+
while (!exited && !stopping) {
|
|
13304
|
+
await sleepMsAsync(POLL_MS);
|
|
13305
|
+
}
|
|
13306
|
+
if (stopping) break;
|
|
13307
|
+
const endedAt = Date.now();
|
|
13308
|
+
if (keeperRunWasHealthy(startedAt, endedAt)) consecutiveFailures = 0;
|
|
13309
|
+
consecutiveFailures += 1;
|
|
13310
|
+
const backoff = nextKeeperBackoffMs(consecutiveFailures);
|
|
13311
|
+
keeperLog("child_exited", {
|
|
13312
|
+
code: exitCode,
|
|
13313
|
+
signal: exitSignal,
|
|
13314
|
+
uptimeMs: endedAt - startedAt,
|
|
13315
|
+
consecutiveFailures,
|
|
13316
|
+
respawnInMs: backoff
|
|
13317
|
+
});
|
|
13318
|
+
await sleepMsAsync(backoff);
|
|
13319
|
+
}
|
|
13320
|
+
keeperLog("stopped", { agentOsId });
|
|
13321
|
+
}
|
|
13322
|
+
|
|
11919
13323
|
// src/plan-progress.ts
|
|
11920
|
-
|
|
13324
|
+
init_config();
|
|
13325
|
+
import path62 from "node:path";
|
|
11921
13326
|
|
|
11922
13327
|
// src/bounded-build/constants.ts
|
|
11923
13328
|
var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
|
|
@@ -11926,6 +13331,9 @@ var DEFAULT_NODE_OLD_SPACE_SIZE_MB = 1024;
|
|
|
11926
13331
|
var DEFAULT_SYSTEMD_MEMORY_MAX = "1.5G";
|
|
11927
13332
|
var DEFAULT_SYSTEMD_MEMORY_SWAP_MAX = "2G";
|
|
11928
13333
|
|
|
13334
|
+
// src/bounded-build/index.ts
|
|
13335
|
+
init_meminfo();
|
|
13336
|
+
|
|
11929
13337
|
// src/bounded-build/node-options.ts
|
|
11930
13338
|
var MAX_OLD_SPACE_RE = /--max-old-space-size=(\d+)/;
|
|
11931
13339
|
function parsePositiveInt(value, fallback) {
|
|
@@ -11955,7 +13363,7 @@ function formatNodeOptionsFlag(mb = resolveNodeOldSpaceSizeMb()) {
|
|
|
11955
13363
|
}
|
|
11956
13364
|
|
|
11957
13365
|
// src/bounded-build/systemd-wrap.ts
|
|
11958
|
-
import { spawnSync as
|
|
13366
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
11959
13367
|
var systemdAvailableCache;
|
|
11960
13368
|
function isSystemdRunAvailable() {
|
|
11961
13369
|
if (process.env.KYNVER_BUILD_SKIP_SYSTEMD === "1" || process.env.KYNVER_BUILD_SKIP_SYSTEMD === "true") {
|
|
@@ -11966,7 +13374,7 @@ function isSystemdRunAvailable() {
|
|
|
11966
13374
|
systemdAvailableCache = false;
|
|
11967
13375
|
return false;
|
|
11968
13376
|
}
|
|
11969
|
-
const res =
|
|
13377
|
+
const res = spawnSync8("systemd-run", ["--version"], { encoding: "utf8", stdio: ["ignore", "ignore", "pipe"] });
|
|
11970
13378
|
systemdAvailableCache = res.status === 0;
|
|
11971
13379
|
return systemdAvailableCache;
|
|
11972
13380
|
}
|
|
@@ -11990,7 +13398,9 @@ function buildSystemdRunArgv(opts) {
|
|
|
11990
13398
|
}
|
|
11991
13399
|
|
|
11992
13400
|
// src/bounded-build/admission.ts
|
|
11993
|
-
|
|
13401
|
+
init_config();
|
|
13402
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
13403
|
+
init_meminfo();
|
|
11994
13404
|
function positiveInt4(value, fallback) {
|
|
11995
13405
|
const n = Number(value);
|
|
11996
13406
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
@@ -12026,7 +13436,7 @@ function assessBuildAdmission(opts = {}) {
|
|
|
12026
13436
|
}
|
|
12027
13437
|
function sleepMs2(ms) {
|
|
12028
13438
|
if (ms <= 0) return;
|
|
12029
|
-
|
|
13439
|
+
spawnSync9(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
12030
13440
|
stdio: "ignore"
|
|
12031
13441
|
});
|
|
12032
13442
|
}
|
|
@@ -12047,33 +13457,34 @@ function waitForBuildAdmission(timeoutMs, pollMs = 2e3, opts = {}) {
|
|
|
12047
13457
|
}
|
|
12048
13458
|
|
|
12049
13459
|
// src/bounded-build/exec.ts
|
|
12050
|
-
import { spawnSync as
|
|
13460
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
12051
13461
|
|
|
12052
13462
|
// src/heavy-verification/slot.ts
|
|
13463
|
+
init_util();
|
|
12053
13464
|
import {
|
|
12054
13465
|
closeSync as closeSync7,
|
|
12055
13466
|
existsSync as existsSync41,
|
|
12056
|
-
mkdirSync as
|
|
13467
|
+
mkdirSync as mkdirSync9,
|
|
12057
13468
|
openSync as openSync7,
|
|
12058
13469
|
readdirSync as readdirSync15,
|
|
12059
|
-
readFileSync as
|
|
13470
|
+
readFileSync as readFileSync15,
|
|
12060
13471
|
unlinkSync as unlinkSync4,
|
|
12061
|
-
writeFileSync as
|
|
13472
|
+
writeFileSync as writeFileSync6
|
|
12062
13473
|
} from "node:fs";
|
|
12063
|
-
import
|
|
13474
|
+
import path60 from "node:path";
|
|
12064
13475
|
|
|
12065
13476
|
// src/heavy-verification/paths.ts
|
|
12066
|
-
import { mkdirSync as
|
|
12067
|
-
import
|
|
13477
|
+
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
13478
|
+
import path59 from "node:path";
|
|
12068
13479
|
function resolveHeavyVerificationRoot() {
|
|
12069
|
-
return
|
|
13480
|
+
return path59.join(resolveKynverStateRoot(), "heavy-verification");
|
|
12070
13481
|
}
|
|
12071
13482
|
function heavyVerificationSlotsDir() {
|
|
12072
|
-
return
|
|
13483
|
+
return path59.join(resolveHeavyVerificationRoot(), "slots");
|
|
12073
13484
|
}
|
|
12074
13485
|
function ensureHeavyVerificationDirs() {
|
|
12075
13486
|
const dir = heavyVerificationSlotsDir();
|
|
12076
|
-
|
|
13487
|
+
mkdirSync8(dir, { recursive: true });
|
|
12077
13488
|
return dir;
|
|
12078
13489
|
}
|
|
12079
13490
|
|
|
@@ -12098,12 +13509,12 @@ function indexedSlotId(index) {
|
|
|
12098
13509
|
return `slot-${index}`;
|
|
12099
13510
|
}
|
|
12100
13511
|
function slotFilePath(slotId, slotsDir = heavyVerificationSlotsDir()) {
|
|
12101
|
-
return
|
|
13512
|
+
return path60.join(slotsDir, `${slotId}.json`);
|
|
12102
13513
|
}
|
|
12103
13514
|
function readSlotRecord(filePath) {
|
|
12104
13515
|
if (!existsSync41(filePath)) return null;
|
|
12105
13516
|
try {
|
|
12106
|
-
const parsed = JSON.parse(
|
|
13517
|
+
const parsed = JSON.parse(readFileSync15(filePath, "utf8"));
|
|
12107
13518
|
if (typeof parsed.slotId === "string" && typeof parsed.pid === "number" && typeof parsed.acquiredAt === "string" && typeof parsed.command === "string") {
|
|
12108
13519
|
return parsed;
|
|
12109
13520
|
}
|
|
@@ -12128,7 +13539,7 @@ function reclaimStaleSlot(filePath, staleMs) {
|
|
|
12128
13539
|
}
|
|
12129
13540
|
}
|
|
12130
13541
|
function ensureSlotsDir(slotsDir) {
|
|
12131
|
-
|
|
13542
|
+
mkdirSync9(slotsDir, { recursive: true });
|
|
12132
13543
|
return slotsDir;
|
|
12133
13544
|
}
|
|
12134
13545
|
function reclaimStaleHeavyVerificationSlots(opts = {}) {
|
|
@@ -12137,7 +13548,7 @@ function reclaimStaleHeavyVerificationSlots(opts = {}) {
|
|
|
12137
13548
|
let reclaimed = 0;
|
|
12138
13549
|
for (const name of readdirSync15(slotsDir)) {
|
|
12139
13550
|
if (!name.endsWith(".json")) continue;
|
|
12140
|
-
const filePath =
|
|
13551
|
+
const filePath = path60.join(slotsDir, name);
|
|
12141
13552
|
const before = existsSync41(filePath);
|
|
12142
13553
|
reclaimStaleSlot(filePath, staleMs);
|
|
12143
13554
|
if (before && !existsSync41(filePath)) reclaimed += 1;
|
|
@@ -12151,7 +13562,7 @@ function listActiveHeavyVerificationSlots(opts = {}) {
|
|
|
12151
13562
|
const active = [];
|
|
12152
13563
|
for (const name of readdirSync15(slotsDir)) {
|
|
12153
13564
|
if (!name.endsWith(".json")) continue;
|
|
12154
|
-
const record = readSlotRecord(
|
|
13565
|
+
const record = readSlotRecord(path60.join(slotsDir, name));
|
|
12155
13566
|
if (record && !slotIsStale(record, staleMs)) active.push(record);
|
|
12156
13567
|
}
|
|
12157
13568
|
return active;
|
|
@@ -12193,7 +13604,7 @@ function tryAcquireHeavyVerificationSlot(command, opts = {}) {
|
|
|
12193
13604
|
};
|
|
12194
13605
|
try {
|
|
12195
13606
|
const fd = openSync7(filePath, "wx");
|
|
12196
|
-
|
|
13607
|
+
writeFileSync6(fd, JSON.stringify(record, null, 2), "utf8");
|
|
12197
13608
|
closeSync7(fd);
|
|
12198
13609
|
const activeSlots2 = countActiveHeavyVerificationSlots({ slotsDir, staleMs });
|
|
12199
13610
|
return {
|
|
@@ -12253,10 +13664,10 @@ function assessHeavyVerificationGate(command, opts = {}) {
|
|
|
12253
13664
|
}
|
|
12254
13665
|
|
|
12255
13666
|
// src/heavy-verification/gate.ts
|
|
12256
|
-
import { spawnSync as
|
|
13667
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
12257
13668
|
function sleepMs3(ms) {
|
|
12258
13669
|
if (ms <= 0) return;
|
|
12259
|
-
|
|
13670
|
+
spawnSync10(process.execPath, ["-e", `const d=Date.now()+${Math.floor(ms)};while(Date.now()<d);`], {
|
|
12260
13671
|
stdio: "ignore"
|
|
12261
13672
|
});
|
|
12262
13673
|
}
|
|
@@ -12271,11 +13682,12 @@ function waitForHeavyVerificationSlot(command, timeoutMs, pollMs = 2e3, opts = {
|
|
|
12271
13682
|
}
|
|
12272
13683
|
|
|
12273
13684
|
// src/harness-worktree-build-guard.ts
|
|
12274
|
-
|
|
13685
|
+
init_paths();
|
|
13686
|
+
import path61 from "node:path";
|
|
12275
13687
|
function isPathUnderHarnessWorktree(cwd) {
|
|
12276
13688
|
const worktreesDir = harnessWorktreesDir(resolveHarnessRoot());
|
|
12277
|
-
const rel =
|
|
12278
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
13689
|
+
const rel = path61.relative(worktreesDir, path61.resolve(cwd));
|
|
13690
|
+
return rel.length > 0 && !rel.startsWith("..") && !path61.isAbsolute(rel);
|
|
12279
13691
|
}
|
|
12280
13692
|
function assessHarnessWorktreeBuildGuard(cwd) {
|
|
12281
13693
|
if (!isPathUnderHarnessWorktree(cwd)) return { ok: true };
|
|
@@ -12299,7 +13711,7 @@ function envArgv(env) {
|
|
|
12299
13711
|
return out;
|
|
12300
13712
|
}
|
|
12301
13713
|
function runSpawn(argv, opts) {
|
|
12302
|
-
const res =
|
|
13714
|
+
const res = spawnSync11(argv[0], argv.slice(1), {
|
|
12303
13715
|
cwd: opts.cwd,
|
|
12304
13716
|
env: opts.env,
|
|
12305
13717
|
encoding: "utf8",
|
|
@@ -12425,6 +13837,7 @@ function runHarnessVerifyCommands(cwd, commands = DEFAULT_HARNESS_VERIFY_COMMAND
|
|
|
12425
13837
|
}
|
|
12426
13838
|
|
|
12427
13839
|
// src/plan-progress.ts
|
|
13840
|
+
init_util();
|
|
12428
13841
|
function parseEvidenceArg(raw) {
|
|
12429
13842
|
const idx = raw.indexOf(":");
|
|
12430
13843
|
if (idx <= 0) throw new Error(`invalid --evidence ${raw} (expected type:value)`);
|
|
@@ -12487,7 +13900,7 @@ async function emitPlanProgress(args) {
|
|
|
12487
13900
|
}
|
|
12488
13901
|
function verifyPlanLocal(args) {
|
|
12489
13902
|
const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
|
|
12490
|
-
const cwd =
|
|
13903
|
+
const cwd = path62.resolve(worktree);
|
|
12491
13904
|
const summary = runHarnessVerifyCommands(cwd);
|
|
12492
13905
|
const emitJson = args.json === true || args.json === "true";
|
|
12493
13906
|
const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
|
|
@@ -12536,9 +13949,10 @@ async function verifyPlan(args) {
|
|
|
12536
13949
|
}
|
|
12537
13950
|
|
|
12538
13951
|
// src/harness-verify-cli.ts
|
|
12539
|
-
import
|
|
13952
|
+
import path63 from "node:path";
|
|
13953
|
+
init_util();
|
|
12540
13954
|
function runHarnessVerifyCli(args) {
|
|
12541
|
-
const cwd =
|
|
13955
|
+
const cwd = path63.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
|
|
12542
13956
|
const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
|
|
12543
13957
|
const commands = [];
|
|
12544
13958
|
const rawCmd = args.command;
|
|
@@ -12583,7 +13997,9 @@ function runHarnessVerifyCli(args) {
|
|
|
12583
13997
|
}
|
|
12584
13998
|
|
|
12585
13999
|
// src/plan-persist-cli.ts
|
|
12586
|
-
|
|
14000
|
+
init_config();
|
|
14001
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
14002
|
+
init_util();
|
|
12587
14003
|
var OPERATIONS = ["create", "add_version", "update_metadata"];
|
|
12588
14004
|
var FAILURE_KINDS = [
|
|
12589
14005
|
"approval_guard",
|
|
@@ -12595,7 +14011,7 @@ var FAILURE_KINDS = [
|
|
|
12595
14011
|
function readBodyArg(args) {
|
|
12596
14012
|
const bodyFile = args.bodyFile ? String(args.bodyFile) : void 0;
|
|
12597
14013
|
if (bodyFile) {
|
|
12598
|
-
return { body:
|
|
14014
|
+
return { body: readFileSync16(bodyFile, "utf8"), bodyPathHint: bodyFile };
|
|
12599
14015
|
}
|
|
12600
14016
|
const inline = args.body ? String(args.body) : void 0;
|
|
12601
14017
|
if (inline) return { body: inline };
|
|
@@ -12746,9 +14162,14 @@ function formatMonitorTickNotice(tick) {
|
|
|
12746
14162
|
}
|
|
12747
14163
|
|
|
12748
14164
|
// src/monitor/monitor.service.ts
|
|
12749
|
-
import
|
|
14165
|
+
import path65 from "node:path";
|
|
14166
|
+
init_run_store();
|
|
14167
|
+
init_status();
|
|
14168
|
+
init_util();
|
|
12750
14169
|
|
|
12751
14170
|
// src/monitor/monitor.classify.ts
|
|
14171
|
+
init_status();
|
|
14172
|
+
init_util();
|
|
12752
14173
|
function classifyWorkerHealth(input) {
|
|
12753
14174
|
const { worker, status, taskLease } = input;
|
|
12754
14175
|
const leaseOwner = taskLease?.leaseOwner ?? null;
|
|
@@ -12798,19 +14219,21 @@ function classifyWorkerHealth(input) {
|
|
|
12798
14219
|
}
|
|
12799
14220
|
|
|
12800
14221
|
// src/monitor/monitor.store.ts
|
|
12801
|
-
|
|
12802
|
-
|
|
14222
|
+
init_paths();
|
|
14223
|
+
init_util();
|
|
14224
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync10, readdirSync as readdirSync16, unlinkSync as unlinkSync5 } from "node:fs";
|
|
14225
|
+
import path64 from "node:path";
|
|
12803
14226
|
function monitorsDir() {
|
|
12804
14227
|
const { harnessRoot } = getHarnessPaths();
|
|
12805
|
-
const dir =
|
|
12806
|
-
|
|
14228
|
+
const dir = path64.join(harnessRoot, "monitors");
|
|
14229
|
+
mkdirSync10(dir, { recursive: true });
|
|
12807
14230
|
return dir;
|
|
12808
14231
|
}
|
|
12809
14232
|
function monitorIdFor(runId, workerName) {
|
|
12810
14233
|
return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
|
|
12811
14234
|
}
|
|
12812
14235
|
function monitorPath(monitorId) {
|
|
12813
|
-
return
|
|
14236
|
+
return path64.join(monitorsDir(), `${monitorId}.json`);
|
|
12814
14237
|
}
|
|
12815
14238
|
function loadMonitorSession(monitorId) {
|
|
12816
14239
|
return readJson(monitorPath(monitorId), void 0);
|
|
@@ -12831,7 +14254,7 @@ function listMonitorSessions() {
|
|
|
12831
14254
|
for (const name of readdirSync16(dir)) {
|
|
12832
14255
|
if (!name.endsWith(".json")) continue;
|
|
12833
14256
|
const session = readJson(
|
|
12834
|
-
|
|
14257
|
+
path64.join(dir, name),
|
|
12835
14258
|
void 0
|
|
12836
14259
|
);
|
|
12837
14260
|
if (!session?.monitorId) continue;
|
|
@@ -12851,6 +14274,7 @@ function listMonitorSessions() {
|
|
|
12851
14274
|
}
|
|
12852
14275
|
|
|
12853
14276
|
// src/monitor/monitor.terminal.ts
|
|
14277
|
+
init_status();
|
|
12854
14278
|
function assessAutoCompleteEligibility(input) {
|
|
12855
14279
|
const { worker, status } = input;
|
|
12856
14280
|
const blockers = [];
|
|
@@ -12894,6 +14318,7 @@ function assessAutoCompleteEligibility(input) {
|
|
|
12894
14318
|
}
|
|
12895
14319
|
|
|
12896
14320
|
// src/monitor/monitor.task-lease.ts
|
|
14321
|
+
init_config();
|
|
12897
14322
|
async function fetchTaskLeasesForWorkers(input) {
|
|
12898
14323
|
const out = /* @__PURE__ */ new Map();
|
|
12899
14324
|
const agentOsId = input.agentOsId?.trim();
|
|
@@ -12922,7 +14347,7 @@ async function fetchTaskLeasesForWorkers(input) {
|
|
|
12922
14347
|
// src/monitor/monitor.service.ts
|
|
12923
14348
|
function workerRecord2(runId, name) {
|
|
12924
14349
|
return readJson(
|
|
12925
|
-
|
|
14350
|
+
path65.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
|
|
12926
14351
|
void 0
|
|
12927
14352
|
);
|
|
12928
14353
|
}
|
|
@@ -13092,6 +14517,7 @@ async function monitorAutoCompleteCli(args) {
|
|
|
13092
14517
|
}
|
|
13093
14518
|
|
|
13094
14519
|
// src/monitor/monitor-loop.ts
|
|
14520
|
+
init_util();
|
|
13095
14521
|
var DEFAULT_POLL_MS2 = 5e3;
|
|
13096
14522
|
var DEFAULT_MAX_TOTAL_MS2 = 6 * 60 * 60 * 1e3;
|
|
13097
14523
|
async function runMonitorLoop(args) {
|
|
@@ -13127,19 +14553,21 @@ async function runMonitorLoop(args) {
|
|
|
13127
14553
|
}
|
|
13128
14554
|
|
|
13129
14555
|
// src/monitor/monitor-spawn.ts
|
|
13130
|
-
|
|
14556
|
+
init_util();
|
|
14557
|
+
init_paths();
|
|
14558
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
13131
14559
|
import { closeSync as closeSync8, existsSync as existsSync43, openSync as openSync8 } from "node:fs";
|
|
13132
|
-
import
|
|
14560
|
+
import path66 from "node:path";
|
|
13133
14561
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
13134
14562
|
function resolveDefaultCliPath2() {
|
|
13135
|
-
return
|
|
14563
|
+
return path66.join(fileURLToPath3(new URL(".", import.meta.url)), "cli.js");
|
|
13136
14564
|
}
|
|
13137
14565
|
function spawnMonitorSidecar(opts) {
|
|
13138
14566
|
const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
|
|
13139
14567
|
if (!existsSync43(cliPath)) return void 0;
|
|
13140
14568
|
const monitorId = monitorIdFor(opts.runId, opts.workerName);
|
|
13141
14569
|
const { harnessRoot } = getHarnessPaths();
|
|
13142
|
-
const logPath =
|
|
14570
|
+
const logPath = path66.join(harnessRoot, "monitors", `${monitorId}.log`);
|
|
13143
14571
|
let logFd;
|
|
13144
14572
|
try {
|
|
13145
14573
|
logFd = openSync8(logPath, "a");
|
|
@@ -13173,7 +14601,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
13173
14601
|
logFd ?? "ignore"
|
|
13174
14602
|
];
|
|
13175
14603
|
try {
|
|
13176
|
-
const child =
|
|
14604
|
+
const child = spawn7(
|
|
13177
14605
|
nodeExecutable,
|
|
13178
14606
|
args,
|
|
13179
14607
|
hiddenSpawnOptions({
|
|
@@ -13208,6 +14636,7 @@ function spawnMonitorSidecar(opts) {
|
|
|
13208
14636
|
}
|
|
13209
14637
|
|
|
13210
14638
|
// src/monitor/monitor-cli.ts
|
|
14639
|
+
init_util();
|
|
13211
14640
|
async function startMonitorCli(args) {
|
|
13212
14641
|
const runId = String(args.run || "");
|
|
13213
14642
|
required(runId, "--run");
|
|
@@ -13259,7 +14688,7 @@ async function monitorTickCli(args) {
|
|
|
13259
14688
|
}
|
|
13260
14689
|
|
|
13261
14690
|
// src/package-version.ts
|
|
13262
|
-
import { existsSync as existsSync44, readFileSync as
|
|
14691
|
+
import { existsSync as existsSync44, readFileSync as readFileSync17 } from "node:fs";
|
|
13263
14692
|
import { dirname, join } from "node:path";
|
|
13264
14693
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
13265
14694
|
function resolvePackageRoot(moduleUrl) {
|
|
@@ -13274,7 +14703,7 @@ function resolvePackageRoot(moduleUrl) {
|
|
|
13274
14703
|
}
|
|
13275
14704
|
function readOwnPackageVersion(moduleUrl = import.meta.url) {
|
|
13276
14705
|
const pkgPath = join(resolvePackageRoot(moduleUrl), "package.json");
|
|
13277
|
-
const pkg = JSON.parse(
|
|
14706
|
+
const pkg = JSON.parse(readFileSync17(pkgPath, "utf8"));
|
|
13278
14707
|
if (typeof pkg.version !== "string" || !pkg.version.trim()) {
|
|
13279
14708
|
throw new Error(`Missing package.json version at ${pkgPath}`);
|
|
13280
14709
|
}
|
|
@@ -13341,6 +14770,7 @@ function shouldEnforceMemoryCostPackageGuardCli(scope, action) {
|
|
|
13341
14770
|
}
|
|
13342
14771
|
|
|
13343
14772
|
// src/run-resolve.ts
|
|
14773
|
+
init_util();
|
|
13344
14774
|
function resolveHarnessRunByName(runName) {
|
|
13345
14775
|
const name = runName.trim();
|
|
13346
14776
|
if (!name) return null;
|
|
@@ -13365,7 +14795,11 @@ function resolveHarnessRunCli(args) {
|
|
|
13365
14795
|
}
|
|
13366
14796
|
|
|
13367
14797
|
// src/post-restart-unblock.ts
|
|
13368
|
-
|
|
14798
|
+
init_run_store();
|
|
14799
|
+
init_status();
|
|
14800
|
+
init_util();
|
|
14801
|
+
init_config();
|
|
14802
|
+
import path67 from "node:path";
|
|
13369
14803
|
function skip(runId, worker, taskId, agentOsId, leaseOwner, reason) {
|
|
13370
14804
|
return { runId, worker, taskId, agentOsId, leaseOwner, action: "skipped", reason };
|
|
13371
14805
|
}
|
|
@@ -13378,7 +14812,7 @@ async function postRestartUnblock(args) {
|
|
|
13378
14812
|
const errors = [];
|
|
13379
14813
|
for (const run of listRunRecords()) {
|
|
13380
14814
|
for (const name of Object.keys(run.workers ?? {})) {
|
|
13381
|
-
const workerPath =
|
|
14815
|
+
const workerPath = path67.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
|
|
13382
14816
|
const worker = readJson(workerPath, void 0);
|
|
13383
14817
|
if (!worker) {
|
|
13384
14818
|
skipped.push(skip(run.id, name, "", "", "", "worker.json missing"));
|
|
@@ -13490,9 +14924,11 @@ async function postRestartUnblockCli(args) {
|
|
|
13490
14924
|
}
|
|
13491
14925
|
|
|
13492
14926
|
// src/default-repo-cli.ts
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
14927
|
+
init_path_values();
|
|
14928
|
+
init_config();
|
|
14929
|
+
import path68 from "node:path";
|
|
14930
|
+
import { homedir as homedir15 } from "node:os";
|
|
14931
|
+
var CONFIG_FILE2 = path68.join(homedir15(), ".kynver", "config.json");
|
|
13496
14932
|
function ensureDefaultRepo(opts) {
|
|
13497
14933
|
const existing = loadUserConfig();
|
|
13498
14934
|
const resolved = resolveDefaultRepo({ ...opts, config: existing });
|
|
@@ -13573,16 +15009,19 @@ function summarizeResolvedDefaultRepo(resolved) {
|
|
|
13573
15009
|
}
|
|
13574
15010
|
|
|
13575
15011
|
// src/doctor/runtime-takeover.ts
|
|
13576
|
-
import
|
|
15012
|
+
import path70 from "node:path";
|
|
15013
|
+
init_path_values();
|
|
13577
15014
|
|
|
13578
15015
|
// src/doctor/runtime-takeover.probes.ts
|
|
13579
|
-
|
|
13580
|
-
import {
|
|
13581
|
-
import
|
|
13582
|
-
import
|
|
15016
|
+
init_config();
|
|
15017
|
+
import { accessSync, constants, existsSync as existsSync45, readFileSync as readFileSync18 } from "node:fs";
|
|
15018
|
+
import { homedir as homedir16 } from "node:os";
|
|
15019
|
+
import path69 from "node:path";
|
|
15020
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
15021
|
+
init_paths();
|
|
13583
15022
|
function captureCommand(bin, args) {
|
|
13584
15023
|
try {
|
|
13585
|
-
const res =
|
|
15024
|
+
const res = spawnSync12(bin, args, { encoding: "utf8" });
|
|
13586
15025
|
const stdout = (res.stdout || "").trim();
|
|
13587
15026
|
const stderr = (res.stderr || "").trim();
|
|
13588
15027
|
const ok = res.status === 0;
|
|
@@ -13620,15 +15059,15 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
13620
15059
|
commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
|
|
13621
15060
|
kynverVersion: (bin) => captureCommand(bin, ["--version"]),
|
|
13622
15061
|
loadConfig: () => loadUserConfig(),
|
|
13623
|
-
configFilePath: () =>
|
|
13624
|
-
credentialsFilePath: () =>
|
|
15062
|
+
configFilePath: () => path69.join(homedir16(), ".kynver", "config.json"),
|
|
15063
|
+
credentialsFilePath: () => path69.join(homedir16(), ".kynver", "credentials"),
|
|
13625
15064
|
readCredentials: () => {
|
|
13626
|
-
const credPath =
|
|
15065
|
+
const credPath = path69.join(homedir16(), ".kynver", "credentials");
|
|
13627
15066
|
if (!existsSync45(credPath)) {
|
|
13628
15067
|
return { hasApiKey: false };
|
|
13629
15068
|
}
|
|
13630
15069
|
try {
|
|
13631
|
-
const parsed = JSON.parse(
|
|
15070
|
+
const parsed = JSON.parse(readFileSync18(credPath, "utf8"));
|
|
13632
15071
|
return {
|
|
13633
15072
|
hasApiKey: Boolean(parsed.apiKey?.trim()),
|
|
13634
15073
|
runnerTokenPrefix: tokenPrefix(parsed.runnerToken),
|
|
@@ -13658,7 +15097,7 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
13658
15097
|
})()
|
|
13659
15098
|
}),
|
|
13660
15099
|
harnessRoot: () => resolveHarnessRoot(),
|
|
13661
|
-
legacyOpenclawHarnessRoot: () =>
|
|
15100
|
+
legacyOpenclawHarnessRoot: () => path69.join(homedir16(), ".openclaw", "harness"),
|
|
13662
15101
|
pathExists: (target) => existsSync45(target),
|
|
13663
15102
|
pathWritable: (target) => isWritable(target)
|
|
13664
15103
|
};
|
|
@@ -13831,12 +15270,12 @@ function assessRuntimeTakeoverScheduler(env, ctx) {
|
|
|
13831
15270
|
return check({
|
|
13832
15271
|
id: "hotspot_openclaw_scheduler",
|
|
13833
15272
|
label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
|
|
13834
|
-
status: "
|
|
13835
|
-
summary: "
|
|
13836
|
-
remediation: "
|
|
15273
|
+
status: "warn",
|
|
15274
|
+
summary: "Hosted deployment with no QSTASH_TOKEN and no KYNVER_SCHEDULER_PROVIDER \u2014 kynver-cron is an in-process stub here and will NOT fire; no firing scheduler is configured",
|
|
15275
|
+
remediation: "Set QSTASH_TOKEN + KYNVER_SCHEDULER_PROVIDER=qstash on the Kynver server for hosted AgentOS schedules. Only use kynver-cron when a `kynver daemon` (or local cron store) actually owns firing on this box.",
|
|
13837
15276
|
details: {
|
|
13838
15277
|
schedulerProvider: null,
|
|
13839
|
-
resolvedFallback: "
|
|
15278
|
+
resolvedFallback: "none",
|
|
13840
15279
|
qstashTokenPresent: false,
|
|
13841
15280
|
hostedDeployment
|
|
13842
15281
|
}
|
|
@@ -14065,8 +15504,8 @@ function assessVercelDeployEvidence(probes) {
|
|
|
14065
15504
|
}
|
|
14066
15505
|
function assessHarnessDirs(probes) {
|
|
14067
15506
|
const harnessRoot = probes.harnessRoot();
|
|
14068
|
-
const runsDir =
|
|
14069
|
-
const worktreesDir =
|
|
15507
|
+
const runsDir = path70.join(harnessRoot, "runs");
|
|
15508
|
+
const worktreesDir = path70.join(harnessRoot, "worktrees");
|
|
14070
15509
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
14071
15510
|
const displayRunsDir = redactHomePath(runsDir);
|
|
14072
15511
|
const displayWorktreesDir = redactHomePath(worktreesDir);
|
|
@@ -14242,6 +15681,7 @@ function runRuntimeTakeoverDoctorCli(args = {}) {
|
|
|
14242
15681
|
}
|
|
14243
15682
|
|
|
14244
15683
|
// src/command-center-contract-cli.ts
|
|
15684
|
+
init_config();
|
|
14245
15685
|
async function runCommandCenterContractCli(args) {
|
|
14246
15686
|
const config = loadUserConfig();
|
|
14247
15687
|
const agentOsId = (args.agentOsId ? String(args.agentOsId) : config.agentOsId) || "";
|
|
@@ -14272,6 +15712,9 @@ async function runCommandCenterContractCli(args) {
|
|
|
14272
15712
|
console.log(JSON.stringify(res.response, null, 2));
|
|
14273
15713
|
}
|
|
14274
15714
|
|
|
15715
|
+
// src/scheduler-cutover-cli.ts
|
|
15716
|
+
init_path_values();
|
|
15717
|
+
|
|
14275
15718
|
// src/scheduler-cutover.ts
|
|
14276
15719
|
var DEPLOYMENT_SCHEDULER_CUTOVER_STEPS = [
|
|
14277
15720
|
"Vercel/hosted: set KYNVER_SCHEDULER_PROVIDER=qstash",
|
|
@@ -14330,9 +15773,10 @@ function applySchedulerCutoverAttestation(config) {
|
|
|
14330
15773
|
}
|
|
14331
15774
|
|
|
14332
15775
|
// src/scheduler-cutover-cli.ts
|
|
14333
|
-
|
|
14334
|
-
import
|
|
14335
|
-
|
|
15776
|
+
init_config();
|
|
15777
|
+
import path71 from "node:path";
|
|
15778
|
+
import { homedir as homedir17 } from "node:os";
|
|
15779
|
+
var CONFIG_FILE3 = path71.join(homedir17(), ".kynver", "config.json");
|
|
14336
15780
|
function runSchedulerCutoverCheckCli(json = false) {
|
|
14337
15781
|
const config = loadUserConfig();
|
|
14338
15782
|
const report = assessSchedulerCutover(config);
|
|
@@ -14470,7 +15914,12 @@ async function runCronTickCli(args) {
|
|
|
14470
15914
|
}
|
|
14471
15915
|
|
|
14472
15916
|
// src/lane/landing-maintainer-tick.ts
|
|
14473
|
-
|
|
15917
|
+
init_config();
|
|
15918
|
+
import os11 from "node:os";
|
|
15919
|
+
init_config();
|
|
15920
|
+
init_box_identity();
|
|
15921
|
+
init_resource_gate();
|
|
15922
|
+
init_util();
|
|
14474
15923
|
|
|
14475
15924
|
// src/lane/lane-spec.ts
|
|
14476
15925
|
var LANDING_MAINTAINER_LANE_SPEC = {
|
|
@@ -14482,10 +15931,10 @@ var LANDING_MAINTAINER_LANE_SPEC = {
|
|
|
14482
15931
|
};
|
|
14483
15932
|
|
|
14484
15933
|
// src/lane/landing-maintainer-local.ts
|
|
14485
|
-
import { spawnSync as
|
|
14486
|
-
import
|
|
15934
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
15935
|
+
import path72 from "node:path";
|
|
14487
15936
|
function runLandingWrapper(prNumber, repoRoot, execute) {
|
|
14488
|
-
const script =
|
|
15937
|
+
const script = path72.join(repoRoot, LANDING_MAINTAINER_LANE_SPEC.landScript);
|
|
14489
15938
|
const args = [script, String(prNumber), ...LANDING_MAINTAINER_LANE_SPEC.landScriptArgs];
|
|
14490
15939
|
if (!execute) {
|
|
14491
15940
|
return {
|
|
@@ -14496,7 +15945,7 @@ function runLandingWrapper(prNumber, repoRoot, execute) {
|
|
|
14496
15945
|
stderr: ""
|
|
14497
15946
|
};
|
|
14498
15947
|
}
|
|
14499
|
-
const result =
|
|
15948
|
+
const result = spawnSync13("node", args, {
|
|
14500
15949
|
cwd: repoRoot,
|
|
14501
15950
|
encoding: "utf8",
|
|
14502
15951
|
timeout: 10 * 60 * 1e3
|
|
@@ -14511,7 +15960,7 @@ function runLandingWrapper(prNumber, repoRoot, execute) {
|
|
|
14511
15960
|
}
|
|
14512
15961
|
function resolveLandingMaintainerRepoRoot(args) {
|
|
14513
15962
|
const explicit = args.repoPath ? String(args.repoPath).trim() : "";
|
|
14514
|
-
if (explicit) return
|
|
15963
|
+
if (explicit) return path72.resolve(explicit);
|
|
14515
15964
|
const resolved = resolveDefaultRepo();
|
|
14516
15965
|
return resolved?.repo ?? process.cwd();
|
|
14517
15966
|
}
|
|
@@ -14530,7 +15979,7 @@ async function runLandingMaintainerLaneTick(args) {
|
|
|
14530
15979
|
...buildBoxResourceSnapshotFromGate(resourceGate, {
|
|
14531
15980
|
harnessRunId: runId,
|
|
14532
15981
|
boxKind: resolveBoxKindFromConfig(loadUserConfig()),
|
|
14533
|
-
hostLabel:
|
|
15982
|
+
hostLabel: os11.hostname()
|
|
14534
15983
|
}),
|
|
14535
15984
|
providerHealthy: resourceGate.ok,
|
|
14536
15985
|
authorizedForRepair: resourceGate.ok,
|
|
@@ -14634,18 +16083,20 @@ function usage(code = 0) {
|
|
|
14634
16083
|
out(
|
|
14635
16084
|
[
|
|
14636
16085
|
"Usage:",
|
|
14637
|
-
" kynver login --api-key KEY",
|
|
16086
|
+
" kynver login [--api-key KEY] [--api-base-url URL] (omit --api-key to authorize in the browser)",
|
|
16087
|
+
" kynver bootstrap [--api-base-url URL] [--api-key KEY] [--repo PATH] (login + setup + runner credential in one shot)",
|
|
14638
16088
|
" kynver runner credential [--agent-os-id ID] [--base-url URL]",
|
|
14639
16089
|
" kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--box-kind forge|ghost] [--repo PATH] [--discover-repo] [--max-workers N] [--provider claude|cursor]",
|
|
14640
|
-
" kynver daemon --run RUN_ID --agent-os-id AOS_ID [--execute] [--interval-ms MS]",
|
|
16090
|
+
" kynver daemon --run RUN_ID --agent-os-id AOS_ID [--execute] [--interval-ms MS] [--stall-ms MS] [--no-supervise]",
|
|
16091
|
+
" kynver status --run RUN_ID [--blocked] [--running] [--task TASK_ID] [--worker WORKER] [--full] # top-level compact run status",
|
|
14641
16092
|
" kynver run create [--repo /path/repo] [--name name] [--base origin/main]",
|
|
14642
16093
|
" kynver run list",
|
|
14643
16094
|
" kynver run resolve --name RUN_NAME",
|
|
14644
|
-
" kynver run status --run RUN_ID [--
|
|
16095
|
+
" kynver run status --run RUN_ID [--full] # defaults to compact shallow map with drill-down commands",
|
|
14645
16096
|
" kynver run dispatch --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--execute] [--lane any|implementation|review|landing] [--target-task-id TASK_ID] [--executor harness] [--max-starts 1] [--lease-ms MS] [--owned path[,path]] [--model claude-opus-4-8] [--disk-path /] [--reconcile-stale-blockers]",
|
|
14646
16097
|
" kynver run sweep --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--grace-ms MS]",
|
|
14647
16098
|
' kynver worker start --run RUN_ID --name worker --task "..." [--owned path[,path]] [--model MODEL] [--provider claude|cursor] [--agent-os-id AOS_ID] [--task-id TASK_ID] [--wait]',
|
|
14648
|
-
" kynver worker list --run RUN_ID [--
|
|
16099
|
+
" kynver worker list --run RUN_ID [--full] # defaults to compact shallow map with drill-down commands",
|
|
14649
16100
|
" kynver worker status --run RUN_ID --name worker",
|
|
14650
16101
|
" kynver worker tail --run RUN_ID --name worker [--lines 40] [--raw]",
|
|
14651
16102
|
" kynver worker stop --run RUN_ID --name worker",
|
|
@@ -14697,8 +16148,11 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
14697
16148
|
if (action && isHelpFlag(action) || rest.some(isHelpFlag)) return usage(0);
|
|
14698
16149
|
const args = parseArgs(rest);
|
|
14699
16150
|
const { runsDir, worktreesDir } = getPaths();
|
|
14700
|
-
|
|
14701
|
-
|
|
16151
|
+
mkdirSync11(runsDir, { recursive: true });
|
|
16152
|
+
mkdirSync11(worktreesDir, { recursive: true });
|
|
16153
|
+
if (scope === "daemon") {
|
|
16154
|
+
assertNativeDaemonAllowed();
|
|
16155
|
+
}
|
|
14702
16156
|
if (shouldEnforceMemoryCostPackageGuardCli(scope, action)) {
|
|
14703
16157
|
let repoRoot;
|
|
14704
16158
|
const runId = args.run ? String(args.run).trim() : "";
|
|
@@ -14715,9 +16169,16 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
14715
16169
|
});
|
|
14716
16170
|
}
|
|
14717
16171
|
if (scope === "login") return void await runLogin(args);
|
|
16172
|
+
if (scope === "bootstrap") return void await runBootstrap(args);
|
|
16173
|
+
if (scope === "status") return runStatus(args);
|
|
14718
16174
|
if (scope === "runner" && action === "credential") return void await mintRunnerCredential(args);
|
|
14719
16175
|
if (scope === "setup") return void await runSetup(args);
|
|
14720
|
-
if (scope === "daemon")
|
|
16176
|
+
if (scope === "daemon") {
|
|
16177
|
+
if (shouldRunDaemonKeeper(args)) {
|
|
16178
|
+
return void await runDaemonKeeper(args);
|
|
16179
|
+
}
|
|
16180
|
+
return void await runDaemon(args);
|
|
16181
|
+
}
|
|
14721
16182
|
if (scope === "plan" && action === "progress") return void await emitPlanProgress(args);
|
|
14722
16183
|
if (scope === "plan" && action === "verify") return void await verifyPlan(args);
|
|
14723
16184
|
if (scope === "harness" && action === "verify") return runHarnessVerifyCli(args);
|