@kynver-app/runtime 0.1.48 → 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 +160 -34
- package/dist/cli.js.map +4 -4
- package/dist/doctor/runtime-takeover-scheduler.d.ts +20 -0
- package/dist/doctor/runtime-takeover.probes.d.ts +2 -0
- package/dist/index.js +160 -34
- package/dist/index.js.map +4 -4
- package/dist/pr-handoff/pr-handoff-assess.d.ts +10 -1
- package/dist/pr-handoff/pr-handoff.types.d.ts +1 -1
- package/package.json +1 -1
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
|
|
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
|
}
|
|
@@ -2369,6 +2369,11 @@ function isHarnessExpertReviewWorker(worker) {
|
|
|
2369
2369
|
|
|
2370
2370
|
// src/pr-handoff/pr-handoff-assess.ts
|
|
2371
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
|
+
}
|
|
2372
2377
|
function trimOrNull4(value) {
|
|
2373
2378
|
if (typeof value !== "string") return null;
|
|
2374
2379
|
const trimmed = value.trim();
|
|
@@ -2387,8 +2392,30 @@ function extractPrUrlFromText(value) {
|
|
|
2387
2392
|
);
|
|
2388
2393
|
return m ? trimOrNull4(m[0]) : null;
|
|
2389
2394
|
}
|
|
2390
|
-
function
|
|
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) {
|
|
2391
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
|
+
}
|
|
2392
2419
|
if (trimOrNull4(snapshot.headCommit)) return true;
|
|
2393
2420
|
if (committedHead(snapshot.gitAncestry)) return true;
|
|
2394
2421
|
return false;
|
|
@@ -2409,6 +2436,13 @@ function assessPrHandoffRequirement(input) {
|
|
|
2409
2436
|
if (rule && REVIEW_LANE_RULE.test(rule)) {
|
|
2410
2437
|
return { required: false, reason: "review_lane" };
|
|
2411
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
|
+
}
|
|
2412
2446
|
if (trimOrNull4(input.patchPath) || trimOrNull4(input.artifactBundlePath)) {
|
|
2413
2447
|
return { required: false, reason: "patch_or_bundle" };
|
|
2414
2448
|
}
|
|
@@ -2416,7 +2450,12 @@ function assessPrHandoffRequirement(input) {
|
|
|
2416
2450
|
if (prUrl) {
|
|
2417
2451
|
return { required: false, reason: "already_has_pr" };
|
|
2418
2452
|
}
|
|
2419
|
-
|
|
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)) {
|
|
2420
2459
|
return { required: false, reason: "no_work_product" };
|
|
2421
2460
|
}
|
|
2422
2461
|
return { required: true, snapshot: input.snapshot };
|
|
@@ -2625,15 +2664,19 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
|
|
|
2625
2664
|
prUrl: prUrlHint,
|
|
2626
2665
|
headCommit: null
|
|
2627
2666
|
});
|
|
2667
|
+
const baseRef = input.run.baseCommit?.trim() || input.run.base?.trim() || "origin/main";
|
|
2628
2668
|
const requirement = assessPrHandoffRequirement({
|
|
2629
2669
|
dispatched: input.worker.dispatched,
|
|
2630
2670
|
routingRule: input.worker.routingRule,
|
|
2671
|
+
personaSlug: input.worker.personaSlug,
|
|
2631
2672
|
prUrl: prUrlHint,
|
|
2632
2673
|
taskTitle: input.worker.taskTitle,
|
|
2633
2674
|
executorRef: input.worker.executorRef,
|
|
2634
2675
|
parentTaskId: input.worker.parentTaskId,
|
|
2635
|
-
personaSlug: input.worker.personaSlug,
|
|
2636
2676
|
taskPrUrl: input.worker.taskPrUrl,
|
|
2677
|
+
baseRef,
|
|
2678
|
+
exec,
|
|
2679
|
+
worker: input.worker,
|
|
2637
2680
|
snapshot
|
|
2638
2681
|
});
|
|
2639
2682
|
if (!requirement.required) {
|
|
@@ -2718,6 +2761,14 @@ function ensurePrReadyHandoff(input, exec = defaultPrHandoffExec) {
|
|
|
2718
2761
|
exec
|
|
2719
2762
|
});
|
|
2720
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
|
+
}
|
|
2721
2772
|
const dirty = snapshot.changedFiles.length;
|
|
2722
2773
|
const detail = dirty ? `${dirty} uncommitted change(s) and no PR URL after handoff attempt` : "no PR URL after handoff attempt";
|
|
2723
2774
|
return {
|
|
@@ -6586,7 +6637,12 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
6586
6637
|
openclawCronSecret: Boolean(process.env.OPENCLAW_CRON_SECRET?.trim()),
|
|
6587
6638
|
kynverHarnessRoot: process.env.KYNVER_HARNESS_ROOT?.trim() || void 0,
|
|
6588
6639
|
opusHarnessRoot: process.env.OPUS_HARNESS_ROOT?.trim() || void 0,
|
|
6589
|
-
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
|
+
})()
|
|
6590
6646
|
}),
|
|
6591
6647
|
harnessRoot: () => resolveHarnessRoot(),
|
|
6592
6648
|
legacyOpenclawHarnessRoot: () => path36.join(homedir6(), ".openclaw", "harness"),
|
|
@@ -6596,10 +6652,76 @@ var defaultRuntimeTakeoverProbes = {
|
|
|
6596
6652
|
vercelWhoami: () => captureCommand("vercel", ["whoami"])
|
|
6597
6653
|
};
|
|
6598
6654
|
|
|
6599
|
-
// src/doctor/runtime-takeover.ts
|
|
6655
|
+
// src/doctor/runtime-takeover-scheduler.ts
|
|
6600
6656
|
function check(partial) {
|
|
6601
6657
|
return partial;
|
|
6602
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
|
+
}
|
|
6603
6725
|
function summarizeCounts(sections) {
|
|
6604
6726
|
const counts = { pass: 0, warn: 0, fail: 0 };
|
|
6605
6727
|
for (const section of sections) {
|
|
@@ -6616,14 +6738,14 @@ function assessCliPackage(probes) {
|
|
|
6616
6738
|
const firstPath = onPath ? which.stdout.split(/\r?\n/)[0]?.trim() : void 0;
|
|
6617
6739
|
const displayCliPath = firstPath ? displayUserPath(firstPath) : void 0;
|
|
6618
6740
|
const checks = [
|
|
6619
|
-
|
|
6741
|
+
check2({
|
|
6620
6742
|
id: "cli_running_version",
|
|
6621
6743
|
label: "Running @kynver-app/runtime version",
|
|
6622
6744
|
status: "pass",
|
|
6623
6745
|
summary: `@kynver-app/runtime ${runningVersion}`,
|
|
6624
6746
|
details: { version: runningVersion }
|
|
6625
6747
|
}),
|
|
6626
|
-
|
|
6748
|
+
check2({
|
|
6627
6749
|
id: "cli_on_path",
|
|
6628
6750
|
label: "kynver executable on PATH",
|
|
6629
6751
|
status: onPath ? "pass" : "warn",
|
|
@@ -6637,7 +6759,7 @@ function assessCliPackage(probes) {
|
|
|
6637
6759
|
const installedVersion = versionProbe.stdout.replace(/^kynver\s+/i, "").trim() || void 0;
|
|
6638
6760
|
const versionMatch = versionProbe.ok && (!installedVersion || installedVersion === runningVersion);
|
|
6639
6761
|
checks.push(
|
|
6640
|
-
|
|
6762
|
+
check2({
|
|
6641
6763
|
id: "cli_installed_version",
|
|
6642
6764
|
label: "Installed kynver CLI version matches running package",
|
|
6643
6765
|
status: versionMatch ? "pass" : "warn",
|
|
@@ -6655,7 +6777,7 @@ function assessUserConfig(probes) {
|
|
|
6655
6777
|
const exists = probes.pathExists(configPath);
|
|
6656
6778
|
const config = probes.loadConfig();
|
|
6657
6779
|
const checks = [
|
|
6658
|
-
|
|
6780
|
+
check2({
|
|
6659
6781
|
id: "config_file",
|
|
6660
6782
|
label: "~/.kynver/config.json present",
|
|
6661
6783
|
status: exists ? "pass" : "fail",
|
|
@@ -6670,7 +6792,7 @@ function assessUserConfig(probes) {
|
|
|
6670
6792
|
const defaultRepo = config.defaultRepo?.trim();
|
|
6671
6793
|
const displayDefaultRepo = defaultRepo ? displayUserPath(defaultRepo) : null;
|
|
6672
6794
|
checks.push(
|
|
6673
|
-
|
|
6795
|
+
check2({
|
|
6674
6796
|
id: "config_api_base_url",
|
|
6675
6797
|
label: "Default API base URL",
|
|
6676
6798
|
status: apiBaseUrl ? "pass" : "warn",
|
|
@@ -6678,7 +6800,7 @@ function assessUserConfig(probes) {
|
|
|
6678
6800
|
remediation: apiBaseUrl ? void 0 : "Set `apiBaseUrl` via `kynver setup --api-base-url https://\u2026`.",
|
|
6679
6801
|
details: { apiBaseUrl: apiBaseUrl ?? null }
|
|
6680
6802
|
}),
|
|
6681
|
-
|
|
6803
|
+
check2({
|
|
6682
6804
|
id: "config_agent_os_id",
|
|
6683
6805
|
label: "Default AgentOS id",
|
|
6684
6806
|
status: agentOsId ? "pass" : "warn",
|
|
@@ -6686,7 +6808,7 @@ function assessUserConfig(probes) {
|
|
|
6686
6808
|
remediation: agentOsId ? void 0 : "Set `agentOsId` via `kynver setup --agent-os-id <uuid>`.",
|
|
6687
6809
|
details: { agentOsId: agentOsId ?? null, agentOsSlug: config.agentOsSlug ?? null }
|
|
6688
6810
|
}),
|
|
6689
|
-
|
|
6811
|
+
check2({
|
|
6690
6812
|
id: "config_default_repo",
|
|
6691
6813
|
label: "Default repo path",
|
|
6692
6814
|
status: defaultRepo ? "pass" : "warn",
|
|
@@ -6714,7 +6836,7 @@ function assessRunnerToken(probes) {
|
|
|
6714
6836
|
const scopedSaved = Boolean(savedToken) && (!targetAgentOsId || !savedAgentOsId || savedAgentOsId === targetAgentOsId);
|
|
6715
6837
|
const hasScoped = Boolean(envToken?.startsWith("krc1.")) || scopedSaved && savedToken?.startsWith("krc1.");
|
|
6716
6838
|
const checks = [
|
|
6717
|
-
|
|
6839
|
+
check2({
|
|
6718
6840
|
id: "runner_token_scoped",
|
|
6719
6841
|
label: "Scoped runner token (krc1.*) ready",
|
|
6720
6842
|
status: hasScoped ? "pass" : "fail",
|
|
@@ -6727,7 +6849,7 @@ function assessRunnerToken(probes) {
|
|
|
6727
6849
|
credentialsPath: displayCredPath
|
|
6728
6850
|
}
|
|
6729
6851
|
}),
|
|
6730
|
-
|
|
6852
|
+
check2({
|
|
6731
6853
|
id: "runner_token_agent_os_match",
|
|
6732
6854
|
label: "Saved runner token matches configured agentOsId",
|
|
6733
6855
|
status: !savedToken || !targetAgentOsId || !savedAgentOsId || savedAgentOsId === targetAgentOsId ? "pass" : "warn",
|
|
@@ -6735,7 +6857,7 @@ function assessRunnerToken(probes) {
|
|
|
6735
6857
|
remediation: savedToken && targetAgentOsId && savedAgentOsId && savedAgentOsId !== targetAgentOsId ? "`kynver runner credential --agent-os-id <configured-id>` to mint a workspace-bound token." : void 0,
|
|
6736
6858
|
details: { configuredAgentOsId: targetAgentOsId ?? null, savedAgentOsId: savedAgentOsId ?? null }
|
|
6737
6859
|
}),
|
|
6738
|
-
|
|
6860
|
+
check2({
|
|
6739
6861
|
id: "runner_api_key_for_refresh",
|
|
6740
6862
|
label: "API key available for token refresh",
|
|
6741
6863
|
status: creds.hasApiKey || Boolean(process.env.KYNVER_API_KEY?.trim()) ? "pass" : "warn",
|
|
@@ -6754,7 +6876,7 @@ function assessVercelCli(probes) {
|
|
|
6754
6876
|
id: "vercel_cli",
|
|
6755
6877
|
label: "Vercel CLI",
|
|
6756
6878
|
checks: [
|
|
6757
|
-
|
|
6879
|
+
check2({
|
|
6758
6880
|
id: "vercel_installed",
|
|
6759
6881
|
label: "Vercel CLI installed",
|
|
6760
6882
|
status: installed ? "pass" : "warn",
|
|
@@ -6762,7 +6884,7 @@ function assessVercelCli(probes) {
|
|
|
6762
6884
|
remediation: installed ? void 0 : "Install Vercel CLI (`npm i -g vercel`) for deploy evidence and env pulls.",
|
|
6763
6885
|
details: { stderr: version.stderr || null }
|
|
6764
6886
|
}),
|
|
6765
|
-
|
|
6887
|
+
check2({
|
|
6766
6888
|
id: "vercel_authenticated",
|
|
6767
6889
|
label: "Vercel CLI authenticated",
|
|
6768
6890
|
status: !installed ? "warn" : whoami.ok ? "pass" : "warn",
|
|
@@ -6786,14 +6908,14 @@ function assessHarnessDirs(probes) {
|
|
|
6786
6908
|
id: "harness_dirs",
|
|
6787
6909
|
label: "Harness / daemon directories",
|
|
6788
6910
|
checks: [
|
|
6789
|
-
|
|
6911
|
+
check2({
|
|
6790
6912
|
id: "harness_root",
|
|
6791
6913
|
label: "Harness root resolved",
|
|
6792
6914
|
status: "pass",
|
|
6793
6915
|
summary: displayHarnessRoot,
|
|
6794
6916
|
details: { harnessRoot: displayHarnessRoot }
|
|
6795
6917
|
}),
|
|
6796
|
-
|
|
6918
|
+
check2({
|
|
6797
6919
|
id: "harness_runs_dir",
|
|
6798
6920
|
label: "Runs directory ready",
|
|
6799
6921
|
status: runsExists && probes.pathWritable(runsDir) ? "pass" : runsExists ? "warn" : "warn",
|
|
@@ -6801,7 +6923,7 @@ function assessHarnessDirs(probes) {
|
|
|
6801
6923
|
remediation: runsExists && !probes.pathWritable(runsDir) ? `Fix permissions on ${displayRunsDir} or set KYNVER_HARNESS_ROOT to a writable path.` : void 0,
|
|
6802
6924
|
details: { runsDir: displayRunsDir, exists: runsExists, writable: probes.pathWritable(runsDir) }
|
|
6803
6925
|
}),
|
|
6804
|
-
|
|
6926
|
+
check2({
|
|
6805
6927
|
id: "harness_worktrees_dir",
|
|
6806
6928
|
label: "Worktrees directory ready",
|
|
6807
6929
|
status: worktreesExists && probes.pathWritable(worktreesDir) ? "pass" : "warn",
|
|
@@ -6822,7 +6944,7 @@ function assessCallbackAuth(probes) {
|
|
|
6822
6944
|
const creds = probes.readCredentials();
|
|
6823
6945
|
const savedScoped = creds.runnerTokenPrefix?.startsWith("krc1.");
|
|
6824
6946
|
const checks = [
|
|
6825
|
-
|
|
6947
|
+
check2({
|
|
6826
6948
|
id: "callback_base_url",
|
|
6827
6949
|
label: "Callback base URL configured",
|
|
6828
6950
|
status: baseUrl ? usingLegacyBase ? "warn" : "pass" : "fail",
|
|
@@ -6833,7 +6955,7 @@ function assessCallbackAuth(probes) {
|
|
|
6833
6955
|
baseUrl: baseUrl ?? null
|
|
6834
6956
|
}
|
|
6835
6957
|
}),
|
|
6836
|
-
|
|
6958
|
+
check2({
|
|
6837
6959
|
id: "callback_auth_mode",
|
|
6838
6960
|
label: "Callback auth uses scoped runner token",
|
|
6839
6961
|
status: envScoped || savedScoped ? "pass" : legacySecret ? "warn" : "fail",
|
|
@@ -6849,15 +6971,22 @@ function assessCallbackAuth(probes) {
|
|
|
6849
6971
|
}
|
|
6850
6972
|
function assessOpenclawHotspots(probes) {
|
|
6851
6973
|
const env = probes.envSnapshot();
|
|
6974
|
+
const config = probes.loadConfig();
|
|
6975
|
+
const creds = probes.readCredentials();
|
|
6852
6976
|
const harnessRoot = probes.harnessRoot();
|
|
6853
6977
|
const legacyRoot = probes.legacyOpenclawHarnessRoot();
|
|
6854
6978
|
const displayHarnessRoot = redactHomePath(harnessRoot);
|
|
6855
6979
|
const displayLegacyRoot = redactHomePath(legacyRoot);
|
|
6856
6980
|
const displayOpusHarnessRoot = env.opusHarnessRoot ? redactHomePath(env.opusHarnessRoot) : null;
|
|
6857
6981
|
const legacyHarnessActive = harnessRoot === legacyRoot && probes.pathExists(legacyRoot);
|
|
6858
|
-
const
|
|
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."));
|
|
6859
6988
|
const checks = [
|
|
6860
|
-
|
|
6989
|
+
check2({
|
|
6861
6990
|
id: "hotspot_legacy_harness_root",
|
|
6862
6991
|
label: "Legacy ~/.openclaw/harness still active",
|
|
6863
6992
|
status: legacyHarnessActive ? "warn" : "pass",
|
|
@@ -6865,7 +6994,7 @@ function assessOpenclawHotspots(probes) {
|
|
|
6865
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,
|
|
6866
6995
|
details: { harnessRoot: displayHarnessRoot, legacyRoot: displayLegacyRoot, opusHarnessRoot: displayOpusHarnessRoot }
|
|
6867
6996
|
}),
|
|
6868
|
-
|
|
6997
|
+
check2({
|
|
6869
6998
|
id: "hotspot_openclaw_env_secrets",
|
|
6870
6999
|
label: "OpenClaw deployment secrets in runner env",
|
|
6871
7000
|
status: env.openclawCronSecret || env.openclawCronFireBaseUrl ? "warn" : "pass",
|
|
@@ -6875,15 +7004,12 @@ function assessOpenclawHotspots(probes) {
|
|
|
6875
7004
|
].filter(Boolean).join("; ") : "No OpenClaw cron env overrides on this runner",
|
|
6876
7005
|
remediation: env.openclawCronSecret || env.openclawCronFireBaseUrl ? "Move to KYNVER_API_URL + scoped runner tokens; unset OpenClaw cron env on user-hosted runners." : void 0
|
|
6877
7006
|
}),
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
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}`,
|
|
6883
|
-
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,
|
|
6884
|
-
details: { schedulerProvider: env.kynverSchedulerProvider ?? null }
|
|
7007
|
+
assessRuntimeTakeoverScheduler(env, {
|
|
7008
|
+
agentOsId: targetAgentOsId ?? null,
|
|
7009
|
+
apiBaseUrl: config.apiBaseUrl?.trim() ?? env.kynverApiUrl ?? null,
|
|
7010
|
+
hasScopedRunnerToken
|
|
6885
7011
|
}),
|
|
6886
|
-
|
|
7012
|
+
check2({
|
|
6887
7013
|
id: "hotspot_lease_source_names",
|
|
6888
7014
|
label: "Harness lease/completion source names",
|
|
6889
7015
|
status: "pass",
|