@kynver-app/runtime 0.1.123 → 0.1.129

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.
Files changed (53) hide show
  1. package/dist/chat/chat-claim-loop.d.ts +11 -0
  2. package/dist/chat/command-allowlist.d.ts +8 -0
  3. package/dist/chat/command-executor.d.ts +13 -0
  4. package/dist/cli.js +62 -17782
  5. package/dist/config.d.ts +2 -0
  6. package/dist/cron/cron-cli-bin.d.ts +7 -0
  7. package/dist/cron/cron-readiness.d.ts +35 -0
  8. package/dist/daemon-heartbeat.d.ts +3 -0
  9. package/dist/disk-gate.d.ts +7 -0
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +79 -19281
  12. package/dist/instruction-bundle/cache.d.ts +6 -0
  13. package/dist/instruction-bundle/client.d.ts +25 -0
  14. package/dist/instruction-bundle/contract.d.ts +4 -0
  15. package/dist/instruction-bundle/contract.js +5 -0
  16. package/dist/instruction-bundle/embedded-bundle.d.ts +3 -0
  17. package/dist/instruction-bundle/index.d.ts +7 -0
  18. package/dist/instruction-bundle/keys.d.ts +14 -0
  19. package/dist/instruction-bundle/state.d.ts +24 -0
  20. package/dist/instruction-bundle/types.d.ts +42 -0
  21. package/dist/instruction-bundle/verify.d.ts +15 -0
  22. package/dist/mesh-liveness/mesh-cron-lease-store.d.ts +9 -0
  23. package/dist/retry-limits.d.ts +4 -0
  24. package/dist/server/cleanup.js +16 -4054
  25. package/dist/server/default-repo.js +1 -458
  26. package/dist/server/harness-notice.js +15 -287
  27. package/dist/server/heavy-verification.js +1 -223
  28. package/dist/server/landing.js +1 -44
  29. package/dist/server/memory-cost-enforce.js +2 -480
  30. package/dist/server/memory-cost.js +2 -184
  31. package/dist/server/monitor.js +8 -1805
  32. package/dist/server/orchestration.js +1 -444
  33. package/dist/server/pr-evidence.js +1 -163
  34. package/dist/server/repo-search.js +1 -224
  35. package/dist/server/worker-policy.js +1 -432
  36. package/dist/worker-persona-catalog.d.ts +5 -0
  37. package/dist/worker-persona-catalog.js +5 -138
  38. package/package.json +8 -2
  39. package/dist/cli.js.map +0 -7
  40. package/dist/index.js.map +0 -7
  41. package/dist/server/cleanup.js.map +0 -7
  42. package/dist/server/default-repo.js.map +0 -7
  43. package/dist/server/harness-notice.js.map +0 -7
  44. package/dist/server/heavy-verification.js.map +0 -7
  45. package/dist/server/landing.js.map +0 -7
  46. package/dist/server/memory-cost-enforce.js.map +0 -7
  47. package/dist/server/memory-cost.js.map +0 -7
  48. package/dist/server/monitor.js.map +0 -7
  49. package/dist/server/orchestration.js.map +0 -7
  50. package/dist/server/pr-evidence.js.map +0 -7
  51. package/dist/server/repo-search.js.map +0 -7
  52. package/dist/server/worker-policy.js.map +0 -7
  53. package/dist/worker-persona-catalog.js.map +0 -7
@@ -1,1805 +1,8 @@
1
- var __getOwnPropNames = Object.getOwnPropertyNames;
2
- var __esm = (fn, res) => function __init() {
3
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
- };
5
-
6
- // src/heartbeat-final-result.ts
7
- function tryParseJsonObject(text) {
8
- const trimmed = text.trim();
9
- if (!trimmed.startsWith("{")) return null;
10
- try {
11
- const parsed = JSON.parse(trimmed);
12
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
13
- return parsed;
14
- }
15
- } catch {
16
- return null;
17
- }
18
- return null;
19
- }
20
- function embeddedRecordFromProse(text) {
21
- const trimmed = text.trim();
22
- if (!trimmed) return null;
23
- const direct = tryParseJsonObject(trimmed);
24
- if (direct) return direct;
25
- const candidates = [];
26
- const fenceRe = /```(?:json)?\s*([\s\S]*?)```/gi;
27
- let fenceMatch;
28
- while ((fenceMatch = fenceRe.exec(trimmed)) !== null) {
29
- const fromFence = tryParseJsonObject(fenceMatch[1] ?? "");
30
- if (fromFence) candidates.push(fromFence);
31
- }
32
- const firstBrace = trimmed.indexOf("{");
33
- const lastBrace = trimmed.lastIndexOf("}");
34
- if (firstBrace >= 0 && lastBrace > firstBrace) {
35
- const slice = tryParseJsonObject(trimmed.slice(firstBrace, lastBrace + 1));
36
- if (slice) candidates.push(slice);
37
- }
38
- return candidates.length > 0 ? candidates[candidates.length - 1] : null;
39
- }
40
- function terminalFinalResultFromHeartbeatRow(row) {
41
- const explicit = row.finalResult ?? row.final_result;
42
- if (explicit !== void 0 && explicit !== null) {
43
- if (typeof explicit === "string") {
44
- const embedded2 = embeddedRecordFromProse(explicit);
45
- return embedded2 ?? (explicit.trim() || null);
46
- }
47
- return explicit;
48
- }
49
- const summary = typeof row.summary === "string" ? row.summary.trim() : "";
50
- if (!summary) return null;
51
- const embedded = embeddedRecordFromProse(summary);
52
- if (embedded) return embedded;
53
- return summary;
54
- }
55
- var init_heartbeat_final_result = __esm({
56
- "src/heartbeat-final-result.ts"() {
57
- "use strict";
58
- }
59
- });
60
-
61
- // src/util.ts
62
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
63
- function fail(message) {
64
- console.error(message);
65
- process.exit(1);
66
- }
67
- function hiddenSpawnOptions(opts) {
68
- if (process.platform !== "win32") return opts;
69
- return { windowsHide: true, ...opts };
70
- }
71
- function safeJson(line) {
72
- try {
73
- return JSON.parse(line);
74
- } catch {
75
- return null;
76
- }
77
- }
78
- function fileSize(file) {
79
- try {
80
- return statSync(file).size;
81
- } catch {
82
- return 0;
83
- }
84
- }
85
- function fileMtime(file) {
86
- try {
87
- return statSync(file).mtime.toISOString();
88
- } catch {
89
- return null;
90
- }
91
- }
92
- function tailFile(file, lines) {
93
- if (!existsSync(file)) return "";
94
- const data = readFileSync(file, "utf8");
95
- return data.split("\n").slice(-lines).join("\n");
96
- }
97
- function isPidAlive(pid) {
98
- if (!pid) return false;
99
- try {
100
- process.kill(pid, 0);
101
- return true;
102
- } catch {
103
- return false;
104
- }
105
- }
106
- function latestIso(values) {
107
- let best = null;
108
- let bestMs = -Infinity;
109
- for (const value of values) {
110
- if (!value) continue;
111
- const ms = Date.parse(value);
112
- if (Number.isFinite(ms) && ms > bestMs) {
113
- bestMs = ms;
114
- best = value;
115
- }
116
- }
117
- return best;
118
- }
119
- function secsAgo(ms) {
120
- return Math.max(0, Math.round((Date.now() - ms) / 1e3));
121
- }
122
- var init_util = __esm({
123
- "src/util.ts"() {
124
- "use strict";
125
- }
126
- });
127
-
128
- // src/heartbeat.ts
129
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
130
- function isTerminalHeartbeatPhase(phase) {
131
- return phase === "complete";
132
- }
133
- function terminalFinalResultFromHeartbeat(heartbeat) {
134
- if (!isTerminalHeartbeatPhase(heartbeat.lastHeartbeatPhase)) return null;
135
- if (heartbeat.terminalFinalResult !== void 0 && heartbeat.terminalFinalResult !== null) {
136
- return heartbeat.terminalFinalResult;
137
- }
138
- const summary = heartbeat.lastHeartbeatSummary?.trim();
139
- return summary || "completed";
140
- }
141
- function parseHeartbeat(file) {
142
- const result = {
143
- heartbeatCount: 0,
144
- lastHeartbeatAt: null,
145
- lastHeartbeatPhase: null,
146
- lastHeartbeatSummary: null,
147
- terminalFinalResult: null,
148
- heartbeatBlocker: null,
149
- timestampAnomalies: [],
150
- lastBoxResourceSnapshot: null,
151
- lastPrEvidence: []
152
- };
153
- if (!existsSync2(file)) return result;
154
- const maxFutureMs = Date.now() + HEARTBEAT_FUTURE_SKEW_MS;
155
- const clampedTo = new Date(maxFutureMs).toISOString();
156
- const lines = readFileSync2(file, "utf8").split("\n").filter(Boolean);
157
- for (const line of lines) {
158
- const entry = safeJson(line);
159
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
160
- const row = entry;
161
- result.heartbeatCount++;
162
- if (row.ts) {
163
- const ts = String(row.ts);
164
- const tsMs = Date.parse(ts);
165
- if (Number.isFinite(tsMs) && tsMs > maxFutureMs) {
166
- result.timestampAnomalies.push({
167
- kind: "future_heartbeat_timestamp",
168
- observedAt: ts,
169
- clampedTo
170
- });
171
- } else {
172
- result.lastHeartbeatAt = ts;
173
- }
174
- }
175
- if (row.phase !== void 0 && row.phase !== null) result.lastHeartbeatPhase = String(row.phase);
176
- if (row.summary !== void 0 && row.summary !== null) result.lastHeartbeatSummary = String(row.summary);
177
- if (isTerminalHeartbeatPhase(result.lastHeartbeatPhase)) {
178
- result.terminalFinalResult = terminalFinalResultFromHeartbeatRow(row);
179
- }
180
- result.heartbeatBlocker = row.blocker ? String(row.blocker) : null;
181
- if (row.boxResourceSnapshot && typeof row.boxResourceSnapshot === "object" && !Array.isArray(row.boxResourceSnapshot)) {
182
- result.lastBoxResourceSnapshot = row.boxResourceSnapshot;
183
- }
184
- if (Array.isArray(row.prEvidence)) {
185
- result.lastPrEvidence = row.prEvidence.filter(
186
- (entry2) => !!entry2 && typeof entry2 === "object" && typeof entry2.prUrl === "string"
187
- );
188
- }
189
- }
190
- return result;
191
- }
192
- var HEARTBEAT_FUTURE_SKEW_MS;
193
- var init_heartbeat = __esm({
194
- "src/heartbeat.ts"() {
195
- "use strict";
196
- init_heartbeat_final_result();
197
- init_util();
198
- HEARTBEAT_FUTURE_SKEW_MS = 6e4;
199
- }
200
- });
201
-
202
- // src/repo-search.ts
203
- function binaryName(token) {
204
- if (!token) return null;
205
- const base = token.split("/").pop() ?? token;
206
- return base.replace(/\.exe$/i, "").toLowerCase();
207
- }
208
- function splitShellWords(input) {
209
- if (!input) return [];
210
- const words = [];
211
- let current = "";
212
- let quote;
213
- let escaped = false;
214
- for (const char of input) {
215
- if (escaped) {
216
- current += char;
217
- escaped = false;
218
- continue;
219
- }
220
- if (char === "\\") {
221
- escaped = true;
222
- continue;
223
- }
224
- if (quote) {
225
- if (char === quote) quote = void 0;
226
- else current += char;
227
- continue;
228
- }
229
- if (char === '"' || char === "'") {
230
- quote = char;
231
- continue;
232
- }
233
- if (/\s/.test(char)) {
234
- if (current) {
235
- words.push(current);
236
- current = "";
237
- }
238
- continue;
239
- }
240
- current += char;
241
- }
242
- if (current) words.push(current);
243
- return words;
244
- }
245
- function isRgArgv(argv) {
246
- const bin = binaryName(argv[0]);
247
- return Boolean(bin && RG_BINARIES.has(bin));
248
- }
249
- function isSingleFileSearchTarget(target) {
250
- if (!target || target.includes("/") || target.includes("*")) return false;
251
- return /\.(?:json|md|mjs|cjs|js|ts|tsx|yaml|yml)$/iu.test(target);
252
- }
253
- function isRgExcludeScopeTarget(target) {
254
- if (!target) return false;
255
- const t = target.trim();
256
- return t.startsWith("!") && !t.includes("/") && !t.endsWith("/**");
257
- }
258
- function fixRgGlobToken(token) {
259
- if (!token.startsWith("--glob=")) return token;
260
- const value = token.slice("--glob=".length);
261
- if (value.startsWith("!") && !value.includes("/") && !value.endsWith("/**")) {
262
- return `--glob=${value}/**`;
263
- }
264
- return token;
265
- }
266
- function collectRgPositional(argv) {
267
- const positional = [];
268
- for (let i = 1; i < argv.length; i += 1) {
269
- const token = argv[i];
270
- if (!token) continue;
271
- if (token === "--") {
272
- positional.push(...argv.slice(i + 1));
273
- break;
274
- }
275
- if (token.startsWith("-")) {
276
- if (token.includes("=")) continue;
277
- if (RG_OPTS_WITH_VALUE.has(token)) i += 1;
278
- continue;
279
- }
280
- positional.push(token);
281
- }
282
- return positional;
283
- }
284
- function normalizeRgArgv(argv) {
285
- let changed = false;
286
- const out = argv.map((token) => {
287
- const fixed = fixRgGlobToken(token);
288
- if (fixed !== token) changed = true;
289
- return fixed;
290
- });
291
- const positional = collectRgPositional(out);
292
- if (positional.length === 2) {
293
- const [pattern, target] = positional;
294
- if (isSingleFileSearchTarget(target)) {
295
- return { argv: [out[0] ?? "rg", "-g", target, pattern, "."], changed: true };
296
- }
297
- }
298
- return { argv: out, changed };
299
- }
300
- function normalizeRepoSearchCommand(command) {
301
- const trimmed = command.trim();
302
- if (!trimmed) return { command: trimmed, changed: false };
303
- const joiner = trimmed.includes("&&") ? " && " : trimmed.includes("||") ? " || " : "; ";
304
- const stages = trimmed.split(/\s*(?:&&|\|\||;)\s*/u);
305
- let changed = false;
306
- const normalizedStages = stages.map((stage) => {
307
- const argv = splitShellWords(stage.trim());
308
- if (!argv.length || !isRgArgv(argv)) return stage;
309
- const normalized = normalizeRgArgv(argv);
310
- if (normalized.changed) {
311
- changed = true;
312
- return normalized.argv.join(" ");
313
- }
314
- return stage;
315
- });
316
- if (!changed) return { command: trimmed, changed: false };
317
- return { command: normalizedStages.join(joiner), changed: true };
318
- }
319
- function extractSearchMeta(meta) {
320
- if (!meta) return {};
321
- const pipelineMatch = meta.match(/search\s+"(.+)"\s+in\s+([^()]+?)(?:\s*\(|$)/iu);
322
- if (pipelineMatch) {
323
- return { pattern: pipelineMatch[1], target: pipelineMatch[2]?.trim() };
324
- }
325
- const match = meta.match(/^search\s+"(.+)"\s+in\s+(.+)$/iu);
326
- if (!match) return {};
327
- return { pattern: match[1], target: match[2]?.trim() };
328
- }
329
- function classifyRepoSearchMeta(meta) {
330
- const { pattern, target } = extractSearchMeta(meta);
331
- if (!pattern) return { kind: "not_repo_search" };
332
- if (isRgExcludeScopeTarget(target)) {
333
- return { kind: "rg_exclude_syntax", pattern, target };
334
- }
335
- if (isSingleFileSearchTarget(target)) {
336
- return { kind: "bad_scope", pattern, target };
337
- }
338
- return { kind: "not_repo_search", pattern, target };
339
- }
340
- function metaToNormalizedRgCommand(meta) {
341
- const { pattern, target } = extractSearchMeta(meta);
342
- if (!pattern) return null;
343
- if (isRgExcludeScopeTarget(target)) {
344
- const glob = `${target.trim()}/**`;
345
- return {
346
- command: `rg "${pattern}" -g '${glob}' .`,
347
- changed: true
348
- };
349
- }
350
- if (target && isSingleFileSearchTarget(target)) {
351
- return {
352
- command: `rg -g ${target} "${pattern}" .`,
353
- changed: true
354
- };
355
- }
356
- return null;
357
- }
358
- function formatRepoSearchGuidance(ctx) {
359
- if (ctx.kind === "bad_scope" && ctx.pattern?.includes("agent-os-land-pr") && ctx.target === "package.json") {
360
- return "Search package.json with a glob from the repo root: `rg -g package.json agent-os-land-pr .` \u2014 or run `node scripts/agent-os-land-pr.mjs <pr-url>` directly.";
361
- }
362
- if (ctx.kind === "bad_scope" && ctx.pattern && ctx.target) {
363
- return `Use \`rg -g '${ctx.target}' ${ctx.pattern} .\` from the repo root instead of treating ${ctx.target} as a folder.`;
364
- }
365
- if (ctx.kind === "rg_exclude_syntax" && ctx.pattern) {
366
- const glob = ctx.target ? `${ctx.target.trim()}/**` : "!node_modules/**";
367
- return `Repo search scope \`${ctx.target ?? "!node_modules"}\` is not a valid ripgrep path. Use \`rg "${ctx.pattern}" -g '${glob}' .\` from the repo root (exclude globs need a \`/**\` suffix).`;
368
- }
369
- if (ctx.kind === "no_matches" && ctx.pattern) {
370
- return `No matches for "${ctx.pattern}". Try a broader pattern, drop overly short tokens, or search from the repo root with \`rg "${ctx.pattern}" .\`.`;
371
- }
372
- return null;
373
- }
374
- function extractSearchMetaFromToolLine(line) {
375
- const match = line.match(/search\s+"(.+)"\s+in\s+([^()]+?)(?:\s*\(agent\)|\s*failed|$)/iu);
376
- if (!match) return null;
377
- return `search "${match[1]}" in ${match[2]?.trim()}`;
378
- }
379
- function diagnoseRepoSearchFailure(input) {
380
- const meta = input.meta?.trim() || (input.command ? extractSearchMetaFromToolLine(input.command) : null) || null;
381
- if (meta) {
382
- const ctx = classifyRepoSearchMeta(meta);
383
- const guidance = formatRepoSearchGuidance(ctx);
384
- if (guidance) return guidance;
385
- const normalized = metaToNormalizedRgCommand(meta);
386
- if (normalized?.changed) {
387
- return `Repo search used an invalid scope. Retry with: \`${normalized.command}\`.`;
388
- }
389
- }
390
- if (input.command && /\b(rg|ripgrep)\b/i.test(input.command)) {
391
- const normalized = normalizeRepoSearchCommand(input.command);
392
- if (normalized.changed) {
393
- return `Ripgrep scope may be invalid. Retry with: \`${normalized.command}\`.`;
394
- }
395
- if (input.exitCode === 1) {
396
- return "Ripgrep returned no matches (exit 1). Try a broader pattern or search from the repo root.";
397
- }
398
- }
399
- return null;
400
- }
401
- var RG_BINARIES, RG_OPTS_WITH_VALUE;
402
- var init_repo_search = __esm({
403
- "src/repo-search.ts"() {
404
- "use strict";
405
- RG_BINARIES = /* @__PURE__ */ new Set(["rg", "ripgrep", "grep"]);
406
- RG_OPTS_WITH_VALUE = /* @__PURE__ */ new Set([
407
- "-e",
408
- "--regexp",
409
- "-f",
410
- "--file",
411
- "-m",
412
- "--max-count",
413
- "-A",
414
- "--after-context",
415
- "-B",
416
- "--before-context",
417
- "-C",
418
- "--context",
419
- "-g",
420
- "--glob",
421
- "--iglob"
422
- ]);
423
- }
424
- });
425
-
426
- // src/shell-command-outcome.ts
427
- function tidy(text, max = 200) {
428
- const one = text.replace(/\s+/g, " ").trim();
429
- return one.length > max ? `${one.slice(0, max - 1)}\u2026` : one;
430
- }
431
- function extractJsonObject(text) {
432
- const trimmed = text.trim();
433
- if (!trimmed) return null;
434
- if (trimmed.startsWith("{")) {
435
- try {
436
- return JSON.parse(trimmed);
437
- } catch {
438
- }
439
- }
440
- const start = trimmed.indexOf("{");
441
- const end = trimmed.lastIndexOf("}");
442
- if (start >= 0 && end > start) {
443
- try {
444
- return JSON.parse(trimmed.slice(start, end + 1));
445
- } catch {
446
- return null;
447
- }
448
- }
449
- return null;
450
- }
451
- function isRecord(value) {
452
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
453
- }
454
- function summarizeNpmAuditReport(report) {
455
- const meta = report.metadata;
456
- if (!isRecord(meta)) return null;
457
- const vuln = meta.vulnerabilities;
458
- if (!isRecord(vuln)) return null;
459
- const num = (key) => typeof vuln[key] === "number" ? vuln[key] : 0;
460
- const summary = {
461
- info: num("info"),
462
- low: num("low"),
463
- moderate: num("moderate"),
464
- high: num("high"),
465
- critical: num("critical"),
466
- total: num("total")
467
- };
468
- if (typeof vuln.total !== "number" && !summary.critical && !summary.high && !summary.moderate && !summary.low && !summary.info) {
469
- return null;
470
- }
471
- return summary;
472
- }
473
- function formatAuditSummaryLine(audit) {
474
- const parts = [];
475
- if (audit.critical) parts.push(`${audit.critical} critical`);
476
- if (audit.high) parts.push(`${audit.high} high`);
477
- if (audit.moderate) parts.push(`${audit.moderate} moderate`);
478
- if (audit.low) parts.push(`${audit.low} low`);
479
- if (audit.info) parts.push(`${audit.info} info`);
480
- const breakdown = parts.length ? parts.join(", ") : "see report";
481
- return `npm audit: ${audit.total} vulnerabilit${audit.total === 1 ? "y" : "ies"} (${breakdown}) \u2014 remediation required`;
482
- }
483
- function npmAuditFailureReason(report, stderr) {
484
- const err = report.error;
485
- if (isRecord(err)) {
486
- const summary = typeof err.summary === "string" ? err.summary.trim() : "";
487
- const code = typeof err.code === "string" ? err.code.trim() : "";
488
- if (summary) return code ? `${code}: ${summary}` : summary;
489
- if (code) return code;
490
- }
491
- const detail = typeof report.message === "string" ? report.message.trim() : "";
492
- if (detail) return detail;
493
- const errTail = stderr.trim();
494
- if (errTail) return tidy(errTail.split("\n").find(Boolean) ?? errTail, 160);
495
- return "npm audit failed";
496
- }
497
- function classifyNpmAuditOutcome(input) {
498
- const combined = `${input.stdout}
499
- ${input.stderr}`.trim();
500
- const parsed = extractJsonObject(combined);
501
- if (!parsed || !isRecord(parsed)) {
502
- const tail = tidy(combined || `exit ${input.exitCode}`, 180);
503
- return {
504
- kind: "command_failure",
505
- exitCode: input.exitCode,
506
- summary: `npm audit failed (invalid or missing JSON): ${tail}`,
507
- parseError: "invalid_json"
508
- };
509
- }
510
- if (isRecord(parsed.error)) {
511
- return {
512
- kind: "command_failure",
513
- exitCode: input.exitCode,
514
- summary: `npm audit command failed: ${npmAuditFailureReason(parsed, input.stderr)}`
515
- };
516
- }
517
- const audit = summarizeNpmAuditReport(parsed);
518
- if (!audit) {
519
- return {
520
- kind: "command_failure",
521
- exitCode: input.exitCode,
522
- summary: "npm audit failed: JSON response missing vulnerability metadata",
523
- parseError: "missing_metadata"
524
- };
525
- }
526
- if (input.exitCode === 0 && audit.total === 0) {
527
- return {
528
- kind: "success",
529
- exitCode: 0,
530
- summary: "npm audit: no vulnerabilities reported",
531
- audit
532
- };
533
- }
534
- return {
535
- kind: "audit_findings",
536
- exitCode: input.exitCode,
537
- summary: formatAuditSummaryLine(audit),
538
- audit
539
- };
540
- }
541
- function isNpmAuditCommand(command) {
542
- return NPM_AUDIT_RE.test(command);
543
- }
544
- function isRgCommand(command) {
545
- return RG_CMD_RE.test(command);
546
- }
547
- function classifyRgOutcome(input) {
548
- const diagnosis = diagnoseRepoSearchFailure({
549
- command: input.command,
550
- exitCode: input.exitCode
551
- });
552
- if (input.exitCode === 0) {
553
- return {
554
- kind: "success",
555
- exitCode: 0,
556
- summary: "ripgrep finished (exit 0)"
557
- };
558
- }
559
- if (input.exitCode === 1) {
560
- const errText = (input.stderr || input.interleaved).trim();
561
- if (errText && RG_REAL_ERROR_RE.test(errText)) {
562
- const tail2 = tidy(errText, 160);
563
- return {
564
- kind: "command_failure",
565
- exitCode: 1,
566
- summary: diagnosis ?? `ripgrep failed (exit 1): ${tail2}`
567
- };
568
- }
569
- const normalized = normalizeRepoSearchCommand(input.command);
570
- const retry = normalized.changed && !diagnosis ? ` Retry with: \`${normalized.command}\`.` : "";
571
- return {
572
- kind: "search_no_matches",
573
- exitCode: 1,
574
- summary: diagnosis ?? `ripgrep: no matches (exit 1).${retry} Try a broader pattern or search from the repo root.`
575
- };
576
- }
577
- const tail = tidy(input.interleaved || input.stdout || input.stderr || `exit ${input.exitCode}`, 180);
578
- return {
579
- kind: "command_failure",
580
- exitCode: input.exitCode,
581
- summary: diagnosis ?? `ripgrep failed (exit ${input.exitCode}): ${tail}`
582
- };
583
- }
584
- function classifyShellCommandOutcome(input) {
585
- const stdout = input.stdout ?? "";
586
- const stderr = input.stderr ?? "";
587
- const interleaved = input.interleavedOutput ?? "";
588
- if (isNpmAuditCommand(input.command)) {
589
- const body = stdout.trim() || interleaved.trim() || stderr.trim();
590
- return classifyNpmAuditOutcome({
591
- exitCode: input.exitCode,
592
- stdout: body,
593
- stderr
594
- });
595
- }
596
- if (isRgCommand(input.command)) {
597
- return classifyRgOutcome({
598
- command: input.command,
599
- exitCode: input.exitCode,
600
- stdout,
601
- stderr,
602
- interleaved
603
- });
604
- }
605
- const searchDiagnosis = diagnoseRepoSearchFailure({
606
- command: input.command,
607
- exitCode: input.exitCode
608
- });
609
- if (searchDiagnosis && input.exitCode !== 0) {
610
- return {
611
- kind: "command_failure",
612
- exitCode: input.exitCode,
613
- summary: searchDiagnosis
614
- };
615
- }
616
- if (input.exitCode === 0) {
617
- return {
618
- kind: "success",
619
- exitCode: 0,
620
- summary: `command succeeded (exit 0)`
621
- };
622
- }
623
- const tail = tidy(interleaved || stdout || stderr || `exit ${input.exitCode}`, 180);
624
- return {
625
- kind: "command_failure",
626
- exitCode: input.exitCode,
627
- summary: `command failed (exit ${input.exitCode}): ${tail}`
628
- };
629
- }
630
- var NPM_AUDIT_RE, RG_CMD_RE, RG_REAL_ERROR_RE;
631
- var init_shell_command_outcome = __esm({
632
- "src/shell-command-outcome.ts"() {
633
- "use strict";
634
- init_repo_search();
635
- NPM_AUDIT_RE = /\bnpm\s+audit\b/i;
636
- RG_CMD_RE = /\b(rg|ripgrep)\b/i;
637
- RG_REAL_ERROR_RE = /\b(error|invalid|unknown|panic|not found)\b/i;
638
- }
639
- });
640
-
641
- // src/stream.ts
642
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
643
- function eventTimestampIso(event) {
644
- const tsMs = event.timestamp_ms;
645
- return event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : void 0);
646
- }
647
- function cursorToolNameFromCall(toolCall) {
648
- if (!toolCall) return null;
649
- for (const key of Object.keys(toolCall)) {
650
- if (key.endsWith("ToolCall")) {
651
- const stem = key.slice(0, -"ToolCall".length);
652
- return stem.length ? stem : key;
653
- }
654
- }
655
- return null;
656
- }
657
- function recordStreamResult(result, event) {
658
- result.finalResult = event.result || event.subtype || event.terminal_reason || "completed";
659
- if (event.is_error) {
660
- result.error = String(event.result || event.api_error_status || "stream result error");
661
- }
662
- }
663
- function shellPayloadFromCursorEvent(event) {
664
- if (event.type !== "tool_call" || event.subtype !== "completed") return null;
665
- const toolCall = event.tool_call && typeof event.tool_call === "object" && !Array.isArray(event.tool_call) ? event.tool_call : null;
666
- const shell = toolCall?.shellToolCall;
667
- if (!shell || typeof shell !== "object" || Array.isArray(shell)) return null;
668
- const shellObj = shell;
669
- const args = shellObj.args;
670
- const command = args && typeof args === "object" && !Array.isArray(args) && typeof args.command === "string" ? String(args.command) : "";
671
- const result = shellObj.result;
672
- if (!result || typeof result !== "object" || Array.isArray(result)) return null;
673
- const body = result.success ?? result.failure;
674
- if (!body || typeof body !== "object" || Array.isArray(body)) return null;
675
- const row = body;
676
- const exitCode = typeof row.exitCode === "number" ? row.exitCode : 0;
677
- return {
678
- command,
679
- exitCode,
680
- stdout: typeof row.stdout === "string" ? row.stdout : "",
681
- stderr: typeof row.stderr === "string" ? row.stderr : "",
682
- interleaved: typeof row.interleavedOutput === "string" ? row.interleavedOutput : ""
683
- };
684
- }
685
- function applyShellOutcome(parsed, outcome) {
686
- if (outcome.kind === "success" || outcome.kind === "search_no_matches") return;
687
- parsed.lastShellOutcome = outcome;
688
- }
689
- function parseHarnessStream(file) {
690
- const result = {
691
- firstEventAt: null,
692
- lastEventAt: null,
693
- currentTool: null,
694
- finalResult: null,
695
- error: null,
696
- lastShellOutcome: null
697
- };
698
- if (!existsSync3(file)) return result;
699
- const lines = readFileSync3(file, "utf8").split("\n").filter(Boolean);
700
- for (const line of lines) {
701
- const event = safeJson(line);
702
- if (!event) continue;
703
- const ts = eventTimestampIso(event);
704
- if (ts) {
705
- result.firstEventAt ||= ts;
706
- result.lastEventAt = ts;
707
- }
708
- if (event.type === "stream_event" && event.event && typeof event.event === "object" && event.event.type === "content_block_start") {
709
- const block = event.event.content_block;
710
- if (block?.type === "tool_use") result.currentTool = String(block.name || "tool");
711
- }
712
- if (event.type === "assistant" && event.message && typeof event.message === "object") {
713
- const content = event.message.content;
714
- if (Array.isArray(content)) {
715
- const tool = content.find((item) => item?.type === "tool_use");
716
- if (tool) result.currentTool = String(tool.name || result.currentTool);
717
- }
718
- }
719
- if (event.type === "tool_call" && event.subtype === "started") {
720
- const toolCall = event.tool_call && typeof event.tool_call === "object" && !Array.isArray(event.tool_call) ? event.tool_call : void 0;
721
- const name = cursorToolNameFromCall(toolCall);
722
- if (name) result.currentTool = name;
723
- }
724
- const shell = shellPayloadFromCursorEvent(event);
725
- if (shell) {
726
- applyShellOutcome(
727
- result,
728
- classifyShellCommandOutcome({
729
- command: shell.command,
730
- exitCode: shell.exitCode,
731
- stdout: shell.stdout,
732
- stderr: shell.stderr,
733
- interleavedOutput: shell.interleaved
734
- })
735
- );
736
- }
737
- if (event.type === "result") {
738
- recordStreamResult(result, event);
739
- }
740
- }
741
- return result;
742
- }
743
- var init_stream = __esm({
744
- "src/stream.ts"() {
745
- "use strict";
746
- init_shell_command_outcome();
747
- init_util();
748
- }
749
- });
750
-
751
- // src/exit-classify.ts
752
- function tidy2(errorText, max = 240) {
753
- const oneLine2 = errorText.replace(/\s+/g, " ").trim();
754
- return oneLine2.length > max ? `${oneLine2.slice(0, max - 1)}\u2026` : oneLine2;
755
- }
756
- function classifyExitFailure(errorText) {
757
- const text = (errorText ?? "").trim();
758
- if (!text) return null;
759
- for (const pattern of FAILURE_PATTERNS) {
760
- if (pattern.test.test(text)) {
761
- return { blocked: true, reason: `${pattern.label}: ${tidy2(text)}` };
762
- }
763
- }
764
- return null;
765
- }
766
- var FAILURE_PATTERNS;
767
- var init_exit_classify = __esm({
768
- "src/exit-classify.ts"() {
769
- "use strict";
770
- FAILURE_PATTERNS = [
771
- {
772
- test: /\b(?:invalid|unknown|unsupported|unrecognized)\b[^.\n]*\bmodel\b/i,
773
- label: "provider rejected the requested model"
774
- },
775
- {
776
- test: /\bmodel\b[^.\n]*\b(?:not\s+(?:found|supported|available|recognized|valid)|is\s+not\s+valid|does\s+not\s+exist)/i,
777
- label: "provider rejected the requested model"
778
- },
779
- {
780
- test: /\b(?:did you mean|available models|choose (?:a|one of)|supported models)\b/i,
781
- label: "provider rejected the requested model"
782
- },
783
- {
784
- test: /model preflight failed/i,
785
- label: "model/provider preflight failed"
786
- },
787
- {
788
- test: /\b(?:command not found|ENOENT|is the .*CLI on PATH|executable not found|no such file or directory)\b/i,
789
- label: "provider CLI is missing or not on PATH"
790
- },
791
- {
792
- test: /\bfailed to spawn\b/i,
793
- label: "provider failed to spawn the worker process"
794
- },
795
- {
796
- test: /\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\b/i,
797
- label: "provider authentication failed"
798
- }
799
- ];
800
- }
801
- });
802
-
803
- // src/exited-salvage.ts
804
- function trimOrNull(value) {
805
- if (typeof value !== "string") return null;
806
- const trimmed = value.trim();
807
- return trimmed.length ? trimmed : null;
808
- }
809
- function hasFinalResult(value) {
810
- if (value === void 0 || value === null) return false;
811
- if (typeof value === "string") return value.trim().length > 0;
812
- if (typeof value === "boolean") return value;
813
- if (Array.isArray(value)) return value.length > 0;
814
- if (typeof value === "object") return Object.keys(value).length > 0;
815
- return true;
816
- }
817
- function committedHeadFromAncestry(ancestry) {
818
- if (!ancestry?.checked) return null;
819
- if (ancestry.headIsAncestorOfBase !== false) return null;
820
- return trimOrNull(ancestry.head);
821
- }
822
- function buildAttentionReason(kind, uncommittedCount, headCommit) {
823
- const parts = ["exited_with_changes_salvage"];
824
- if (kind === "uncommitted" || kind === "both") {
825
- parts.push(
826
- `${uncommittedCount} uncommitted change${uncommittedCount === 1 ? "" : "s"} with no final result`
827
- );
828
- }
829
- if ((kind === "committed_ahead" || kind === "both") && headCommit) {
830
- const sha = headCommit.length > 12 ? headCommit.slice(0, 12) : headCommit;
831
- parts.push(`commit ${sha} ahead of base with no final result`);
832
- }
833
- parts.push("review worktree \u2014 commit, open a PR, or run a salvage worker before discarding");
834
- return parts.join(": ");
835
- }
836
- function assessExitedWorkerSalvage(input) {
837
- if (input.alive || hasFinalResult(input.finalResult)) return null;
838
- const uncommittedCount = (input.changedFiles ?? []).filter((line) => line.trim()).length;
839
- const headCommit = trimOrNull(input.headCommit) ?? committedHeadFromAncestry(input.gitAncestry);
840
- const hasUncommitted = uncommittedCount > 0;
841
- const hasCommittedAhead = Boolean(headCommit);
842
- if (!hasUncommitted && !hasCommittedAhead) {
843
- return {
844
- kind: "none",
845
- salvageable: false,
846
- uncommittedCount: 0,
847
- headCommit: null,
848
- attentionReason: "process exited without a final result"
849
- };
850
- }
851
- const kind = hasUncommitted && hasCommittedAhead ? "both" : hasUncommitted ? "uncommitted" : "committed_ahead";
852
- return {
853
- kind,
854
- salvageable: true,
855
- uncommittedCount,
856
- headCommit,
857
- attentionReason: buildAttentionReason(kind, uncommittedCount, headCommit)
858
- };
859
- }
860
- var init_exited_salvage = __esm({
861
- "src/exited-salvage.ts"() {
862
- "use strict";
863
- }
864
- });
865
-
866
- // src/worker-env.ts
867
- var FORBIDDEN_WORKER_ENV_KEYS, FORBIDDEN_KEY_SET;
868
- var init_worker_env = __esm({
869
- "src/worker-env.ts"() {
870
- "use strict";
871
- FORBIDDEN_WORKER_ENV_KEYS = [
872
- "ANTHROPIC_API_KEY",
873
- "ANALYST_API_KEY",
874
- "RECRUITER_API_KEY",
875
- "AUTH_SECRET",
876
- "NEXTAUTH_SECRET",
877
- "DATABASE_URL",
878
- "PRODUCTION_DATABASE_URL",
879
- "KYNVER_PRODUCTION_DATABASE_URL",
880
- "REDIS_URL",
881
- "GOOGLE_CLIENT_SECRET",
882
- "GITHUB_CLIENT_SECRET",
883
- "KYNVER_API_KEY",
884
- "KYNVER_SERVICE_SECRET",
885
- "KYNVER_RUNTIME_SECRET",
886
- "KYNVER_CRON_SECRET",
887
- "OPENCLAW_CRON_SECRET",
888
- "QSTASH_TOKEN",
889
- "QSTASH_CURRENT_SIGNING_KEY",
890
- "QSTASH_NEXT_SIGNING_KEY",
891
- "TOOL_SECRETS_KEK",
892
- "TOOL_EXECUTOR_DISPATCH_SECRET",
893
- "CLOUDFLARE_API_TOKEN",
894
- "STRIPE_SECRET_KEY",
895
- "STRIPE_WEBHOOK_SECRET",
896
- "STRIPE_IDENTITY_WEBHOOK_SECRET",
897
- "VOYAGE_API_KEY",
898
- "PERPLEXITY_API_KEY",
899
- "FRED_API_KEY",
900
- "FMP_API_KEY",
901
- "CURSOR_API_KEY"
902
- ];
903
- FORBIDDEN_KEY_SET = new Set(FORBIDDEN_WORKER_ENV_KEYS);
904
- }
905
- });
906
-
907
- // src/git.ts
908
- import { spawnSync } from "node:child_process";
909
- function git(cwd, args, options = {}) {
910
- const res = spawnSync(
911
- "git",
912
- args,
913
- hiddenSpawnOptions({ cwd, encoding: "utf8" })
914
- );
915
- if (res.status !== 0 && !options.allowFailure) {
916
- const message = `git ${args.join(" ")} failed: ${res.stderr || res.stdout}`;
917
- if (options.throwError) throw new Error(message);
918
- fail(message);
919
- }
920
- return res.stdout || "";
921
- }
922
- function gitStatusShort(worktreePath) {
923
- return git(worktreePath, ["status", "--short"], { allowFailure: true }).split("\n").map((line) => line.trim()).filter(Boolean);
924
- }
925
- function gitCapture(cwd, args) {
926
- try {
927
- const res = spawnSync(
928
- "git",
929
- args,
930
- hiddenSpawnOptions({ cwd, encoding: "utf8" })
931
- );
932
- return {
933
- status: res.status,
934
- stdout: res.stdout || "",
935
- stderr: res.stderr || "",
936
- error: res.error ? res.error.message : null
937
- };
938
- } catch (error) {
939
- return {
940
- status: null,
941
- stdout: "",
942
- stderr: "",
943
- error: error.message
944
- };
945
- }
946
- }
947
- function gitIsAncestor(cwd, ancestor, descendant) {
948
- const res = gitCapture(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]);
949
- if (res.status === 0) return { isAncestor: true, error: null };
950
- if (res.status === 1) return { isAncestor: false, error: null };
951
- return { isAncestor: null, error: res.error || res.stderr || res.stdout || `git exited ${res.status}` };
952
- }
953
- function computeGitAncestry(worktreePath, baseOrOptions = "origin/main") {
954
- const options = typeof baseOrOptions === "string" ? { base: baseOrOptions } : baseOrOptions;
955
- const baseLabel = options.baseCommit?.trim() || options.base?.trim() || "origin/main";
956
- const pinnedBaseCommit = options.baseCommit?.trim() || null;
957
- if (!worktreePath) {
958
- return unknownAncestry(baseLabel, "missing worktree path");
959
- }
960
- const head = gitCapture(worktreePath, ["rev-parse", "HEAD"]);
961
- if (head.status !== 0) {
962
- return unknownAncestry(baseLabel, head.error || head.stderr || head.stdout || "failed to resolve HEAD");
963
- }
964
- let baseSha;
965
- if (pinnedBaseCommit) {
966
- baseSha = pinnedBaseCommit;
967
- } else {
968
- const baseHead = gitCapture(worktreePath, ["rev-parse", baseLabel]);
969
- if (baseHead.status !== 0) {
970
- return unknownAncestry(
971
- baseLabel,
972
- baseHead.error || baseHead.stderr || baseHead.stdout || `failed to resolve ${baseLabel}`,
973
- head.stdout.trim()
974
- );
975
- }
976
- baseSha = baseHead.stdout.trim();
977
- }
978
- const headSha = head.stdout.trim();
979
- if (headSha === baseSha) {
980
- return {
981
- checked: true,
982
- base: baseLabel,
983
- head: headSha,
984
- baseHead: baseSha,
985
- baseIsAncestorOfHead: true,
986
- headIsAncestorOfBase: true,
987
- relation: "synced"
988
- };
989
- }
990
- const baseIsAncestorOfHead = gitIsAncestor(worktreePath, baseSha, headSha);
991
- const headIsAncestorOfBase = gitIsAncestor(worktreePath, headSha, baseSha);
992
- const error = baseIsAncestorOfHead.error || headIsAncestorOfBase.error || void 0;
993
- if (baseIsAncestorOfHead.isAncestor == null || headIsAncestorOfBase.isAncestor == null) {
994
- return {
995
- checked: false,
996
- base: baseLabel,
997
- head: headSha,
998
- baseHead: baseSha,
999
- baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
1000
- headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
1001
- relation: "unknown",
1002
- ...error ? { error } : {}
1003
- };
1004
- }
1005
- const relation = baseIsAncestorOfHead.isAncestor ? "ahead" : headIsAncestorOfBase.isAncestor ? "merged" : "diverged";
1006
- return {
1007
- checked: true,
1008
- base: baseLabel,
1009
- head: headSha,
1010
- baseHead: baseSha,
1011
- baseIsAncestorOfHead: baseIsAncestorOfHead.isAncestor,
1012
- headIsAncestorOfBase: headIsAncestorOfBase.isAncestor,
1013
- relation,
1014
- ...error ? { error } : {}
1015
- };
1016
- }
1017
- function unknownAncestry(base, error, head = null) {
1018
- return {
1019
- checked: false,
1020
- base,
1021
- head,
1022
- baseHead: null,
1023
- baseIsAncestorOfHead: null,
1024
- headIsAncestorOfBase: null,
1025
- relation: "unknown",
1026
- error
1027
- };
1028
- }
1029
- var init_git = __esm({
1030
- "src/git.ts"() {
1031
- "use strict";
1032
- init_util();
1033
- init_worker_env();
1034
- }
1035
- });
1036
-
1037
- // src/landing-gate.ts
1038
- function trimOrNull2(value) {
1039
- if (typeof value !== "string") return null;
1040
- const trimmed = value.trim();
1041
- return trimmed.length ? trimmed : null;
1042
- }
1043
- function hasFinalResult2(value) {
1044
- if (value === void 0 || value === null) return false;
1045
- if (typeof value === "string") return value.trim().length > 0;
1046
- if (typeof value === "boolean") return value;
1047
- if (Array.isArray(value)) return value.length > 0;
1048
- if (typeof value === "object") return Object.keys(value).length > 0;
1049
- return true;
1050
- }
1051
- function hasCommittedLandingRef(snapshot) {
1052
- if (trimOrNull2(snapshot.headCommit)) return true;
1053
- if (trimOrNull2(snapshot.prUrl)) return true;
1054
- if (trimOrNull2(snapshot.artifactBundlePath)) return true;
1055
- if (trimOrNull2(snapshot.patchPath)) return true;
1056
- const ancestry = snapshot.gitAncestry;
1057
- if (ancestry?.checked && ancestry.headIsAncestorOfBase === false && trimOrNull2(ancestry.head)) {
1058
- return true;
1059
- }
1060
- return false;
1061
- }
1062
- function assessWorkerLanding(snapshot) {
1063
- if (!hasFinalResult2(snapshot.finalResult)) return { blocked: false };
1064
- if (snapshot.changedFiles.length === 0) return { blocked: false };
1065
- if (!hasCommittedLandingRef(snapshot)) {
1066
- return {
1067
- blocked: true,
1068
- reason: "dirty_worktree_no_pr",
1069
- detail: `Worktree has ${snapshot.changedFiles.length} uncommitted change(s) with no commit or PR; commit, open a PR, or discard before landing`
1070
- };
1071
- }
1072
- return {
1073
- blocked: true,
1074
- detail: `Worktree has ${snapshot.changedFiles.length} uncommitted change(s); commit or discard before landing`
1075
- };
1076
- }
1077
- function landingAttentionReason(verdict) {
1078
- if (!verdict.blocked) return void 0;
1079
- return verdict.detail ?? verdict.reason ?? "dirty_worktree_no_pr";
1080
- }
1081
- var init_landing_gate = __esm({
1082
- "src/landing-gate.ts"() {
1083
- "use strict";
1084
- }
1085
- });
1086
-
1087
- // src/worker-final-result-embed.ts
1088
- function tryParseJsonObject2(text) {
1089
- const trimmed = text.trim();
1090
- if (!trimmed.startsWith("{")) return null;
1091
- try {
1092
- const parsed = JSON.parse(trimmed);
1093
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1094
- return parsed;
1095
- }
1096
- } catch {
1097
- return null;
1098
- }
1099
- return null;
1100
- }
1101
- function reconciliationEntryCount(record) {
1102
- const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation ?? record.targetPrs ?? record.target_prs;
1103
- return Array.isArray(raw) ? raw.length : 0;
1104
- }
1105
- function extractEmbeddedWorkerFinalResultRecord(value) {
1106
- const trimmed = value.trim();
1107
- if (!trimmed) return null;
1108
- const direct = tryParseJsonObject2(trimmed);
1109
- if (direct) return direct;
1110
- const candidates = [];
1111
- const fenceRe = /```(?:json)?\s*([\s\S]*?)```/gi;
1112
- let fenceMatch;
1113
- while ((fenceMatch = fenceRe.exec(trimmed)) !== null) {
1114
- const fromFence = tryParseJsonObject2(fenceMatch[1] ?? "");
1115
- if (fromFence) candidates.push(fromFence);
1116
- }
1117
- const firstBrace = trimmed.indexOf("{");
1118
- const lastBrace = trimmed.lastIndexOf("}");
1119
- if (firstBrace >= 0 && lastBrace > firstBrace) {
1120
- const slice = tryParseJsonObject2(trimmed.slice(firstBrace, lastBrace + 1));
1121
- if (slice) candidates.push(slice);
1122
- }
1123
- if (candidates.length === 0) return null;
1124
- let best = candidates[candidates.length - 1];
1125
- let bestScore = reconciliationEntryCount(best);
1126
- for (const candidate of candidates) {
1127
- const score = reconciliationEntryCount(candidate);
1128
- if (score > bestScore) {
1129
- best = candidate;
1130
- bestScore = score;
1131
- }
1132
- }
1133
- return best;
1134
- }
1135
- var init_worker_final_result_embed = __esm({
1136
- "src/worker-final-result-embed.ts"() {
1137
- "use strict";
1138
- }
1139
- });
1140
-
1141
- // src/landing-contract-gate.ts
1142
- function trimOrNull3(value) {
1143
- if (typeof value !== "string") return null;
1144
- const t = value.trim();
1145
- return t.length ? t : null;
1146
- }
1147
- function hasFinalResult3(value) {
1148
- if (value === void 0 || value === null) return false;
1149
- if (typeof value === "string") return value.trim().length > 0;
1150
- if (typeof value === "object") return Object.keys(value).length > 0;
1151
- return true;
1152
- }
1153
- function normalizePrUrl(url) {
1154
- const m = url.trim().match(/github\.com\/([^/]+\/[^/]+)\/(?:pull|pulls)\/(\d+)/i);
1155
- if (!m) return trimOrNull3(url);
1156
- return `https://github.com/${m[1]}/pull/${m[2]}`;
1157
- }
1158
- function prUrlSetKey(url) {
1159
- const m = url.trim().match(/github\.com\/([^/]+\/[^/]+)\/(?:pull|pulls)\/(\d+)/i);
1160
- if (!m) return url.trim().toLowerCase();
1161
- return `${m[1].toLowerCase()}/pull/${m[2]}`;
1162
- }
1163
- function parseReconciliation(finalResult) {
1164
- let record = null;
1165
- if (typeof finalResult === "string") {
1166
- const embedded = extractEmbeddedWorkerFinalResultRecord(finalResult);
1167
- if (embedded) record = embedded;
1168
- } else if (finalResult && typeof finalResult === "object" && !Array.isArray(finalResult)) {
1169
- record = finalResult;
1170
- }
1171
- if (!record) return [];
1172
- const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation;
1173
- if (!Array.isArray(raw)) return [];
1174
- const out = [];
1175
- for (const item of raw) {
1176
- if (!item || typeof item !== "object" || Array.isArray(item)) continue;
1177
- const row = item;
1178
- const prUrl = normalizePrUrl(String(row.prUrl ?? row.pr_url ?? ""));
1179
- const outcome = trimOrNull3(row.outcome);
1180
- if (!prUrl || outcome !== "merged" && outcome !== "skipped" && outcome !== "blocked") continue;
1181
- out.push({
1182
- prUrl,
1183
- outcome,
1184
- mergeCommit: trimOrNull3(row.mergeCommit ?? row.merge_commit),
1185
- reason: trimOrNull3(row.reason)
1186
- });
1187
- }
1188
- return out;
1189
- }
1190
- function workerAttachedPrUrls(snapshot, finalResult) {
1191
- const urls = [];
1192
- const fromSnapshot = normalizePrUrl(trimOrNull3(snapshot.prUrl) ?? "");
1193
- if (fromSnapshot) urls.push(fromSnapshot);
1194
- if (finalResult && typeof finalResult === "object" && !Array.isArray(finalResult)) {
1195
- const record = finalResult;
1196
- const pr = normalizePrUrl(String(record.prUrl ?? record.pr_url ?? ""));
1197
- if (pr) urls.push(pr);
1198
- }
1199
- return [...new Set(urls)];
1200
- }
1201
- function assessWorkerLandingContract(input) {
1202
- const { contract, snapshot } = input;
1203
- const finalResult = input.finalResult ?? snapshot.finalResult;
1204
- if (!contract.landingOnly && contract.targetPrUrls.length === 0 && !contract.repairEnforceOriginalPr) {
1205
- return { blocked: false };
1206
- }
1207
- if (!hasFinalResult3(finalResult)) {
1208
- const requiresEarly = contract.requiresTargetPrReconciliation ?? (contract.landingOnly || Boolean(contract.repairEnforceOriginalPr) || contract.targetPrUrls.length > 0);
1209
- if (requiresEarly && contract.targetPrUrls.length > 0) {
1210
- return {
1211
- blocked: true,
1212
- reason: "missing_target_pr_reconciliation",
1213
- detail: `Final result required to reconcile target PR(s): ${contract.targetPrUrls.join(", ")}`
1214
- };
1215
- }
1216
- return { blocked: false };
1217
- }
1218
- const requiresTargetPrReconciliation = contract.requiresTargetPrReconciliation ?? (contract.landingOnly || Boolean(contract.repairEnforceOriginalPr) || contract.targetPrUrls.length > 0);
1219
- if (!requiresTargetPrReconciliation && !contract.repairEnforceOriginalPr) {
1220
- return { blocked: false };
1221
- }
1222
- const repairTarget = contract.repairEnforceOriginalPr ? normalizePrUrl(trimOrNull3(contract.targetPrUrl) ?? "") ?? (contract.targetPrUrls.length === 1 ? normalizePrUrl(contract.targetPrUrls[0]) : null) : null;
1223
- if (repairTarget) {
1224
- const workerPrs = workerAttachedPrUrls(snapshot, finalResult);
1225
- const supersedes = finalResult && typeof finalResult === "object" && !Array.isArray(finalResult) && finalResult.supersedesOriginalTargetPr === true;
1226
- if (!supersedes) {
1227
- for (const pr of workerPrs) {
1228
- if (pr !== repairTarget) {
1229
- return {
1230
- blocked: true,
1231
- reason: "duplicate_repair_pr",
1232
- detail: `Repair worker opened or attached PR ${pr} instead of canonical target ${repairTarget}`
1233
- };
1234
- }
1235
- }
1236
- }
1237
- const reconciliation2 = parseReconciliation(finalResult);
1238
- const entry = reconciliation2.find((r) => r.prUrl === repairTarget);
1239
- if (!entry || entry.outcome !== "merged" && !(entry.reason?.trim() && (entry.outcome === "skipped" || entry.outcome === "blocked"))) {
1240
- return {
1241
- blocked: true,
1242
- reason: "missing_repair_target_reconciliation",
1243
- detail: `Repair worker must reconcile target PR ${repairTarget}`
1244
- };
1245
- }
1246
- }
1247
- const reconciliation = parseReconciliation(finalResult);
1248
- const byUrl = new Map(
1249
- reconciliation.map((r) => [prUrlSetKey(r.prUrl), r])
1250
- );
1251
- const targetSet = new Set(
1252
- contract.targetPrUrls.map((u) => prUrlSetKey(normalizePrUrl(u) ?? u)).filter(Boolean)
1253
- );
1254
- const attachedPrs = workerAttachedPrUrls(snapshot, finalResult);
1255
- if (contract.landingOnly) {
1256
- for (const pr of attachedPrs) {
1257
- if (targetSet.size > 0 && !targetSet.has(prUrlSetKey(pr))) {
1258
- return {
1259
- blocked: true,
1260
- reason: "unrelated_implementation_pr",
1261
- detail: `Landing-only worker attached unrelated PR ${pr}`
1262
- };
1263
- }
1264
- if (targetSet.size === 0) {
1265
- return {
1266
- blocked: true,
1267
- reason: "unrelated_implementation_pr",
1268
- detail: "Landing-only worker must not open new implementation PRs"
1269
- };
1270
- }
1271
- }
1272
- }
1273
- if (contract.targetPrUrls.length === 0) return { blocked: false };
1274
- const missing = [];
1275
- for (const target of contract.targetPrUrls) {
1276
- const key = prUrlSetKey(normalizePrUrl(target) ?? target);
1277
- const entry = byUrl.get(key);
1278
- if (!entry) {
1279
- missing.push(key);
1280
- continue;
1281
- }
1282
- if (entry.outcome !== "merged" && !entry.reason?.trim()) {
1283
- missing.push(key);
1284
- }
1285
- }
1286
- if (missing.length > 0) {
1287
- return {
1288
- blocked: true,
1289
- reason: missing.every((u) => byUrl.has(u)) ? "incomplete_target_pr_landing" : "missing_target_pr_reconciliation",
1290
- detail: `Target PR reconciliation incomplete: ${missing.join(", ")}`
1291
- };
1292
- }
1293
- return { blocked: false };
1294
- }
1295
- function landingContractAttentionReason(verdict) {
1296
- if (!verdict.blocked) return void 0;
1297
- return verdict.detail ?? verdict.reason;
1298
- }
1299
- var init_landing_contract_gate = __esm({
1300
- "src/landing-contract-gate.ts"() {
1301
- "use strict";
1302
- init_worker_final_result_embed();
1303
- }
1304
- });
1305
-
1306
- // src/status.ts
1307
- function computeAttention(input) {
1308
- const now = Date.now();
1309
- if (input.completionBlocker && !isSkippedTerminalCompletionBlocker(input.completionBlocker)) {
1310
- return { state: "blocked", reason: input.completionBlocker };
1311
- }
1312
- if (input.finalResult) {
1313
- if (input.localOnly && hasMergedTargetPrReconciliation(input.finalResult)) {
1314
- return { state: "done", reason: "local-only worker superseded by merged PR" };
1315
- }
1316
- const landingSnapshot = {
1317
- finalResult: input.finalResult,
1318
- changedFiles: input.changedFiles ?? [],
1319
- gitAncestry: input.gitAncestry ?? null,
1320
- prUrl: input.prUrl ?? null
1321
- };
1322
- const landing = assessWorkerLanding(landingSnapshot);
1323
- if (landing.blocked) {
1324
- const detail = landingAttentionReason(landing);
1325
- return {
1326
- state: "needs_attention",
1327
- reason: landing.reason ? `landing blocked (${landing.reason}): ${detail}` : `landing blocked: ${detail}`
1328
- };
1329
- }
1330
- if (input.landingContract) {
1331
- const contractVerdict = assessWorkerLandingContract({
1332
- contract: input.landingContract,
1333
- snapshot: landingSnapshot,
1334
- finalResult: input.finalResult
1335
- });
1336
- const contractDetail = landingContractAttentionReason(contractVerdict);
1337
- if (contractDetail) {
1338
- return {
1339
- state: "needs_attention",
1340
- reason: contractVerdict.reason ? `landing contract (${contractVerdict.reason}): ${contractDetail}` : `landing contract: ${contractDetail}`
1341
- };
1342
- }
1343
- }
1344
- return { state: "done", reason: "final result recorded" };
1345
- }
1346
- if (!input.alive) {
1347
- if (isAbandonedEmptyWorker(input)) {
1348
- return { state: "done", reason: "empty abandoned worker record" };
1349
- }
1350
- const classified = classifyExitFailure(input.error);
1351
- if (classified) return { state: "blocked", reason: classified.reason };
1352
- const salvage = assessExitedWorkerSalvage({
1353
- alive: false,
1354
- finalResult: null,
1355
- changedFiles: input.changedFiles,
1356
- gitAncestry: input.gitAncestry
1357
- });
1358
- if (salvage?.salvageable) {
1359
- const tail2 = input.error?.trim();
1360
- return {
1361
- state: "needs_attention",
1362
- reason: tail2 ? `${salvage.attentionReason} (${tail2})` : salvage.attentionReason
1363
- };
1364
- }
1365
- const tail = input.error?.trim();
1366
- return {
1367
- state: "needs_attention",
1368
- reason: tail ? `process exited without a final result: ${tail}` : salvage?.attentionReason ?? "process exited without a final result"
1369
- };
1370
- }
1371
- if (input.heartbeatBlocker) {
1372
- return { state: "blocked", reason: `worker heartbeat reported blocker: ${input.heartbeatBlocker}` };
1373
- }
1374
- const startMs = input.startedAt ? Date.parse(input.startedAt) : NaN;
1375
- if (!input.firstEventAt && input.stdoutBytes === 0 && input.heartbeatBytes === 0 && Number.isFinite(startMs) && now - startMs > NO_START_MS) {
1376
- return { state: "needs_attention", reason: `no first stream event ${secsAgo(startMs)}s after start` };
1377
- }
1378
- const actMs = input.lastActivityAt ? Date.parse(input.lastActivityAt) : NaN;
1379
- if (Number.isFinite(actMs) && now - actMs > STALE_MS) {
1380
- return { state: "stale", reason: `no log/event/heartbeat activity for ${secsAgo(actMs)}s` };
1381
- }
1382
- return { state: "ok", reason: "recent activity" };
1383
- }
1384
- function isSkippedTerminalCompletionBlocker(reason) {
1385
- const text = reason?.trim();
1386
- if (!text) return false;
1387
- return /completion acknowledged but board not advanced/i.test(text) && /task already terminal/i.test(text);
1388
- }
1389
- function isAbandonedEmptyWorker(input) {
1390
- if (input.finalResult) return false;
1391
- if (input.taskId || input.agentOsId) return false;
1392
- if (input.stdoutBytes > 0 || (input.stderrBytes ?? 0) > 0 || input.heartbeatBytes > 0) return false;
1393
- if (input.error?.trim()) return false;
1394
- if ((input.changedFiles ?? []).some((line) => line.trim())) return false;
1395
- return /empty worker dir|marked abandoned/i.test(input.reconcileReason ?? "");
1396
- }
1397
- function hasMergedTargetPrReconciliation(value) {
1398
- let record = null;
1399
- if (typeof value === "string") record = extractEmbeddedWorkerFinalResultRecord(value);
1400
- else if (value && typeof value === "object" && !Array.isArray(value)) record = value;
1401
- if (!record) return false;
1402
- const raw = record.targetPrReconciliation ?? record.target_pr_reconciliation;
1403
- if (!Array.isArray(raw)) return false;
1404
- return raw.some((item) => {
1405
- if (!item || typeof item !== "object" || Array.isArray(item)) return false;
1406
- return String(item.outcome ?? "").trim() === "merged";
1407
- });
1408
- }
1409
- function resolveFinalResult(worker, parsedFinalResult, heartbeat) {
1410
- const ackSnapshot = worker.completionSnapshot?.finalResult;
1411
- if (worker.completionAckSource === "local-pr-merged-reconcile" && ackSnapshot !== void 0 && ackSnapshot !== null) {
1412
- return ackSnapshot;
1413
- }
1414
- if (parsedFinalResult) return parsedFinalResult;
1415
- if (ackSnapshot !== void 0 && ackSnapshot !== null) return ackSnapshot;
1416
- return terminalFinalResultFromHeartbeat(heartbeat);
1417
- }
1418
- function computeWorkerStatus(worker, options = {}) {
1419
- const parsed = parseHarnessStream(worker.stdoutPath);
1420
- const heartbeat = parseHeartbeat(worker.heartbeatPath);
1421
- const completionAcknowledged = typeof worker.completionReportedAt === "string" && worker.completionReportedAt.trim().length > 0;
1422
- const finalResult = resolveFinalResult(worker, parsed.finalResult, heartbeat);
1423
- const alive = completionAcknowledged ? false : isPidAlive(worker.pid);
1424
- const stdoutBytes = fileSize(worker.stdoutPath);
1425
- const stderrBytes = fileSize(worker.stderrPath);
1426
- const heartbeatBytes = fileSize(worker.heartbeatPath);
1427
- const changedFiles = gitStatusShort(worker.worktreePath);
1428
- const gitAncestry = computeGitAncestry(worker.worktreePath, {
1429
- base: options.base,
1430
- baseCommit: options.baseCommit
1431
- });
1432
- const lastActivityAt = latestIso([
1433
- parsed.lastEventAt,
1434
- heartbeat.lastHeartbeatAt,
1435
- fileMtime(worker.stdoutPath),
1436
- fileMtime(worker.stderrPath),
1437
- fileMtime(worker.heartbeatPath)
1438
- ]);
1439
- const error = parsed.error || (!alive && !finalResult ? tailFile(worker.stderrPath, 10).trim() || void 0 : void 0);
1440
- const completionBlocker = typeof worker.completionBlocker === "string" && worker.completionBlocker.trim() ? worker.completionBlocker.trim() : null;
1441
- const effectiveCompletionBlocker = isSkippedTerminalCompletionBlocker(completionBlocker) ? null : completionBlocker;
1442
- const landingContract = worker.repairTargetPrUrl ? {
1443
- landingOnly: false,
1444
- targetPrUrls: [worker.repairTargetPrUrl],
1445
- targetPrUrl: worker.repairTargetPrUrl,
1446
- repairEnforceOriginalPr: true
1447
- } : null;
1448
- const attention = computeAttention({
1449
- alive,
1450
- finalResult,
1451
- firstEventAt: parsed.firstEventAt,
1452
- stdoutBytes,
1453
- stderrBytes,
1454
- heartbeatBytes,
1455
- lastActivityAt,
1456
- heartbeatBlocker: heartbeat.heartbeatBlocker,
1457
- startedAt: worker.startedAt,
1458
- error,
1459
- changedFiles,
1460
- gitAncestry,
1461
- completionBlocker: effectiveCompletionBlocker,
1462
- landingContract,
1463
- prUrl: worker.repairTargetPrUrl ?? worker.taskPrUrl ?? null,
1464
- localOnly: worker.localOnly === true,
1465
- taskId: worker.taskId ?? null,
1466
- agentOsId: worker.agentOsId ?? null,
1467
- reconcileReason: worker.reconcileReason ?? null
1468
- });
1469
- const workerStatusLabel = effectiveCompletionBlocker || attention.state === "blocked" ? "blocked" : completionAcknowledged || attention.state === "done" ? "done" : finalResult ? "exited" : alive ? "running" : "exited";
1470
- return {
1471
- runId: worker.runId,
1472
- worker: worker.name,
1473
- pid: worker.pid,
1474
- alive,
1475
- status: workerStatusLabel,
1476
- attention,
1477
- branch: worker.branch,
1478
- worktreePath: worker.worktreePath,
1479
- ownedPaths: worker.ownedPaths,
1480
- stdoutBytes,
1481
- stderrBytes,
1482
- heartbeatBytes,
1483
- firstEventAt: parsed.firstEventAt,
1484
- lastEventAt: parsed.lastEventAt,
1485
- lastActivityAt,
1486
- currentTool: completionAcknowledged ? null : parsed.currentTool,
1487
- heartbeatCount: heartbeat.heartbeatCount,
1488
- lastHeartbeatAt: heartbeat.lastHeartbeatAt,
1489
- lastHeartbeatPhase: heartbeat.lastHeartbeatPhase,
1490
- lastHeartbeatSummary: heartbeat.lastHeartbeatSummary,
1491
- heartbeatBlocker: heartbeat.heartbeatBlocker,
1492
- timestampAnomalies: heartbeat.timestampAnomalies,
1493
- finalResult,
1494
- error,
1495
- changedFiles,
1496
- gitAncestry,
1497
- instructionPolicyFingerprint: worker.instructionPolicyFingerprint ?? null,
1498
- instructionPolicyEvidence: worker.instructionPolicyEvidence ?? null,
1499
- model: worker.model ?? worker.orchestrationAudit?.model ?? null,
1500
- provider: worker.orchestrationAudit?.provider ?? null,
1501
- boxKind: worker.boxKind ?? null,
1502
- boxId: worker.boxId ?? null,
1503
- runtimeId: worker.runtimeId ?? null,
1504
- personaSlug: worker.personaSlug ?? null,
1505
- dispatched: worker.dispatched ?? null,
1506
- localOnly: worker.localOnly ?? null
1507
- };
1508
- }
1509
- function isFinishedWorkerStatus(status) {
1510
- if (status.finalResult) return true;
1511
- if (status.alive === false) return true;
1512
- if (status.status === "exited" || status.status === "done") return true;
1513
- return false;
1514
- }
1515
- function isLandingBlockedWorkerStatus(status) {
1516
- if (!status.finalResult) return false;
1517
- return status.attention.state === "needs_attention" || status.attention.state === "blocked";
1518
- }
1519
- var NO_START_MS, STALE_MS;
1520
- var init_status = __esm({
1521
- "src/status.ts"() {
1522
- "use strict";
1523
- init_heartbeat();
1524
- init_stream();
1525
- init_exit_classify();
1526
- init_exited_salvage();
1527
- init_git();
1528
- init_landing_gate();
1529
- init_landing_contract_gate();
1530
- init_worker_final_result_embed();
1531
- init_util();
1532
- NO_START_MS = 18e4;
1533
- STALE_MS = 6e5;
1534
- }
1535
- });
1536
-
1537
- // src/path-values.ts
1538
- var init_path_values = __esm({
1539
- "src/path-values.ts"() {
1540
- "use strict";
1541
- }
1542
- });
1543
-
1544
- // src/default-repo-discovery.ts
1545
- var init_default_repo_discovery = __esm({
1546
- "src/default-repo-discovery.ts"() {
1547
- "use strict";
1548
- init_git();
1549
- init_path_values();
1550
- }
1551
- });
1552
-
1553
- // src/box-identity.ts
1554
- var init_box_identity = __esm({
1555
- "src/box-identity.ts"() {
1556
- "use strict";
1557
- }
1558
- });
1559
-
1560
- // src/bounded-build/meminfo.ts
1561
- var init_meminfo = __esm({
1562
- "src/bounded-build/meminfo.ts"() {
1563
- "use strict";
1564
- }
1565
- });
1566
-
1567
- // src/wsl-host.ts
1568
- var DEFAULT_WSL_HOST_WARN_FREE_BYTES, DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES;
1569
- var init_wsl_host = __esm({
1570
- "src/wsl-host.ts"() {
1571
- "use strict";
1572
- DEFAULT_WSL_HOST_WARN_FREE_BYTES = 25 * 1024 * 1024 * 1024;
1573
- DEFAULT_WSL_HOST_CRITICAL_FREE_BYTES = 12 * 1024 * 1024 * 1024;
1574
- }
1575
- });
1576
-
1577
- // src/disk-gate.ts
1578
- var DEFAULT_WARN_FREE_BYTES, DEFAULT_CRITICAL_FREE_BYTES;
1579
- var init_disk_gate = __esm({
1580
- "src/disk-gate.ts"() {
1581
- "use strict";
1582
- init_wsl_host();
1583
- DEFAULT_WARN_FREE_BYTES = 30 * 1024 * 1024 * 1024;
1584
- DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
1585
- }
1586
- });
1587
-
1588
- // src/run-worker-index.ts
1589
- var init_run_worker_index = __esm({
1590
- "src/run-worker-index.ts"() {
1591
- "use strict";
1592
- init_run_store();
1593
- init_util();
1594
- }
1595
- });
1596
-
1597
- // src/harness-worker-active.ts
1598
- var init_harness_worker_active = __esm({
1599
- "src/harness-worker-active.ts"() {
1600
- "use strict";
1601
- init_status();
1602
- }
1603
- });
1604
-
1605
- // src/resource-gate.ts
1606
- var DEFAULT_PER_WORKER_MEM_BYTES, DEFAULT_MEM_RESERVE_BYTES;
1607
- var init_resource_gate = __esm({
1608
- "src/resource-gate.ts"() {
1609
- "use strict";
1610
- init_meminfo();
1611
- init_config();
1612
- init_box_identity();
1613
- init_worker_cap_source();
1614
- init_disk_gate();
1615
- init_run_store();
1616
- init_run_worker_index();
1617
- init_harness_worker_active();
1618
- init_util();
1619
- DEFAULT_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;
1620
- DEFAULT_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;
1621
- }
1622
- });
1623
-
1624
- // src/worker-cap-source.ts
1625
- var init_worker_cap_source = __esm({
1626
- "src/worker-cap-source.ts"() {
1627
- "use strict";
1628
- init_resource_gate();
1629
- }
1630
- });
1631
-
1632
- // src/config.ts
1633
- import { homedir, totalmem } from "node:os";
1634
- import path from "node:path";
1635
- var CONFIG_DIR, CONFIG_FILE, CREDENTIALS_FILE, SETUP_PER_WORKER_MEM_BYTES, SETUP_MEM_RESERVE_BYTES;
1636
- var init_config = __esm({
1637
- "src/config.ts"() {
1638
- "use strict";
1639
- init_default_repo_discovery();
1640
- init_path_values();
1641
- init_util();
1642
- init_box_identity();
1643
- init_worker_cap_source();
1644
- init_disk_gate();
1645
- CONFIG_DIR = path.join(homedir(), ".kynver");
1646
- CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
1647
- CREDENTIALS_FILE = path.join(CONFIG_DIR, "credentials");
1648
- SETUP_PER_WORKER_MEM_BYTES = 500 * 1024 * 1024;
1649
- SETUP_MEM_RESERVE_BYTES = 4 * 1024 * 1024 * 1024;
1650
- }
1651
- });
1652
-
1653
- // src/paths.ts
1654
- import { homedir as homedir2 } from "node:os";
1655
- import path2 from "node:path";
1656
- var LEGACY_ROOT;
1657
- var init_paths = __esm({
1658
- "src/paths.ts"() {
1659
- "use strict";
1660
- init_config();
1661
- init_path_values();
1662
- init_util();
1663
- LEGACY_ROOT = path2.join(homedir2(), ".openclaw", "harness");
1664
- }
1665
- });
1666
-
1667
- // src/run-store.ts
1668
- var init_run_store = __esm({
1669
- "src/run-store.ts"() {
1670
- "use strict";
1671
- init_paths();
1672
- init_util();
1673
- }
1674
- });
1675
-
1676
- // src/server/monitor.ts
1677
- init_status();
1678
-
1679
- // src/harness-lease-owner.ts
1680
- var HARNESS_LEASE_PREFIX = "kynver-harness:";
1681
- var RUNNER_MARKER = "@runner:";
1682
- function trimOrNull4(value) {
1683
- if (!value?.trim()) return null;
1684
- return value.trim();
1685
- }
1686
- function parseHarnessLeaseRunId(leaseOwner) {
1687
- const owner = trimOrNull4(leaseOwner);
1688
- if (!owner?.startsWith(HARNESS_LEASE_PREFIX)) return null;
1689
- const body = owner.slice(HARNESS_LEASE_PREFIX.length);
1690
- const atRunner = body.indexOf(RUNNER_MARKER);
1691
- if (atRunner >= 0) return body.slice(0, atRunner).trim() || null;
1692
- return body.trim() || null;
1693
- }
1694
- function harnessLeaseOwnerMatchesRun(leaseOwner, runId) {
1695
- const expectedRun = trimOrNull4(runId);
1696
- if (!expectedRun) return false;
1697
- return parseHarnessLeaseRunId(leaseOwner) === expectedRun;
1698
- }
1699
-
1700
- // src/monitor/monitor.classify.ts
1701
- init_status();
1702
- init_util();
1703
- function classifyWorkerHealth(input) {
1704
- const { worker, status, taskLease } = input;
1705
- const leaseOwner = taskLease?.leaseOwner ?? null;
1706
- if (worker.dispatched && taskLease) {
1707
- if (taskLease.status === "running" && leaseOwner && !harnessLeaseOwnerMatchesRun(leaseOwner, worker.runId)) {
1708
- return {
1709
- health: "orphaned",
1710
- reason: `task lease held by ${leaseOwner}, expected harness run ${worker.runId}`
1711
- };
1712
- }
1713
- if (taskLease.status === "running" && !status.alive && !status.finalResult) {
1714
- return {
1715
- health: "orphaned",
1716
- reason: "board task running but worker process is not alive"
1717
- };
1718
- }
1719
- }
1720
- if (worker.status === "running" && !status.alive && !status.finalResult) {
1721
- return {
1722
- health: "orphaned",
1723
- reason: "worker.json still running but process is dead"
1724
- };
1725
- }
1726
- if (status.attention.state === "stale") {
1727
- return { health: "stale", reason: status.attention.reason };
1728
- }
1729
- const hbMs = status.lastHeartbeatAt ? Date.parse(status.lastHeartbeatAt) : NaN;
1730
- if (status.alive && Number.isFinite(hbMs) && Date.now() - hbMs > STALE_MS) {
1731
- return {
1732
- health: "stale",
1733
- reason: `heartbeat older than ${Math.floor(STALE_MS / 1e3)}s`
1734
- };
1735
- }
1736
- if (status.alive && worker.pid && !isPidAlive(worker.pid)) {
1737
- return { health: "orphaned", reason: "pid recorded but process is not alive" };
1738
- }
1739
- if (taskLease?.status === "running" && !status.alive && status.finalResult) {
1740
- return {
1741
- health: "healthy",
1742
- reason: "finished worker awaiting completion replay"
1743
- };
1744
- }
1745
- return {
1746
- health: "healthy",
1747
- reason: status.attention.reason || "worker within expected lifecycle bounds"
1748
- };
1749
- }
1750
-
1751
- // src/completion-ack.ts
1752
- init_run_store();
1753
- function hasCompletionAck(worker) {
1754
- return Boolean(worker.completionReportedAt?.trim());
1755
- }
1756
-
1757
- // src/monitor/monitor.terminal.ts
1758
- init_status();
1759
- function assessAutoCompleteEligibility(input) {
1760
- const { worker, status } = input;
1761
- const blockers = [];
1762
- if (worker.localOnly) {
1763
- blockers.push("local-only worker (no board linkage)");
1764
- }
1765
- if (!worker.agentOsId || !worker.taskId) {
1766
- blockers.push("missing agentOsId/taskId linkage");
1767
- }
1768
- if (hasCompletionAck(worker)) {
1769
- blockers.push("completion already acknowledged");
1770
- }
1771
- if (worker.completionBlocker) {
1772
- blockers.push(worker.completionBlocker);
1773
- }
1774
- if (status.heartbeatBlocker && status.alive) {
1775
- blockers.push(`worker heartbeat blocker: ${status.heartbeatBlocker}`);
1776
- }
1777
- if (status.attention.state === "blocked") {
1778
- blockers.push(status.attention.reason || "worker attention blocked");
1779
- }
1780
- if (isLandingBlockedWorkerStatus(status)) {
1781
- blockers.push(status.attention.reason || "landing gate blocked");
1782
- }
1783
- const terminalVerified = isFinishedWorkerStatus(status);
1784
- let terminalReason;
1785
- if (terminalVerified) {
1786
- if (status.finalResult) terminalReason = "final_result";
1787
- else if (!status.alive) terminalReason = "process_exited";
1788
- else terminalReason = "terminal_status";
1789
- } else {
1790
- blockers.push("worker has not reached a terminal condition");
1791
- }
1792
- const eligible = terminalVerified && blockers.length === 0;
1793
- return {
1794
- eligible,
1795
- terminalVerified,
1796
- terminalReason,
1797
- blockers
1798
- };
1799
- }
1800
- export {
1801
- assessAutoCompleteEligibility,
1802
- classifyWorkerHealth,
1803
- computeWorkerStatus
1804
- };
1805
- //# sourceMappingURL=monitor.js.map
1
+ var c=(e,r)=>()=>(e&&(r=e(e=0)),r);function U(e){let r=e.trim();if(!r.startsWith("{"))return null;try{let t=JSON.parse(r);if(t&&typeof t=="object"&&!Array.isArray(t))return t}catch{return null}return null}function X(e){let r=e.trim();if(!r)return null;let t=U(r);if(t)return t;let n=[],o=/```(?:json)?\s*([\s\S]*?)```/gi,s;for(;(s=o.exec(r))!==null;){let l=U(s[1]??"");l&&n.push(l)}let i=r.indexOf("{"),a=r.lastIndexOf("}");if(i>=0&&a>i){let l=U(r.slice(i,a+1));l&&n.push(l)}return n.length>0?n[n.length-1]:null}function Q(e){let r=e.finalResult??e.final_result;if(r!=null)return typeof r=="string"?X(r)??(r.trim()||null):r;let t=typeof e.summary=="string"?e.summary.trim():"";if(!t)return null;let n=X(t);return n||t}var Z=c(()=>{"use strict"});import{existsSync as Qe,mkdirSync as dt,readFileSync as Ze,readdirSync as mt,statSync as ee,writeFileSync as ft}from"node:fs";function re(e){console.error(e),process.exit(1)}function I(e){return process.platform!=="win32"?e:{windowsHide:!0,...e}}function E(e){try{return JSON.parse(e)}catch{return null}}function A(e){try{return ee(e).size}catch{return 0}}function v(e){try{return ee(e).mtime.toISOString()}catch{return null}}function te(e,r){return Qe(e)?Ze(e,"utf8").split(`
2
+ `).slice(-r).join(`
3
+ `):""}function C(e){if(!e)return!1;try{return process.kill(e,0),!0}catch{return!1}}function ne(e){let r=null,t=-1/0;for(let n of e){if(!n)continue;let o=Date.parse(n);Number.isFinite(o)&&o>t&&(t=o,r=n)}return r}function K(e){return Math.max(0,Math.round((Date.now()-e)/1e3))}var p=c(()=>{"use strict"});import{existsSync as er,readFileSync as rr}from"node:fs";function oe(e){return e==="complete"}function se(e){return oe(e.lastHeartbeatPhase)?e.terminalFinalResult!==void 0&&e.terminalFinalResult!==null?e.terminalFinalResult:e.lastHeartbeatSummary?.trim()||"completed":null}function ie(e){let r={heartbeatCount:0,lastHeartbeatAt:null,lastHeartbeatPhase:null,lastHeartbeatSummary:null,terminalFinalResult:null,heartbeatBlocker:null,timestampAnomalies:[],lastBoxResourceSnapshot:null,lastPrEvidence:[]};if(!er(e))return r;let t=Date.now()+tr,n=new Date(t).toISOString(),o=rr(e,"utf8").split(`
4
+ `).filter(Boolean);for(let s of o){let i=E(s);if(!i||typeof i!="object"||Array.isArray(i))continue;let a=i;if(r.heartbeatCount++,a.ts){let l=String(a.ts),m=Date.parse(l);Number.isFinite(m)&&m>t?r.timestampAnomalies.push({kind:"future_heartbeat_timestamp",observedAt:l,clampedTo:n}):r.lastHeartbeatAt=l}a.phase!==void 0&&a.phase!==null&&(r.lastHeartbeatPhase=String(a.phase)),a.summary!==void 0&&a.summary!==null&&(r.lastHeartbeatSummary=String(a.summary)),oe(r.lastHeartbeatPhase)&&(r.terminalFinalResult=Q(a)),r.heartbeatBlocker=a.blocker?String(a.blocker):null,a.boxResourceSnapshot&&typeof a.boxResourceSnapshot=="object"&&!Array.isArray(a.boxResourceSnapshot)&&(r.lastBoxResourceSnapshot=a.boxResourceSnapshot),Array.isArray(a.prEvidence)&&(r.lastPrEvidence=a.prEvidence.filter(l=>!!l&&typeof l=="object"&&typeof l.prUrl=="string"))}return r}var tr,ae=c(()=>{"use strict";Z();p();tr=6e4});function sr(e){return e?(e.split("/").pop()??e).replace(/\.exe$/i,"").toLowerCase():null}function ir(e){if(!e)return[];let r=[],t="",n,o=!1;for(let s of e){if(o){t+=s,o=!1;continue}if(s==="\\"){o=!0;continue}if(n){s===n?n=void 0:t+=s;continue}if(s==='"'||s==="'"){n=s;continue}if(/\s/.test(s)){t&&(r.push(t),t="");continue}t+=s}return t&&r.push(t),r}function ar(e){let r=sr(e[0]);return!!(r&&nr.has(r))}function H(e){return!e||e.includes("/")||e.includes("*")?!1:/\.(?:json|md|mjs|cjs|js|ts|tsx|yaml|yml)$/iu.test(e)}function le(e){if(!e)return!1;let r=e.trim();return r.startsWith("!")&&!r.includes("/")&&!r.endsWith("/**")}function lr(e){if(!e.startsWith("--glob="))return e;let r=e.slice(7);return r.startsWith("!")&&!r.includes("/")&&!r.endsWith("/**")?`--glob=${r}/**`:e}function cr(e){let r=[];for(let t=1;t<e.length;t+=1){let n=e[t];if(n){if(n==="--"){r.push(...e.slice(t+1));break}if(n.startsWith("-")){if(n.includes("="))continue;or.has(n)&&(t+=1);continue}r.push(n)}}return r}function ur(e){let r=!1,t=e.map(o=>{let s=lr(o);return s!==o&&(r=!0),s}),n=cr(t);if(n.length===2){let[o,s]=n;if(H(s))return{argv:[t[0]??"rg","-g",s,o,"."],changed:!0}}return{argv:t,changed:r}}function M(e){let r=e.trim();if(!r)return{command:r,changed:!1};let t=r.includes("&&")?" && ":r.includes("||")?" || ":"; ",n=r.split(/\s*(?:&&|\|\||;)\s*/u),o=!1,s=n.map(i=>{let a=ir(i.trim());if(!a.length||!ar(a))return i;let l=ur(a);return l.changed?(o=!0,l.argv.join(" ")):i});return o?{command:s.join(t),changed:!0}:{command:r,changed:!1}}function ce(e){if(!e)return{};let r=e.match(/search\s+"(.+)"\s+in\s+([^()]+?)(?:\s*\(|$)/iu);if(r)return{pattern:r[1],target:r[2]?.trim()};let t=e.match(/^search\s+"(.+)"\s+in\s+(.+)$/iu);return t?{pattern:t[1],target:t[2]?.trim()}:{}}function dr(e){let{pattern:r,target:t}=ce(e);return r?le(t)?{kind:"rg_exclude_syntax",pattern:r,target:t}:H(t)?{kind:"bad_scope",pattern:r,target:t}:{kind:"not_repo_search",pattern:r,target:t}:{kind:"not_repo_search"}}function mr(e){let{pattern:r,target:t}=ce(e);if(!r)return null;if(le(t)){let n=`${t.trim()}/**`;return{command:`rg "${r}" -g '${n}' .`,changed:!0}}return t&&H(t)?{command:`rg -g ${t} "${r}" .`,changed:!0}:null}function fr(e){if(e.kind==="bad_scope"&&e.pattern?.includes("agent-os-land-pr")&&e.target==="package.json")return"Search package.json with a glob from the repo root: `rg -g package.json agent-os-land-pr .` \u2014 or run `node scripts/agent-os-land-pr.mjs <pr-url>` directly.";if(e.kind==="bad_scope"&&e.pattern&&e.target)return`Use \`rg -g '${e.target}' ${e.pattern} .\` from the repo root instead of treating ${e.target} as a folder.`;if(e.kind==="rg_exclude_syntax"&&e.pattern){let r=e.target?`${e.target.trim()}/**`:"!node_modules/**";return`Repo search scope \`${e.target??"!node_modules"}\` is not a valid ripgrep path. Use \`rg "${e.pattern}" -g '${r}' .\` from the repo root (exclude globs need a \`/**\` suffix).`}return e.kind==="no_matches"&&e.pattern?`No matches for "${e.pattern}". Try a broader pattern, drop overly short tokens, or search from the repo root with \`rg "${e.pattern}" .\`.`:null}function pr(e){let r=e.match(/search\s+"(.+)"\s+in\s+([^()]+?)(?:\s*\(agent\)|\s*failed|$)/iu);return r?`search "${r[1]}" in ${r[2]?.trim()}`:null}function F(e){let r=e.meta?.trim()||(e.command?pr(e.command):null)||null;if(r){let t=dr(r),n=fr(t);if(n)return n;let o=mr(r);if(o?.changed)return`Repo search used an invalid scope. Retry with: \`${o.command}\`.`}if(e.command&&/\b(rg|ripgrep)\b/i.test(e.command)){let t=M(e.command);if(t.changed)return`Ripgrep scope may be invalid. Retry with: \`${t.command}\`.`;if(e.exitCode===1)return"Ripgrep returned no matches (exit 1). Try a broader pattern or search from the repo root."}return null}var nr,or,ue=c(()=>{"use strict";nr=new Set(["rg","ripgrep","grep"]),or=new Set(["-e","--regexp","-f","--file","-m","--max-count","-A","--after-context","-B","--before-context","-C","--context","-g","--glob","--iglob"])});function R(e,r=200){let t=e.replace(/\s+/g," ").trim();return t.length>r?`${t.slice(0,r-1)}\u2026`:t}function yr(e){let r=e.trim();if(!r)return null;if(r.startsWith("{"))try{return JSON.parse(r)}catch{}let t=r.indexOf("{"),n=r.lastIndexOf("}");if(t>=0&&n>t)try{return JSON.parse(r.slice(t,n+1))}catch{return null}return null}function x(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function br(e){let r=e.metadata;if(!x(r))return null;let t=r.vulnerabilities;if(!x(t))return null;let n=s=>typeof t[s]=="number"?t[s]:0,o={info:n("info"),low:n("low"),moderate:n("moderate"),high:n("high"),critical:n("critical"),total:n("total")};return typeof t.total!="number"&&!o.critical&&!o.high&&!o.moderate&&!o.low&&!o.info?null:o}function Rr(e){let r=[];e.critical&&r.push(`${e.critical} critical`),e.high&&r.push(`${e.high} high`),e.moderate&&r.push(`${e.moderate} moderate`),e.low&&r.push(`${e.low} low`),e.info&&r.push(`${e.info} info`);let t=r.length?r.join(", "):"see report";return`npm audit: ${e.total} vulnerabilit${e.total===1?"y":"ies"} (${t}) \u2014 remediation required`}function xr(e,r){let t=e.error;if(x(t)){let s=typeof t.summary=="string"?t.summary.trim():"",i=typeof t.code=="string"?t.code.trim():"";if(s)return i?`${i}: ${s}`:s;if(i)return i}let n=typeof e.message=="string"?e.message.trim():"";if(n)return n;let o=r.trim();return o?R(o.split(`
5
+ `).find(Boolean)??o,160):"npm audit failed"}function Sr(e){let r=`${e.stdout}
6
+ ${e.stderr}`.trim(),t=yr(r);if(!t||!x(t)){let o=R(r||`exit ${e.exitCode}`,180);return{kind:"command_failure",exitCode:e.exitCode,summary:`npm audit failed (invalid or missing JSON): ${o}`,parseError:"invalid_json"}}if(x(t.error))return{kind:"command_failure",exitCode:e.exitCode,summary:`npm audit command failed: ${xr(t,e.stderr)}`};let n=br(t);return n?e.exitCode===0&&n.total===0?{kind:"success",exitCode:0,summary:"npm audit: no vulnerabilities reported",audit:n}:{kind:"audit_findings",exitCode:e.exitCode,summary:Rr(n),audit:n}:{kind:"command_failure",exitCode:e.exitCode,summary:"npm audit failed: JSON response missing vulnerability metadata",parseError:"missing_metadata"}}function _r(e){return gr.test(e)}function Er(e){return hr.test(e)}function Ar(e){let r=F({command:e.command,exitCode:e.exitCode});if(e.exitCode===0)return{kind:"success",exitCode:0,summary:"ripgrep finished (exit 0)"};if(e.exitCode===1){let n=(e.stderr||e.interleaved).trim();if(n&&kr.test(n)){let i=R(n,160);return{kind:"command_failure",exitCode:1,summary:r??`ripgrep failed (exit 1): ${i}`}}let o=M(e.command),s=o.changed&&!r?` Retry with: \`${o.command}\`.`:"";return{kind:"search_no_matches",exitCode:1,summary:r??`ripgrep: no matches (exit 1).${s} Try a broader pattern or search from the repo root.`}}let t=R(e.interleaved||e.stdout||e.stderr||`exit ${e.exitCode}`,180);return{kind:"command_failure",exitCode:e.exitCode,summary:r??`ripgrep failed (exit ${e.exitCode}): ${t}`}}function de(e){let r=e.stdout??"",t=e.stderr??"",n=e.interleavedOutput??"";if(_r(e.command)){let i=r.trim()||n.trim()||t.trim();return Sr({exitCode:e.exitCode,stdout:i,stderr:t})}if(Er(e.command))return Ar({command:e.command,exitCode:e.exitCode,stdout:r,stderr:t,interleaved:n});let o=F({command:e.command,exitCode:e.exitCode});if(o&&e.exitCode!==0)return{kind:"command_failure",exitCode:e.exitCode,summary:o};if(e.exitCode===0)return{kind:"success",exitCode:0,summary:"command succeeded (exit 0)"};let s=R(n||r||t||`exit ${e.exitCode}`,180);return{kind:"command_failure",exitCode:e.exitCode,summary:`command failed (exit ${e.exitCode}): ${s}`}}var gr,hr,kr,me=c(()=>{"use strict";ue();gr=/\bnpm\s+audit\b/i,hr=/\b(rg|ripgrep)\b/i,kr=/\b(error|invalid|unknown|panic|not found)\b/i});import{existsSync as vr,readFileSync as Cr}from"node:fs";function wr(e){let r=e.timestamp_ms;return e.timestamp||e.ts||(r?new Date(r).toISOString():void 0)}function Pr(e){if(!e)return null;for(let r of Object.keys(e))if(r.endsWith("ToolCall")){let t=r.slice(0,-8);return t.length?t:r}return null}function Or(e,r){e.finalResult=r.result||r.subtype||r.terminal_reason||"completed",r.is_error&&(e.error=String(r.result||r.api_error_status||"stream result error"))}function Wr(e){if(e.type!=="tool_call"||e.subtype!=="completed")return null;let t=(e.tool_call&&typeof e.tool_call=="object"&&!Array.isArray(e.tool_call)?e.tool_call:null)?.shellToolCall;if(!t||typeof t!="object"||Array.isArray(t))return null;let n=t,o=n.args,s=o&&typeof o=="object"&&!Array.isArray(o)&&typeof o.command=="string"?String(o.command):"",i=n.result;if(!i||typeof i!="object"||Array.isArray(i))return null;let a=i.success??i.failure;if(!a||typeof a!="object"||Array.isArray(a))return null;let l=a,m=typeof l.exitCode=="number"?l.exitCode:0;return{command:s,exitCode:m,stdout:typeof l.stdout=="string"?l.stdout:"",stderr:typeof l.stderr=="string"?l.stderr:"",interleaved:typeof l.interleavedOutput=="string"?l.interleavedOutput:""}}function Br(e,r){r.kind==="success"||r.kind==="search_no_matches"||(e.lastShellOutcome=r)}function fe(e){let r={firstEventAt:null,lastEventAt:null,currentTool:null,finalResult:null,error:null,lastShellOutcome:null};if(!vr(e))return r;let t=Cr(e,"utf8").split(`
7
+ `).filter(Boolean);for(let n of t){let o=E(n);if(!o)continue;let s=wr(o);if(s&&(r.firstEventAt||=s,r.lastEventAt=s),o.type==="stream_event"&&o.event&&typeof o.event=="object"&&o.event.type==="content_block_start"){let a=o.event.content_block;a?.type==="tool_use"&&(r.currentTool=String(a.name||"tool"))}if(o.type==="assistant"&&o.message&&typeof o.message=="object"){let a=o.message.content;if(Array.isArray(a)){let l=a.find(m=>m?.type==="tool_use");l&&(r.currentTool=String(l.name||r.currentTool))}}if(o.type==="tool_call"&&o.subtype==="started"){let a=o.tool_call&&typeof o.tool_call=="object"&&!Array.isArray(o.tool_call)?o.tool_call:void 0,l=Pr(a);l&&(r.currentTool=l)}let i=Wr(o);i&&Br(r,de({command:i.command,exitCode:i.exitCode,stdout:i.stdout,stderr:i.stderr,interleavedOutput:i.interleaved})),o.type==="result"&&Or(r,o)}return r}var pe=c(()=>{"use strict";me();p()});function Nr(e,r=240){let t=e.replace(/\s+/g," ").trim();return t.length>r?`${t.slice(0,r-1)}\u2026`:t}function ge(e){let r=(e??"").trim();if(!r)return null;for(let t of Tr)if(t.test.test(r))return{blocked:!0,reason:`${t.label}: ${Nr(r)}`};return null}var Tr,he=c(()=>{"use strict";Tr=[{test:/\b(?:invalid|unknown|unsupported|unrecognized)\b[^.\n]*\bmodel\b/i,label:"provider rejected the requested model"},{test:/\bmodel\b[^.\n]*\b(?:not\s+(?:found|supported|available|recognized|valid)|is\s+not\s+valid|does\s+not\s+exist)/i,label:"provider rejected the requested model"},{test:/\b(?:did you mean|available models|choose (?:a|one of)|supported models)\b/i,label:"provider rejected the requested model"},{test:/model preflight failed/i,label:"model/provider preflight failed"},{test:/\b(?:command not found|ENOENT|is the .*CLI on PATH|executable not found|no such file or directory)\b/i,label:"provider CLI is missing or not on PATH"},{test:/\bfailed to spawn\b/i,label:"provider failed to spawn the worker process"},{test:/\b(?:not logged in|unauthorized|authentication (?:failed|required)|invalid api key|missing api key|401)\b/i,label:"provider authentication failed"}]});function ke(e){if(typeof e!="string")return null;let r=e.trim();return r.length?r:null}function Ur(e){return e==null?!1:typeof e=="string"?e.trim().length>0:typeof e=="boolean"?e:Array.isArray(e)?e.length>0:typeof e=="object"?Object.keys(e).length>0:!0}function Ir(e){return!e?.checked||e.headIsAncestorOfBase!==!1?null:ke(e.head)}function Kr(e,r,t){let n=["exited_with_changes_salvage"];if((e==="uncommitted"||e==="both")&&n.push(`${r} uncommitted change${r===1?"":"s"} with no final result`),(e==="committed_ahead"||e==="both")&&t){let o=t.length>12?t.slice(0,12):t;n.push(`commit ${o} ahead of base with no final result`)}return n.push("review worktree \u2014 commit, open a PR, or run a salvage worker before discarding"),n.join(": ")}function ye(e){if(e.alive||Ur(e.finalResult))return null;let r=(e.changedFiles??[]).filter(i=>i.trim()).length,t=ke(e.headCommit)??Ir(e.gitAncestry),n=r>0,o=!!t;if(!n&&!o)return{kind:"none",salvageable:!1,uncommittedCount:0,headCommit:null,attentionReason:"process exited without a final result"};let s=n&&o?"both":n?"uncommitted":"committed_ahead";return{kind:s,salvageable:!0,uncommittedCount:r,headCommit:t,attentionReason:Kr(s,r,t)}}var be=c(()=>{"use strict"});var Hr,Pt,Re=c(()=>{"use strict";Hr=["ANTHROPIC_API_KEY","ANALYST_API_KEY","RECRUITER_API_KEY","AUTH_SECRET","NEXTAUTH_SECRET","DATABASE_URL","PRODUCTION_DATABASE_URL","KYNVER_PRODUCTION_DATABASE_URL","REDIS_URL","GOOGLE_CLIENT_SECRET","GITHUB_CLIENT_SECRET","KYNVER_API_KEY","KYNVER_SERVICE_SECRET","KYNVER_RUNTIME_SECRET","KYNVER_CRON_SECRET","OPENCLAW_CRON_SECRET","QSTASH_TOKEN","QSTASH_CURRENT_SIGNING_KEY","QSTASH_NEXT_SIGNING_KEY","TOOL_SECRETS_KEK","TOOL_EXECUTOR_DISPATCH_SECRET","CLOUDFLARE_API_TOKEN","STRIPE_SECRET_KEY","STRIPE_WEBHOOK_SECRET","STRIPE_IDENTITY_WEBHOOK_SECRET","VOYAGE_API_KEY","PERPLEXITY_API_KEY","FRED_API_KEY","FMP_API_KEY","CURSOR_API_KEY"],Pt=new Set(Hr)});import{spawnSync as Se}from"node:child_process";function Mr(e,r,t={}){let n=Se("git",r,I({cwd:e,encoding:"utf8"}));if(n.status!==0&&!t.allowFailure){let o=`git ${r.join(" ")} failed: ${n.stderr||n.stdout}`;if(t.throwError)throw new Error(o);re(o)}return n.stdout||""}function _e(e){return Mr(e,["status","--short"],{allowFailure:!0}).split(`
8
+ `).map(r=>r.trim()).filter(Boolean)}function w(e,r){try{let t=Se("git",r,I({cwd:e,encoding:"utf8"}));return{status:t.status,stdout:t.stdout||"",stderr:t.stderr||"",error:t.error?t.error.message:null}}catch(t){return{status:null,stdout:"",stderr:"",error:t.message}}}function xe(e,r,t){let n=w(e,["merge-base","--is-ancestor",r,t]);return n.status===0?{isAncestor:!0,error:null}:n.status===1?{isAncestor:!1,error:null}:{isAncestor:null,error:n.error||n.stderr||n.stdout||`git exited ${n.status}`}}function Ee(e,r="origin/main"){let t=typeof r=="string"?{base:r}:r,n=t.baseCommit?.trim()||t.base?.trim()||"origin/main",o=t.baseCommit?.trim()||null;if(!e)return $(n,"missing worktree path");let s=w(e,["rev-parse","HEAD"]);if(s.status!==0)return $(n,s.error||s.stderr||s.stdout||"failed to resolve HEAD");let i;if(o)i=o;else{let f=w(e,["rev-parse",n]);if(f.status!==0)return $(n,f.error||f.stderr||f.stdout||`failed to resolve ${n}`,s.stdout.trim());i=f.stdout.trim()}let a=s.stdout.trim();if(a===i)return{checked:!0,base:n,head:a,baseHead:i,baseIsAncestorOfHead:!0,headIsAncestorOfBase:!0,relation:"synced"};let l=xe(e,i,a),m=xe(e,a,i),d=l.error||m.error||void 0;if(l.isAncestor==null||m.isAncestor==null)return{checked:!1,base:n,head:a,baseHead:i,baseIsAncestorOfHead:l.isAncestor,headIsAncestorOfBase:m.isAncestor,relation:"unknown",...d?{error:d}:{}};let u=l.isAncestor?"ahead":m.isAncestor?"merged":"diverged";return{checked:!0,base:n,head:a,baseHead:i,baseIsAncestorOfHead:l.isAncestor,headIsAncestorOfBase:m.isAncestor,relation:u,...d?{error:d}:{}}}function $(e,r,t=null){return{checked:!1,base:e,head:t,baseHead:null,baseIsAncestorOfHead:null,headIsAncestorOfBase:null,relation:"unknown",error:r}}var D=c(()=>{"use strict";p();Re()});function S(e){if(typeof e!="string")return null;let r=e.trim();return r.length?r:null}function Fr(e){return e==null?!1:typeof e=="string"?e.trim().length>0:typeof e=="boolean"?e:Array.isArray(e)?e.length>0:typeof e=="object"?Object.keys(e).length>0:!0}function $r(e){if(S(e.headCommit)||S(e.prUrl)||S(e.artifactBundlePath)||S(e.patchPath))return!0;let r=e.gitAncestry;return!!(r?.checked&&r.headIsAncestorOfBase===!1&&S(r.head))}function Ae(e){return Fr(e.finalResult)?e.changedFiles.length===0?{blocked:!1}:$r(e)?{blocked:!0,detail:`Worktree has ${e.changedFiles.length} uncommitted change(s); commit or discard before landing`}:{blocked:!0,reason:"dirty_worktree_no_pr",detail:`Worktree has ${e.changedFiles.length} uncommitted change(s) with no commit or PR; commit, open a PR, or discard before landing`}:{blocked:!1}}function ve(e){if(e.blocked)return e.detail??e.reason??"dirty_worktree_no_pr"}var Ce=c(()=>{"use strict"});function L(e){let r=e.trim();if(!r.startsWith("{"))return null;try{let t=JSON.parse(r);if(t&&typeof t=="object"&&!Array.isArray(t))return t}catch{return null}return null}function we(e){let r=e.targetPrReconciliation??e.target_pr_reconciliation??e.targetPrs??e.target_prs;return Array.isArray(r)?r.length:0}function P(e){let r=e.trim();if(!r)return null;let t=L(r);if(t)return t;let n=[],o=/```(?:json)?\s*([\s\S]*?)```/gi,s;for(;(s=o.exec(r))!==null;){let d=L(s[1]??"");d&&n.push(d)}let i=r.indexOf("{"),a=r.lastIndexOf("}");if(i>=0&&a>i){let d=L(r.slice(i,a+1));d&&n.push(d)}if(n.length===0)return null;let l=n[n.length-1],m=we(l);for(let d of n){let u=we(d);u>m&&(l=d,m=u)}return l}var j=c(()=>{"use strict"});function b(e){if(typeof e!="string")return null;let r=e.trim();return r.length?r:null}function Dr(e){return e==null?!1:typeof e=="string"?e.trim().length>0:typeof e=="object"?Object.keys(e).length>0:!0}function y(e){let r=e.trim().match(/github\.com\/([^/]+\/[^/]+)\/(?:pull|pulls)\/(\d+)/i);return r?`https://github.com/${r[1]}/pull/${r[2]}`:b(e)}function O(e){let r=e.trim().match(/github\.com\/([^/]+\/[^/]+)\/(?:pull|pulls)\/(\d+)/i);return r?`${r[1].toLowerCase()}/pull/${r[2]}`:e.trim().toLowerCase()}function Pe(e){let r=null;if(typeof e=="string"){let o=P(e);o&&(r=o)}else e&&typeof e=="object"&&!Array.isArray(e)&&(r=e);if(!r)return[];let t=r.targetPrReconciliation??r.target_pr_reconciliation;if(!Array.isArray(t))return[];let n=[];for(let o of t){if(!o||typeof o!="object"||Array.isArray(o))continue;let s=o,i=y(String(s.prUrl??s.pr_url??"")),a=b(s.outcome);!i||a!=="merged"&&a!=="skipped"&&a!=="blocked"||n.push({prUrl:i,outcome:a,mergeCommit:b(s.mergeCommit??s.merge_commit),reason:b(s.reason)})}return n}function Oe(e,r){let t=[],n=y(b(e.prUrl)??"");if(n&&t.push(n),r&&typeof r=="object"&&!Array.isArray(r)){let o=r,s=y(String(o.prUrl??o.pr_url??""));s&&t.push(s)}return[...new Set(t)]}function We(e){let{contract:r,snapshot:t}=e,n=e.finalResult??t.finalResult;if(!r.landingOnly&&r.targetPrUrls.length===0&&!r.repairEnforceOriginalPr)return{blocked:!1};if(!Dr(n))return(r.requiresTargetPrReconciliation??(r.landingOnly||!!r.repairEnforceOriginalPr||r.targetPrUrls.length>0))&&r.targetPrUrls.length>0?{blocked:!0,reason:"missing_target_pr_reconciliation",detail:`Final result required to reconcile target PR(s): ${r.targetPrUrls.join(", ")}`}:{blocked:!1};if(!(r.requiresTargetPrReconciliation??(r.landingOnly||!!r.repairEnforceOriginalPr||r.targetPrUrls.length>0))&&!r.repairEnforceOriginalPr)return{blocked:!1};let s=r.repairEnforceOriginalPr?y(b(r.targetPrUrl)??"")??(r.targetPrUrls.length===1?y(r.targetPrUrls[0]):null):null;if(s){let u=Oe(t,n);if(!(n&&typeof n=="object"&&!Array.isArray(n)&&n.supersedesOriginalTargetPr===!0)){for(let k of u)if(k!==s)return{blocked:!0,reason:"duplicate_repair_pr",detail:`Repair worker opened or attached PR ${k} instead of canonical target ${s}`}}let g=Pe(n).find(k=>k.prUrl===s);if(!g||g.outcome!=="merged"&&!(g.reason?.trim()&&(g.outcome==="skipped"||g.outcome==="blocked")))return{blocked:!0,reason:"missing_repair_target_reconciliation",detail:`Repair worker must reconcile target PR ${s}`}}let i=Pe(n),a=new Map(i.map(u=>[O(u.prUrl),u])),l=new Set(r.targetPrUrls.map(u=>O(y(u)??u)).filter(Boolean)),m=Oe(t,n);if(r.landingOnly)for(let u of m){if(l.size>0&&!l.has(O(u)))return{blocked:!0,reason:"unrelated_implementation_pr",detail:`Landing-only worker attached unrelated PR ${u}`};if(l.size===0)return{blocked:!0,reason:"unrelated_implementation_pr",detail:"Landing-only worker must not open new implementation PRs"}}if(r.targetPrUrls.length===0)return{blocked:!1};let d=[];for(let u of r.targetPrUrls){let f=O(y(u)??u),h=a.get(f);if(!h){d.push(f);continue}h.outcome!=="merged"&&!h.reason?.trim()&&d.push(f)}return d.length>0?{blocked:!0,reason:d.every(u=>a.has(u))?"incomplete_target_pr_landing":"missing_target_pr_reconciliation",detail:`Target PR reconciliation incomplete: ${d.join(", ")}`}:{blocked:!1}}function Be(e){if(e.blocked)return e.detail??e.reason}var Te=c(()=>{"use strict";j()});function jr(e){let r=Date.now();if(e.completionBlocker&&!Ne(e.completionBlocker))return{state:"blocked",reason:e.completionBlocker};if(e.finalResult){if(e.localOnly&&Yr(e.finalResult))return{state:"done",reason:"local-only worker superseded by merged PR"};let o={finalResult:e.finalResult,changedFiles:e.changedFiles??[],gitAncestry:e.gitAncestry??null,prUrl:e.prUrl??null},s=Ae(o);if(s.blocked){let i=ve(s);return{state:"needs_attention",reason:s.reason?`landing blocked (${s.reason}): ${i}`:`landing blocked: ${i}`}}if(e.landingContract){let i=We({contract:e.landingContract,snapshot:o,finalResult:e.finalResult}),a=Be(i);if(a)return{state:"needs_attention",reason:i.reason?`landing contract (${i.reason}): ${a}`:`landing contract: ${a}`}}return{state:"done",reason:"final result recorded"}}if(!e.alive){if(Gr(e))return{state:"done",reason:"empty abandoned worker record"};let o=ge(e.error);if(o)return{state:"blocked",reason:o.reason};let s=ye({alive:!1,finalResult:null,changedFiles:e.changedFiles,gitAncestry:e.gitAncestry});if(s?.salvageable){let a=e.error?.trim();return{state:"needs_attention",reason:a?`${s.attentionReason} (${a})`:s.attentionReason}}let i=e.error?.trim();return{state:"needs_attention",reason:i?`process exited without a final result: ${i}`:s?.attentionReason??"process exited without a final result"}}if(e.heartbeatBlocker)return{state:"blocked",reason:`worker heartbeat reported blocker: ${e.heartbeatBlocker}`};let t=e.startedAt?Date.parse(e.startedAt):NaN;if(!e.firstEventAt&&e.stdoutBytes===0&&e.heartbeatBytes===0&&Number.isFinite(t)&&r-t>Lr)return{state:"needs_attention",reason:`no first stream event ${K(t)}s after start`};let n=e.lastActivityAt?Date.parse(e.lastActivityAt):NaN;return Number.isFinite(n)&&r-n>W?{state:"stale",reason:`no log/event/heartbeat activity for ${K(n)}s`}:{state:"ok",reason:"recent activity"}}function Ne(e){let r=e?.trim();return r?/completion acknowledged but board not advanced/i.test(r)&&/task already terminal/i.test(r):!1}function Gr(e){return e.finalResult||e.taskId||e.agentOsId||e.stdoutBytes>0||(e.stderrBytes??0)>0||e.heartbeatBytes>0||e.error?.trim()||(e.changedFiles??[]).some(r=>r.trim())?!1:/empty worker dir|marked abandoned/i.test(e.reconcileReason??"")}function Yr(e){let r=null;if(typeof e=="string"?r=P(e):e&&typeof e=="object"&&!Array.isArray(e)&&(r=e),!r)return!1;let t=r.targetPrReconciliation??r.target_pr_reconciliation;return Array.isArray(t)?t.some(n=>!n||typeof n!="object"||Array.isArray(n)?!1:String(n.outcome??"").trim()==="merged"):!1}function Vr(e,r,t){let n=e.completionSnapshot?.finalResult;return e.completionAckSource==="local-pr-merged-reconcile"&&n!==void 0&&n!==null?n:r||(n??se(t))}function Ue(e,r={}){let t=fe(e.stdoutPath),n=ie(e.heartbeatPath),o=typeof e.completionReportedAt=="string"&&e.completionReportedAt.trim().length>0,s=Vr(e,t.finalResult,n),i=o?!1:C(e.pid),a=A(e.stdoutPath),l=A(e.stderrPath),m=A(e.heartbeatPath),d=_e(e.worktreePath),u=Ee(e.worktreePath,{base:r.base,baseCommit:r.baseCommit}),f=ne([t.lastEventAt,n.lastHeartbeatAt,v(e.stdoutPath),v(e.stderrPath),v(e.heartbeatPath)]),h=t.error||!i&&!s&&te(e.stderrPath,10).trim()||void 0,g=typeof e.completionBlocker=="string"&&e.completionBlocker.trim()?e.completionBlocker.trim():null,k=Ne(g)?null:g,qe=e.repairTargetPrUrl?{landingOnly:!1,targetPrUrls:[e.repairTargetPrUrl],targetPrUrl:e.repairTargetPrUrl,repairEnforceOriginalPr:!0}:null,N=jr({alive:i,finalResult:s,firstEventAt:t.firstEventAt,stdoutBytes:a,stderrBytes:l,heartbeatBytes:m,lastActivityAt:f,heartbeatBlocker:n.heartbeatBlocker,startedAt:e.startedAt,error:h,changedFiles:d,gitAncestry:u,completionBlocker:k,landingContract:qe,prUrl:e.repairTargetPrUrl??e.taskPrUrl??null,localOnly:e.localOnly===!0,taskId:e.taskId??null,agentOsId:e.agentOsId??null,reconcileReason:e.reconcileReason??null}),Xe=k||N.state==="blocked"?"blocked":o||N.state==="done"?"done":s?"exited":i?"running":"exited";return{runId:e.runId,worker:e.name,pid:e.pid,alive:i,status:Xe,attention:N,branch:e.branch,worktreePath:e.worktreePath,ownedPaths:e.ownedPaths,stdoutBytes:a,stderrBytes:l,heartbeatBytes:m,firstEventAt:t.firstEventAt,lastEventAt:t.lastEventAt,lastActivityAt:f,currentTool:o?null:t.currentTool,heartbeatCount:n.heartbeatCount,lastHeartbeatAt:n.lastHeartbeatAt,lastHeartbeatPhase:n.lastHeartbeatPhase,lastHeartbeatSummary:n.lastHeartbeatSummary,heartbeatBlocker:n.heartbeatBlocker,timestampAnomalies:n.timestampAnomalies,finalResult:s,error:h,changedFiles:d,gitAncestry:u,instructionPolicyFingerprint:e.instructionPolicyFingerprint??null,instructionPolicyEvidence:e.instructionPolicyEvidence??null,model:e.model??e.orchestrationAudit?.model??null,provider:e.orchestrationAudit?.provider??null,boxKind:e.boxKind??null,boxId:e.boxId??null,runtimeId:e.runtimeId??null,personaSlug:e.personaSlug??null,dispatched:e.dispatched??null,localOnly:e.localOnly??null}}function Ie(e){return!!(e.finalResult||e.alive===!1||e.status==="exited"||e.status==="done")}function Ke(e){return e.finalResult?e.attention.state==="needs_attention"||e.attention.state==="blocked":!1}var Lr,W,_=c(()=>{"use strict";ae();pe();he();be();D();Ce();Te();j();p();Lr=18e4,W=6e5});var B=c(()=>{"use strict"});var $e=c(()=>{"use strict";D();B()});var G=c(()=>{"use strict"});var De=c(()=>{"use strict"});var cn,un,Le=c(()=>{"use strict";cn=25*1024*1024*1024,un=12*1024*1024*1024});var pn,gn,Y=c(()=>{"use strict";Le();pn=30*1024*1024*1024,gn=15*1024*1024*1024});var je=c(()=>{"use strict";T();p()});var Ge=c(()=>{"use strict";_()});var rt,tt,Ye=c(()=>{"use strict";De();J();G();z();Y();T();je();Ge();p();rt=500*1024*1024,tt=4*1024*1024*1024});var z=c(()=>{"use strict";Ye()});import{homedir as ot,totalmem as Zn}from"node:os";import q from"node:path";var Ve,ao,lo,co,uo,J=c(()=>{"use strict";$e();B();p();G();z();Y();Ve=q.join(ot(),".kynver"),ao=q.join(Ve,"config.json"),lo=q.join(Ve,"credentials"),co=500*1024*1024,uo=4*1024*1024*1024});import{homedir as st}from"node:os";import it from"node:path";var yo,ze=c(()=>{"use strict";J();B();p();yo=it.join(st(),".openclaw","harness")});var T=c(()=>{"use strict";ze();p()});_();var He="kynver-harness:",zr="@runner:";function Me(e){return e?.trim()?e.trim():null}function Jr(e){let r=Me(e);if(!r?.startsWith(He))return null;let t=r.slice(He.length),n=t.indexOf(zr);return n>=0?t.slice(0,n).trim()||null:t.trim()||null}function Fe(e,r){let t=Me(r);return t?Jr(e)===t:!1}_();p();function qr(e){let{worker:r,status:t,taskLease:n}=e,o=n?.leaseOwner??null;if(r.dispatched&&n){if(n.status==="running"&&o&&!Fe(o,r.runId))return{health:"orphaned",reason:`task lease held by ${o}, expected harness run ${r.runId}`};if(n.status==="running"&&!t.alive&&!t.finalResult)return{health:"orphaned",reason:"board task running but worker process is not alive"}}if(r.status==="running"&&!t.alive&&!t.finalResult)return{health:"orphaned",reason:"worker.json still running but process is dead"};if(t.attention.state==="stale")return{health:"stale",reason:t.attention.reason};let s=t.lastHeartbeatAt?Date.parse(t.lastHeartbeatAt):NaN;return t.alive&&Number.isFinite(s)&&Date.now()-s>W?{health:"stale",reason:`heartbeat older than ${Math.floor(W/1e3)}s`}:t.alive&&r.pid&&!C(r.pid)?{health:"orphaned",reason:"pid recorded but process is not alive"}:n?.status==="running"&&!t.alive&&t.finalResult?{health:"healthy",reason:"finished worker awaiting completion replay"}:{health:"healthy",reason:t.attention.reason||"worker within expected lifecycle bounds"}}T();function Je(e){return!!e.completionReportedAt?.trim()}_();function at(e){let{worker:r,status:t}=e,n=[];r.localOnly&&n.push("local-only worker (no board linkage)"),(!r.agentOsId||!r.taskId)&&n.push("missing agentOsId/taskId linkage"),Je(r)&&n.push("completion already acknowledged"),r.completionBlocker&&n.push(r.completionBlocker),t.heartbeatBlocker&&t.alive&&n.push(`worker heartbeat blocker: ${t.heartbeatBlocker}`),t.attention.state==="blocked"&&n.push(t.attention.reason||"worker attention blocked"),Ke(t)&&n.push(t.attention.reason||"landing gate blocked");let o=Ie(t),s;return o?t.finalResult?s="final_result":t.alive?s="terminal_status":s="process_exited":n.push("worker has not reached a terminal condition"),{eligible:o&&n.length===0,terminalVerified:o,terminalReason:s,blockers:n}}export{at as assessAutoCompleteEligibility,qr as classifyWorkerHealth,Ue as computeWorkerStatus};