@kynver-app/runtime 0.1.47 → 0.1.49

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
@@ -1906,7 +1906,7 @@ function inferModelRoutingFromTask(task) {
1906
1906
  rule: "lane:landing"
1907
1907
  };
1908
1908
  }
1909
- if (ref.includes("review") || title.startsWith("review ") || roleLane.includes("review")) {
1909
+ if (ref.includes("review") || /^review[\s:]/.test(title) || roleLane.includes("review")) {
1910
1910
  if (isOpusLane(ref, title) || roleLane === "deep_reviewer") {
1911
1911
  return { model: "claude-opus-4-7", provider: "claude", rule: "lane:deep_review" };
1912
1912
  }
@@ -2099,6 +2099,7 @@ function buildPrompt(input) {
2099
2099
  "Structured final result (recommended): record completion as JSON with summary, laneExpertise { whatChanged, why, files, prUrls, verification, risks, blockers, lessonsLearned, laneGuidance }, and targetPrReconciliation [{ prUrl, outcome: merged|skipped|blocked, mergeCommit?, reason? }] for every target PR on landing-only tasks.",
2100
2100
  "Completion handoff (required): before you stop, ensure the harness records a final result \u2014 summarize outcome in your last message and append a heartbeat line with phase `complete`. If you leave uncommitted changes or committed work without a PR, the orchestrator blocks completion until a GitHub PR exists (or you discard/commit cleanly). Exiting with only dirty files and no PR routes to salvage review, not production review.",
2101
2101
  "PR-ready handoff: for substantial implementation work, commit, push, and open a GitHub PR (draft OK) on your branch before finishing \u2014 or rely on the harness to run `gh pr create` at completion when `gh` is authenticated.",
2102
+ "Expert review / production-review workers (Dalton/Lorentz, plan-review-task, scheduledJob reviewer children): do NOT open new implementation PRs \u2014 review the parent task's existing PR and record reviewVerdict in finalResult; landing-contract targetPrReconciliation does not apply.",
2102
2103
  "Worker resource guard: do not run full monorepo verification (`npm run typecheck`, `npm run build`, or equivalent) from this worker lane unless an operator explicitly requests it. Use targeted checks for touched paths and rely on CI/operator lanes for heavy gates.",
2103
2104
  "npm publish boundary: do not run `npm publish`, do not republish `@kynver-app/*` packages, and do not block on an operator to publish. When you need newer runtime code than npm, use this repo checkout (`npm run kynver:build`, `npm run kynver`) and record evidence: packages/kynver-runtime/package.json version + git ref in your completion report.",
2104
2105
  "If verification fails (including OOM), append a heartbeat line immediately with the last command, failure reason, dirty-file status, commit/PR handoff state, and next action so recovery does not require log spelunking.",
@@ -2340,8 +2341,39 @@ function completionPostSucceeded(summary) {
2340
2341
  return summary.taskAdvanced;
2341
2342
  }
2342
2343
 
2344
+ // src/harness-expert-review.ts
2345
+ var EXPERT_LANE_REVIEW_REF = "expert-lane-pr-review:";
2346
+ var PLAN_REVIEW_EXECUTOR_REF = "plan-review-task";
2347
+ var SCHEDULED_JOB_EXECUTOR_REF = "scheduledjob:";
2348
+ function normalizePersonaSlug(value) {
2349
+ if (!value) return null;
2350
+ const t = value.trim().toLowerCase();
2351
+ return t.length ? t : null;
2352
+ }
2353
+ function isHarnessExpertReviewWorker(worker) {
2354
+ const ref = (worker.executorRef ?? "").toLowerCase();
2355
+ if (ref.startsWith(EXPERT_LANE_REVIEW_REF)) return true;
2356
+ if (ref === PLAN_REVIEW_EXECUTOR_REF || ref.startsWith("daemon-review:")) return true;
2357
+ if (ref.startsWith(SCHEDULED_JOB_EXECUTOR_REF) && worker.parentTaskId) {
2358
+ const persona = normalizePersonaSlug(worker.personaSlug);
2359
+ if (persona === "lorentz" || persona === "dalton") return true;
2360
+ }
2361
+ const title = (worker.title ?? "").toLowerCase();
2362
+ if (title.includes("expert pr review")) return true;
2363
+ if (worker.parentTaskId && (title.startsWith("review:") || title.includes("review required") || title.includes("runtime review"))) {
2364
+ const persona = normalizePersonaSlug(worker.personaSlug);
2365
+ if (persona === "lorentz" || persona === "dalton") return true;
2366
+ }
2367
+ return false;
2368
+ }
2369
+
2343
2370
  // src/pr-handoff/pr-handoff-assess.ts
2344
2371
  var REVIEW_LANE_RULE = /^(lane:)?(review|deep_review|planning|landing)(:|$)/i;
2372
+ var REVIEW_PERSONA_SLUGS = /* @__PURE__ */ new Set(["lorentz", "sentinel"]);
2373
+ var NO_PR_COMMITS_BETWEEN_RE = /no commits between/i;
2374
+ function isGhNoCommitsBetweenError(detail) {
2375
+ return Boolean(detail && NO_PR_COMMITS_BETWEEN_RE.test(detail));
2376
+ }
2345
2377
  function trimOrNull4(value) {
2346
2378
  if (typeof value !== "string") return null;
2347
2379
  const trimmed = value.trim();
@@ -2360,8 +2392,30 @@ function extractPrUrlFromText(value) {
2360
2392
  );
2361
2393
  return m ? trimOrNull4(m[0]) : null;
2362
2394
  }
2363
- function hasWorkProduct(snapshot) {
2395
+ function countCommitsAheadOfBase(worktreePath, baseRef, exec) {
2396
+ const base = baseRef.trim();
2397
+ if (!base) return null;
2398
+ const count = exec.git(worktreePath, ["rev-list", "--count", `${base}..HEAD`]);
2399
+ if (count.status !== 0) return null;
2400
+ const n = Number.parseInt(count.stdout.trim(), 10);
2401
+ return Number.isFinite(n) ? n : null;
2402
+ }
2403
+ function isReviewArtifactWorker(worker, snapshot) {
2404
+ if (snapshot.changedFiles.length > 0) return false;
2405
+ const persona = trimOrNull4(worker.personaSlug)?.toLowerCase();
2406
+ if (persona && REVIEW_PERSONA_SLUGS.has(persona)) return true;
2407
+ const rule = trimOrNull4(worker.routingRule) ?? "";
2408
+ if (rule && REVIEW_LANE_RULE.test(rule)) return true;
2409
+ return false;
2410
+ }
2411
+ function hasWorkProduct(snapshot, options) {
2364
2412
  if (snapshot.changedFiles.length > 0) return true;
2413
+ const baseRef = trimOrNull4(options?.baseRef);
2414
+ if (baseRef && options?.exec && options.worktreePath) {
2415
+ const ahead = countCommitsAheadOfBase(options.worktreePath, baseRef, options.exec);
2416
+ if (ahead === 0) return false;
2417
+ if (ahead !== null && ahead > 0) return true;
2418
+ }
2365
2419
  if (trimOrNull4(snapshot.headCommit)) return true;
2366
2420
  if (committedHead(snapshot.gitAncestry)) return true;
2367
2421
  return false;
@@ -2370,18 +2424,38 @@ function assessPrHandoffRequirement(input) {
2370
2424
  if (!input.dispatched) {
2371
2425
  return { required: false, reason: "not_dispatched" };
2372
2426
  }
2427
+ if (isHarnessExpertReviewWorker({
2428
+ title: input.taskTitle ?? void 0,
2429
+ personaSlug: input.personaSlug,
2430
+ parentTaskId: input.parentTaskId,
2431
+ executorRef: input.executorRef
2432
+ })) {
2433
+ return { required: false, reason: "expert_review_task" };
2434
+ }
2373
2435
  const rule = trimOrNull4(input.routingRule) ?? "";
2374
2436
  if (rule && REVIEW_LANE_RULE.test(rule)) {
2375
2437
  return { required: false, reason: "review_lane" };
2376
2438
  }
2439
+ const workerCtx = input.worker ?? {
2440
+ personaSlug: input.personaSlug,
2441
+ routingRule: input.routingRule
2442
+ };
2443
+ if (isReviewArtifactWorker(workerCtx, input.snapshot)) {
2444
+ return { required: false, reason: "review_artifact" };
2445
+ }
2377
2446
  if (trimOrNull4(input.patchPath) || trimOrNull4(input.artifactBundlePath)) {
2378
2447
  return { required: false, reason: "patch_or_bundle" };
2379
2448
  }
2380
- const prUrl = trimOrNull4(input.prUrl) ?? trimOrNull4(input.snapshot.prUrl);
2449
+ const prUrl = trimOrNull4(input.prUrl) ?? trimOrNull4(input.taskPrUrl) ?? trimOrNull4(input.snapshot.prUrl);
2381
2450
  if (prUrl) {
2382
2451
  return { required: false, reason: "already_has_pr" };
2383
2452
  }
2384
- if (!hasWorkProduct(input.snapshot)) {
2453
+ const workProductOpts = input.exec && input.baseRef ? {
2454
+ baseRef: input.baseRef,
2455
+ exec: input.exec,
2456
+ worktreePath: input.snapshot.worktreePath
2457
+ } : void 0;
2458
+ if (!hasWorkProduct(input.snapshot, workProductOpts)) {
2385
2459
  return { required: false, reason: "no_work_product" };
2386
2460
  }
2387
2461
  return { required: true, snapshot: input.snapshot };
@@ -2590,10 +2664,19 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
2590
2664
  prUrl: prUrlHint,
2591
2665
  headCommit: null
2592
2666
  });
2667
+ const baseRef = input.run.baseCommit?.trim() || input.run.base?.trim() || "origin/main";
2593
2668
  const requirement = assessPrHandoffRequirement({
2594
2669
  dispatched: input.worker.dispatched,
2595
2670
  routingRule: input.worker.routingRule,
2671
+ personaSlug: input.worker.personaSlug,
2596
2672
  prUrl: prUrlHint,
2673
+ taskTitle: input.worker.taskTitle,
2674
+ executorRef: input.worker.executorRef,
2675
+ parentTaskId: input.worker.parentTaskId,
2676
+ taskPrUrl: input.worker.taskPrUrl,
2677
+ baseRef,
2678
+ exec,
2679
+ worker: input.worker,
2597
2680
  snapshot
2598
2681
  });
2599
2682
  if (!requirement.required) {
@@ -2678,6 +2761,14 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
2678
2761
  exec
2679
2762
  });
2680
2763
  if (!pr.ok || !pr.prUrl) {
2764
+ if (isGhNoCommitsBetweenError(pr.detail)) {
2765
+ return {
2766
+ ok: true,
2767
+ headCommit: headCommit ?? void 0,
2768
+ committed,
2769
+ pushed
2770
+ };
2771
+ }
2681
2772
  const dirty = snapshot.changedFiles.length;
2682
2773
  const detail = dirty ? `${dirty} uncommitted change(s) and no PR URL after handoff attempt` : "no PR URL after handoff attempt";
2683
2774
  return {
@@ -3473,6 +3564,10 @@ function spawnWorkerProcess(run, opts) {
3473
3564
  ...!opts.agentOsId || !opts.taskId ? { localOnly: true } : {},
3474
3565
  routingRule: routing.rule,
3475
3566
  ...routing.requestedModel ? { requestedModel: routing.requestedModel } : {},
3567
+ ...opts.executorRef ? { executorRef: String(opts.executorRef) } : {},
3568
+ ...opts.parentTaskId ? { parentTaskId: String(opts.parentTaskId) } : {},
3569
+ ...opts.taskTitle ? { taskTitle: String(opts.taskTitle) } : {},
3570
+ ...opts.taskPrUrl ? { taskPrUrl: String(opts.taskPrUrl) } : {},
3476
3571
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
3477
3572
  };
3478
3573
  saveWorker(run.id, worker);
@@ -4167,7 +4262,7 @@ function readHarnessWorkerContext(decision) {
4167
4262
  personaInjectionReady
4168
4263
  };
4169
4264
  }
4170
- function normalizePersonaSlug(value) {
4265
+ function normalizePersonaSlug2(value) {
4171
4266
  if (typeof value !== "string") return null;
4172
4267
  const trimmed = value.trim().toLowerCase();
4173
4268
  return trimmed.length ? trimmed : null;
@@ -4298,7 +4393,7 @@ async function dispatchRun(args) {
4298
4393
  const task = decision.task;
4299
4394
  const harnessContext = readHarnessWorkerContext(decision);
4300
4395
  const taskId = String(task.id);
4301
- const expectedPersona = normalizePersonaSlug(task.personaSlug);
4396
+ const expectedPersona = normalizePersonaSlug2(task.personaSlug);
4302
4397
  if (expectedPersona && (!harnessContext?.personaInjectionReady || !harnessContext.personaMarkdown)) {
4303
4398
  outcomes.push({
4304
4399
  taskId,
@@ -4342,6 +4437,10 @@ async function dispatchRun(args) {
4342
4437
  agentOsId,
4343
4438
  taskId: String(task.id),
4344
4439
  planId,
4440
+ executorRef: task.executorRef ? String(task.executorRef) : void 0,
4441
+ parentTaskId: task.parentTaskId ? String(task.parentTaskId) : void 0,
4442
+ taskTitle: task.title ? String(task.title) : void 0,
4443
+ taskPrUrl: task.prUrl ? String(task.prUrl) : void 0,
4345
4444
  instructionPolicyMarkdown: harnessContext?.instructionPolicyMarkdown ?? null,
4346
4445
  instructionPolicyFingerprint: harnessContext?.instructionPolicyFingerprint ?? null,
4347
4446
  instructionPolicyEvidence: harnessContext?.instructionPolicyEvidence ?? null,
@@ -6538,7 +6637,12 @@ var defaultRuntimeTakeoverProbes = {
6538
6637
  openclawCronSecret: Boolean(process.env.OPENCLAW_CRON_SECRET?.trim()),
6539
6638
  kynverHarnessRoot: process.env.KYNVER_HARNESS_ROOT?.trim() || void 0,
6540
6639
  opusHarnessRoot: process.env.OPUS_HARNESS_ROOT?.trim() || void 0,
6541
- kynverSchedulerProvider: process.env.KYNVER_SCHEDULER_PROVIDER?.trim() || void 0
6640
+ kynverSchedulerProvider: process.env.KYNVER_SCHEDULER_PROVIDER?.trim() || void 0,
6641
+ qstashTokenPresent: Boolean(process.env.QSTASH_TOKEN?.trim()),
6642
+ kynverHostedDeployment: (() => {
6643
+ const v = process.env.KYNVER_HOSTED_DEPLOYMENT?.trim().toLowerCase();
6644
+ return v === "1" || v === "true" || v === "yes";
6645
+ })()
6542
6646
  }),
6543
6647
  harnessRoot: () => resolveHarnessRoot(),
6544
6648
  legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
@@ -6548,10 +6652,76 @@ var defaultRuntimeTakeoverProbes = {
6548
6652
  vercelWhoami: () => captureCommand("vercel", ["whoami"])
6549
6653
  };
6550
6654
 
6551
- // src/doctor/runtime-takeover.ts
6655
+ // src/doctor/runtime-takeover-scheduler.ts
6552
6656
  function check(partial) {
6553
6657
  return partial;
6554
6658
  }
6659
+ function assessRuntimeTakeoverScheduler(env, ctx) {
6660
+ const runnerOpenclaw = env.kynverSchedulerProvider === "openclaw-cron";
6661
+ const runnerQstash = env.kynverSchedulerProvider === "qstash";
6662
+ const hostedDeployment = Boolean(env.qstashTokenPresent) || Boolean(env.kynverHostedDeployment);
6663
+ 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";
6666
+ if (runnerOpenclaw) {
6667
+ return check({
6668
+ id: "hotspot_openclaw_scheduler",
6669
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6670
+ status: "warn",
6671
+ summary: "KYNVER_SCHEDULER_PROVIDER=openclaw-cron on this runner \u2014 hosted dispatch still depends on the OpenClaw local-cron adapter",
6672
+ 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.",
6673
+ details: { schedulerProvider: env.kynverSchedulerProvider ?? null, hostedDeployment }
6674
+ });
6675
+ }
6676
+ if (deploymentOpenclaw || deploymentNeedsQstash) {
6677
+ return check({
6678
+ id: "hotspot_openclaw_scheduler",
6679
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6680
+ 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",
6682
+ 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
+ details: {
6684
+ schedulerProvider: env.kynverSchedulerProvider ?? null,
6685
+ qstashTokenPresent: env.qstashTokenPresent ?? false,
6686
+ hostedDeployment
6687
+ }
6688
+ });
6689
+ }
6690
+ if (daemonDispatchReady) {
6691
+ return check({
6692
+ id: "hotspot_openclaw_scheduler",
6693
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6694
+ 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",
6696
+ details: {
6697
+ schedulerProvider: env.kynverSchedulerProvider ?? null,
6698
+ dispatchPath: "kynver-daemon-pipeline-tick",
6699
+ hostedDeployment
6700
+ }
6701
+ });
6702
+ }
6703
+ if (!env.kynverSchedulerProvider) {
6704
+ return check({
6705
+ id: "hotspot_openclaw_scheduler",
6706
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6707
+ status: "pass",
6708
+ summary: "No KYNVER_SCHEDULER_PROVIDER on runner (expected) \u2014 finish runner setup so daemon pipeline-tick owns dispatch",
6709
+ details: { schedulerProvider: null, dispatchPath: "kynver-daemon-pipeline-tick-pending" }
6710
+ });
6711
+ }
6712
+ return check({
6713
+ id: "hotspot_openclaw_scheduler",
6714
+ label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
6715
+ status: "pass",
6716
+ summary: `KYNVER_SCHEDULER_PROVIDER=${env.kynverSchedulerProvider}`,
6717
+ details: { schedulerProvider: env.kynverSchedulerProvider ?? null }
6718
+ });
6719
+ }
6720
+
6721
+ // src/doctor/runtime-takeover.ts
6722
+ function check2(partial) {
6723
+ return partial;
6724
+ }
6555
6725
  function summarizeCounts(sections) {
6556
6726
  const counts = { pass: 0, warn: 0, fail: 0 };
6557
6727
  for (const section of sections) {
@@ -6568,14 +6738,14 @@ function assessCliPackage(probes) {
6568
6738
  const firstPath = onPath ? which.stdout.split(/\r?\n/)[0]?.trim() : void 0;
6569
6739
  const displayCliPath = firstPath ? displayUserPath(firstPath) : void 0;
6570
6740
  const checks = [
6571
- check({
6741
+ check2({
6572
6742
  id: "cli_running_version",
6573
6743
  label: "Running @kynver-app/runtime version",
6574
6744
  status: "pass",
6575
6745
  summary: `@kynver-app/runtime ${runningVersion}`,
6576
6746
  details: { version: runningVersion }
6577
6747
  }),
6578
- check({
6748
+ check2({
6579
6749
  id: "cli_on_path",
6580
6750
  label: "kynver executable on PATH",
6581
6751
  status: onPath ? "pass" : "warn",
@@ -6589,7 +6759,7 @@ function assessCliPackage(probes) {
6589
6759
  const installedVersion = versionProbe.stdout.replace(/^kynver\s+/i, "").trim() || void 0;
6590
6760
  const versionMatch = versionProbe.ok && (!installedVersion || installedVersion === runningVersion);
6591
6761
  checks.push(
6592
- check({
6762
+ check2({
6593
6763
  id: "cli_installed_version",
6594
6764
  label: "Installed kynver CLI version matches running package",
6595
6765
  status: versionMatch ? "pass" : "warn",
@@ -6607,7 +6777,7 @@ function assessUserConfig(probes) {
6607
6777
  const exists = probes.pathExists(configPath);
6608
6778
  const config = probes.loadConfig();
6609
6779
  const checks = [
6610
- check({
6780
+ check2({
6611
6781
  id: "config_file",
6612
6782
  label: "~/.kynver/config.json present",
6613
6783
  status: exists ? "pass" : "fail",
@@ -6622,7 +6792,7 @@ function assessUserConfig(probes) {
6622
6792
  const defaultRepo = config.defaultRepo?.trim();
6623
6793
  const displayDefaultRepo = defaultRepo ? displayUserPath(defaultRepo) : null;
6624
6794
  checks.push(
6625
- check({
6795
+ check2({
6626
6796
  id: "config_api_base_url",
6627
6797
  label: "Default API base URL",
6628
6798
  status: apiBaseUrl ? "pass" : "warn",
@@ -6630,7 +6800,7 @@ function assessUserConfig(probes) {
6630
6800
  remediation: apiBaseUrl ? void 0 : "Set `apiBaseUrl` via `kynver setup --api-base-url https://\u2026`.",
6631
6801
  details: { apiBaseUrl: apiBaseUrl ?? null }
6632
6802
  }),
6633
- check({
6803
+ check2({
6634
6804
  id: "config_agent_os_id",
6635
6805
  label: "Default AgentOS id",
6636
6806
  status: agentOsId ? "pass" : "warn",
@@ -6638,7 +6808,7 @@ function assessUserConfig(probes) {
6638
6808
  remediation: agentOsId ? void 0 : "Set `agentOsId` via `kynver setup --agent-os-id <uuid>`.",
6639
6809
  details: { agentOsId: agentOsId ?? null, agentOsSlug: config.agentOsSlug ?? null }
6640
6810
  }),
6641
- check({
6811
+ check2({
6642
6812
  id: "config_default_repo",
6643
6813
  label: "Default repo path",
6644
6814
  status: defaultRepo ? "pass" : "warn",
@@ -6666,7 +6836,7 @@ function assessRunnerToken(probes) {
6666
6836
  const scopedSaved = Boolean(savedToken) && (!targetAgentOsId || !savedAgentOsId || savedAgentOsId === targetAgentOsId);
6667
6837
  const hasScoped = Boolean(envToken?.startsWith("krc1.")) || scopedSaved && savedToken?.startsWith("krc1.");
6668
6838
  const checks = [
6669
- check({
6839
+ check2({
6670
6840
  id: "runner_token_scoped",
6671
6841
  label: "Scoped runner token (krc1.*) ready",
6672
6842
  status: hasScoped ? "pass" : "fail",
@@ -6679,7 +6849,7 @@ function assessRunnerToken(probes) {
6679
6849
  credentialsPath: displayCredPath
6680
6850
  }
6681
6851
  }),
6682
- check({
6852
+ check2({
6683
6853
  id: "runner_token_agent_os_match",
6684
6854
  label: "Saved runner token matches configured agentOsId",
6685
6855
  status: !savedToken || !targetAgentOsId || !savedAgentOsId || savedAgentOsId === targetAgentOsId ? "pass" : "warn",
@@ -6687,7 +6857,7 @@ function assessRunnerToken(probes) {
6687
6857
  remediation: savedToken && targetAgentOsId && savedAgentOsId && savedAgentOsId !== targetAgentOsId ? "`kynver runner credential --agent-os-id <configured-id>` to mint a workspace-bound token." : void 0,
6688
6858
  details: { configuredAgentOsId: targetAgentOsId ?? null, savedAgentOsId: savedAgentOsId ?? null }
6689
6859
  }),
6690
- check({
6860
+ check2({
6691
6861
  id: "runner_api_key_for_refresh",
6692
6862
  label: "API key available for token refresh",
6693
6863
  status: creds.hasApiKey || Boolean(process.env.KYNVER_API_KEY?.trim()) ? "pass" : "warn",
@@ -6706,7 +6876,7 @@ function assessVercelCli(probes) {
6706
6876
  id: "vercel_cli",
6707
6877
  label: "Vercel CLI",
6708
6878
  checks: [
6709
- check({
6879
+ check2({
6710
6880
  id: "vercel_installed",
6711
6881
  label: "Vercel CLI installed",
6712
6882
  status: installed ? "pass" : "warn",
@@ -6714,7 +6884,7 @@ function assessVercelCli(probes) {
6714
6884
  remediation: installed ? void 0 : "Install Vercel CLI (`npm i -g vercel`) for deploy evidence and env pulls.",
6715
6885
  details: { stderr: version.stderr || null }
6716
6886
  }),
6717
- check({
6887
+ check2({
6718
6888
  id: "vercel_authenticated",
6719
6889
  label: "Vercel CLI authenticated",
6720
6890
  status: !installed ? "warn" : whoami.ok ? "pass" : "warn",
@@ -6738,14 +6908,14 @@ function assessHarnessDirs(probes) {
6738
6908
  id: "harness_dirs",
6739
6909
  label: "Harness / daemon directories",
6740
6910
  checks: [
6741
- check({
6911
+ check2({
6742
6912
  id: "harness_root",
6743
6913
  label: "Harness root resolved",
6744
6914
  status: "pass",
6745
6915
  summary: displayHarnessRoot,
6746
6916
  details: { harnessRoot: displayHarnessRoot }
6747
6917
  }),
6748
- check({
6918
+ check2({
6749
6919
  id: "harness_runs_dir",
6750
6920
  label: "Runs directory ready",
6751
6921
  status: runsExists && probes.pathWritable(runsDir) ? "pass" : runsExists ? "warn" : "warn",
@@ -6753,7 +6923,7 @@ function assessHarnessDirs(probes) {
6753
6923
  remediation: runsExists && !probes.pathWritable(runsDir) ? `Fix permissions on ${displayRunsDir} or set KYNVER_HARNESS_ROOT to a writable path.` : void 0,
6754
6924
  details: { runsDir: displayRunsDir, exists: runsExists, writable: probes.pathWritable(runsDir) }
6755
6925
  }),
6756
- check({
6926
+ check2({
6757
6927
  id: "harness_worktrees_dir",
6758
6928
  label: "Worktrees directory ready",
6759
6929
  status: worktreesExists && probes.pathWritable(worktreesDir) ? "pass" : "warn",
@@ -6774,7 +6944,7 @@ function assessCallbackAuth(probes) {
6774
6944
  const creds = probes.readCredentials();
6775
6945
  const savedScoped = creds.runnerTokenPrefix?.startsWith("krc1.");
6776
6946
  const checks = [
6777
- check({
6947
+ check2({
6778
6948
  id: "callback_base_url",
6779
6949
  label: "Callback base URL configured",
6780
6950
  status: baseUrl ? usingLegacyBase ? "warn" : "pass" : "fail",
@@ -6785,7 +6955,7 @@ function assessCallbackAuth(probes) {
6785
6955
  baseUrl: baseUrl ?? null
6786
6956
  }
6787
6957
  }),
6788
- check({
6958
+ check2({
6789
6959
  id: "callback_auth_mode",
6790
6960
  label: "Callback auth uses scoped runner token",
6791
6961
  status: envScoped || savedScoped ? "pass" : legacySecret ? "warn" : "fail",
@@ -6801,15 +6971,22 @@ function assessCallbackAuth(probes) {
6801
6971
  }
6802
6972
  function assessOpenclawHotspots(probes) {
6803
6973
  const env = probes.envSnapshot();
6974
+ const config = probes.loadConfig();
6975
+ const creds = probes.readCredentials();
6804
6976
  const harnessRoot = probes.harnessRoot();
6805
6977
  const legacyRoot = probes.legacyOpenclawHarnessRoot();
6806
6978
  const displayHarnessRoot = redactHomePath(harnessRoot);
6807
6979
  const displayLegacyRoot = redactHomePath(legacyRoot);
6808
6980
  const displayOpusHarnessRoot = env.opusHarnessRoot ? redactHomePath(env.opusHarnessRoot) : null;
6809
6981
  const legacyHarnessActive = harnessRoot === legacyRoot && probes.pathExists(legacyRoot);
6810
- const schedulerOpenclaw = !env.kynverSchedulerProvider || env.kynverSchedulerProvider === "openclaw-cron";
6982
+ const targetAgentOsId = config.agentOsId?.trim();
6983
+ const envToken = env.kynverRunnerTokenPrefix;
6984
+ const savedToken = creds.runnerTokenPrefix;
6985
+ const savedAgentOsId = creds.runnerTokenAgentOsId;
6986
+ const scopedSaved = Boolean(savedToken) && (!targetAgentOsId || !savedAgentOsId || savedAgentOsId === targetAgentOsId);
6987
+ const hasScopedRunnerToken = Boolean(envToken?.startsWith("krc1.")) || scopedSaved && Boolean(savedToken?.startsWith("krc1."));
6811
6988
  const checks = [
6812
- check({
6989
+ check2({
6813
6990
  id: "hotspot_legacy_harness_root",
6814
6991
  label: "Legacy ~/.openclaw/harness still active",
6815
6992
  status: legacyHarnessActive ? "warn" : "pass",
@@ -6817,7 +6994,7 @@ function assessOpenclawHotspots(probes) {
6817
6994
  remediation: legacyHarnessActive ? "Set KYNVER_HARNESS_ROOT=~/.kynver/harness (or run setup), migrate artifacts, retire OPUS_HARNESS_ROOT." : env.opusHarnessRoot ? "Prefer KYNVER_HARNESS_ROOT over OPUS_HARNESS_ROOT." : void 0,
6818
6995
  details: { harnessRoot: displayHarnessRoot, legacyRoot: displayLegacyRoot, opusHarnessRoot: displayOpusHarnessRoot }
6819
6996
  }),
6820
- check({
6997
+ check2({
6821
6998
  id: "hotspot_openclaw_env_secrets",
6822
6999
  label: "OpenClaw deployment secrets in runner env",
6823
7000
  status: env.openclawCronSecret || env.openclawCronFireBaseUrl ? "warn" : "pass",
@@ -6827,15 +7004,12 @@ function assessOpenclawHotspots(probes) {
6827
7004
  ].filter(Boolean).join("; ") : "No OpenClaw cron env overrides on this runner",
6828
7005
  remediation: env.openclawCronSecret || env.openclawCronFireBaseUrl ? "Move to KYNVER_API_URL + scoped runner tokens; unset OpenClaw cron env on user-hosted runners." : void 0
6829
7006
  }),
6830
- check({
6831
- id: "hotspot_openclaw_scheduler",
6832
- label: "openclaw-cron scheduler dependency (deployment)",
6833
- status: schedulerOpenclaw ? "warn" : "pass",
6834
- summary: schedulerOpenclaw ? env.kynverSchedulerProvider === "openclaw-cron" ? "KYNVER_SCHEDULER_PROVIDER=openclaw-cron \u2014 AgentOS ticks still routed via OpenClaw local cron adapter" : "KYNVER_SCHEDULER_PROVIDER unset \u2014 server may fall back to openclaw-cron when QStash is absent" : `KYNVER_SCHEDULER_PROVIDER=${env.kynverSchedulerProvider}`,
6835
- remediation: schedulerOpenclaw ? "On Kynver-hosted scheduler: set KYNVER_SCHEDULER_PROVIDER=qstash where QStash is configured; retire openclaw-cron stub when runtime daemon owns dispatch." : void 0,
6836
- details: { schedulerProvider: env.kynverSchedulerProvider ?? null }
7007
+ assessRuntimeTakeoverScheduler(env, {
7008
+ agentOsId: targetAgentOsId ?? null,
7009
+ apiBaseUrl: config.apiBaseUrl?.trim() ?? env.kynverApiUrl ?? null,
7010
+ hasScopedRunnerToken
6837
7011
  }),
6838
- check({
7012
+ check2({
6839
7013
  id: "hotspot_lease_source_names",
6840
7014
  label: "Harness lease/completion source names",
6841
7015
  status: "pass",