@kynver-app/runtime 0.1.108 → 0.1.112
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/cleanup-git-rev-cache.d.ts +5 -0
- package/dist/cleanup-git-status-cache.d.ts +5 -0
- package/dist/cleanup-guards.d.ts +2 -0
- package/dist/cleanup-index-status.d.ts +8 -1
- package/dist/cleanup-run-liveness.d.ts +8 -1
- package/dist/cli.js +372 -73
- package/dist/cli.js.map +4 -4
- package/dist/daemon-platform-guard.d.ts +2 -0
- package/dist/index.js +364 -65
- package/dist/index.js.map +4 -4
- package/dist/landing/cli-auth.d.ts +5 -1
- package/dist/landing/land-pr.d.ts +8 -0
- package/dist/server/cleanup.js +185 -38
- package/dist/server/cleanup.js.map +3 -3
- package/dist/server/default-repo.js +11 -1
- package/dist/server/default-repo.js.map +3 -3
- package/dist/server/memory-cost-enforce.js +11 -1
- package/dist/server/memory-cost-enforce.js.map +3 -3
- package/dist/server/monitor.js +14 -2
- package/dist/server/monitor.js.map +2 -2
- package/dist/worker-ops.d.ts +4 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -175,7 +175,11 @@ function scrubWorkerEnv(env) {
|
|
|
175
175
|
|
|
176
176
|
// src/git.ts
|
|
177
177
|
function git(cwd, args, options = {}) {
|
|
178
|
-
const res = spawnSync(
|
|
178
|
+
const res = spawnSync(
|
|
179
|
+
"git",
|
|
180
|
+
args,
|
|
181
|
+
hiddenSpawnOptions({ cwd, encoding: "utf8" })
|
|
182
|
+
);
|
|
179
183
|
if (res.status !== 0 && !options.allowFailure) {
|
|
180
184
|
const message = `git ${args.join(" ")} failed: ${res.stderr || res.stdout}`;
|
|
181
185
|
if (options.throwError) throw new Error(message);
|
|
@@ -191,7 +195,11 @@ function gitStatusShort(worktreePath) {
|
|
|
191
195
|
}
|
|
192
196
|
function gitCapture(cwd, args) {
|
|
193
197
|
try {
|
|
194
|
-
const res = spawnSync(
|
|
198
|
+
const res = spawnSync(
|
|
199
|
+
"git",
|
|
200
|
+
args,
|
|
201
|
+
hiddenSpawnOptions({ cwd, encoding: "utf8" })
|
|
202
|
+
);
|
|
195
203
|
return {
|
|
196
204
|
status: res.status,
|
|
197
205
|
stdout: res.stdout || "",
|
|
@@ -5648,32 +5656,98 @@ function workerStatus(args) {
|
|
|
5648
5656
|
writeJson(path19.join(worker.workerDir, "last-status.json"), status);
|
|
5649
5657
|
console.log(JSON.stringify(status, null, 2));
|
|
5650
5658
|
}
|
|
5659
|
+
function buildWorkerListDrilldownCommands(runId) {
|
|
5660
|
+
return {
|
|
5661
|
+
full: `kynver worker list --run ${runId} --full`,
|
|
5662
|
+
blocked: `kynver worker list --run ${runId} --blocked`,
|
|
5663
|
+
running: `kynver worker list --run ${runId} --running`,
|
|
5664
|
+
task: `kynver worker list --run ${runId} --task <task-id>`,
|
|
5665
|
+
worker: `kynver worker list --run ${runId} --worker <worker>`,
|
|
5666
|
+
runFull: `kynver run status --run ${runId} --full`,
|
|
5667
|
+
workerFull: `kynver worker status --run ${runId} --name <worker>`,
|
|
5668
|
+
workerTail: `kynver worker tail --run ${runId} --name <worker> --lines 80`
|
|
5669
|
+
};
|
|
5670
|
+
}
|
|
5671
|
+
function asOptionalArg(value) {
|
|
5672
|
+
if (typeof value !== "string") return void 0;
|
|
5673
|
+
const trimmed = value.trim();
|
|
5674
|
+
return trimmed.length ? trimmed : void 0;
|
|
5675
|
+
}
|
|
5676
|
+
function activeWorkerFilters(args) {
|
|
5677
|
+
const filters = {};
|
|
5678
|
+
if (args.blocked === true || args.blocked === "true") filters.blocked = true;
|
|
5679
|
+
if (args.running === true || args.running === "true") filters.running = true;
|
|
5680
|
+
const task = asOptionalArg(args.task ?? args.taskId);
|
|
5681
|
+
if (task) filters.task = task;
|
|
5682
|
+
const worker = asOptionalArg(args.worker ?? args.name);
|
|
5683
|
+
if (worker) filters.worker = worker;
|
|
5684
|
+
const status = asOptionalArg(args.status);
|
|
5685
|
+
if (status) filters.status = status;
|
|
5686
|
+
return filters;
|
|
5687
|
+
}
|
|
5688
|
+
function workerMatchesFilters(worker, filters) {
|
|
5689
|
+
if (filters.blocked) {
|
|
5690
|
+
const attention = typeof worker.attention === "string" ? worker.attention : "";
|
|
5691
|
+
const status = typeof worker.status === "string" ? worker.status : "";
|
|
5692
|
+
if (!(attention === "blocked" || attention === "needs_attention" || attention === "stale" || status === "blocked")) {
|
|
5693
|
+
return false;
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
if (filters.running) {
|
|
5697
|
+
if (!(worker.status === "running" && worker.attention !== "blocked" && worker.attention !== "needs_attention")) {
|
|
5698
|
+
return false;
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
if (typeof filters.task === "string" && worker.taskId !== filters.task) return false;
|
|
5702
|
+
if (typeof filters.worker === "string" && worker.worker !== filters.worker) return false;
|
|
5703
|
+
if (typeof filters.status === "string" && worker.status !== filters.status) return false;
|
|
5704
|
+
return true;
|
|
5705
|
+
}
|
|
5706
|
+
function applyWorkerFilters(board, args) {
|
|
5707
|
+
const filters = activeWorkerFilters(args);
|
|
5708
|
+
if (Object.keys(filters).length === 0) return board;
|
|
5709
|
+
const workers = board.workers.filter((worker) => workerMatchesFilters(worker, filters));
|
|
5710
|
+
const filtered = {
|
|
5711
|
+
...board,
|
|
5712
|
+
workerCount: workers.length,
|
|
5713
|
+
needsAttention: workers.filter((w) => w.attention && w.attention !== "ok" && w.attention !== "done").map((w) => w.worker),
|
|
5714
|
+
workers,
|
|
5715
|
+
activeFilters: filters
|
|
5716
|
+
};
|
|
5717
|
+
if (board.summary) {
|
|
5718
|
+
filtered.summary = {
|
|
5719
|
+
statusCounts: countBy(workers, "status"),
|
|
5720
|
+
attentionCounts: countBy(workers, "attention"),
|
|
5721
|
+
lifecycleCounts: countBy(workers, "lifecycleStage")
|
|
5722
|
+
};
|
|
5723
|
+
}
|
|
5724
|
+
if (board.controller) filtered.controller = buildControllerSummary(workers);
|
|
5725
|
+
return filtered;
|
|
5726
|
+
}
|
|
5651
5727
|
function workerList(args) {
|
|
5652
5728
|
const runId = resolveRunTargetArg(args);
|
|
5653
|
-
const explicitCompact = args.compact === true || args.compact === "true";
|
|
5654
5729
|
const explicitFull = args.full === true || args.full === "true";
|
|
5655
|
-
const
|
|
5656
|
-
const
|
|
5657
|
-
const compact = explicitCompact || !explicitFull && workerCount > 100;
|
|
5658
|
-
const board = compact ? buildCompactRunBoard(runId) : buildRunBoard(runId);
|
|
5659
|
-
const autoCompact = compact && !explicitCompact;
|
|
5660
|
-
const outputWorkers = autoCompact ? board.workers.filter((worker) => worker.attention && worker.attention !== "done" && worker.attention !== "ok") : board.workers;
|
|
5730
|
+
const board = applyWorkerFilters(explicitFull ? buildRunBoard(runId) : buildCompactRunBoard(runId), args);
|
|
5731
|
+
const outputWorkers = board.workers;
|
|
5661
5732
|
console.log(
|
|
5662
5733
|
JSON.stringify(
|
|
5663
5734
|
{
|
|
5664
5735
|
runId: board.runId,
|
|
5665
5736
|
status: board.status,
|
|
5737
|
+
projection: explicitFull ? "full" : "compact",
|
|
5666
5738
|
workerCount: board.workerCount,
|
|
5667
|
-
...
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5739
|
+
...board.activeFilters ? { activeFilters: board.activeFilters } : {},
|
|
5740
|
+
...!explicitFull ? {
|
|
5741
|
+
resultContract: {
|
|
5742
|
+
projection: "compact",
|
|
5743
|
+
rawWorkerPayloadsOmitted: true,
|
|
5744
|
+
deepDetailAvailableVia: ["--full", "worker status", "worker tail", "run status --full"]
|
|
5745
|
+
},
|
|
5746
|
+
drilldownCommands: buildWorkerListDrilldownCommands(runId)
|
|
5673
5747
|
} : {},
|
|
5674
5748
|
needsAttention: board.needsAttention,
|
|
5675
|
-
...
|
|
5676
|
-
...
|
|
5749
|
+
..."summary" in board ? { summary: board.summary } : {},
|
|
5750
|
+
..."controller" in board ? { controller: board.controller } : {},
|
|
5677
5751
|
workers: outputWorkers
|
|
5678
5752
|
},
|
|
5679
5753
|
null,
|
|
@@ -5941,9 +6015,33 @@ async function publishHarnessBoardSnapshot(args, source) {
|
|
|
5941
6015
|
authRefreshFailure: res.authRefreshFailure
|
|
5942
6016
|
};
|
|
5943
6017
|
}
|
|
6018
|
+
function buildRunStatusDrilldownCommands(runId) {
|
|
6019
|
+
return {
|
|
6020
|
+
full: `kynver run status --run ${runId} --full`,
|
|
6021
|
+
blocked: `kynver status --run ${runId} --blocked`,
|
|
6022
|
+
running: `kynver status --run ${runId} --running`,
|
|
6023
|
+
task: `kynver status --run ${runId} --task <task-id>`,
|
|
6024
|
+
worker: `kynver status --run ${runId} --worker <worker>`,
|
|
6025
|
+
workersFull: `kynver worker list --run ${runId} --full`,
|
|
6026
|
+
workerFull: `kynver worker status --run ${runId} --name <worker>`,
|
|
6027
|
+
workerTail: `kynver worker tail --run ${runId} --name <worker> --lines 80`,
|
|
6028
|
+
monitorTick: `kynver monitor status --run ${runId} --tick`
|
|
6029
|
+
};
|
|
6030
|
+
}
|
|
5944
6031
|
function runStatus(args) {
|
|
5945
|
-
const
|
|
5946
|
-
const
|
|
6032
|
+
const runId = resolveRunTargetArg(args);
|
|
6033
|
+
const explicitFull = args.full === true || args.full === "true";
|
|
6034
|
+
const board = applyWorkerFilters(explicitFull ? buildRunBoard(runId) : buildCompactRunBoard(runId), args);
|
|
6035
|
+
board.projection = explicitFull ? "full" : "compact";
|
|
6036
|
+
if (!explicitFull) {
|
|
6037
|
+
board.resultContract = {
|
|
6038
|
+
projection: "compact",
|
|
6039
|
+
rawWorkerPayloadsOmitted: true,
|
|
6040
|
+
omittedWorkerFields: ["finalResult", "changedFiles", "gitAncestry", "completionResponse", "stdout/stderr tails"],
|
|
6041
|
+
deepDetailAvailableVia: ["--full", "worker status", "worker tail", "monitor status --tick"]
|
|
6042
|
+
};
|
|
6043
|
+
board.drilldownCommands = buildRunStatusDrilldownCommands(runId);
|
|
6044
|
+
}
|
|
5947
6045
|
console.log(JSON.stringify(board, null, 2));
|
|
5948
6046
|
}
|
|
5949
6047
|
function tailWorker(args) {
|
|
@@ -7081,6 +7179,10 @@ var READY_MERGE_STATES = /* @__PURE__ */ new Set(["CLEAN", "HAS_HOOKS"]);
|
|
|
7081
7179
|
function repoArgs(repo) {
|
|
7082
7180
|
return repo?.trim() ? ["--repo", repo.trim()] : [];
|
|
7083
7181
|
}
|
|
7182
|
+
function repoFromPrUrl(prUrl) {
|
|
7183
|
+
const m = /github\.com\/([^/]+)\/([^/]+)\/pull\/\d+/i.exec(prUrl.trim());
|
|
7184
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
7185
|
+
}
|
|
7084
7186
|
function ghJson(exec, cwd, args) {
|
|
7085
7187
|
const res = exec.gh(cwd, args);
|
|
7086
7188
|
if (res.status !== 0) {
|
|
@@ -7136,14 +7238,21 @@ var STRUCTURED_SECTION_RE = /^##\s*(test\s*plan|verification|test\s*evidence|ver
|
|
|
7136
7238
|
var LOCAL_VERIFICATION_RE = /typecheck|npm run (test|build|typecheck)|vitest|tsc\b|verify-pr-local|local verify|local-verify|tests? (pass|green)|build green|node --test/i;
|
|
7137
7239
|
var DOCS_TITLE_RE = /^docs[(:]/i;
|
|
7138
7240
|
var DOCS_BODY_RE = /docs[- ]only|documentation only|no[- ]code change|no code changes|low[- ]risk|plan tracker only|markdown only/i;
|
|
7139
|
-
function
|
|
7140
|
-
const title = typeof
|
|
7141
|
-
const body = typeof
|
|
7241
|
+
function runtimeVerificationEvidenceSufficient(input) {
|
|
7242
|
+
const title = typeof input.title === "string" ? input.title : "";
|
|
7243
|
+
const body = typeof input.body === "string" ? input.body : "";
|
|
7142
7244
|
const docsLowRisk = DOCS_TITLE_RE.test(title) || DOCS_BODY_RE.test(body);
|
|
7143
7245
|
const structuredSection = STRUCTURED_SECTION_RE.test(body);
|
|
7144
7246
|
const localVerification = LOCAL_VERIFICATION_RE.test(body);
|
|
7145
|
-
|
|
7146
|
-
|
|
7247
|
+
return docsLowRisk || structuredSection || localVerification || input.vercelCheckSuccess === true;
|
|
7248
|
+
}
|
|
7249
|
+
function assertVerificationEvidence(pr) {
|
|
7250
|
+
const sufficient = runtimeVerificationEvidenceSufficient({
|
|
7251
|
+
title: pr.title,
|
|
7252
|
+
body: pr.body,
|
|
7253
|
+
vercelCheckSuccess: vercelCheckSuccess(pr.statusCheckRollup)
|
|
7254
|
+
});
|
|
7255
|
+
if (sufficient) return;
|
|
7147
7256
|
throw new Error(
|
|
7148
7257
|
`PR #${pr.number} lacks landing verification evidence \u2014 add ## Test plan / ## Verification with local commands, Vercel preview, or docs/no-code rationale`
|
|
7149
7258
|
);
|
|
@@ -7244,6 +7353,14 @@ async function executeLandPrMerge(input) {
|
|
|
7244
7353
|
"mergeCommit"
|
|
7245
7354
|
].join(",")
|
|
7246
7355
|
]);
|
|
7356
|
+
if (before.state === "MERGED" || before.mergedAt) {
|
|
7357
|
+
return {
|
|
7358
|
+
prUrl: before.url || prTarget,
|
|
7359
|
+
outcome: "skipped",
|
|
7360
|
+
mergeCommit: before.mergeCommit?.oid ?? null,
|
|
7361
|
+
reason: `PR #${before.number} is already merged \u2014 land_pr no-op (redelivery)`
|
|
7362
|
+
};
|
|
7363
|
+
}
|
|
7247
7364
|
const notReadyReason = landingReadinessError(before);
|
|
7248
7365
|
if (notReadyReason) {
|
|
7249
7366
|
if (input.skipNotReady) {
|
|
@@ -7598,7 +7715,11 @@ async function dispatchRun(args) {
|
|
|
7598
7715
|
return abortClaimedSpawn(task, "land_pr task missing prUrl");
|
|
7599
7716
|
}
|
|
7600
7717
|
try {
|
|
7601
|
-
const report = await executeLandPrMerge({
|
|
7718
|
+
const report = await executeLandPrMerge({
|
|
7719
|
+
prUrl,
|
|
7720
|
+
repo: repoFromPrUrl(prUrl),
|
|
7721
|
+
cwd: run.repo
|
|
7722
|
+
});
|
|
7602
7723
|
const post = await postLandPrHarnessCompletion({
|
|
7603
7724
|
baseUrl: base,
|
|
7604
7725
|
secret,
|
|
@@ -7625,6 +7746,27 @@ async function dispatchRun(args) {
|
|
|
7625
7746
|
return abortClaimedSpawn(task, error.message);
|
|
7626
7747
|
}
|
|
7627
7748
|
}
|
|
7749
|
+
async function releaseDuplicateLocalClaim(task) {
|
|
7750
|
+
const error = "duplicate_dispatch_prevented: live local worker already owns this task";
|
|
7751
|
+
const release = await releaseDispatchClaimAfterSpawnFailure({
|
|
7752
|
+
baseUrl: base,
|
|
7753
|
+
secret,
|
|
7754
|
+
agentOsId,
|
|
7755
|
+
taskId: String(task.id),
|
|
7756
|
+
leaseOwner,
|
|
7757
|
+
failureDetail: error
|
|
7758
|
+
});
|
|
7759
|
+
outcomes.push({
|
|
7760
|
+
taskId: task.id,
|
|
7761
|
+
started: false,
|
|
7762
|
+
error,
|
|
7763
|
+
alreadyRunning: true,
|
|
7764
|
+
nonFatal: true,
|
|
7765
|
+
released: release.released,
|
|
7766
|
+
releaseResponse: release.releaseResponse
|
|
7767
|
+
});
|
|
7768
|
+
return false;
|
|
7769
|
+
}
|
|
7628
7770
|
async function spawnClaimed(decision) {
|
|
7629
7771
|
const task = decision.task;
|
|
7630
7772
|
const harnessContext = readHarnessWorkerContext(decision);
|
|
@@ -7646,10 +7788,7 @@ async function dispatchRun(args) {
|
|
|
7646
7788
|
);
|
|
7647
7789
|
}
|
|
7648
7790
|
if (hasLiveWorkerForTask(run.id, taskId)) {
|
|
7649
|
-
return
|
|
7650
|
-
task,
|
|
7651
|
-
"duplicate_dispatch_prevented: live local worker already owns this task"
|
|
7652
|
-
);
|
|
7791
|
+
return releaseDuplicateLocalClaim(task);
|
|
7653
7792
|
}
|
|
7654
7793
|
const attempt = Number(task.attempt) || 1;
|
|
7655
7794
|
if (attempt > retryLimits.maxTaskAttempts) {
|
|
@@ -7819,11 +7958,12 @@ async function dispatchRun(args) {
|
|
|
7819
7958
|
diskGate: result.diskGate,
|
|
7820
7959
|
resourceGate: result.resourceGate
|
|
7821
7960
|
};
|
|
7961
|
+
const fatalOutcome = (outcome) => !outcome.started && outcome.nonFatal !== true;
|
|
7822
7962
|
if (pipeline) {
|
|
7823
|
-
return { ok: !outcomes.some(
|
|
7963
|
+
return { ok: !outcomes.some(fatalOutcome), ...summary };
|
|
7824
7964
|
}
|
|
7825
7965
|
console.log(JSON.stringify(summary, null, 2));
|
|
7826
|
-
if (outcomes.some(
|
|
7966
|
+
if (outcomes.some(fatalOutcome)) process.exit(1);
|
|
7827
7967
|
} catch (error) {
|
|
7828
7968
|
if (pipeline) return { ok: false, error: error.message };
|
|
7829
7969
|
console.error(`run dispatch failed: ${error.message}`);
|
|
@@ -9057,11 +9197,29 @@ function validateDaemonInstallIdentity(config = loadUserConfig(), env = process.
|
|
|
9057
9197
|
};
|
|
9058
9198
|
}
|
|
9059
9199
|
|
|
9200
|
+
// src/daemon-platform-guard.ts
|
|
9201
|
+
function envFlag(name) {
|
|
9202
|
+
const raw = process.env[name]?.trim().toLowerCase();
|
|
9203
|
+
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
9204
|
+
}
|
|
9205
|
+
function assertNativeDaemonAllowed() {
|
|
9206
|
+
if (process.platform !== "win32") return;
|
|
9207
|
+
if (envFlag("KYNVER_DAEMON_ALLOW_NATIVE_WINDOWS")) return;
|
|
9208
|
+
console.error(
|
|
9209
|
+
JSON.stringify({
|
|
9210
|
+
event: "daemon_start_blocked",
|
|
9211
|
+
reason: "native_windows_console_flash",
|
|
9212
|
+
remedy: "Run the daemon inside WSL: .\\scripts\\start-tier2-wsl.ps1 \u2014 or set KYNVER_DAEMON_ALLOW_NATIVE_WINDOWS=1 to override (flashes visible consoles)."
|
|
9213
|
+
})
|
|
9214
|
+
);
|
|
9215
|
+
process.exit(1);
|
|
9216
|
+
}
|
|
9217
|
+
|
|
9060
9218
|
// src/cron/cron-env.ts
|
|
9061
9219
|
import { existsSync as existsSync27 } from "node:fs";
|
|
9062
9220
|
import { homedir as homedir11 } from "node:os";
|
|
9063
9221
|
import path37 from "node:path";
|
|
9064
|
-
function
|
|
9222
|
+
function envFlag2(name, defaultValue) {
|
|
9065
9223
|
const raw = process.env[name]?.trim().toLowerCase();
|
|
9066
9224
|
if (!raw) return defaultValue;
|
|
9067
9225
|
if (raw === "0" || raw === "false" || raw === "no" || raw === "off") return false;
|
|
@@ -9097,14 +9255,14 @@ function resolveKynverCronEnv() {
|
|
|
9097
9255
|
const secret = resolveKynverCronSecret();
|
|
9098
9256
|
const credsReady = Boolean(fireBaseUrl && secret);
|
|
9099
9257
|
const storeExists = existsSync27(storePath);
|
|
9100
|
-
const defaultEnabled = credsReady && (storeExists ||
|
|
9258
|
+
const defaultEnabled = credsReady && (storeExists || envFlag2("KYNVER_CRON_TICK_FORCE", false));
|
|
9101
9259
|
return {
|
|
9102
9260
|
storePath,
|
|
9103
9261
|
statePath,
|
|
9104
9262
|
lockPath: `${statePath}.lock`,
|
|
9105
9263
|
fireBaseUrl,
|
|
9106
9264
|
secret,
|
|
9107
|
-
tickEnabled:
|
|
9265
|
+
tickEnabled: envFlag2("KYNVER_CRON_TICK_ENABLED", defaultEnabled),
|
|
9108
9266
|
tickIntervalMs: envInt("KYNVER_CRON_TICK_INTERVAL_MS", 6e4, 5e3),
|
|
9109
9267
|
missedRunPolicy: process.env.KYNVER_CRON_MISSED_RUN_POLICY?.trim().toLowerCase() === "skip" ? "skip" : "catch_up",
|
|
9110
9268
|
maxCatchUpPerTick: envInt("KYNVER_CRON_MAX_CATCH_UP_PER_TICK", 3, 0),
|
|
@@ -9791,23 +9949,6 @@ function materialWorktreeChanges2(changedFiles) {
|
|
|
9791
9949
|
});
|
|
9792
9950
|
}
|
|
9793
9951
|
|
|
9794
|
-
// src/cleanup-index-status.ts
|
|
9795
|
-
function indexedWorktreeStatus(entry) {
|
|
9796
|
-
if (!entry.status) {
|
|
9797
|
-
entry.status = computeWorkerStatus(entry.worker, {
|
|
9798
|
-
base: entry.run.base,
|
|
9799
|
-
baseCommit: entry.run.baseCommit
|
|
9800
|
-
});
|
|
9801
|
-
}
|
|
9802
|
-
return entry.status;
|
|
9803
|
-
}
|
|
9804
|
-
function indexedWorktreeHasMaterialChanges(entry) {
|
|
9805
|
-
if (entry.status) {
|
|
9806
|
-
return materialWorktreeChanges2(entry.status.changedFiles).length > 0;
|
|
9807
|
-
}
|
|
9808
|
-
return materialWorktreeChanges2(gitStatusShort(entry.worktreePath)).length > 0;
|
|
9809
|
-
}
|
|
9810
|
-
|
|
9811
9952
|
// src/cleanup-worktree-salvage.ts
|
|
9812
9953
|
function prUrlFromFinalResult(finalResult) {
|
|
9813
9954
|
if (typeof finalResult === "string") {
|
|
@@ -9834,6 +9975,83 @@ function isPrOrUnmergedWork(status) {
|
|
|
9834
9975
|
return false;
|
|
9835
9976
|
}
|
|
9836
9977
|
|
|
9978
|
+
// src/cleanup-index-status.ts
|
|
9979
|
+
function indexedWorktreeStatus(entry) {
|
|
9980
|
+
if (!entry.status) {
|
|
9981
|
+
entry.status = computeWorkerStatus(entry.worker, {
|
|
9982
|
+
base: entry.run.base,
|
|
9983
|
+
baseCommit: entry.run.baseCommit
|
|
9984
|
+
});
|
|
9985
|
+
}
|
|
9986
|
+
return entry.status;
|
|
9987
|
+
}
|
|
9988
|
+
function indexedWorktreeHasMaterialChanges(entry, gitStatusCache) {
|
|
9989
|
+
if (entry.status) {
|
|
9990
|
+
return materialWorktreeChanges2(entry.status.changedFiles).length > 0;
|
|
9991
|
+
}
|
|
9992
|
+
const porcelain = gitStatusCache ? gitStatusCache.porcelain(entry.worktreePath) : gitStatusShort(entry.worktreePath);
|
|
9993
|
+
return materialWorktreeChanges2(porcelain).length > 0;
|
|
9994
|
+
}
|
|
9995
|
+
function finalResultFromWorkerJson(entry) {
|
|
9996
|
+
const snapshot = entry.worker.completionSnapshot?.finalResult;
|
|
9997
|
+
if (snapshot !== void 0 && snapshot !== null) return snapshot;
|
|
9998
|
+
if (entry.worker.taskPrUrl) {
|
|
9999
|
+
return { prUrl: entry.worker.taskPrUrl };
|
|
10000
|
+
}
|
|
10001
|
+
return null;
|
|
10002
|
+
}
|
|
10003
|
+
function resolveWorktreeGuardStatus(entry, ctx) {
|
|
10004
|
+
if (entry.status) return entry.status;
|
|
10005
|
+
const worker = entry.worker;
|
|
10006
|
+
const completionAcknowledged = typeof worker.completionReportedAt === "string" && worker.completionReportedAt.trim().length > 0;
|
|
10007
|
+
const workerJsonTerminal = Boolean(worker.status && ["done", "exited", "blocked", "failed", "abandoned"].includes(worker.status)) || completionAcknowledged;
|
|
10008
|
+
const finalResult = finalResultFromWorkerJson(entry);
|
|
10009
|
+
if (workerJsonTerminal && !isPidAlive(worker.pid)) {
|
|
10010
|
+
const changedFiles = ctx?.gitStatusCache ? ctx.gitStatusCache.porcelain(entry.worktreePath) : gitStatusShort(entry.worktreePath);
|
|
10011
|
+
const baseLabel = entry.run.baseCommit?.trim() || entry.run.base?.trim() || "origin/main";
|
|
10012
|
+
const ahead = ctx?.gitRevCache?.countAheadOfMain(entry.worktreePath, baseLabel);
|
|
10013
|
+
const gitAncestry = ahead === 0 ? {
|
|
10014
|
+
checked: true,
|
|
10015
|
+
base: baseLabel,
|
|
10016
|
+
relation: "synced"
|
|
10017
|
+
} : computeGitAncestry(entry.worktreePath, {
|
|
10018
|
+
base: entry.run.base,
|
|
10019
|
+
baseCommit: entry.run.baseCommit
|
|
10020
|
+
});
|
|
10021
|
+
const status = {
|
|
10022
|
+
runId: entry.runId,
|
|
10023
|
+
worker: entry.workerName,
|
|
10024
|
+
pid: worker.pid,
|
|
10025
|
+
alive: false,
|
|
10026
|
+
status: worker.status ?? (completionAcknowledged ? "done" : "exited"),
|
|
10027
|
+
attention: { state: completionAcknowledged ? "done" : "stale" },
|
|
10028
|
+
branch: worker.branch,
|
|
10029
|
+
worktreePath: entry.worktreePath,
|
|
10030
|
+
ownedPaths: worker.ownedPaths,
|
|
10031
|
+
stdoutBytes: 0,
|
|
10032
|
+
stderrBytes: 0,
|
|
10033
|
+
heartbeatBytes: 0,
|
|
10034
|
+
firstEventAt: null,
|
|
10035
|
+
lastEventAt: null,
|
|
10036
|
+
lastActivityAt: worker.completionReportedAt ?? null,
|
|
10037
|
+
currentTool: null,
|
|
10038
|
+
heartbeatCount: 0,
|
|
10039
|
+
lastHeartbeatAt: null,
|
|
10040
|
+
lastHeartbeatPhase: null,
|
|
10041
|
+
lastHeartbeatSummary: null,
|
|
10042
|
+
heartbeatBlocker: null,
|
|
10043
|
+
changedFiles,
|
|
10044
|
+
gitAncestry,
|
|
10045
|
+
finalResult,
|
|
10046
|
+
completionBlocker: typeof worker.completionBlocker === "string" ? worker.completionBlocker.trim() || null : null,
|
|
10047
|
+
prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? prUrlFromFinalResult(finalResult)
|
|
10048
|
+
};
|
|
10049
|
+
entry.status = status;
|
|
10050
|
+
return status;
|
|
10051
|
+
}
|
|
10052
|
+
return indexedWorktreeStatus(entry);
|
|
10053
|
+
}
|
|
10054
|
+
|
|
9837
10055
|
// src/cleanup-completion-blocker.ts
|
|
9838
10056
|
function completionBlockerBlocksWorktreeRemoval(indexed, status) {
|
|
9839
10057
|
const blocker = typeof indexed.worker.completionBlocker === "string" ? indexed.worker.completionBlocker.trim() : "";
|
|
@@ -9854,13 +10072,28 @@ function completionBlockerBlocksWorktreeRemoval(indexed, status) {
|
|
|
9854
10072
|
}
|
|
9855
10073
|
|
|
9856
10074
|
// src/cleanup-run-liveness.ts
|
|
10075
|
+
var TERMINAL_WORKER_JSON_STATUSES = /* @__PURE__ */ new Set([
|
|
10076
|
+
"done",
|
|
10077
|
+
"exited",
|
|
10078
|
+
"blocked",
|
|
10079
|
+
"failed",
|
|
10080
|
+
"abandoned"
|
|
10081
|
+
]);
|
|
9857
10082
|
function deriveRunTerminal(indexed, ctx) {
|
|
9858
10083
|
if (ctx) return ctx.runTerminalCache.derive(indexed.run);
|
|
9859
10084
|
return deriveTerminalRunStatus(indexed.run);
|
|
9860
10085
|
}
|
|
9861
10086
|
function isWorkerProcessLive(indexed) {
|
|
9862
10087
|
if (isPidAlive(indexed.worker.pid)) return true;
|
|
9863
|
-
if (
|
|
10088
|
+
if (typeof indexed.worker.completionReportedAt === "string" && indexed.worker.completionReportedAt.trim().length > 0) {
|
|
10089
|
+
return false;
|
|
10090
|
+
}
|
|
10091
|
+
const workerStatus2 = indexed.worker.status;
|
|
10092
|
+
if (workerStatus2 && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus2)) return false;
|
|
10093
|
+
if (!indexed.worker.pid) {
|
|
10094
|
+
if (workerStatus2 !== "running") return false;
|
|
10095
|
+
return indexedWorktreeStatus(indexed).alive;
|
|
10096
|
+
}
|
|
9864
10097
|
return false;
|
|
9865
10098
|
}
|
|
9866
10099
|
function isRunStaleActive(indexed, ctx) {
|
|
@@ -9869,6 +10102,10 @@ function isRunStaleActive(indexed, ctx) {
|
|
|
9869
10102
|
}
|
|
9870
10103
|
function runBlocksWorktreeRemoval(indexed, ctx) {
|
|
9871
10104
|
if (isWorkerProcessLive(indexed)) return true;
|
|
10105
|
+
const workerStatus2 = indexed.worker.status;
|
|
10106
|
+
if (workerStatus2 && TERMINAL_WORKER_JSON_STATUSES.has(workerStatus2) && !indexed.worker.completionBlocker) {
|
|
10107
|
+
return false;
|
|
10108
|
+
}
|
|
9872
10109
|
const status = indexedWorktreeStatus(indexed);
|
|
9873
10110
|
if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return true;
|
|
9874
10111
|
if (isFinishedWorkerStatus(status)) return false;
|
|
@@ -9887,7 +10124,7 @@ function effectiveWorktreeAgeMs(input) {
|
|
|
9887
10124
|
if (input.liveness && isRunStaleActive(indexed, input.liveness)) {
|
|
9888
10125
|
return terminalWorktreesAgeMs;
|
|
9889
10126
|
}
|
|
9890
|
-
if (input.liveness && isFinishedWorkerStatus(
|
|
10127
|
+
if (input.liveness && isFinishedWorkerStatus(resolveWorktreeGuardStatus(indexed, input.liveness)) && !isWorkerProcessLive(indexed)) {
|
|
9891
10128
|
return terminalWorktreesAgeMs;
|
|
9892
10129
|
}
|
|
9893
10130
|
return worktreesAgeMs;
|
|
@@ -9901,8 +10138,13 @@ function skipWorktreeRemoval(input) {
|
|
|
9901
10138
|
const ageThresholdMs = effectiveWorktreeAgeMs(input);
|
|
9902
10139
|
if (worktreesAgeMs <= 0 && !includeOrphans && ageThresholdMs <= 0) return "worktrees_disabled";
|
|
9903
10140
|
if (ageThresholdMs > 0 && ageMs < ageThresholdMs) return "below_age_threshold";
|
|
9904
|
-
const status = indexedWorktreeStatus(indexed);
|
|
9905
10141
|
if (isWorkerProcessLive(indexed)) return "active_worker";
|
|
10142
|
+
if (indexedWorktreeHasMaterialChanges(indexed, input.liveness?.gitStatusCache)) {
|
|
10143
|
+
return "dirty_worktree";
|
|
10144
|
+
}
|
|
10145
|
+
const ahead = input.liveness?.gitRevCache?.countAheadOfMain(input.worktreePath);
|
|
10146
|
+
if (ahead !== null && ahead !== void 0 && ahead > 0) return "pr_or_unmerged_commits";
|
|
10147
|
+
const status = resolveWorktreeGuardStatus(indexed, input.liveness);
|
|
9906
10148
|
if (completionBlockerBlocksWorktreeRemoval(indexed, status)) return "completion_blocked";
|
|
9907
10149
|
if (runBlocksWorktreeRemoval(indexed, input.liveness)) return "run_still_active";
|
|
9908
10150
|
if (!isFinishedWorkerStatus(status)) return "run_still_active";
|
|
@@ -9933,7 +10175,9 @@ function skipDependencyCacheRemoval(input) {
|
|
|
9933
10175
|
if (!diskPressure && ageMs < nodeModulesAgeMs) return "below_age_threshold";
|
|
9934
10176
|
if (activeWorktreePaths.has(path40.resolve(worktreePath))) return "active_worker";
|
|
9935
10177
|
if (indexed && isWorkerProcessLive(indexed)) return "active_worker";
|
|
9936
|
-
if (indexed && indexedWorktreeHasMaterialChanges(indexed))
|
|
10178
|
+
if (indexed && indexedWorktreeHasMaterialChanges(indexed, input.gitStatusCache)) {
|
|
10179
|
+
return "dirty_worktree";
|
|
10180
|
+
}
|
|
9937
10181
|
return null;
|
|
9938
10182
|
}
|
|
9939
10183
|
function skipBuildCacheRemoval(input) {
|
|
@@ -10775,7 +11019,7 @@ function buildWorktreeIndexAt(harnessRoot) {
|
|
|
10775
11019
|
}
|
|
10776
11020
|
|
|
10777
11021
|
// src/cleanup-retention-config.ts
|
|
10778
|
-
function
|
|
11022
|
+
function envFlag3(name) {
|
|
10779
11023
|
const v = process.env[name];
|
|
10780
11024
|
return v === "1" || v === "true" || v === "yes";
|
|
10781
11025
|
}
|
|
@@ -10786,17 +11030,17 @@ function envMs(name, fallback) {
|
|
|
10786
11030
|
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
10787
11031
|
}
|
|
10788
11032
|
function resolveHarnessRetention(options = {}) {
|
|
10789
|
-
const execute = options.execute === true || options.execute !== false &&
|
|
10790
|
-
const finalizeStaleRuns2 = options.finalizeStaleRuns !== false && !
|
|
11033
|
+
const execute = options.execute === true || options.execute !== false && envFlag3("KYNVER_CLEANUP_EXECUTE");
|
|
11034
|
+
const finalizeStaleRuns2 = options.finalizeStaleRuns !== false && !envFlag3("KYNVER_CLEANUP_SKIP_FINALIZE");
|
|
10791
11035
|
const nodeModulesAgeMs = options.nodeModulesAgeMs ?? envMs("KYNVER_CLEANUP_NODE_MODULES_AGE_MS", DEFAULT_NODE_MODULES_AGE_MS);
|
|
10792
11036
|
const worktreesAgeMs = options.worktreesAgeMs ?? envMs("KYNVER_CLEANUP_WORKTREES_AGE_MS", 0);
|
|
10793
11037
|
const terminalWorktreesAgeMs = options.terminalWorktreesAgeMs ?? envMs("KYNVER_CLEANUP_TERMINAL_WORKTREES_AGE_MS", DEFAULT_TERMINAL_WORKTREES_AGE_MS);
|
|
10794
11038
|
const runDirectoriesAgeMs = options.runDirectoriesAgeMs ?? envMs("KYNVER_CLEANUP_RUN_DIRECTORIES_AGE_MS", DEFAULT_RUN_DIRECTORIES_AGE_MS);
|
|
10795
11039
|
const maxActionsPerSweep = options.maxActionsPerSweep ?? envMs("KYNVER_CLEANUP_MAX_ACTIONS_PER_SWEEP", DEFAULT_MAX_ACTIONS_PER_SWEEP);
|
|
10796
|
-
const includeOrphans = options.includeOrphans === true ||
|
|
10797
|
-
const scopeAll =
|
|
11040
|
+
const includeOrphans = options.includeOrphans === true || envFlag3("KYNVER_CLEANUP_INCLUDE_ORPHANS");
|
|
11041
|
+
const scopeAll = envFlag3("KYNVER_CLEANUP_SCOPE_ALL") || process.env.KYNVER_CLEANUP_SCOPE === "all";
|
|
10798
11042
|
const runIdFilter = scopeAll ? options.runIdFilter : options.runIdFilter ?? (process.env.KYNVER_CLEANUP_RUN_ID || void 0);
|
|
10799
|
-
const accountBytes = options.accountBytes !== false && !
|
|
11043
|
+
const accountBytes = options.accountBytes !== false && !envFlag3("KYNVER_CLEANUP_SKIP_BYTE_ACCOUNTING");
|
|
10800
11044
|
const storageCapEnv = envMs("KYNVER_CLEANUP_STORAGE_ENTRY_CAP", 2e3);
|
|
10801
11045
|
const storagePerRunEntryCap = options.storagePerRunEntryCap !== void 0 ? options.storagePerRunEntryCap : accountBytes ? storageCapEnv > 0 ? storageCapEnv : null : null;
|
|
10802
11046
|
const byteCapEnv = envMs("KYNVER_CLEANUP_BYTE_ENTRY_CAP", 2e3);
|
|
@@ -10993,7 +11237,7 @@ function resolveHarnessScanRoots(options = {}) {
|
|
|
10993
11237
|
}
|
|
10994
11238
|
|
|
10995
11239
|
// src/cleanup-disk-pressure.ts
|
|
10996
|
-
function
|
|
11240
|
+
function envFlag4(name) {
|
|
10997
11241
|
const v = process.env[name];
|
|
10998
11242
|
return v === "1" || v === "true" || v === "yes";
|
|
10999
11243
|
}
|
|
@@ -11016,7 +11260,7 @@ function observeCleanupDiskPressure(input = {}) {
|
|
|
11016
11260
|
}
|
|
11017
11261
|
function applyDiskPressureToRetention(retention, pressure) {
|
|
11018
11262
|
if (!pressure.pressured) return retention;
|
|
11019
|
-
const executeOnPressure = retention.execute || !
|
|
11263
|
+
const executeOnPressure = retention.execute || !envFlag4("KYNVER_CLEANUP_DRY_RUN_ON_PRESSURE");
|
|
11020
11264
|
return {
|
|
11021
11265
|
...retention,
|
|
11022
11266
|
execute: executeOnPressure,
|
|
@@ -11041,6 +11285,37 @@ function emitCleanupProgress(phase, detail) {
|
|
|
11041
11285
|
console.error(`[kynver cleanup] ${phase}${suffix}`);
|
|
11042
11286
|
}
|
|
11043
11287
|
|
|
11288
|
+
// src/cleanup-git-rev-cache.ts
|
|
11289
|
+
var CleanupGitRevCache = class {
|
|
11290
|
+
aheadOfMain = /* @__PURE__ */ new Map();
|
|
11291
|
+
countAheadOfMain(worktreePath, base = "origin/main") {
|
|
11292
|
+
const key = `${worktreePath}\0${base}`;
|
|
11293
|
+
if (this.aheadOfMain.has(key)) return this.aheadOfMain.get(key) ?? null;
|
|
11294
|
+
const result = gitCapture(worktreePath, ["rev-list", "--count", `${base}..HEAD`]);
|
|
11295
|
+
if (result.status !== 0) {
|
|
11296
|
+
this.aheadOfMain.set(key, null);
|
|
11297
|
+
return null;
|
|
11298
|
+
}
|
|
11299
|
+
const count = Number(result.stdout.trim());
|
|
11300
|
+
const parsed = Number.isFinite(count) ? count : null;
|
|
11301
|
+
this.aheadOfMain.set(key, parsed);
|
|
11302
|
+
return parsed;
|
|
11303
|
+
}
|
|
11304
|
+
};
|
|
11305
|
+
|
|
11306
|
+
// src/cleanup-git-status-cache.ts
|
|
11307
|
+
var CleanupGitStatusCache = class {
|
|
11308
|
+
cache = /* @__PURE__ */ new Map();
|
|
11309
|
+
porcelain(worktreePath) {
|
|
11310
|
+
const resolved = worktreePath;
|
|
11311
|
+
const cached = this.cache.get(resolved);
|
|
11312
|
+
if (cached !== void 0) return cached;
|
|
11313
|
+
const lines = gitStatusShort(resolved);
|
|
11314
|
+
this.cache.set(resolved, lines);
|
|
11315
|
+
return lines;
|
|
11316
|
+
}
|
|
11317
|
+
};
|
|
11318
|
+
|
|
11044
11319
|
// src/cleanup-run-terminal-cache.ts
|
|
11045
11320
|
var CleanupRunTerminalCache = class {
|
|
11046
11321
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -11158,7 +11433,11 @@ function runHarnessCleanup(options = {}) {
|
|
|
11158
11433
|
emitCleanupProgress("index", "building worktree index");
|
|
11159
11434
|
const index = mergeWorktreeIndexes(paths.scanRoots);
|
|
11160
11435
|
emitCleanupProgress("index", `${index.size} indexed worktree(s)`);
|
|
11161
|
-
const liveness = {
|
|
11436
|
+
const liveness = {
|
|
11437
|
+
runTerminalCache: new CleanupRunTerminalCache(),
|
|
11438
|
+
gitStatusCache: new CleanupGitStatusCache(),
|
|
11439
|
+
gitRevCache: new CleanupGitRevCache()
|
|
11440
|
+
};
|
|
11162
11441
|
const skips = [];
|
|
11163
11442
|
const actions = [];
|
|
11164
11443
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
@@ -11178,8 +11457,15 @@ function runHarnessCleanup(options = {}) {
|
|
|
11178
11457
|
index,
|
|
11179
11458
|
now: paths.now
|
|
11180
11459
|
};
|
|
11181
|
-
|
|
11460
|
+
const dependencyCandidates = scanDependencyCacheCandidates(scanOpts);
|
|
11461
|
+
emitCleanupProgress("dependency", `${dependencyCandidates.length} cache candidate(s) at ${harnessRoot}`);
|
|
11462
|
+
let dependencyProcessed = 0;
|
|
11463
|
+
for (const raw of dependencyCandidates) {
|
|
11182
11464
|
if (atSweepCap()) break;
|
|
11465
|
+
dependencyProcessed += 1;
|
|
11466
|
+
if (dependencyProcessed % 50 === 0) {
|
|
11467
|
+
emitCleanupProgress("dependency", `${dependencyProcessed}/${dependencyCandidates.length} evaluated`);
|
|
11468
|
+
}
|
|
11183
11469
|
const resolved = path53.resolve(raw.path);
|
|
11184
11470
|
if (processedPaths.has(resolved)) continue;
|
|
11185
11471
|
processedPaths.add(resolved);
|
|
@@ -11199,7 +11485,8 @@ function runHarnessCleanup(options = {}) {
|
|
|
11199
11485
|
ageMs: candidate.ageMs,
|
|
11200
11486
|
worktreePath,
|
|
11201
11487
|
activeWorktreePaths: activeGuards.activeWorktreePaths,
|
|
11202
|
-
diskPressure: retention.diskPressure
|
|
11488
|
+
diskPressure: retention.diskPressure,
|
|
11489
|
+
gitStatusCache: liveness.gitStatusCache
|
|
11203
11490
|
});
|
|
11204
11491
|
if (guardReason) {
|
|
11205
11492
|
recordSkip(skips, candidate.path, guardReason);
|
|
@@ -11234,7 +11521,8 @@ function runHarnessCleanup(options = {}) {
|
|
|
11234
11521
|
ageMs: candidate.ageMs,
|
|
11235
11522
|
worktreePath,
|
|
11236
11523
|
activeWorktreePaths: activeGuards.activeWorktreePaths,
|
|
11237
|
-
diskPressure: retention.diskPressure
|
|
11524
|
+
diskPressure: retention.diskPressure,
|
|
11525
|
+
gitStatusCache: liveness.gitStatusCache
|
|
11238
11526
|
});
|
|
11239
11527
|
if (guardReason) {
|
|
11240
11528
|
recordSkip(skips, candidate.path, guardReason);
|
|
@@ -11254,8 +11542,13 @@ function runHarnessCleanup(options = {}) {
|
|
|
11254
11542
|
];
|
|
11255
11543
|
emitCleanupProgress("worktrees", `${worktreeCandidates.length} candidate(s) at ${harnessRoot}`);
|
|
11256
11544
|
const worktreeSeen = /* @__PURE__ */ new Set();
|
|
11545
|
+
let worktreeProcessed = 0;
|
|
11257
11546
|
for (const raw of worktreeCandidates) {
|
|
11258
11547
|
if (atSweepCap()) break;
|
|
11548
|
+
worktreeProcessed += 1;
|
|
11549
|
+
if (worktreeProcessed % 50 === 0) {
|
|
11550
|
+
emitCleanupProgress("worktrees", `${worktreeProcessed}/${worktreeCandidates.length} evaluated`);
|
|
11551
|
+
}
|
|
11259
11552
|
const resolved = path53.resolve(raw.path);
|
|
11260
11553
|
if (worktreeSeen.has(resolved)) continue;
|
|
11261
11554
|
worktreeSeen.add(resolved);
|
|
@@ -11851,6 +12144,7 @@ async function awaitDaemonBackoff(ms, isStopping) {
|
|
|
11851
12144
|
}
|
|
11852
12145
|
}
|
|
11853
12146
|
async function runDaemon(args) {
|
|
12147
|
+
assertNativeDaemonAllowed();
|
|
11854
12148
|
const runId = String(required(String(args.run || ""), "--run"));
|
|
11855
12149
|
const agentOsId = String(required(String(args.agentOsId || loadUserConfig().agentOsId || ""), "--agent-os-id"));
|
|
11856
12150
|
const execute = args.execute !== false && args.execute !== "false";
|
|
@@ -13831,12 +14125,12 @@ function assessRuntimeTakeoverScheduler(env, ctx) {
|
|
|
13831
14125
|
return check({
|
|
13832
14126
|
id: "hotspot_openclaw_scheduler",
|
|
13833
14127
|
label: "Scheduler provider (runtime daemon vs OpenClaw cron)",
|
|
13834
|
-
status: "
|
|
13835
|
-
summary: "
|
|
13836
|
-
remediation: "
|
|
14128
|
+
status: "warn",
|
|
14129
|
+
summary: "Hosted deployment with no QSTASH_TOKEN and no KYNVER_SCHEDULER_PROVIDER \u2014 kynver-cron is an in-process stub here and will NOT fire; no firing scheduler is configured",
|
|
14130
|
+
remediation: "Set QSTASH_TOKEN + KYNVER_SCHEDULER_PROVIDER=qstash on the Kynver server for hosted AgentOS schedules. Only use kynver-cron when a `kynver daemon` (or local cron store) actually owns firing on this box.",
|
|
13837
14131
|
details: {
|
|
13838
14132
|
schedulerProvider: null,
|
|
13839
|
-
resolvedFallback: "
|
|
14133
|
+
resolvedFallback: "none",
|
|
13840
14134
|
qstashTokenPresent: false,
|
|
13841
14135
|
hostedDeployment
|
|
13842
14136
|
}
|
|
@@ -14638,14 +14932,15 @@ function usage(code = 0) {
|
|
|
14638
14932
|
" kynver runner credential [--agent-os-id ID] [--base-url URL]",
|
|
14639
14933
|
" kynver setup [--api-base-url URL] [--agent-os-id ID] [--agent-os-slug SLUG] [--box-kind forge|ghost] [--repo PATH] [--discover-repo] [--max-workers N] [--provider claude|cursor]",
|
|
14640
14934
|
" kynver daemon --run RUN_ID --agent-os-id AOS_ID [--execute] [--interval-ms MS]",
|
|
14935
|
+
" kynver status --run RUN_ID [--blocked] [--running] [--task TASK_ID] [--worker WORKER] [--full] # top-level compact run status",
|
|
14641
14936
|
" kynver run create [--repo /path/repo] [--name name] [--base origin/main]",
|
|
14642
14937
|
" kynver run list",
|
|
14643
14938
|
" kynver run resolve --name RUN_NAME",
|
|
14644
|
-
" kynver run status --run RUN_ID [--
|
|
14939
|
+
" kynver run status --run RUN_ID [--full] # defaults to compact shallow map with drill-down commands",
|
|
14645
14940
|
" kynver run dispatch --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--execute] [--lane any|implementation|review|landing] [--target-task-id TASK_ID] [--executor harness] [--max-starts 1] [--lease-ms MS] [--owned path[,path]] [--model claude-opus-4-8] [--disk-path /] [--reconcile-stale-blockers]",
|
|
14646
14941
|
" kynver run sweep --run RUN_ID --agent-os-id AOS_ID [--base-url URL] [--secret SECRET] [--grace-ms MS]",
|
|
14647
14942
|
' kynver worker start --run RUN_ID --name worker --task "..." [--owned path[,path]] [--model MODEL] [--provider claude|cursor] [--agent-os-id AOS_ID] [--task-id TASK_ID] [--wait]',
|
|
14648
|
-
" kynver worker list --run RUN_ID [--
|
|
14943
|
+
" kynver worker list --run RUN_ID [--full] # defaults to compact shallow map with drill-down commands",
|
|
14649
14944
|
" kynver worker status --run RUN_ID --name worker",
|
|
14650
14945
|
" kynver worker tail --run RUN_ID --name worker [--lines 40] [--raw]",
|
|
14651
14946
|
" kynver worker stop --run RUN_ID --name worker",
|
|
@@ -14699,6 +14994,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
14699
14994
|
const { runsDir, worktreesDir } = getPaths();
|
|
14700
14995
|
mkdirSync10(runsDir, { recursive: true });
|
|
14701
14996
|
mkdirSync10(worktreesDir, { recursive: true });
|
|
14997
|
+
if (scope === "daemon") {
|
|
14998
|
+
assertNativeDaemonAllowed();
|
|
14999
|
+
}
|
|
14702
15000
|
if (shouldEnforceMemoryCostPackageGuardCli(scope, action)) {
|
|
14703
15001
|
let repoRoot;
|
|
14704
15002
|
const runId = args.run ? String(args.run).trim() : "";
|
|
@@ -14715,6 +15013,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
14715
15013
|
});
|
|
14716
15014
|
}
|
|
14717
15015
|
if (scope === "login") return void await runLogin(args);
|
|
15016
|
+
if (scope === "status") return runStatus(args);
|
|
14718
15017
|
if (scope === "runner" && action === "credential") return void await mintRunnerCredential(args);
|
|
14719
15018
|
if (scope === "setup") return void await runSetup(args);
|
|
14720
15019
|
if (scope === "daemon") return void await runDaemon(args);
|