@kynver-app/runtime 0.1.49 → 0.1.50

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/cli.js CHANGED
@@ -2,43 +2,25 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { mkdirSync as mkdirSync7, realpathSync } from "node:fs";
5
- import { fileURLToPath as fileURLToPath4 } from "node:url";
5
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
6
6
 
7
7
  // src/config.ts
8
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
8
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
9
+ import { homedir as homedir3 } from "node:os";
10
+ import path4 from "node:path";
11
+
12
+ // src/default-repo-discovery.ts
13
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
9
14
  import { homedir as homedir2 } from "node:os";
10
15
  import path3 from "node:path";
16
+ import { fileURLToPath } from "node:url";
11
17
 
12
- // src/path-values.ts
13
- import { homedir } from "node:os";
14
- import path from "node:path";
15
- function expandHomePath(value) {
16
- if (value === "~") return homedir();
17
- if (value.startsWith("~/") || value.startsWith("~\\")) {
18
- return path.join(homedir(), value.slice(2));
19
- }
20
- return value;
21
- }
22
- function resolveUserPath(value) {
23
- return path.resolve(expandHomePath(value));
24
- }
25
- function redactHomePath(value) {
26
- const expanded = expandHomePath(value);
27
- const resolved = path.resolve(expanded);
28
- const home = path.resolve(homedir());
29
- if (resolved === home) return "~";
30
- if (resolved.startsWith(`${home}${path.sep}`)) {
31
- return `~/${path.relative(home, resolved).split(path.sep).join("/")}`;
32
- }
33
- return resolved.replace(/^\/home\/[^/]+(?=\/|$)/, "~").replace(/^\/Users\/[^/]+(?=\/|$)/, "~");
34
- }
35
- function displayUserPath(value) {
36
- return redactHomePath(value);
37
- }
18
+ // src/git.ts
19
+ import { spawnSync } from "node:child_process";
38
20
 
39
21
  // src/util.ts
40
22
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
41
- import path2 from "node:path";
23
+ import path from "node:path";
42
24
  function fail(message) {
43
25
  console.error(message);
44
26
  process.exit(1);
@@ -67,7 +49,7 @@ function readJson(file, fallback) {
67
49
  }
68
50
  }
69
51
  function writeJson(file, value) {
70
- mkdirSync(path2.dirname(file), { recursive: true });
52
+ mkdirSync(path.dirname(file), { recursive: true });
71
53
  writeFileSync(file, `${JSON.stringify(value, null, 2)}
72
54
  `);
73
55
  }
@@ -103,7 +85,7 @@ function tailFile(file, lines) {
103
85
  return data.split("\n").slice(-lines).join("\n");
104
86
  }
105
87
  function readMaybeFile(file) {
106
- return file ? readFileSync(path2.resolve(file), "utf8") : "";
88
+ return file ? readFileSync(path.resolve(file), "utf8") : "";
107
89
  }
108
90
  function listRunIds(runsDir) {
109
91
  if (!existsSync(runsDir)) return [];
@@ -145,14 +127,270 @@ function secsAgo(ms) {
145
127
  return Math.max(0, Math.round((Date.now() - ms) / 1e3));
146
128
  }
147
129
 
130
+ // src/worker-env.ts
131
+ var FORBIDDEN_WORKER_ENV_KEYS = [
132
+ "ANTHROPIC_API_KEY",
133
+ "ANALYST_API_KEY",
134
+ "RECRUITER_API_KEY",
135
+ "AUTH_SECRET",
136
+ "NEXTAUTH_SECRET",
137
+ "DATABASE_URL",
138
+ "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
+ "OPENCLAW_CRON_SECRET",
146
+ "QSTASH_TOKEN",
147
+ "QSTASH_CURRENT_SIGNING_KEY",
148
+ "QSTASH_NEXT_SIGNING_KEY",
149
+ "TOOL_SECRETS_KEK",
150
+ "TOOL_EXECUTOR_DISPATCH_SECRET",
151
+ "CLOUDFLARE_API_TOKEN",
152
+ "STRIPE_SECRET_KEY",
153
+ "STRIPE_WEBHOOK_SECRET",
154
+ "STRIPE_IDENTITY_WEBHOOK_SECRET",
155
+ "VOYAGE_API_KEY",
156
+ "PERPLEXITY_API_KEY",
157
+ "FRED_API_KEY",
158
+ "FMP_API_KEY",
159
+ "CURSOR_API_KEY"
160
+ ];
161
+ var FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
162
+ var FORBIDDEN_SUFFIXES = ["_SECRET", "_API_KEY"];
163
+ function isForbiddenWorkerEnvKey(key) {
164
+ if (FORBIDDEN_KEY_SET.has(key)) return true;
165
+ return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));
166
+ }
167
+ function scrubWorkerEnv(env) {
168
+ const next = { ...env };
169
+ for (const key of Object.keys(next)) {
170
+ if (isForbiddenWorkerEnvKey(key)) delete next[key];
171
+ }
172
+ return next;
173
+ }
174
+
175
+ // src/git.ts
176
+ function git(cwd, args, options = {}) {
177
+ const res = spawnSync("git", args, { cwd, encoding: "utf8" });
178
+ if (res.status !== 0 && !options.allowFailure) {
179
+ const message = `git ${args.join(" ")} failed: ${res.stderr || res.stdout}`;
180
+ if (options.throwError) throw new Error(message);
181
+ fail(message);
182
+ }
183
+ return res.stdout || "";
184
+ }
185
+ function ensureGitRepo(repo) {
186
+ git(repo, ["rev-parse", "--show-toplevel"]);
187
+ }
188
+ function gitStatusShort(worktreePath) {
189
+ return git(worktreePath, ["status", "--short"], { allowFailure: true }).split("\n").map((line) => line.trim()).filter(Boolean);
190
+ }
191
+ function gitCapture(cwd, args) {
192
+ try {
193
+ const res = spawnSync("git", args, { cwd, encoding: "utf8" });
194
+ return {
195
+ status: res.status,
196
+ stdout: res.stdout || "",
197
+ stderr: res.stderr || "",
198
+ error: res.error ? res.error.message : null
199
+ };
200
+ } catch (error) {
201
+ return {
202
+ status: null,
203
+ stdout: "",
204
+ stderr: "",
205
+ error: error.message
206
+ };
207
+ }
208
+ }
209
+ function gitIsAncestor(cwd, ancestor, descendant) {
210
+ const res = gitCapture(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]);
211
+ if (res.status === 0) return { isAncestor: true, error: null };
212
+ if (res.status === 1) return { isAncestor: false, error: null };
213
+ return { isAncestor: null, error: res.error || res.stderr || res.stdout || `git exited ${res.status}` };
214
+ }
215
+ function computeGitAncestry(worktreePath, baseOrOptions = "origin/main") {
216
+ const options = typeof baseOrOptions === "string" ? { base: baseOrOptions } : baseOrOptions;
217
+ const baseLabel = options.baseCommit?.trim() || options.base?.trim() || "origin/main";
218
+ const pinnedBaseCommit = options.baseCommit?.trim() || null;
219
+ if (!worktreePath) {
220
+ return unknownAncestry(baseLabel, "missing worktree path");
221
+ }
222
+ const head = gitCapture(worktreePath, ["rev-parse", "HEAD"]);
223
+ if (head.status !== 0) {
224
+ return unknownAncestry(baseLabel, head.error || head.stderr || head.stdout || "failed to resolve HEAD");
225
+ }
226
+ let baseSha;
227
+ if (pinnedBaseCommit) {
228
+ baseSha = pinnedBaseCommit;
229
+ } else {
230
+ const baseHead = gitCapture(worktreePath, ["rev-parse", baseLabel]);
231
+ if (baseHead.status !== 0) {
232
+ return unknownAncestry(
233
+ baseLabel,
234
+ baseHead.error || baseHead.stderr || baseHead.stdout || `failed to resolve ${baseLabel}`,
235
+ head.stdout.trim()
236
+ );
237
+ }
238
+ baseSha = baseHead.stdout.trim();
239
+ }
240
+ const headSha = head.stdout.trim();
241
+ if (headSha === baseSha) {
242
+ return {
243
+ checked: true,
244
+ base: baseLabel,
245
+ head: headSha,
246
+ baseHead: baseSha,
247
+ baseIsAncestorOfHead: true,
248
+ headIsAncestorOfBase: true,
249
+ relation: "synced"
250
+ };
251
+ }
252
+ const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);
253
+ const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);
254
+ const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || void 0;
255
+ if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {
256
+ return {
257
+ checked: false,
258
+ base: baseLabel,
259
+ head: headSha,
260
+ baseHead: baseSha,
261
+ baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
262
+ headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
263
+ relation: "unknown",
264
+ ...error ? { error } : {}
265
+ };
266
+ }
267
+ const relation = baseIsAncestorOfHead.isAncestor ? "ahead" : headIsAncestorOfBase.isAncestor ? "merged" : "diverged";
268
+ return {
269
+ checked: true,
270
+ base: baseLabel,
271
+ head: headSha,
272
+ baseHead: baseSha,
273
+ baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
274
+ headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
275
+ relation,
276
+ ...error ? { error } : {}
277
+ };
278
+ }
279
+ function unknownAncestry(base, error, head = null) {
280
+ return {
281
+ checked: false,
282
+ base,
283
+ head,
284
+ baseHead: null,
285
+ baseIsAncestorOfHead: null,
286
+ headIsAncestorOfBase: null,
287
+ relation: "unknown",
288
+ error
289
+ };
290
+ }
291
+
292
+ // src/path-values.ts
293
+ import { homedir } from "node:os";
294
+ import path2 from "node:path";
295
+ function expandHomePath(value) {
296
+ if (value === "~") return homedir();
297
+ if (value.startsWith("~/") || value.startsWith("~\\")) {
298
+ return path2.join(homedir(), value.slice(2));
299
+ }
300
+ return value;
301
+ }
302
+ function resolveUserPath(value) {
303
+ return path2.resolve(expandHomePath(value));
304
+ }
305
+ function redactHomePath(value) {
306
+ const expanded = expandHomePath(value);
307
+ const resolved = path2.resolve(expanded);
308
+ const home = path2.resolve(homedir());
309
+ if (resolved === home) return "~";
310
+ if (resolved.startsWith(`${home}${path2.sep}`)) {
311
+ return `~/${path2.relative(home, resolved).split(path2.sep).join("/")}`;
312
+ }
313
+ return resolved.replace(/^\/home\/[^/]+(?=\/|$)/, "~").replace(/^\/Users\/[^/]+(?=\/|$)/, "~");
314
+ }
315
+ function displayUserPath(value) {
316
+ return redactHomePath(value);
317
+ }
318
+
319
+ // src/default-repo-discovery.ts
320
+ var WELL_KNOWN_REPO_DIRS = ["Kynver", "repos/Kynver", "code/Kynver", "projects/Kynver"];
321
+ function readPackageName(repoRoot) {
322
+ const pkgPath = path3.join(repoRoot, "package.json");
323
+ if (!existsSync2(pkgPath)) return null;
324
+ try {
325
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
326
+ return typeof pkg.name === "string" ? pkg.name.trim() : null;
327
+ } catch {
328
+ return null;
329
+ }
330
+ }
331
+ function isKynverMonorepoRoot(repoRoot) {
332
+ return readPackageName(repoRoot) === "kynver";
333
+ }
334
+ function gitRepoRoot(startDir) {
335
+ const resolvedStart = path3.resolve(startDir);
336
+ if (!existsSync2(resolvedStart)) return null;
337
+ const probe = gitCapture(resolvedStart, ["rev-parse", "--show-toplevel"]);
338
+ if (probe.status !== 0) return null;
339
+ const root = probe.stdout.trim();
340
+ return root.length ? path3.resolve(root) : null;
341
+ }
342
+ function resolveRuntimePackageRoot(moduleUrl = import.meta.url) {
343
+ let dir = path3.dirname(fileURLToPath(moduleUrl));
344
+ for (let depth = 0; depth < 8; depth += 1) {
345
+ const pkgPath = path3.join(dir, "package.json");
346
+ if (existsSync2(pkgPath)) {
347
+ try {
348
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
349
+ if (pkg.name === "@kynver-app/runtime") return dir;
350
+ } catch {
351
+ }
352
+ }
353
+ const parent = path3.dirname(dir);
354
+ if (parent === dir) break;
355
+ dir = parent;
356
+ }
357
+ return null;
358
+ }
359
+ function pushCandidate(seen, out, repo, source) {
360
+ if (!repo) return;
361
+ const resolved = path3.resolve(repo);
362
+ if (seen.has(resolved)) return;
363
+ if (!isKynverMonorepoRoot(resolved)) return;
364
+ seen.add(resolved);
365
+ out.push({ repo: resolved, source });
366
+ }
367
+ function discoverDefaultRepoCandidates(opts) {
368
+ const cwd = opts?.cwd ?? process.cwd();
369
+ const seen = /* @__PURE__ */ new Set();
370
+ const candidates = [];
371
+ pushCandidate(seen, candidates, gitRepoRoot(cwd), "cwd_git");
372
+ const runtimePkgRoot = resolveRuntimePackageRoot(opts?.runtimeModuleUrl ?? import.meta.url);
373
+ if (runtimePkgRoot) {
374
+ pushCandidate(seen, candidates, gitRepoRoot(runtimePkgRoot), "runtime_checkout");
375
+ }
376
+ const home = homedir2();
377
+ for (const rel of WELL_KNOWN_REPO_DIRS) {
378
+ pushCandidate(seen, candidates, resolveUserPath(path3.join(home, rel)), "well_known_path");
379
+ }
380
+ return candidates;
381
+ }
382
+ function discoverDefaultRepo(opts) {
383
+ return discoverDefaultRepoCandidates(opts)[0] ?? null;
384
+ }
385
+
148
386
  // src/config.ts
149
- var CONFIG_DIR = path3.join(homedir2(), ".kynver");
150
- var CONFIG_FILE = path3.join(CONFIG_DIR, "config.json");
151
- var CREDENTIALS_FILE = path3.join(CONFIG_DIR, "credentials");
387
+ var CONFIG_DIR = path4.join(homedir3(), ".kynver");
388
+ var CONFIG_FILE = path4.join(CONFIG_DIR, "config.json");
389
+ var CREDENTIALS_FILE = path4.join(CONFIG_DIR, "credentials");
152
390
  function loadUserConfig() {
153
- if (!existsSync2(CONFIG_FILE)) return {};
391
+ if (!existsSync3(CONFIG_FILE)) return {};
154
392
  try {
155
- return JSON.parse(readFileSync2(CONFIG_FILE, "utf8"));
393
+ return JSON.parse(readFileSync3(CONFIG_FILE, "utf8"));
156
394
  } catch {
157
395
  return {};
158
396
  }
@@ -176,7 +414,8 @@ function inferSetupFields(existing, args) {
176
414
  const creds = loadCredentialsFile();
177
415
  const apiBaseUrl = (typeof args.apiBaseUrl === "string" ? args.apiBaseUrl : void 0) || existing.apiBaseUrl?.trim() || process.env.KYNVER_API_URL?.trim() || process.env.OPENCLAW_CRON_FIRE_BASE_URL?.trim();
178
416
  const agentOsId = (typeof args.agentOsId === "string" ? args.agentOsId : void 0) || existing.agentOsId?.trim() || process.env.KYNVER_AGENT_OS_ID?.trim() || (creds.runnerToken?.trim().startsWith("krc1.") ? creds.runnerTokenAgentOsId?.trim() : void 0);
179
- const defaultRepo = (typeof args.repo === "string" ? args.repo : void 0) || existing.defaultRepo?.trim() || process.env.KYNVER_DEFAULT_REPO?.trim() || process.env.KYNVER_HARNESS_REPO?.trim();
417
+ const explicitRepo = typeof args.repo === "string" ? args.repo : args.discoverRepo === true || args.discoverRepo === "true" ? discoverDefaultRepo()?.repo : void 0;
418
+ const defaultRepo = explicitRepo || existing.defaultRepo?.trim() || process.env.KYNVER_DEFAULT_REPO?.trim() || process.env.KYNVER_HARNESS_REPO?.trim() || discoverDefaultRepo()?.repo;
180
419
  const harnessRoot = (typeof args.harnessRoot === "string" ? args.harnessRoot : void 0) || existing.harnessRoot?.trim() || process.env.KYNVER_HARNESS_ROOT?.trim() || process.env.OPUS_HARNESS_ROOT?.trim();
181
420
  return {
182
421
  ...apiBaseUrl ? { apiBaseUrl: trimTrailingSlash(apiBaseUrl) } : {},
@@ -187,9 +426,9 @@ function inferSetupFields(existing, args) {
187
426
  };
188
427
  }
189
428
  function loadCredentialsFile() {
190
- if (!existsSync2(CREDENTIALS_FILE)) return {};
429
+ if (!existsSync3(CREDENTIALS_FILE)) return {};
191
430
  try {
192
- return JSON.parse(readFileSync2(CREDENTIALS_FILE, "utf8"));
431
+ return JSON.parse(readFileSync3(CREDENTIALS_FILE, "utf8"));
193
432
  } catch {
194
433
  return {};
195
434
  }
@@ -409,7 +648,7 @@ async function runLogin(args) {
409
648
  }
410
649
 
411
650
  // src/dispatch.ts
412
- import path17 from "node:path";
651
+ import path18 from "node:path";
413
652
 
414
653
  // src/callback-headers.ts
415
654
  function buildHarnessCallbackHeaders(secret) {
@@ -471,12 +710,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
471
710
  var DEFAULT_MAX_USED_PERCENT = 80;
472
711
  var DEFAULT_HARD_MAX_USED_PERCENT = 90;
473
712
  function observeRunnerDiskGate(input = {}) {
474
- const path38 = input.diskPath?.trim() || "/";
713
+ const path40 = input.diskPath?.trim() || "/";
475
714
  const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
476
715
  const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
477
716
  const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
478
717
  const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
479
- const stats = statfsSync(path38);
718
+ const stats = statfsSync(path40);
480
719
  const freeBytes = Number(stats.bavail) * Number(stats.bsize);
481
720
  const totalBytes = Number(stats.blocks) * Number(stats.bsize);
482
721
  const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
@@ -496,7 +735,7 @@ function observeRunnerDiskGate(input = {}) {
496
735
  }
497
736
  return {
498
737
  ok,
499
- path: path38,
738
+ path: path40,
500
739
  freeBytes,
501
740
  totalBytes,
502
741
  usedPercent,
@@ -512,7 +751,7 @@ function observeRunnerDiskGate(input = {}) {
512
751
  import os2 from "node:os";
513
752
 
514
753
  // src/bounded-build/meminfo.ts
515
- import { readFileSync as readFileSync3 } from "node:fs";
754
+ import { readFileSync as readFileSync4 } from "node:fs";
516
755
  import os from "node:os";
517
756
  function readMemAvailableBytes(meminfoText) {
518
757
  if (meminfoText !== void 0) {
@@ -522,7 +761,7 @@ function readMemAvailableBytes(meminfoText) {
522
761
  }
523
762
  if (process.platform === "linux") {
524
763
  try {
525
- const meminfo = readFileSync3("/proc/meminfo", "utf8");
764
+ const meminfo = readFileSync4("/proc/meminfo", "utf8");
526
765
  const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB/m);
527
766
  if (match) return Number(match[1]) * 1024;
528
767
  } catch {
@@ -532,37 +771,37 @@ function readMemAvailableBytes(meminfoText) {
532
771
  }
533
772
 
534
773
  // src/resource-gate.ts
535
- import path6 from "node:path";
774
+ import path7 from "node:path";
536
775
 
537
776
  // src/run-store.ts
538
- import { existsSync as existsSync4, readdirSync as readdirSync2 } from "node:fs";
539
- import path5 from "node:path";
777
+ import { existsSync as existsSync5, readdirSync as readdirSync2 } from "node:fs";
778
+ import path6 from "node:path";
540
779
 
541
780
  // src/paths.ts
542
- import { existsSync as existsSync3 } from "node:fs";
543
- import { homedir as homedir3 } from "node:os";
544
- import path4 from "node:path";
545
- var LEGACY_ROOT = path4.join(homedir3(), ".openclaw", "harness");
781
+ import { existsSync as existsSync4 } from "node:fs";
782
+ import { homedir as homedir4 } from "node:os";
783
+ import path5 from "node:path";
784
+ var LEGACY_ROOT = path5.join(homedir4(), ".openclaw", "harness");
546
785
  function resolveHarnessRoot() {
547
786
  const env = process.env.KYNVER_HARNESS_ROOT || process.env.OPUS_HARNESS_ROOT;
548
787
  if (env) return resolveUserPath(env);
549
788
  const configured = loadUserConfig().harnessRoot?.trim();
550
789
  if (configured) return resolveUserPath(configured);
551
- const kynverRoot = path4.join(homedir3(), ".kynver", "harness");
552
- if (existsSync3(kynverRoot)) return kynverRoot;
553
- if (existsSync3(LEGACY_ROOT)) return LEGACY_ROOT;
790
+ const kynverRoot = path5.join(homedir4(), ".kynver", "harness");
791
+ if (existsSync4(kynverRoot)) return kynverRoot;
792
+ if (existsSync4(LEGACY_ROOT)) return LEGACY_ROOT;
554
793
  return kynverRoot;
555
794
  }
556
795
  function getHarnessPaths() {
557
796
  const harnessRoot = resolveHarnessRoot();
558
797
  return {
559
798
  harnessRoot,
560
- runsDir: path4.join(harnessRoot, "runs"),
561
- worktreesDir: path4.join(harnessRoot, "worktrees")
799
+ runsDir: path5.join(harnessRoot, "runs"),
800
+ worktreesDir: path5.join(harnessRoot, "worktrees")
562
801
  };
563
802
  }
564
803
  function runDir(runsDir, id) {
565
- return path4.join(runsDir, safeSlug(id));
804
+ return path5.join(runsDir, safeSlug(id));
566
805
  }
567
806
 
568
807
  // src/run-store.ts
@@ -571,16 +810,16 @@ function getPaths() {
571
810
  }
572
811
  function loadRun(id) {
573
812
  const { runsDir } = getPaths();
574
- return readJson(path5.join(runDir(runsDir, safeSlug(id)), "run.json"));
813
+ return readJson(path6.join(runDir(runsDir, safeSlug(id)), "run.json"));
575
814
  }
576
815
  function listRunRecords() {
577
816
  const { runsDir } = getPaths();
578
- if (!existsSync4(runsDir)) return [];
817
+ if (!existsSync5(runsDir)) return [];
579
818
  const runs = [];
580
819
  for (const entry of readdirSync2(runsDir, { withFileTypes: true })) {
581
820
  if (!entry.isDirectory()) continue;
582
821
  const run = readJson(
583
- path5.join(runsDir, entry.name, "run.json"),
822
+ path6.join(runsDir, entry.name, "run.json"),
584
823
  void 0
585
824
  );
586
825
  if (run?.id) runs.push(run);
@@ -590,16 +829,16 @@ function listRunRecords() {
590
829
  function loadWorker(runId, name) {
591
830
  const { runsDir } = getPaths();
592
831
  return readJson(
593
- path5.join(runDir(runsDir, safeSlug(runId)), "workers", safeSlug(name), "worker.json")
832
+ path6.join(runDir(runsDir, safeSlug(runId)), "workers", safeSlug(name), "worker.json")
594
833
  );
595
834
  }
596
835
  function saveRun(run) {
597
836
  const { runsDir } = getPaths();
598
- writeJson(path5.join(runDir(runsDir, run.id), "run.json"), run);
837
+ writeJson(path6.join(runDir(runsDir, run.id), "run.json"), run);
599
838
  }
600
839
  function saveWorker(runId, worker) {
601
840
  const { runsDir } = getPaths();
602
- writeJson(path5.join(runDir(runsDir, runId), "workers", worker.name, "worker.json"), worker);
841
+ writeJson(path6.join(runDir(runsDir, runId), "workers", worker.name, "worker.json"), worker);
603
842
  }
604
843
  function runDirectory(id) {
605
844
  const { runsDir } = getPaths();
@@ -607,7 +846,7 @@ function runDirectory(id) {
607
846
  }
608
847
 
609
848
  // src/heartbeat.ts
610
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
849
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
611
850
  var HEARTBEAT_FUTURE_SKEW_MS = 6e4;
612
851
  function isTerminalHeartbeatPhase(phase) {
613
852
  return phase === "complete";
@@ -626,10 +865,10 @@ function parseHeartbeat(file) {
626
865
  heartbeatBlocker: null,
627
866
  timestampAnomalies: []
628
867
  };
629
- if (!existsSync5(file)) return result;
868
+ if (!existsSync6(file)) return result;
630
869
  const maxFutureMs = Date.now() + HEARTBEAT_FUTURE_SKEW_MS;
631
870
  const clampedTo = new Date(maxFutureMs).toISOString();
632
- const lines = readFileSync4(file, "utf8").split("\n").filter(Boolean);
871
+ const lines = readFileSync5(file, "utf8").split("\n").filter(Boolean);
633
872
  for (const line of lines) {
634
873
  const entry = safeJson(line);
635
874
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
@@ -656,7 +895,7 @@ function parseHeartbeat(file) {
656
895
  }
657
896
 
658
897
  // src/stream.ts
659
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
898
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
660
899
 
661
900
  // src/shell-command-outcome.ts
662
901
  var NPM_AUDIT_RE = /\bnpm\s+audit\b/i;
@@ -860,8 +1099,8 @@ function parseHarnessStream(file) {
860
1099
  error: null,
861
1100
  lastShellOutcome: null
862
1101
  };
863
- if (!existsSync6(file)) return result;
864
- const lines = readFileSync5(file, "utf8").split("\n").filter(Boolean);
1102
+ if (!existsSync7(file)) return result;
1103
+ const lines = readFileSync6(file, "utf8").split("\n").filter(Boolean);
865
1104
  for (const line of lines) {
866
1105
  const event = safeJson(line);
867
1106
  if (!event) continue;
@@ -998,242 +1237,77 @@ var FAILURE_PATTERNS = [
998
1237
  test: /\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\b/i,
999
1238
  label: "provider authentication failed"
1000
1239
  }
1001
- ];
1002
- function tidy2(errorText, max = 240) {
1003
- const oneLine2 = errorText.replace(/\s+/g, " ").trim();
1004
- return oneLine2.length > max ? `${oneLine2.slice(0, max - 1)}\u2026` : oneLine2;
1005
- }
1006
- function classifyExitFailure(errorText) {
1007
- const text = (errorText ?? "").trim();
1008
- if (!text) return null;
1009
- for (const pattern of FAILURE_PATTERNS) {
1010
- if (pattern.test.test(text)) {
1011
- return { blocked: true, reason: `${pattern.label}: ${tidy2(text)}` };
1012
- }
1013
- }
1014
- return null;
1015
- }
1016
-
1017
- // src/exited-salvage.ts
1018
- function trimOrNull(value) {
1019
- if (typeof value !== "string") return null;
1020
- const trimmed = value.trim();
1021
- return trimmed.length ? trimmed : null;
1022
- }
1023
- function hasFinalResult(value) {
1024
- if (value === void 0 || value === null) return false;
1025
- if (typeof value === "string") return value.trim().length > 0;
1026
- if (typeof value === "boolean") return value;
1027
- if (Array.isArray(value)) return value.length > 0;
1028
- if (typeof value === "object") return Object.keys(value).length > 0;
1029
- return true;
1030
- }
1031
- function committedHeadFromAncestry(ancestry) {
1032
- if (!ancestry?.checked) return null;
1033
- if (ancestry.headIsAncestorOfBase !== false) return null;
1034
- return trimOrNull(ancestry.head);
1035
- }
1036
- function buildAttentionReason(kind, uncommittedCount, headCommit) {
1037
- const parts = ["exited_with_changes_salvage"];
1038
- if (kind === "uncommitted" || kind === "both") {
1039
- parts.push(
1040
- `${uncommittedCount} uncommitted change${uncommittedCount === 1 ? "" : "s"} with no final result`
1041
- );
1042
- }
1043
- if ((kind === "committed_ahead" || kind === "both") && headCommit) {
1044
- const sha = headCommit.length > 12 ? headCommit.slice(0, 12) : headCommit;
1045
- parts.push(`commit ${sha} ahead of base with no final result`);
1046
- }
1047
- parts.push("review worktree \u2014 commit, open a PR, or run a salvage worker before discarding");
1048
- return parts.join(": ");
1049
- }
1050
- function assessExitedWorkerSalvage(input) {
1051
- if (input.alive || hasFinalResult(input.finalResult)) return null;
1052
- const uncommittedCount = (input.changedFiles ?? []).filter((line) => line.trim()).length;
1053
- const headCommit = trimOrNull(input.headCommit) ?? committedHeadFromAncestry(input.gitAncestry);
1054
- const hasUncommitted = uncommittedCount > 0;
1055
- const hasCommittedAhead = Boolean(headCommit);
1056
- if (!hasUncommitted && !hasCommittedAhead) {
1057
- return {
1058
- kind: "none",
1059
- salvageable: false,
1060
- uncommittedCount: 0,
1061
- headCommit: null,
1062
- attentionReason: "process exited without a final result"
1063
- };
1064
- }
1065
- const kind = hasUncommitted && hasCommittedAhead ? "both" : hasUncommitted ? "uncommitted" : "committed_ahead";
1066
- return {
1067
- kind,
1068
- salvageable: true,
1069
- uncommittedCount,
1070
- headCommit,
1071
- attentionReason: buildAttentionReason(kind, uncommittedCount, headCommit)
1072
- };
1073
- }
1074
-
1075
- // src/git.ts
1076
- import { spawnSync } from "node:child_process";
1077
-
1078
- // src/worker-env.ts
1079
- var FORBIDDEN_WORKER_ENV_KEYS = [
1080
- "ANTHROPIC_API_KEY",
1081
- "ANALYST_API_KEY",
1082
- "RECRUITER_API_KEY",
1083
- "AUTH_SECRET",
1084
- "NEXTAUTH_SECRET",
1085
- "DATABASE_URL",
1086
- "PRODUCTION_DATABASE_URL",
1087
- "REDIS_URL",
1088
- "GOOGLE_CLIENT_SECRET",
1089
- "GITHUB_CLIENT_SECRET",
1090
- "KYNVER_API_KEY",
1091
- "KYNVER_SERVICE_SECRET",
1092
- "KYNVER_RUNTIME_SECRET",
1093
- "OPENCLAW_CRON_SECRET",
1094
- "QSTASH_TOKEN",
1095
- "QSTASH_CURRENT_SIGNING_KEY",
1096
- "QSTASH_NEXT_SIGNING_KEY",
1097
- "TOOL_SECRETS_KEK",
1098
- "TOOL_EXECUTOR_DISPATCH_SECRET",
1099
- "CLOUDFLARE_API_TOKEN",
1100
- "STRIPE_SECRET_KEY",
1101
- "STRIPE_WEBHOOK_SECRET",
1102
- "STRIPE_IDENTITY_WEBHOOK_SECRET",
1103
- "VOYAGE_API_KEY",
1104
- "PERPLEXITY_API_KEY",
1105
- "FRED_API_KEY",
1106
- "FMP_API_KEY",
1107
- "CURSOR_API_KEY"
1108
- ];
1109
- var FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
1110
- var FORBIDDEN_SUFFIXES = ["_SECRET", "_API_KEY"];
1111
- function isForbiddenWorkerEnvKey(key) {
1112
- if (FORBIDDEN_KEY_SET.has(key)) return true;
1113
- return FORBIDDEN_SUFFIXES.some((suffix) => key.endsWith(suffix));
1114
- }
1115
- function scrubWorkerEnv(env) {
1116
- const next = { ...env };
1117
- for (const key of Object.keys(next)) {
1118
- if (isForbiddenWorkerEnvKey(key)) delete next[key];
1119
- }
1120
- return next;
1121
- }
1122
-
1123
- // src/git.ts
1124
- function git(cwd, args, options = {}) {
1125
- const res = spawnSync("git", args, { cwd, encoding: "utf8" });
1126
- if (res.status !== 0 && !options.allowFailure) {
1127
- const message = `git ${args.join(" ")} failed: ${res.stderr || res.stdout}`;
1128
- if (options.throwError) throw new Error(message);
1129
- fail(message);
1130
- }
1131
- return res.stdout || "";
1132
- }
1133
- function ensureGitRepo(repo) {
1134
- git(repo, ["rev-parse", "--show-toplevel"]);
1135
- }
1136
- function gitStatusShort(worktreePath) {
1137
- return git(worktreePath, ["status", "--short"], { allowFailure: true }).split("\n").map((line) => line.trim()).filter(Boolean);
1138
- }
1139
- function gitCapture(cwd, args) {
1140
- try {
1141
- const res = spawnSync("git", args, { cwd, encoding: "utf8" });
1142
- return {
1143
- status: res.status,
1144
- stdout: res.stdout || "",
1145
- stderr: res.stderr || "",
1146
- error: res.error ? res.error.message : null
1147
- };
1148
- } catch (error) {
1149
- return {
1150
- status: null,
1151
- stdout: "",
1152
- stderr: "",
1153
- error: error.message
1154
- };
1155
- }
1156
- }
1157
- function gitIsAncestor(cwd, ancestor, descendant) {
1158
- const res = gitCapture(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]);
1159
- if (res.status === 0) return { isAncestor: true, error: null };
1160
- if (res.status === 1) return { isAncestor: false, error: null };
1161
- return { isAncestor: null, error: res.error || res.stderr || res.stdout || `git exited ${res.status}` };
1240
+ ];
1241
+ function tidy2(errorText, max = 240) {
1242
+ const oneLine2 = errorText.replace(/\s+/g, " ").trim();
1243
+ return oneLine2.length > max ? `${oneLine2.slice(0, max - 1)}\u2026` : oneLine2;
1162
1244
  }
1163
- function computeGitAncestry(worktreePath, baseOrOptions = "origin/main") {
1164
- const options = typeof baseOrOptions === "string" ? { base: baseOrOptions } : baseOrOptions;
1165
- const baseLabel = options.baseCommit?.trim() || options.base?.trim() || "origin/main";
1166
- const pinnedBaseCommit = options.baseCommit?.trim() || null;
1167
- if (!worktreePath) {
1168
- return unknownAncestry(baseLabel, "missing worktree path");
1169
- }
1170
- const head = gitCapture(worktreePath, ["rev-parse", "HEAD"]);
1171
- if (head.status !== 0) {
1172
- return unknownAncestry(baseLabel, head.error || head.stderr || head.stdout || "failed to resolve HEAD");
1173
- }
1174
- let baseSha;
1175
- if (pinnedBaseCommit) {
1176
- baseSha = pinnedBaseCommit;
1177
- } else {
1178
- const baseHead = gitCapture(worktreePath, ["rev-parse", baseLabel]);
1179
- if (baseHead.status !== 0) {
1180
- return unknownAncestry(
1181
- baseLabel,
1182
- baseHead.error || baseHead.stderr || baseHead.stdout || `failed to resolve ${baseLabel}`,
1183
- head.stdout.trim()
1184
- );
1245
+ function classifyExitFailure(errorText) {
1246
+ const text = (errorText ?? "").trim();
1247
+ if (!text) return null;
1248
+ for (const pattern of FAILURE_PATTERNS) {
1249
+ if (pattern.test.test(text)) {
1250
+ return { blocked: true, reason: `${pattern.label}: ${tidy2(text)}` };
1185
1251
  }
1186
- baseSha = baseHead.stdout.trim();
1187
1252
  }
1188
- const headSha = head.stdout.trim();
1189
- if (headSha === baseSha) {
1190
- return {
1191
- checked: true,
1192
- base: baseLabel,
1193
- head: headSha,
1194
- baseHead: baseSha,
1195
- baseIsAncestorOfHead: true,
1196
- headIsAncestorOfBase: true,
1197
- relation: "synced"
1198
- };
1253
+ return null;
1254
+ }
1255
+
1256
+ // src/exited-salvage.ts
1257
+ function trimOrNull(value) {
1258
+ if (typeof value !== "string") return null;
1259
+ const trimmed = value.trim();
1260
+ return trimmed.length ? trimmed : null;
1261
+ }
1262
+ function hasFinalResult(value) {
1263
+ if (value === void 0 || value === null) return false;
1264
+ if (typeof value === "string") return value.trim().length > 0;
1265
+ if (typeof value === "boolean") return value;
1266
+ if (Array.isArray(value)) return value.length > 0;
1267
+ if (typeof value === "object") return Object.keys(value).length > 0;
1268
+ return true;
1269
+ }
1270
+ function committedHeadFromAncestry(ancestry) {
1271
+ if (!ancestry?.checked) return null;
1272
+ if (ancestry.headIsAncestorOfBase !== false) return null;
1273
+ return trimOrNull(ancestry.head);
1274
+ }
1275
+ function buildAttentionReason(kind, uncommittedCount, headCommit) {
1276
+ const parts = ["exited_with_changes_salvage"];
1277
+ if (kind === "uncommitted" || kind === "both") {
1278
+ parts.push(
1279
+ `${uncommittedCount} uncommitted change${uncommittedCount === 1 ? "" : "s"} with no final result`
1280
+ );
1199
1281
  }
1200
- const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);
1201
- const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);
1202
- const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || void 0;
1203
- if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {
1282
+ if ((kind === "committed_ahead" || kind === "both") && headCommit) {
1283
+ const sha = headCommit.length > 12 ? headCommit.slice(0, 12) : headCommit;
1284
+ parts.push(`commit ${sha} ahead of base with no final result`);
1285
+ }
1286
+ parts.push("review worktree \u2014 commit, open a PR, or run a salvage worker before discarding");
1287
+ return parts.join(": ");
1288
+ }
1289
+ function assessExitedWorkerSalvage(input) {
1290
+ if (input.alive || hasFinalResult(input.finalResult)) return null;
1291
+ const uncommittedCount = (input.changedFiles ?? []).filter((line) => line.trim()).length;
1292
+ const headCommit = trimOrNull(input.headCommit) ?? committedHeadFromAncestry(input.gitAncestry);
1293
+ const hasUncommitted = uncommittedCount > 0;
1294
+ const hasCommittedAhead = Boolean(headCommit);
1295
+ if (!hasUncommitted && !hasCommittedAhead) {
1204
1296
  return {
1205
- checked: false,
1206
- base: baseLabel,
1207
- head: headSha,
1208
- baseHead: baseSha,
1209
- baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
1210
- headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
1211
- relation: "unknown",
1212
- ...error ? { error } : {}
1297
+ kind: "none",
1298
+ salvageable: false,
1299
+ uncommittedCount: 0,
1300
+ headCommit: null,
1301
+ attentionReason: "process exited without a final result"
1213
1302
  };
1214
1303
  }
1215
- const relation = baseIsAncestorOfHead.isAncestor ? "ahead" : headIsAncestorOfBase.isAncestor ? "merged" : "diverged";
1216
- return {
1217
- checked: true,
1218
- base: baseLabel,
1219
- head: headSha,
1220
- baseHead: baseSha,
1221
- baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
1222
- headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
1223
- relation,
1224
- ...error ? { error } : {}
1225
- };
1226
- }
1227
- function unknownAncestry(base, error, head = null) {
1304
+ const kind = hasUncommitted && hasCommittedAhead ? "both" : hasUncommitted ? "uncommitted" : "committed_ahead";
1228
1305
  return {
1229
- checked: false,
1230
- base,
1231
- head,
1232
- baseHead: null,
1233
- baseIsAncestorOfHead: null,
1234
- headIsAncestorOfBase: null,
1235
- relation: "unknown",
1236
- error
1306
+ kind,
1307
+ salvageable: true,
1308
+ uncommittedCount,
1309
+ headCommit,
1310
+ attentionReason: buildAttentionReason(kind, uncommittedCount, headCommit)
1237
1311
  };
1238
1312
  }
1239
1313
 
@@ -1595,7 +1669,7 @@ function countActiveWorkersForRun(run) {
1595
1669
  let active = 0;
1596
1670
  for (const name of Object.keys(run.workers || {})) {
1597
1671
  const worker = readJson(
1598
- path6.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1672
+ path7.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1599
1673
  void 0
1600
1674
  );
1601
1675
  if (!worker || !isActiveHarnessWorker(worker)) continue;
@@ -1980,10 +2054,10 @@ function readHarnessRetryLimits() {
1980
2054
  }
1981
2055
 
1982
2056
  // src/lease-renewal.ts
1983
- import path7 from "node:path";
2057
+ import path8 from "node:path";
1984
2058
  function workerRecord(runId, name) {
1985
2059
  return readJson(
1986
- path7.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
2060
+ path8.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
1987
2061
  void 0
1988
2062
  );
1989
2063
  }
@@ -2049,8 +2123,8 @@ function hasLiveWorkerForTask(runId, taskId) {
2049
2123
  }
2050
2124
 
2051
2125
  // src/supervisor.ts
2052
- import { existsSync as existsSync10, mkdirSync as mkdirSync3 } from "node:fs";
2053
- import path13 from "node:path";
2126
+ import { existsSync as existsSync11, mkdirSync as mkdirSync3 } from "node:fs";
2127
+ import path14 from "node:path";
2054
2128
 
2055
2129
  // src/prompt.ts
2056
2130
  function buildPrompt(input) {
@@ -2119,13 +2193,13 @@ function buildPrompt(input) {
2119
2193
  }
2120
2194
 
2121
2195
  // src/providers/cursor.ts
2122
- import { closeSync as closeSync2, existsSync as existsSync8, openSync as openSync2 } from "node:fs";
2196
+ import { closeSync as closeSync2, existsSync as existsSync9, openSync as openSync2 } from "node:fs";
2123
2197
  import { spawn as spawn2 } from "node:child_process";
2124
- import path9 from "node:path";
2198
+ import path10 from "node:path";
2125
2199
 
2126
2200
  // src/providers/cursor-windows.ts
2127
- import { existsSync as existsSync7, readdirSync as readdirSync3 } from "node:fs";
2128
- import path8 from "node:path";
2201
+ import { existsSync as existsSync8, readdirSync as readdirSync3 } from "node:fs";
2202
+ import path9 from "node:path";
2129
2203
  var CURSOR_VERSION_DIR = /^\d{4}\.\d{1,2}\.\d{1,2}-[a-f0-9]+$/i;
2130
2204
  function parseCursorVersionSortKey(versionName) {
2131
2205
  const datePart = versionName.split("-")[0];
@@ -2136,8 +2210,8 @@ function parseCursorVersionSortKey(versionName) {
2136
2210
  return Number(`${year}${month.padStart(2, "0")}${day.padStart(2, "0")}`);
2137
2211
  }
2138
2212
  function pickLatestCursorVersionDir(agentRoot) {
2139
- const versionsRoot = path8.join(agentRoot, "versions");
2140
- if (!existsSync7(versionsRoot)) return null;
2213
+ const versionsRoot = path9.join(agentRoot, "versions");
2214
+ if (!existsSync8(versionsRoot)) return null;
2141
2215
  let bestDir = null;
2142
2216
  let bestKey = -1;
2143
2217
  for (const entry of readdirSync3(versionsRoot, { withFileTypes: true })) {
@@ -2145,22 +2219,22 @@ function pickLatestCursorVersionDir(agentRoot) {
2145
2219
  const key = parseCursorVersionSortKey(entry.name);
2146
2220
  if (key == null || key <= bestKey) continue;
2147
2221
  bestKey = key;
2148
- bestDir = path8.join(versionsRoot, entry.name);
2222
+ bestDir = path9.join(versionsRoot, entry.name);
2149
2223
  }
2150
2224
  return bestDir;
2151
2225
  }
2152
2226
  function resolveWindowsCursorBundled(agentRoot) {
2153
- const root = agentRoot?.trim() || path8.join(process.env.LOCALAPPDATA || "", "cursor-agent");
2154
- const directNode = path8.join(root, "node.exe");
2155
- const directIndex = path8.join(root, "index.js");
2156
- if (existsSync7(directNode) && existsSync7(directIndex)) {
2227
+ const root = agentRoot?.trim() || path9.join(process.env.LOCALAPPDATA || "", "cursor-agent");
2228
+ const directNode = path9.join(root, "node.exe");
2229
+ const directIndex = path9.join(root, "index.js");
2230
+ if (existsSync8(directNode) && existsSync8(directIndex)) {
2157
2231
  return { nodeExe: directNode, indexJs: directIndex, versionDir: root };
2158
2232
  }
2159
2233
  const versionDir = pickLatestCursorVersionDir(root);
2160
2234
  if (!versionDir) return null;
2161
- const nodeExe = path8.join(versionDir, "node.exe");
2162
- const indexJs = path8.join(versionDir, "index.js");
2163
- if (!existsSync7(nodeExe) || !existsSync7(indexJs)) return null;
2235
+ const nodeExe = path9.join(versionDir, "node.exe");
2236
+ const indexJs = path9.join(versionDir, "index.js");
2237
+ if (!existsSync8(nodeExe) || !existsSync8(indexJs)) return null;
2164
2238
  return { nodeExe, indexJs, versionDir };
2165
2239
  }
2166
2240
 
@@ -2178,13 +2252,13 @@ function bundledSpawnTarget(nodeExe, indexJs, versionDir) {
2178
2252
  function resolveCursorSpawn(agentBin) {
2179
2253
  if (process.platform === "win32") {
2180
2254
  const isCursorWrapper = /\.(cmd|bat)$/i.test(agentBin);
2181
- const isBundledNode = /node\.exe$/i.test(agentBin) && existsSync8(path9.join(path9.dirname(agentBin), "index.js"));
2255
+ const isBundledNode = /node\.exe$/i.test(agentBin) && existsSync9(path10.join(path10.dirname(agentBin), "index.js"));
2182
2256
  const isDefaultShim = agentBin === "agent";
2183
2257
  if (isCursorWrapper || isBundledNode || isDefaultShim) {
2184
- const bundled = isCursorWrapper ? resolveWindowsCursorBundled(path9.dirname(agentBin)) : isBundledNode ? {
2258
+ const bundled = isCursorWrapper ? resolveWindowsCursorBundled(path10.dirname(agentBin)) : isBundledNode ? {
2185
2259
  nodeExe: agentBin,
2186
- indexJs: path9.join(path9.dirname(agentBin), "index.js"),
2187
- versionDir: path9.dirname(agentBin)
2260
+ indexJs: path10.join(path10.dirname(agentBin), "index.js"),
2261
+ versionDir: path10.dirname(agentBin)
2188
2262
  } : resolveWindowsCursorBundled();
2189
2263
  if (bundled) {
2190
2264
  return bundledSpawnTarget(bundled.nodeExe, bundled.indexJs, bundled.versionDir);
@@ -2204,8 +2278,8 @@ function resolveAgentBin() {
2204
2278
  process.env.KYNVER_CURSOR_AGENT_ROOT?.trim() || void 0
2205
2279
  );
2206
2280
  if (bundled) return bundled.nodeExe;
2207
- const localAgent = path9.join(process.env.LOCALAPPDATA || "", "cursor-agent", "agent.cmd");
2208
- if (existsSync8(localAgent)) return localAgent;
2281
+ const localAgent = path10.join(process.env.LOCALAPPDATA || "", "cursor-agent", "agent.cmd");
2282
+ if (existsSync9(localAgent)) return localAgent;
2209
2283
  }
2210
2284
  return "agent";
2211
2285
  }
@@ -2214,7 +2288,7 @@ function cursorWorkerEnv(agentBin, spawnTarget) {
2214
2288
  ...process.env,
2215
2289
  CI: "1",
2216
2290
  NO_COLOR: "1",
2217
- ...spawnTarget.bundledVersionDir ? { CURSOR_INVOKED_AS: path9.basename(agentBin) || "agent.cmd" } : {}
2291
+ ...spawnTarget.bundledVersionDir ? { CURSOR_INVOKED_AS: path10.basename(agentBin) || "agent.cmd" } : {}
2218
2292
  });
2219
2293
  }
2220
2294
  var cursorProvider = {
@@ -2288,9 +2362,9 @@ function resolveWorkerProvider(name) {
2288
2362
 
2289
2363
  // src/auto-complete.ts
2290
2364
  import { spawn as spawn3 } from "node:child_process";
2291
- import { existsSync as existsSync9, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
2292
- import path12 from "node:path";
2293
- import { fileURLToPath } from "node:url";
2365
+ import { existsSync as existsSync10, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
2366
+ import path13 from "node:path";
2367
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
2294
2368
 
2295
2369
  // src/completion-ack.ts
2296
2370
  function hasCompletionAck(worker) {
@@ -2306,7 +2380,7 @@ function persistCompletionAck(worker, runId, fields) {
2306
2380
  }
2307
2381
 
2308
2382
  // src/worker-ops.ts
2309
- import path11 from "node:path";
2383
+ import path12 from "node:path";
2310
2384
 
2311
2385
  // src/completion-response.ts
2312
2386
  function asRecord(value) {
@@ -2788,7 +2862,7 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
2788
2862
  }
2789
2863
 
2790
2864
  // src/worker-lifecycle.ts
2791
- import path10 from "node:path";
2865
+ import path11 from "node:path";
2792
2866
  var TASK_LEFT_RUNNING = /* @__PURE__ */ new Set([
2793
2867
  "awaiting_review",
2794
2868
  "blocked",
@@ -2844,7 +2918,7 @@ function syncCompletionAcknowledgedFromOperatorTick(runId, operatorTick) {
2844
2918
  const synced = [];
2845
2919
  for (const name of Object.keys(run.workers || {})) {
2846
2920
  const worker = readJson(
2847
- path10.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
2921
+ path11.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
2848
2922
  void 0
2849
2923
  );
2850
2924
  if (!worker?.taskId || isCompletionAcknowledged(worker)) continue;
@@ -3102,7 +3176,7 @@ function workerStatus(args) {
3102
3176
  const worker = loadWorker(String(args.run), String(args.name));
3103
3177
  const run = loadRun(worker.runId);
3104
3178
  const status = computeWorkerStatus(worker, workerStatusOptions(run));
3105
- writeJson(path11.join(worker.workerDir, "last-status.json"), status);
3179
+ writeJson(path12.join(worker.workerDir, "last-status.json"), status);
3106
3180
  console.log(JSON.stringify(status, null, 2));
3107
3181
  }
3108
3182
  function buildRunBoard(runId) {
@@ -3110,7 +3184,7 @@ function buildRunBoard(runId) {
3110
3184
  const names = Object.keys(run.workers || {});
3111
3185
  const workers = names.map((name) => {
3112
3186
  const worker = readJson(
3113
- path11.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
3187
+ path12.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
3114
3188
  void 0
3115
3189
  );
3116
3190
  if (!worker) {
@@ -3221,7 +3295,7 @@ function buildRunBoard(runId) {
3221
3295
  needsAttention: workers.filter((w) => w.attention && w.attention !== "ok" && w.attention !== "done").map((w) => w.worker),
3222
3296
  workers
3223
3297
  };
3224
- writeJson(path11.join(runDirectory(run.id), "last-board.json"), board);
3298
+ writeJson(path12.join(runDirectory(run.id), "last-board.json"), board);
3225
3299
  return board;
3226
3300
  }
3227
3301
  async function publishHarnessBoardSnapshot(args, source) {
@@ -3410,12 +3484,12 @@ async function autoCompleteWorkerCli(raw) {
3410
3484
  }
3411
3485
  }
3412
3486
  function resolveDefaultCliPath() {
3413
- return path12.join(fileURLToPath(new URL(".", import.meta.url)), "cli.js");
3487
+ return path13.join(fileURLToPath2(new URL(".", import.meta.url)), "cli.js");
3414
3488
  }
3415
3489
  function spawnCompletionSidecar(opts) {
3416
3490
  const cliPath = opts.cliPath ?? resolveDefaultCliPath();
3417
- if (!existsSync9(cliPath)) return void 0;
3418
- const logPath = path12.join(opts.workerDir, "auto-complete.log");
3491
+ if (!existsSync10(cliPath)) return void 0;
3492
+ const logPath = path13.join(opts.workerDir, "auto-complete.log");
3419
3493
  let logFd;
3420
3494
  try {
3421
3495
  logFd = openSync3(logPath, "a");
@@ -3497,16 +3571,16 @@ function spawnWorkerProcess(run, opts) {
3497
3571
  launchModel = preflight.model;
3498
3572
  }
3499
3573
  const { worktreesDir } = getPaths();
3500
- const workerDir = path13.join(runDirectory(run.id), "workers", name);
3574
+ const workerDir = path14.join(runDirectory(run.id), "workers", name);
3501
3575
  mkdirSync3(workerDir, { recursive: true });
3502
- const worktreePath = path13.join(worktreesDir, run.id, name);
3576
+ const worktreePath = path14.join(worktreesDir, run.id, name);
3503
3577
  const branch = opts.branch || `agent/${run.id}/${name}`;
3504
- if (existsSync10(worktreePath)) throw new Error(`worktree path already exists: ${worktreePath}`);
3578
+ if (existsSync11(worktreePath)) throw new Error(`worktree path already exists: ${worktreePath}`);
3505
3579
  git(run.repo, ["fetch", "origin", "--prune"], { allowFailure: true });
3506
3580
  git(run.repo, ["worktree", "add", "-b", branch, worktreePath, run.baseCommit], { throwError: true });
3507
- const stdoutPath = path13.join(workerDir, "stdout.jsonl");
3508
- const stderrPath = path13.join(workerDir, "stderr.log");
3509
- const heartbeatPath = path13.join(workerDir, "heartbeat.jsonl");
3581
+ const stdoutPath = path14.join(workerDir, "stdout.jsonl");
3582
+ const stderrPath = path14.join(workerDir, "stderr.log");
3583
+ const heartbeatPath = path14.join(workerDir, "heartbeat.jsonl");
3510
3584
  const prompt = buildPrompt({
3511
3585
  task: opts.task,
3512
3586
  ownedPaths: opts.ownedPaths || [],
@@ -3571,7 +3645,7 @@ function spawnWorkerProcess(run, opts) {
3571
3645
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
3572
3646
  };
3573
3647
  saveWorker(run.id, worker);
3574
- run.workers = { ...run.workers || {}, [name]: { workerDir, statusPath: path13.join(workerDir, "worker.json") } };
3648
+ run.workers = { ...run.workers || {}, [name]: { workerDir, statusPath: path14.join(workerDir, "worker.json") } };
3575
3649
  run.status = "running";
3576
3650
  saveRun(run);
3577
3651
  if (worker.agentOsId && worker.taskId) {
@@ -3863,18 +3937,18 @@ function buildPlanPersistIdempotencyKey(input) {
3863
3937
 
3864
3938
  // src/plan-persist/paths.ts
3865
3939
  import { mkdirSync as mkdirSync4 } from "node:fs";
3866
- import { homedir as homedir4 } from "node:os";
3867
- import path14 from "node:path";
3940
+ import { homedir as homedir5 } from "node:os";
3941
+ import path15 from "node:path";
3868
3942
  function resolveKynverStateRoot() {
3869
3943
  const env = process.env.KYNVER_STATE_ROOT;
3870
- if (env) return path14.resolve(env);
3871
- return path14.join(homedir4(), ".kynver", "state");
3944
+ if (env) return path15.resolve(env);
3945
+ return path15.join(homedir5(), ".kynver", "state");
3872
3946
  }
3873
3947
  function planOutboxDir() {
3874
- return path14.join(resolveKynverStateRoot(), "plan-outbox");
3948
+ return path15.join(resolveKynverStateRoot(), "plan-outbox");
3875
3949
  }
3876
3950
  function planOutboxArchiveDir() {
3877
- return path14.join(resolveKynverStateRoot(), "plan-outbox-archive");
3951
+ return path15.join(resolveKynverStateRoot(), "plan-outbox-archive");
3878
3952
  }
3879
3953
  function ensurePlanOutboxDirs() {
3880
3954
  const outboxDir = planOutboxDir();
@@ -3885,20 +3959,20 @@ function ensurePlanOutboxDirs() {
3885
3959
  }
3886
3960
  function isTmpOnlyPath(filePath) {
3887
3961
  if (filePath.startsWith("/tmp/") || filePath.startsWith("/var/folders/")) return true;
3888
- const resolved = path14.resolve(filePath);
3889
- return resolved.startsWith("/tmp/") || resolved.startsWith(path14.join("/var", "folders"));
3962
+ const resolved = path15.resolve(filePath);
3963
+ return resolved.startsWith("/tmp/") || resolved.startsWith(path15.join("/var", "folders"));
3890
3964
  }
3891
3965
 
3892
3966
  // src/plan-persist/outbox-store.ts
3893
3967
  import {
3894
- existsSync as existsSync12,
3895
- readFileSync as readFileSync6,
3968
+ existsSync as existsSync13,
3969
+ readFileSync as readFileSync7,
3896
3970
  renameSync,
3897
3971
  readdirSync as readdirSync4,
3898
3972
  writeFileSync as writeFileSync3,
3899
3973
  unlinkSync
3900
3974
  } from "node:fs";
3901
- import path15 from "node:path";
3975
+ import path16 from "node:path";
3902
3976
  import { randomUUID } from "node:crypto";
3903
3977
  var DEFAULT_MAX_RETRIES = 12;
3904
3978
  function listOutboxItems() {
@@ -3906,7 +3980,7 @@ function listOutboxItems() {
3906
3980
  const files = readdirSync4(outboxDir).filter((f) => f.endsWith(".json"));
3907
3981
  const items = [];
3908
3982
  for (const file of files) {
3909
- const item = readOutboxItem(path15.join(outboxDir, file));
3983
+ const item = readOutboxItem(path16.join(outboxDir, file));
3910
3984
  if (item && item.queueStatus === "queued") items.push(item);
3911
3985
  }
3912
3986
  return items.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
@@ -3918,25 +3992,25 @@ function findOutboxByIdempotencyKey(key) {
3918
3992
  return null;
3919
3993
  }
3920
3994
  function readOutboxItem(jsonPath) {
3921
- if (!existsSync12(jsonPath)) return null;
3995
+ if (!existsSync13(jsonPath)) return null;
3922
3996
  try {
3923
- return JSON.parse(readFileSync6(jsonPath, "utf8"));
3997
+ return JSON.parse(readFileSync7(jsonPath, "utf8"));
3924
3998
  } catch {
3925
3999
  return null;
3926
4000
  }
3927
4001
  }
3928
4002
  function readOutboxBody(item) {
3929
4003
  const { outboxDir } = ensurePlanOutboxDirs();
3930
- const bodyFile = path15.join(outboxDir, item.bodyPath);
3931
- return readFileSync6(bodyFile, "utf8");
4004
+ const bodyFile = path16.join(outboxDir, item.bodyPath);
4005
+ return readFileSync7(bodyFile, "utf8");
3932
4006
  }
3933
4007
  function writeOutboxItem(input, opts) {
3934
4008
  const { outboxDir } = ensurePlanOutboxDirs();
3935
4009
  const now = (/* @__PURE__ */ new Date()).toISOString();
3936
4010
  const id = opts.existing?.id ?? randomUUID();
3937
4011
  const bodyPath = opts.existing?.bodyPath ?? `${id}.body.md`;
3938
- const jsonPath = path15.join(outboxDir, `${id}.json`);
3939
- const bodyFile = path15.join(outboxDir, bodyPath);
4012
+ const jsonPath = path16.join(outboxDir, `${id}.json`);
4013
+ const bodyFile = path16.join(outboxDir, bodyPath);
3940
4014
  if (!opts.existing) {
3941
4015
  writeFileSync3(bodyFile, input.body, "utf8");
3942
4016
  }
@@ -3972,24 +4046,24 @@ function writeOutboxItem(input, opts) {
3972
4046
  }
3973
4047
  function saveOutboxItem(item) {
3974
4048
  const { outboxDir } = ensurePlanOutboxDirs();
3975
- const jsonPath = path15.join(outboxDir, `${item.id}.json`);
4049
+ const jsonPath = path16.join(outboxDir, `${item.id}.json`);
3976
4050
  writeFileSync3(jsonPath, `${JSON.stringify(item, null, 2)}
3977
4051
  `, { mode: 384 });
3978
4052
  }
3979
4053
  function archiveOutboxItem(item) {
3980
4054
  const { outboxDir, archiveDir } = ensurePlanOutboxDirs();
3981
- const jsonSrc = path15.join(outboxDir, `${item.id}.json`);
3982
- const bodySrc = path15.join(outboxDir, item.bodyPath);
3983
- const jsonDst = path15.join(archiveDir, `${item.id}.json`);
3984
- const bodyDst = path15.join(archiveDir, item.bodyPath);
3985
- if (existsSync12(jsonSrc)) renameSync(jsonSrc, jsonDst);
3986
- if (existsSync12(bodySrc)) renameSync(bodySrc, bodyDst);
4055
+ const jsonSrc = path16.join(outboxDir, `${item.id}.json`);
4056
+ const bodySrc = path16.join(outboxDir, item.bodyPath);
4057
+ const jsonDst = path16.join(archiveDir, `${item.id}.json`);
4058
+ const bodyDst = path16.join(archiveDir, item.bodyPath);
4059
+ if (existsSync13(jsonSrc)) renameSync(jsonSrc, jsonDst);
4060
+ if (existsSync13(bodySrc)) renameSync(bodySrc, bodyDst);
3987
4061
  }
3988
4062
  function outboxItemPaths(item) {
3989
4063
  const { outboxDir } = ensurePlanOutboxDirs();
3990
4064
  return {
3991
- jsonPath: path15.join(outboxDir, `${item.id}.json`),
3992
- bodyPath: path15.join(outboxDir, item.bodyPath)
4065
+ jsonPath: path16.join(outboxDir, `${item.id}.json`),
4066
+ bodyPath: path16.join(outboxDir, item.bodyPath)
3993
4067
  };
3994
4068
  }
3995
4069
  function outboxInputFromItem(item, body) {
@@ -4175,7 +4249,7 @@ function markOutboxFailed(item, message) {
4175
4249
  }
4176
4250
 
4177
4251
  // src/plan-persist/drain.ts
4178
- import path16 from "node:path";
4252
+ import path17 from "node:path";
4179
4253
  async function drainPlanOutbox(opts = {}, deps = {}) {
4180
4254
  const items = listOutboxItems().filter(
4181
4255
  (item) => opts.outboxId ? item.id === opts.outboxId : true
@@ -4209,7 +4283,7 @@ async function drainPlanOutbox(opts = {}, deps = {}) {
4209
4283
  return result;
4210
4284
  }
4211
4285
  function loadOutboxById(outboxId) {
4212
- const jsonPath = path16.join(planOutboxDir(), `${outboxId}.json`);
4286
+ const jsonPath = path17.join(planOutboxDir(), `${outboxId}.json`);
4213
4287
  return readOutboxItem(jsonPath);
4214
4288
  }
4215
4289
 
@@ -4309,7 +4383,7 @@ async function dispatchRun(args) {
4309
4383
  const activeHarnessWorkers = [];
4310
4384
  for (const name of Object.keys(run.workers || {})) {
4311
4385
  const worker = readJson(
4312
- path17.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4386
+ path18.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4313
4387
  void 0
4314
4388
  );
4315
4389
  if (!worker?.taskId || !isPidAlive(worker.pid)) continue;
@@ -4518,7 +4592,7 @@ async function dispatchRun(args) {
4518
4592
  }
4519
4593
 
4520
4594
  // src/sweep.ts
4521
- import path18 from "node:path";
4595
+ import path19 from "node:path";
4522
4596
  async function sweepRun(args) {
4523
4597
  const pipeline = args.pipeline === true || args.pipeline === "true";
4524
4598
  try {
@@ -4531,7 +4605,7 @@ async function sweepRun(args) {
4531
4605
  const releasedLocalOrphans = [];
4532
4606
  for (const name of Object.keys(run.workers || {})) {
4533
4607
  const worker = readJson(
4534
- path18.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4608
+ path19.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4535
4609
  void 0
4536
4610
  );
4537
4611
  if (!worker || !worker.dispatched || !worker.taskId) continue;
@@ -4574,11 +4648,53 @@ async function sweepRun(args) {
4574
4648
  }
4575
4649
 
4576
4650
  // src/worktree.ts
4577
- import { existsSync as existsSync13, mkdirSync as mkdirSync5 } from "node:fs";
4651
+ import { existsSync as existsSync14, mkdirSync as mkdirSync5 } from "node:fs";
4652
+ import path22 from "node:path";
4653
+
4654
+ // src/default-repo.ts
4578
4655
  import path20 from "node:path";
4656
+ function expandConfiguredRepo(value) {
4657
+ return path20.resolve(resolveUserPath(value.trim()));
4658
+ }
4659
+ function fromConfigured(value, source, persistedInConfig) {
4660
+ const trimmed = value?.trim();
4661
+ if (!trimmed) return null;
4662
+ return {
4663
+ repo: expandConfiguredRepo(trimmed),
4664
+ source,
4665
+ persistedInConfig
4666
+ };
4667
+ }
4668
+ function resolveDefaultRepo(opts = {}) {
4669
+ const env = opts.env ?? process.env;
4670
+ const config = opts.config ?? loadUserConfig();
4671
+ const fromConfig = fromConfigured(config.defaultRepo, "config", true);
4672
+ if (fromConfig) return fromConfig;
4673
+ const fromDefaultEnv = fromConfigured(env.KYNVER_DEFAULT_REPO, "env_default_repo", false);
4674
+ if (fromDefaultEnv) return fromDefaultEnv;
4675
+ const fromHarnessEnv = fromConfigured(env.KYNVER_HARNESS_REPO, "env_harness_repo", false);
4676
+ if (fromHarnessEnv) return fromHarnessEnv;
4677
+ const discovered = discoverDefaultRepo({
4678
+ cwd: opts.cwd,
4679
+ runtimeModuleUrl: opts.runtimeModuleUrl
4680
+ });
4681
+ if (!discovered) return null;
4682
+ return {
4683
+ repo: discovered.repo,
4684
+ source: discovered.source,
4685
+ persistedInConfig: false
4686
+ };
4687
+ }
4688
+ function formatResolvedDefaultRepo(resolved) {
4689
+ return {
4690
+ defaultRepo: displayUserPath(resolved.repo),
4691
+ source: resolved.source,
4692
+ persistedInConfig: resolved.persistedInConfig
4693
+ };
4694
+ }
4579
4695
 
4580
4696
  // src/validate.ts
4581
- import path19 from "node:path";
4697
+ import path21 from "node:path";
4582
4698
  var RUN_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
4583
4699
  function validateRunId(runId) {
4584
4700
  const trimmed = runId.trim();
@@ -4586,18 +4702,26 @@ function validateRunId(runId) {
4586
4702
  return trimmed;
4587
4703
  }
4588
4704
  function validateRepo(repo) {
4589
- const resolved = path19.resolve(repo);
4705
+ const resolved = path21.resolve(repo);
4590
4706
  if (resolved.includes("..")) throw new Error("repo path must not contain .. segments");
4591
4707
  return resolved;
4592
4708
  }
4593
4709
 
4594
4710
  // src/worktree.ts
4711
+ function resolveCreateRunRepo(args) {
4712
+ const explicit = typeof args.repo === "string" ? args.repo.trim() : "";
4713
+ if (explicit) return explicit;
4714
+ const resolved = resolveDefaultRepo();
4715
+ if (resolved) return resolved.repo;
4716
+ required("", "--repo (or set defaultRepo via `kynver setup` / KYNVER_DEFAULT_REPO)");
4717
+ return "";
4718
+ }
4595
4719
  function createRun(args) {
4596
- const repo = validateRepo(required(String(args.repo || ""), "--repo"));
4720
+ const repo = validateRepo(resolveCreateRunRepo(args));
4597
4721
  ensureGitRepo(repo);
4598
4722
  const id = args.id ? validateRunId(String(args.id)) : timestampSlug(String(args.name || "run"));
4599
4723
  const dir = runDirectory(id);
4600
- if (existsSync13(dir)) failExists(`run already exists: ${id}`);
4724
+ if (existsSync14(dir)) failExists(`run already exists: ${id}`);
4601
4725
  mkdirSync5(dir, { recursive: true });
4602
4726
  const base = String(args.base || "origin/main");
4603
4727
  const baseCommit = git(repo, ["rev-parse", base]).trim();
@@ -4611,12 +4735,12 @@ function createRun(args) {
4611
4735
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
4612
4736
  workers: {}
4613
4737
  };
4614
- writeJson(path20.join(dir, "run.json"), run);
4738
+ writeJson(path22.join(dir, "run.json"), run);
4615
4739
  console.log(JSON.stringify({ runId: id, runDir: dir, repo, base, baseCommit }, null, 2));
4616
4740
  }
4617
4741
  function listRuns() {
4618
4742
  const { runsDir } = getPaths();
4619
- const rows = listRunIds(runsDir).map((id) => readJson(path20.join(runDirectory(id), "run.json"), void 0)).filter(Boolean).map((run) => ({
4743
+ const rows = listRunIds(runsDir).map((id) => readJson(path22.join(runDirectory(id), "run.json"), void 0)).filter(Boolean).map((run) => ({
4620
4744
  id: run.id,
4621
4745
  name: run.name,
4622
4746
  status: run.status,
@@ -4631,7 +4755,7 @@ function failExists(message) {
4631
4755
  }
4632
4756
 
4633
4757
  // src/pipeline-tick.ts
4634
- import path30 from "node:path";
4758
+ import path32 from "node:path";
4635
4759
 
4636
4760
  // src/pipeline-dispatch.ts
4637
4761
  var RESERVED_REVIEW_STARTS = 1;
@@ -4685,10 +4809,10 @@ async function runPipelineDispatch(args, slots) {
4685
4809
  }
4686
4810
 
4687
4811
  // src/stale-reconcile.ts
4688
- import path22 from "node:path";
4812
+ import path24 from "node:path";
4689
4813
 
4690
4814
  // src/finalize.ts
4691
- import path21 from "node:path";
4815
+ import path23 from "node:path";
4692
4816
  var ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set(["running", "dispatching", "pending", "queued"]);
4693
4817
  function terminalStatusFor(run) {
4694
4818
  const names = Object.keys(run.workers || {});
@@ -4699,7 +4823,7 @@ function terminalStatusFor(run) {
4699
4823
  let anyLandingBlocked = false;
4700
4824
  for (const name of names) {
4701
4825
  const worker = readJson(
4702
- path21.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4826
+ path23.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4703
4827
  void 0
4704
4828
  );
4705
4829
  if (!worker) continue;
@@ -4751,7 +4875,7 @@ function reconcileStaleWorkers() {
4751
4875
  const now = Date.now();
4752
4876
  for (const run of listRunRecords()) {
4753
4877
  for (const name of Object.keys(run.workers || {})) {
4754
- const workerPath = path22.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
4878
+ const workerPath = path24.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
4755
4879
  const worker = readJson(workerPath, void 0);
4756
4880
  if (!worker || worker.status !== "running") {
4757
4881
  outcomes.push({
@@ -4845,7 +4969,7 @@ function reconcileRunsCli() {
4845
4969
  }
4846
4970
 
4847
4971
  // src/plan-progress-daemon-sync.ts
4848
- import path23 from "node:path";
4972
+ import path25 from "node:path";
4849
4973
 
4850
4974
  // src/plan-progress-sync.ts
4851
4975
  async function syncPlanProgress(args) {
@@ -4869,7 +4993,7 @@ async function syncActiveWorkerPlanProgress(runId, args) {
4869
4993
  const outcomes = [];
4870
4994
  for (const name of Object.keys(run.workers || {})) {
4871
4995
  const worker = readJson(
4872
- path23.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4996
+ path25.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
4873
4997
  void 0
4874
4998
  );
4875
4999
  if (!worker?.dispatched || !worker.taskId) continue;
@@ -4918,7 +5042,7 @@ async function fetchWorkspaceRuntimePreferences(agentOsId, args) {
4918
5042
  }
4919
5043
 
4920
5044
  // src/cleanup.ts
4921
- import path28 from "node:path";
5045
+ import path30 from "node:path";
4922
5046
 
4923
5047
  // src/cleanup-types.ts
4924
5048
  var DEFAULT_NODE_MODULES_AGE_MS = 6 * 60 * 60 * 1e3;
@@ -4989,14 +5113,14 @@ function skipNodeModulesRemoval(input) {
4989
5113
  }
4990
5114
 
4991
5115
  // src/cleanup-execute.ts
4992
- import { existsSync as existsSync15, rmSync } from "node:fs";
4993
- import path25 from "node:path";
5116
+ import { existsSync as existsSync16, rmSync } from "node:fs";
5117
+ import path27 from "node:path";
4994
5118
 
4995
5119
  // src/cleanup-dir-size.ts
4996
- import { existsSync as existsSync14, readdirSync as readdirSync5, statSync as statSync2 } from "node:fs";
4997
- import path24 from "node:path";
5120
+ import { existsSync as existsSync15, readdirSync as readdirSync5, statSync as statSync2 } from "node:fs";
5121
+ import path26 from "node:path";
4998
5122
  function directorySizeBytes(root, maxEntries = 5e4) {
4999
- if (!existsSync14(root)) return 0;
5123
+ if (!existsSync15(root)) return 0;
5000
5124
  let total = 0;
5001
5125
  let seen = 0;
5002
5126
  const stack = [root];
@@ -5010,7 +5134,7 @@ function directorySizeBytes(root, maxEntries = 5e4) {
5010
5134
  }
5011
5135
  for (const name of entries) {
5012
5136
  if (seen++ > maxEntries) return null;
5013
- const full = path24.join(current, name);
5137
+ const full = path26.join(current, name);
5014
5138
  let st;
5015
5139
  try {
5016
5140
  st = statSync2(full);
@@ -5026,7 +5150,7 @@ function directorySizeBytes(root, maxEntries = 5e4) {
5026
5150
 
5027
5151
  // src/cleanup-execute.ts
5028
5152
  function removeNodeModules(candidate, execute) {
5029
- if (!existsSync15(candidate.path)) {
5153
+ if (!existsSync16(candidate.path)) {
5030
5154
  return {
5031
5155
  ...candidate,
5032
5156
  executed: false,
@@ -5057,7 +5181,7 @@ function removeNodeModules(candidate, execute) {
5057
5181
  }
5058
5182
  }
5059
5183
  function removeWorktree(candidate, execute) {
5060
- if (!existsSync15(candidate.path)) {
5184
+ if (!existsSync16(candidate.path)) {
5061
5185
  return {
5062
5186
  ...candidate,
5063
5187
  executed: false,
@@ -5074,7 +5198,7 @@ function removeWorktree(candidate, execute) {
5074
5198
  if (repo) {
5075
5199
  git(repo, ["worktree", "remove", "--force", candidate.path], { allowFailure: true });
5076
5200
  }
5077
- if (existsSync15(candidate.path)) {
5201
+ if (existsSync16(candidate.path)) {
5078
5202
  rmSync(candidate.path, { recursive: true, force: true });
5079
5203
  }
5080
5204
  return {
@@ -5094,20 +5218,20 @@ function removeWorktree(candidate, execute) {
5094
5218
  }
5095
5219
  }
5096
5220
  function isHarnessNodeModulesPath(targetPath, harnessRoot, worktreesDir) {
5097
- const resolved = path25.resolve(targetPath);
5098
- const nm = resolved.endsWith(`${path25.sep}node_modules`) ? resolved : null;
5221
+ const resolved = path27.resolve(targetPath);
5222
+ const nm = resolved.endsWith(`${path27.sep}node_modules`) ? resolved : null;
5099
5223
  if (!nm) return "path_outside_harness";
5100
- const rel = path25.relative(worktreesDir, nm);
5101
- if (rel.startsWith("..") || path25.isAbsolute(rel)) return "path_outside_harness";
5102
- const parts = rel.split(path25.sep);
5224
+ const rel = path27.relative(worktreesDir, nm);
5225
+ if (rel.startsWith("..") || path27.isAbsolute(rel)) return "path_outside_harness";
5226
+ const parts = rel.split(path27.sep);
5103
5227
  if (parts.length < 3 || parts[parts.length - 1] !== "node_modules") return "path_outside_harness";
5104
- if (!resolved.startsWith(path25.resolve(harnessRoot))) return "path_outside_harness";
5228
+ if (!resolved.startsWith(path27.resolve(harnessRoot))) return "path_outside_harness";
5105
5229
  return null;
5106
5230
  }
5107
5231
 
5108
5232
  // src/cleanup-scan.ts
5109
- import { existsSync as existsSync16, readdirSync as readdirSync6, statSync as statSync3 } from "node:fs";
5110
- import path26 from "node:path";
5233
+ import { existsSync as existsSync17, readdirSync as readdirSync6, statSync as statSync3 } from "node:fs";
5234
+ import path28 from "node:path";
5111
5235
  function pathAgeMs(target, now) {
5112
5236
  try {
5113
5237
  const mtime = statSync3(target).mtimeMs;
@@ -5117,17 +5241,17 @@ function pathAgeMs(target, now) {
5117
5241
  }
5118
5242
  }
5119
5243
  function isPathInside(child, parent) {
5120
- const rel = path26.relative(parent, child);
5121
- return rel === "" || !rel.startsWith("..") && !path26.isAbsolute(rel);
5244
+ const rel = path28.relative(parent, child);
5245
+ return rel === "" || !rel.startsWith("..") && !path28.isAbsolute(rel);
5122
5246
  }
5123
5247
  function scanNodeModulesCandidates(opts) {
5124
5248
  const candidates = [];
5125
5249
  const seen = /* @__PURE__ */ new Set();
5126
5250
  for (const entry of opts.index.values()) {
5127
5251
  if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;
5128
- const nm = path26.join(entry.worktreePath, "node_modules");
5129
- if (!existsSync16(nm)) continue;
5130
- const resolved = path26.resolve(nm);
5252
+ const nm = path28.join(entry.worktreePath, "node_modules");
5253
+ if (!existsSync17(nm)) continue;
5254
+ const resolved = path28.resolve(nm);
5131
5255
  if (seen.has(resolved)) continue;
5132
5256
  seen.add(resolved);
5133
5257
  candidates.push({
@@ -5140,16 +5264,16 @@ function scanNodeModulesCandidates(opts) {
5140
5264
  ageMs: pathAgeMs(resolved, opts.now)
5141
5265
  });
5142
5266
  }
5143
- if (!opts.includeOrphans || !existsSync16(opts.worktreesDir)) return candidates;
5267
+ if (!opts.includeOrphans || !existsSync17(opts.worktreesDir)) return candidates;
5144
5268
  for (const runEntry of readdirSync6(opts.worktreesDir, { withFileTypes: true })) {
5145
5269
  if (!runEntry.isDirectory()) continue;
5146
- const runPath = path26.join(opts.worktreesDir, runEntry.name);
5270
+ const runPath = path28.join(opts.worktreesDir, runEntry.name);
5147
5271
  for (const workerEntry of readdirSync6(runPath, { withFileTypes: true })) {
5148
5272
  if (!workerEntry.isDirectory()) continue;
5149
- const worktreePath = path26.join(runPath, workerEntry.name);
5150
- const nm = path26.join(worktreePath, "node_modules");
5151
- if (!existsSync16(nm)) continue;
5152
- const resolved = path26.resolve(nm);
5273
+ const worktreePath = path28.join(runPath, workerEntry.name);
5274
+ const nm = path28.join(worktreePath, "node_modules");
5275
+ if (!existsSync17(nm)) continue;
5276
+ const resolved = path28.resolve(nm);
5153
5277
  if (seen.has(resolved)) continue;
5154
5278
  if (!isPathInside(resolved, opts.harnessRoot)) continue;
5155
5279
  seen.add(resolved);
@@ -5172,7 +5296,7 @@ function scanWorktreeCandidates(opts) {
5172
5296
  for (const entry of opts.index.values()) {
5173
5297
  if (opts.runIdFilter && entry.runId !== opts.runIdFilter) continue;
5174
5298
  const resolved = entry.worktreePath;
5175
- if (!existsSync16(resolved)) continue;
5299
+ if (!existsSync17(resolved)) continue;
5176
5300
  if (seen.has(resolved)) continue;
5177
5301
  seen.add(resolved);
5178
5302
  candidates.push({
@@ -5189,17 +5313,17 @@ function scanWorktreeCandidates(opts) {
5189
5313
  }
5190
5314
 
5191
5315
  // src/cleanup-worktree-index.ts
5192
- import path27 from "node:path";
5316
+ import path29 from "node:path";
5193
5317
  function buildWorktreeIndex() {
5194
5318
  const index = /* @__PURE__ */ new Map();
5195
5319
  for (const run of listRunRecords()) {
5196
5320
  for (const name of Object.keys(run.workers || {})) {
5197
- const workerPath = path27.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
5321
+ const workerPath = path29.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json");
5198
5322
  const worker = readJson(workerPath, void 0);
5199
5323
  if (!worker?.worktreePath) continue;
5200
5324
  const status = computeWorkerStatus(worker, { base: run.base, baseCommit: run.baseCommit });
5201
- index.set(path27.resolve(worker.worktreePath), {
5202
- worktreePath: path27.resolve(worker.worktreePath),
5325
+ index.set(path29.resolve(worker.worktreePath), {
5326
+ worktreePath: path29.resolve(worker.worktreePath),
5203
5327
  runId: run.id,
5204
5328
  workerName: name,
5205
5329
  run,
@@ -5214,7 +5338,7 @@ function buildWorktreeIndex() {
5214
5338
  // src/cleanup.ts
5215
5339
  function resolveOptions(options = {}) {
5216
5340
  const harnessRoot = options.harnessRoot ? resolveUserPath(options.harnessRoot) : resolveHarnessRoot();
5217
- const { worktreesDir } = options.harnessRoot ? { worktreesDir: path28.join(harnessRoot, "worktrees") } : getHarnessPaths();
5341
+ const { worktreesDir } = options.harnessRoot ? { worktreesDir: path30.join(harnessRoot, "worktrees") } : getHarnessPaths();
5218
5342
  const execute = options.execute === true;
5219
5343
  const nodeModulesAgeMs = options.nodeModulesAgeMs ?? DEFAULT_NODE_MODULES_AGE_MS;
5220
5344
  const worktreesAgeMs = options.worktreesAgeMs ?? 0;
@@ -5258,7 +5382,7 @@ function runHarnessCleanup(options = {}) {
5258
5382
  actions.push({ ...candidate, executed: false, skipped: true, skipReason: pathSkip });
5259
5383
  continue;
5260
5384
  }
5261
- const worktreePath = path28.resolve(candidate.path, "..");
5385
+ const worktreePath = path30.resolve(candidate.path, "..");
5262
5386
  const indexed = index.get(worktreePath) ?? null;
5263
5387
  const guardReason = skipNodeModulesRemoval({
5264
5388
  indexed,
@@ -5274,7 +5398,7 @@ function runHarnessCleanup(options = {}) {
5274
5398
  actions.push(removeNodeModules(candidate, resolved.execute));
5275
5399
  }
5276
5400
  for (const candidate of scanWorktreeCandidates(scanOpts)) {
5277
- const indexed = index.get(path28.resolve(candidate.path)) ?? null;
5401
+ const indexed = index.get(path30.resolve(candidate.path)) ?? null;
5278
5402
  const guardReason = skipWorktreeRemoval({
5279
5403
  indexed,
5280
5404
  includeOrphans: resolved.includeOrphans,
@@ -5339,8 +5463,8 @@ function isPipelineCleanupEnabled() {
5339
5463
 
5340
5464
  // src/installed-package-versions.ts
5341
5465
  import { readFile } from "node:fs/promises";
5342
- import { homedir as homedir5 } from "node:os";
5343
- import path29 from "node:path";
5466
+ import { homedir as homedir6 } from "node:os";
5467
+ import path31 from "node:path";
5344
5468
  var MANAGED_PACKAGES = [
5345
5469
  "@kynver-app/runtime",
5346
5470
  "@kynver-app/openclaw-agent-os",
@@ -5354,13 +5478,13 @@ function unique(values) {
5354
5478
  return [...new Set(values.filter((value) => Boolean(value)))];
5355
5479
  }
5356
5480
  function moduleRoots() {
5357
- const home = homedir5();
5358
- const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path29.join(home, ".openclaw", "npm");
5359
- const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path29.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path29.join(home, ".npm-global", "lib", "node_modules"));
5481
+ const home = homedir6();
5482
+ const openClawPrefix = trim(process.env.KYNVER_OPENCLAW_NPM_ROOT) ?? trim(process.env.OPENCLAW_NPM_ROOT) ?? path31.join(home, ".openclaw", "npm");
5483
+ const npmGlobalRoot = trim(process.env.KYNVER_NPM_GLOBAL_ROOT) ?? trim(process.env.KYNVER_NPM_GLOBAL_MODULES_ROOT) ?? (trim(process.env.NPM_CONFIG_PREFIX) ? path31.join(trim(process.env.NPM_CONFIG_PREFIX), "lib", "node_modules") : path31.join(home, ".npm-global", "lib", "node_modules"));
5360
5484
  return unique([
5361
- path29.join(openClawPrefix, "lib", "node_modules"),
5362
- path29.join(openClawPrefix, "node_modules"),
5363
- npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path29.join(npmGlobalRoot, "lib", "node_modules")
5485
+ path31.join(openClawPrefix, "lib", "node_modules"),
5486
+ path31.join(openClawPrefix, "node_modules"),
5487
+ npmGlobalRoot.endsWith("node_modules") ? npmGlobalRoot : path31.join(npmGlobalRoot, "lib", "node_modules")
5364
5488
  ]);
5365
5489
  }
5366
5490
  async function readVersion(packageJsonPath) {
@@ -5376,7 +5500,7 @@ async function collectInstalledPackageVersions(observedAt = (/* @__PURE__ */ new
5376
5500
  const out = {};
5377
5501
  for (const packageName of MANAGED_PACKAGES) {
5378
5502
  for (const root of roots) {
5379
- const packageJsonPath = path29.join(root, packageName, "package.json");
5503
+ const packageJsonPath = path31.join(root, packageName, "package.json");
5380
5504
  const version = await readVersion(packageJsonPath);
5381
5505
  if (!version) continue;
5382
5506
  out[packageName] = { version, observedAt, path: packageJsonPath };
@@ -5392,7 +5516,7 @@ async function completeFinishedWorkers(runId, args) {
5392
5516
  const outcomes = [];
5393
5517
  for (const name of Object.keys(run.workers || {})) {
5394
5518
  const worker = readJson(
5395
- path30.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
5519
+ path32.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
5396
5520
  void 0
5397
5521
  );
5398
5522
  if (!worker?.taskId || worker.localOnly) continue;
@@ -5534,7 +5658,7 @@ async function runDaemon(args) {
5534
5658
  }
5535
5659
 
5536
5660
  // src/plan-progress.ts
5537
- import path31 from "node:path";
5661
+ import path33 from "node:path";
5538
5662
 
5539
5663
  // src/bounded-build/constants.ts
5540
5664
  var DEFAULT_BUILD_MEM_BUDGET_BYTES = 1536 * 1024 * 1024;
@@ -5820,7 +5944,7 @@ async function emitPlanProgress(args) {
5820
5944
  }
5821
5945
  function verifyPlanLocal(args) {
5822
5946
  const worktree = required(args.worktree ? String(args.worktree) : void 0, "worktree");
5823
- const cwd = path31.resolve(worktree);
5947
+ const cwd = path33.resolve(worktree);
5824
5948
  const summary = runHarnessVerifyCommands(cwd);
5825
5949
  const emitJson = args.json === true || args.json === "true";
5826
5950
  const payload = { passed: summary.passed, worktree: cwd, steps: summary.steps };
@@ -5869,9 +5993,9 @@ async function verifyPlan(args) {
5869
5993
  }
5870
5994
 
5871
5995
  // src/harness-verify-cli.ts
5872
- import path32 from "node:path";
5996
+ import path34 from "node:path";
5873
5997
  function runHarnessVerifyCli(args) {
5874
- const cwd = path32.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
5998
+ const cwd = path34.resolve(required(args.worktree ? String(args.worktree) : void 0, "worktree"));
5875
5999
  const emitJson = args.json === true || args.json === "true" || args.emitJson === true || args.emitJson === "true";
5876
6000
  const commands = [];
5877
6001
  const rawCmd = args.command;
@@ -5915,7 +6039,7 @@ function runHarnessVerifyCli(args) {
5915
6039
  }
5916
6040
 
5917
6041
  // src/plan-persist-cli.ts
5918
- import { readFileSync as readFileSync7 } from "node:fs";
6042
+ import { readFileSync as readFileSync8 } from "node:fs";
5919
6043
  var OPERATIONS = ["create", "add_version", "update_metadata"];
5920
6044
  var FAILURE_KINDS = [
5921
6045
  "approval_guard",
@@ -5927,7 +6051,7 @@ var FAILURE_KINDS = [
5927
6051
  function readBodyArg(args) {
5928
6052
  const bodyFile = args.bodyFile ? String(args.bodyFile) : void 0;
5929
6053
  if (bodyFile) {
5930
- return { body: readFileSync7(bodyFile, "utf8"), bodyPathHint: bodyFile };
6054
+ return { body: readFileSync8(bodyFile, "utf8"), bodyPathHint: bodyFile };
5931
6055
  }
5932
6056
  const inline = args.body ? String(args.body) : void 0;
5933
6057
  if (inline) return { body: inline };
@@ -6015,7 +6139,7 @@ function runCleanupCli(args) {
6015
6139
  }
6016
6140
 
6017
6141
  // src/monitor/monitor.service.ts
6018
- import path34 from "node:path";
6142
+ import path36 from "node:path";
6019
6143
 
6020
6144
  // src/monitor/monitor.classify.ts
6021
6145
  function expectedLeaseOwner(runId) {
@@ -6071,11 +6195,11 @@ function classifyWorkerHealth(input) {
6071
6195
  }
6072
6196
 
6073
6197
  // src/monitor/monitor.store.ts
6074
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
6075
- import path33 from "node:path";
6198
+ import { existsSync as existsSync18, mkdirSync as mkdirSync6, readdirSync as readdirSync7, unlinkSync as unlinkSync2 } from "node:fs";
6199
+ import path35 from "node:path";
6076
6200
  function monitorsDir() {
6077
6201
  const { harnessRoot } = getHarnessPaths();
6078
- const dir = path33.join(harnessRoot, "monitors");
6202
+ const dir = path35.join(harnessRoot, "monitors");
6079
6203
  mkdirSync6(dir, { recursive: true });
6080
6204
  return dir;
6081
6205
  }
@@ -6083,7 +6207,7 @@ function monitorIdFor(runId, workerName) {
6083
6207
  return workerName ? `${safeSlug(runId)}--${safeSlug(workerName)}` : safeSlug(runId);
6084
6208
  }
6085
6209
  function monitorPath(monitorId) {
6086
- return path33.join(monitorsDir(), `${monitorId}.json`);
6210
+ return path35.join(monitorsDir(), `${monitorId}.json`);
6087
6211
  }
6088
6212
  function loadMonitorSession(monitorId) {
6089
6213
  return readJson(monitorPath(monitorId), void 0);
@@ -6093,18 +6217,18 @@ function saveMonitorSession(session) {
6093
6217
  }
6094
6218
  function deleteMonitorSession(monitorId) {
6095
6219
  const file = monitorPath(monitorId);
6096
- if (!existsSync17(file)) return false;
6220
+ if (!existsSync18(file)) return false;
6097
6221
  unlinkSync2(file);
6098
6222
  return true;
6099
6223
  }
6100
6224
  function listMonitorSessions() {
6101
6225
  const dir = monitorsDir();
6102
- if (!existsSync17(dir)) return [];
6226
+ if (!existsSync18(dir)) return [];
6103
6227
  const entries = [];
6104
6228
  for (const name of readdirSync7(dir)) {
6105
6229
  if (!name.endsWith(".json")) continue;
6106
6230
  const session = readJson(
6107
- path33.join(dir, name),
6231
+ path35.join(dir, name),
6108
6232
  void 0
6109
6233
  );
6110
6234
  if (!session?.monitorId) continue;
@@ -6195,7 +6319,7 @@ async function fetchTaskLeasesForWorkers(input) {
6195
6319
  // src/monitor/monitor.service.ts
6196
6320
  function workerRecord2(runId, name) {
6197
6321
  return readJson(
6198
- path34.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
6322
+ path36.join(runDirectory(runId), "workers", safeSlug(name), "worker.json"),
6199
6323
  void 0
6200
6324
  );
6201
6325
  }
@@ -6397,18 +6521,18 @@ async function runMonitorLoop(args) {
6397
6521
 
6398
6522
  // src/monitor/monitor-spawn.ts
6399
6523
  import { spawn as spawn4 } from "node:child_process";
6400
- import { closeSync as closeSync4, existsSync as existsSync18, openSync as openSync4 } from "node:fs";
6401
- import path35 from "node:path";
6402
- import { fileURLToPath as fileURLToPath2 } from "node:url";
6524
+ import { closeSync as closeSync4, existsSync as existsSync19, openSync as openSync4 } from "node:fs";
6525
+ import path37 from "node:path";
6526
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
6403
6527
  function resolveDefaultCliPath2() {
6404
- return path35.join(fileURLToPath2(new URL(".", import.meta.url)), "..", "cli.js");
6528
+ return path37.join(fileURLToPath3(new URL(".", import.meta.url)), "..", "cli.js");
6405
6529
  }
6406
6530
  function spawnMonitorSidecar(opts) {
6407
6531
  const cliPath = opts.cliPath ?? resolveDefaultCliPath2();
6408
- if (!existsSync18(cliPath)) return void 0;
6532
+ if (!existsSync19(cliPath)) return void 0;
6409
6533
  const monitorId = monitorIdFor(opts.runId, opts.workerName);
6410
6534
  const { harnessRoot } = getHarnessPaths();
6411
- const logPath = path35.join(harnessRoot, "monitors", `${monitorId}.log`);
6535
+ const logPath = path37.join(harnessRoot, "monitors", `${monitorId}.log`);
6412
6536
  let logFd;
6413
6537
  try {
6414
6538
  logFd = openSync4(logPath, "a");
@@ -6528,22 +6652,22 @@ async function monitorTickCli(args) {
6528
6652
  }
6529
6653
 
6530
6654
  // src/package-version.ts
6531
- import { existsSync as existsSync19, readFileSync as readFileSync8 } from "node:fs";
6655
+ import { existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
6532
6656
  import { dirname, join } from "node:path";
6533
- import { fileURLToPath as fileURLToPath3 } from "node:url";
6657
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
6534
6658
  function resolvePackageRoot(moduleUrl) {
6535
- let dir = dirname(fileURLToPath3(moduleUrl));
6659
+ let dir = dirname(fileURLToPath4(moduleUrl));
6536
6660
  for (let depth = 0; depth < 6; depth += 1) {
6537
- if (existsSync19(join(dir, "package.json"))) return dir;
6661
+ if (existsSync20(join(dir, "package.json"))) return dir;
6538
6662
  const parent = dirname(dir);
6539
6663
  if (parent === dir) break;
6540
6664
  dir = parent;
6541
6665
  }
6542
- throw new Error(`package.json not found above ${dirname(fileURLToPath3(moduleUrl))}`);
6666
+ throw new Error(`package.json not found above ${dirname(fileURLToPath4(moduleUrl))}`);
6543
6667
  }
6544
6668
  function readOwnPackageVersion(moduleUrl = import.meta.url) {
6545
6669
  const pkgPath = join(resolvePackageRoot(moduleUrl), "package.json");
6546
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf8"));
6670
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf8"));
6547
6671
  if (typeof pkg.version !== "string" || !pkg.version.trim()) {
6548
6672
  throw new Error(`Missing package.json version at ${pkgPath}`);
6549
6673
  }
@@ -6564,12 +6688,12 @@ function handleCliVersionFlag(argv, moduleUrl = import.meta.url, binName) {
6564
6688
  }
6565
6689
 
6566
6690
  // src/doctor/runtime-takeover.ts
6567
- import path37 from "node:path";
6691
+ import path39 from "node:path";
6568
6692
 
6569
6693
  // src/doctor/runtime-takeover.probes.ts
6570
- import { accessSync, constants, existsSync as existsSync20, readFileSync as readFileSync9 } from "node:fs";
6571
- import { homedir as homedir6 } from "node:os";
6572
- import path36 from "node:path";
6694
+ import { accessSync, constants, existsSync as existsSync21, readFileSync as readFileSync10 } from "node:fs";
6695
+ import { homedir as homedir7 } from "node:os";
6696
+ import path38 from "node:path";
6573
6697
  import { spawnSync as spawnSync6 } from "node:child_process";
6574
6698
  function captureCommand(bin, args) {
6575
6699
  try {
@@ -6598,7 +6722,7 @@ function tokenPrefix(token) {
6598
6722
  return trimmed.length <= 12 ? `${trimmed}\u2026` : `${trimmed.slice(0, 12)}\u2026`;
6599
6723
  }
6600
6724
  function isWritable(target) {
6601
- if (!existsSync20(target)) return false;
6725
+ if (!existsSync21(target)) return false;
6602
6726
  try {
6603
6727
  accessSync(target, constants.W_OK);
6604
6728
  return true;
@@ -6611,15 +6735,15 @@ var defaultRuntimeTakeoverProbes = {
6611
6735
  commandOnPath: (bin) => captureCommand(process.platform === "win32" ? "where" : "which", [bin]),
6612
6736
  kynverVersion: (bin) => captureCommand(bin, ["--version"]),
6613
6737
  loadConfig: () => loadUserConfig(),
6614
- configFilePath: () => path36.join(homedir6(), ".kynver", "config.json"),
6615
- credentialsFilePath: () => path36.join(homedir6(), ".kynver", "credentials"),
6738
+ configFilePath: () => path38.join(homedir7(), ".kynver", "config.json"),
6739
+ credentialsFilePath: () => path38.join(homedir7(), ".kynver", "credentials"),
6616
6740
  readCredentials: () => {
6617
- const credPath = path36.join(homedir6(), ".kynver", "credentials");
6618
- if (!existsSync20(credPath)) {
6741
+ const credPath = path38.join(homedir7(), ".kynver", "credentials");
6742
+ if (!existsSync21(credPath)) {
6619
6743
  return { hasApiKey: false };
6620
6744
  }
6621
6745
  try {
6622
- const parsed = JSON.parse(readFileSync9(credPath, "utf8"));
6746
+ const parsed = JSON.parse(readFileSync10(credPath, "utf8"));
6623
6747
  return {
6624
6748
  hasApiKey: Boolean(parsed.apiKey?.trim()),
6625
6749
  runnerTokenPrefix: tokenPrefix(parsed.runnerToken),
@@ -6645,8 +6769,8 @@ var defaultRuntimeTakeoverProbes = {
6645
6769
  })()
6646
6770
  }),
6647
6771
  harnessRoot: () => resolveHarnessRoot(),
6648
- legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
6649
- pathExists: (target) => existsSync20(target),
6772
+ legacyOpenclawHarnessRoot: () => path38.join(homedir7(), ".openclaw", "harness"),
6773
+ pathExists: (target) => existsSync21(target),
6650
6774
  pathWritable: (target) => isWritable(target),
6651
6775
  vercelVersion: () => captureCommand("vercel", ["--version"]),
6652
6776
  vercelWhoami: () => captureCommand("vercel", ["whoami"])
@@ -6661,8 +6785,36 @@ function assessRuntimeTakeoverScheduler(env, ctx) {
6661
6785
  const runnerQstash = env.kynverSchedulerProvider === "qstash";
6662
6786
  const hostedDeployment = Boolean(env.qstashTokenPresent) || Boolean(env.kynverHostedDeployment);
6663
6787
  const daemonDispatchReady = Boolean(ctx.agentOsId?.trim()) && Boolean(ctx.apiBaseUrl?.trim()) && ctx.hasScopedRunnerToken;
6664
- const deploymentNeedsQstash = hostedDeployment && !env.qstashTokenPresent && env.kynverSchedulerProvider !== "qstash";
6665
- const deploymentOpenclaw = hostedDeployment && env.kynverSchedulerProvider === "openclaw-cron";
6788
+ const hostedSchedulerProcess = hostedDeployment && !daemonDispatchReady;
6789
+ const deploymentNeedsQstash = hostedSchedulerProcess && !env.qstashTokenPresent && env.kynverSchedulerProvider !== "qstash";
6790
+ const deploymentOpenclaw = hostedSchedulerProcess && env.kynverSchedulerProvider === "openclaw-cron";
6791
+ if (daemonDispatchReady && runnerOpenclaw) {
6792
+ return check({
6793
+ id: "hotspot_openclaw_scheduler",
6794
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6795
+ status: "warn",
6796
+ summary: "KYNVER_SCHEDULER_PROVIDER=openclaw-cron on this runner \u2014 dispatch is owned by kynver daemon; unset the OpenClaw override",
6797
+ remediation: "Unset KYNVER_SCHEDULER_PROVIDER on user runners. Use `kynver daemon` (pipeline-tick \u2192 operator/tick). On the Kynver server set KYNVER_SCHEDULER_PROVIDER=qstash when QStash is configured.",
6798
+ details: {
6799
+ schedulerProvider: env.kynverSchedulerProvider ?? null,
6800
+ dispatchPath: "kynver-daemon-pipeline-tick",
6801
+ hostedDeployment
6802
+ }
6803
+ });
6804
+ }
6805
+ if (daemonDispatchReady) {
6806
+ return check({
6807
+ id: "hotspot_openclaw_scheduler",
6808
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6809
+ status: "pass",
6810
+ summary: runnerQstash ? "Runner override qstash present; hosted dispatch still owned by kynver daemon pipeline-tick" : "Hosted dispatch owned by kynver daemon (pipeline-tick \u2192 operator/tick); no OpenClaw cron on runner",
6811
+ details: {
6812
+ schedulerProvider: env.kynverSchedulerProvider ?? null,
6813
+ dispatchPath: "kynver-daemon-pipeline-tick",
6814
+ hostedDeployment
6815
+ }
6816
+ });
6817
+ }
6666
6818
  if (runnerOpenclaw) {
6667
6819
  return check({
6668
6820
  id: "hotspot_openclaw_scheduler",
@@ -6678,7 +6830,7 @@ function assessRuntimeTakeoverScheduler(env, ctx) {
6678
6830
  id: "hotspot_openclaw_scheduler",
6679
6831
  label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6680
6832
  status: "warn",
6681
- summary: deploymentOpenclaw ? "Hosted deployment has KYNVER_SCHEDULER_PROVIDER=openclaw-cron \u2014 AgentOS scheduled ticks should use QStash" : "Hosted deployment without QSTASH_TOKEN \u2014 scheduler may fall back to openclaw-cron",
6833
+ summary: deploymentOpenclaw ? "Hosted deployment has KYNVER_SCHEDULER_PROVIDER=openclaw-cron \u2014 AgentOS scheduled ticks should use QStash" : env.kynverSchedulerProvider ? `Hosted deployment without QSTASH_TOKEN (KYNVER_SCHEDULER_PROVIDER=${env.kynverSchedulerProvider}) \u2014 scheduler may fall back to openclaw-cron` : "KYNVER_SCHEDULER_PROVIDER unset on hosted deployment; without QSTASH_TOKEN the server may fall back to openclaw-cron",
6682
6834
  remediation: "Set QSTASH_TOKEN and KYNVER_SCHEDULER_PROVIDER=qstash on the Kynver server. User runners use `kynver daemon` for dispatch and should not set a scheduler provider.",
6683
6835
  details: {
6684
6836
  schedulerProvider: env.kynverSchedulerProvider ?? null,
@@ -6687,15 +6839,15 @@ function assessRuntimeTakeoverScheduler(env, ctx) {
6687
6839
  }
6688
6840
  });
6689
6841
  }
6690
- if (daemonDispatchReady) {
6842
+ if (hostedDeployment && env.qstashTokenPresent && !env.kynverSchedulerProvider) {
6691
6843
  return check({
6692
6844
  id: "hotspot_openclaw_scheduler",
6693
6845
  label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6694
6846
  status: "pass",
6695
- summary: runnerQstash ? "Runner override qstash present; hosted dispatch still owned by kynver daemon pipeline-tick" : "Hosted dispatch owned by kynver daemon (pipeline-tick \u2192 operator/tick); no OpenClaw cron on runner",
6847
+ summary: "QSTASH_TOKEN present; hosted scheduler auto-selects qstash (explicit KYNVER_SCHEDULER_PROVIDER=qstash optional)",
6696
6848
  details: {
6697
- schedulerProvider: env.kynverSchedulerProvider ?? null,
6698
- dispatchPath: "kynver-daemon-pipeline-tick",
6849
+ schedulerProvider: null,
6850
+ qstashTokenPresent: true,
6699
6851
  hostedDeployment
6700
6852
  }
6701
6853
  });
@@ -6789,8 +6941,14 @@ function assessUserConfig(probes) {
6789
6941
  if (exists) {
6790
6942
  const apiBaseUrl = config.apiBaseUrl?.trim();
6791
6943
  const agentOsId = config.agentOsId?.trim();
6792
- const defaultRepo = config.defaultRepo?.trim();
6793
- const displayDefaultRepo = defaultRepo ? displayUserPath(defaultRepo) : null;
6944
+ const resolvedDefaultRepo = resolveDefaultRepo({ config });
6945
+ const formatted = resolvedDefaultRepo ? formatResolvedDefaultRepo(resolvedDefaultRepo) : null;
6946
+ let defaultRepoRemediation;
6947
+ if (!resolvedDefaultRepo) {
6948
+ defaultRepoRemediation = "Run `kynver setup` from a Kynver checkout (auto-discovers repo) or `kynver setup --repo /path/to/Kynver`.";
6949
+ } else if (!resolvedDefaultRepo.persistedInConfig) {
6950
+ defaultRepoRemediation = "Run `kynver setup` (no --repo) to persist discovered defaultRepo in ~/.kynver/config.json.";
6951
+ }
6794
6952
  checks.push(
6795
6953
  check2({
6796
6954
  id: "config_api_base_url",
@@ -6811,11 +6969,13 @@ function assessUserConfig(probes) {
6811
6969
  check2({
6812
6970
  id: "config_default_repo",
6813
6971
  label: "Default repo path",
6814
- status: defaultRepo ? "pass" : "warn",
6815
- summary: displayDefaultRepo ?? "Not set (pass --repo on `kynver run create`)",
6816
- remediation: defaultRepo ? void 0 : "Set `defaultRepo` via `kynver setup --repo /path/to/repo`.",
6972
+ status: resolvedDefaultRepo ? "pass" : "warn",
6973
+ summary: resolvedDefaultRepo ? `${formatted.defaultRepo} (${resolvedDefaultRepo.source}${resolvedDefaultRepo.persistedInConfig ? "" : ", not persisted"})` : "Not set (pass --repo on `kynver run create` or run `kynver setup` to auto-discover)",
6974
+ remediation: defaultRepoRemediation,
6817
6975
  details: {
6818
- defaultRepo: displayDefaultRepo,
6976
+ defaultRepo: formatted?.defaultRepo ?? null,
6977
+ source: formatted?.source ?? null,
6978
+ persistedInConfig: formatted?.persistedInConfig ?? false,
6819
6979
  harnessRoot: config.harnessRoot ? redactHomePath(config.harnessRoot) : null
6820
6980
  }
6821
6981
  })
@@ -6897,8 +7057,8 @@ function assessVercelCli(probes) {
6897
7057
  }
6898
7058
  function assessHarnessDirs(probes) {
6899
7059
  const harnessRoot = probes.harnessRoot();
6900
- const runsDir = path37.join(harnessRoot, "runs");
6901
- const worktreesDir = path37.join(harnessRoot, "worktrees");
7060
+ const runsDir = path39.join(harnessRoot, "runs");
7061
+ const worktreesDir = path39.join(harnessRoot, "worktrees");
6902
7062
  const displayHarnessRoot = redactHomePath(harnessRoot);
6903
7063
  const displayRunsDir = redactHomePath(runsDir);
6904
7064
  const displayWorktreesDir = redactHomePath(worktreesDir);
@@ -7101,9 +7261,9 @@ function usage(code = 0) {
7101
7261
  "Usage:",
7102
7262
  " kynver login --api-key KEY",
7103
7263
  " kynver runner credential [--agent-os-id ID] [--base-url URL]",
7104
- " kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--repo PATH] [--max-workers N] [--provider claude|cursor]",
7264
+ " kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--repo PATH] [--discover-repo] [--max-workers N] [--provider claude|cursor]",
7105
7265
  " kynver daemon --run RUN_ID --agent-os-id AOS_ID [--execute] [--interval-ms MS]",
7106
- " kynver run create --repo /path/repo [--name name] [--base origin/main]",
7266
+ " kynver run create [--repo /path/repo] [--name name] [--base origin/main]",
7107
7267
  " kynver run list",
7108
7268
  " kynver run status --run RUN_ID",
7109
7269
  " 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 /]",
@@ -7196,7 +7356,7 @@ async function main(argv = process.argv.slice(2)) {
7196
7356
  if (scope === "monitor" && action === "run-loop") return void await monitorRunLoopCli(args);
7197
7357
  unknownCommand(scope, action);
7198
7358
  }
7199
- var isCliEntry = process.argv[1] && realpathSync.native(process.argv[1]) === realpathSync.native(fileURLToPath4(import.meta.url));
7359
+ var isCliEntry = process.argv[1] && realpathSync.native(process.argv[1]) === realpathSync.native(fileURLToPath5(import.meta.url));
7200
7360
  if (isCliEntry) {
7201
7361
  void main().catch((error) => {
7202
7362
  console.error(error);