@agentskit/harness 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/capabilities/public-surface.json +107 -84
- package/dist/cli.js +407 -73
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +211 -56
- package/dist/index.js +373 -85
- package/dist/index.js.map +1 -1
- package/docs/ADR-0003-doc-bridge-context-binding.md +10 -3
- package/docs/ADR-0031-loop-observability.md +36 -0
- package/docs/LOOP.md +7 -0
- package/docs/MODULE-BOUNDARIES.md +1 -0
- package/loop.config.example.yaml +1 -1
- package/package.json +2 -2
- package/release/manifest.json +3 -3
- package/release/notes.md +19 -0
package/dist/index.js
CHANGED
|
@@ -1234,11 +1234,34 @@ var validateCapabilityManifest = (value) => {
|
|
|
1234
1234
|
var index = (root, indexPath) => JSON.parse(readFileSync(resolve(root, indexPath), "utf8"));
|
|
1235
1235
|
var text = (entry) => [entry.id, entry.type, entry.title, entry.path, entry.description, entry.body, ...Array.isArray(entry.tags) ? entry.tags : []].filter((value) => typeof value === "string").join(" ").toLowerCase();
|
|
1236
1236
|
var sourceHash = (document) => typeof document.contentHash === "string" && document.contentHash.length > 0 ? document.contentHash : hashJson(document);
|
|
1237
|
+
var tokenSeparator = /[^\p{L}\p{N}@/_-]+/gu;
|
|
1238
|
+
var tokenize = (value) => value.toLowerCase().split(tokenSeparator).filter((token) => token.length >= 2);
|
|
1239
|
+
var containsToken = (value, token) => {
|
|
1240
|
+
if (/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}]/u.test(token)) return value.includes(token);
|
|
1241
|
+
const escaped = token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1242
|
+
return new RegExp(`(?:^|[^\\p{L}\\p{N}])${escaped}(?:s|es)?(?:[^\\p{L}\\p{N}]|$)`, "u").test(value);
|
|
1243
|
+
};
|
|
1244
|
+
var score = (value, query) => tokenize(query).reduce((total, token) => total + (containsToken(value, token) ? token.length : 0), 0);
|
|
1237
1245
|
var matches = (entry, query) => {
|
|
1238
|
-
const needle = query.query.trim()
|
|
1239
|
-
|
|
1246
|
+
const needle = query.query.trim();
|
|
1247
|
+
if (!needle) return 0;
|
|
1240
1248
|
const value = text(entry);
|
|
1241
|
-
|
|
1249
|
+
if (query.scope?.length && !query.scope.some((scope) => containsToken(value, scope.toLowerCase()))) return 0;
|
|
1250
|
+
return score(value, needle);
|
|
1251
|
+
};
|
|
1252
|
+
var ownershipEntries = (document) => {
|
|
1253
|
+
if (typeof document.lookup !== "object" || document.lookup === null || Array.isArray(document.lookup)) return [];
|
|
1254
|
+
const ownership = document.lookup.ownership;
|
|
1255
|
+
if (typeof ownership !== "object" || ownership === null || Array.isArray(ownership)) return [];
|
|
1256
|
+
return Object.entries(ownership).flatMap(([id2, value]) => {
|
|
1257
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return [];
|
|
1258
|
+
const owner = value;
|
|
1259
|
+
const path = typeof owner["agentDoc"] === "string" ? owner["agentDoc"] : owner["path"];
|
|
1260
|
+
if (!path) return [];
|
|
1261
|
+
const description = typeof owner["purpose"] === "string" ? owner["purpose"] : void 0;
|
|
1262
|
+
const body3 = [owner["purpose"], owner["group"], owner["layer"], owner["agentDoc"], owner["humanDoc"]].filter((item) => typeof item === "string").join(" ");
|
|
1263
|
+
return [{ id: typeof owner["id"] === "string" ? owner["id"] : id2, type: "ownership", path, ...description ? { description } : {}, ...body3 ? { body: body3 } : {} }];
|
|
1264
|
+
});
|
|
1242
1265
|
};
|
|
1243
1266
|
var inspectDocBridgeIndex = (root, indexPath = ".doc-bridge/index.json", now4 = Date.now()) => {
|
|
1244
1267
|
const path = resolve(root, indexPath);
|
|
@@ -1253,15 +1276,30 @@ var inspectDocBridgeIndex = (root, indexPath = ".doc-bridge/index.json", now4 =
|
|
|
1253
1276
|
return { present: true, path, contentHash: null, mtimeMs: null, ageHours: null, error: error instanceof Error ? error.message : String(error) };
|
|
1254
1277
|
}
|
|
1255
1278
|
};
|
|
1256
|
-
var createDocBridgeContextProvider = ({ root, indexPath = ".doc-bridge/index.json" }) => ({
|
|
1279
|
+
var createDocBridgeContextProvider = ({ root, indexPath = ".doc-bridge/index.json", maxAgeHours, now: now4 = Date.now }) => ({
|
|
1257
1280
|
id: "doc-bridge",
|
|
1258
|
-
version: "1.
|
|
1281
|
+
version: "1.1.0",
|
|
1259
1282
|
resolve: async (query) => {
|
|
1260
1283
|
const started = Date.now();
|
|
1284
|
+
const ageBudget = maxAgeHours ?? 0;
|
|
1285
|
+
const inspection = ageBudget > 0 ? inspectDocBridgeIndex(root, indexPath, now4()) : null;
|
|
1286
|
+
if (inspection?.error) throw new Error(`Doc Bridge index is unreadable: ${inspection.error}`);
|
|
1287
|
+
if (inspection?.ageHours !== null && inspection?.ageHours !== void 0 && inspection.ageHours > ageBudget) {
|
|
1288
|
+
throw new Error(`Doc Bridge index is ${inspection.ageHours.toFixed(1)}h old; refresh it before resolving context.`);
|
|
1289
|
+
}
|
|
1261
1290
|
const document = index(root, indexPath);
|
|
1262
1291
|
const contentHash = sourceHash(document);
|
|
1263
|
-
const
|
|
1264
|
-
const
|
|
1292
|
+
const knowledge = Array.isArray(document.knowledge) ? document.knowledge.filter((value) => typeof value === "object" && value !== null && !Array.isArray(value)) : [];
|
|
1293
|
+
const ranked = [...knowledge, ...ownershipEntries(document)].map((entry) => ({ entry, score: matches(entry, query) })).filter(({ score: entryScore }) => entryScore > 0);
|
|
1294
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
1295
|
+
for (const candidate of ranked) {
|
|
1296
|
+
const path = typeof candidate.entry.path === "string" ? candidate.entry.path : String(candidate.entry.id ?? "");
|
|
1297
|
+
const current = byPath.get(path);
|
|
1298
|
+
if (!current || candidate.score > current.score || candidate.score === current.score && candidate.entry.type === "ownership" && current.entry.type !== "ownership") byPath.set(path, candidate);
|
|
1299
|
+
}
|
|
1300
|
+
const entries = [...byPath.values()].sort((left, right) => right.score - left.score || String(left.entry.id ?? "").localeCompare(String(right.entry.id ?? ""))).slice(0, 8);
|
|
1301
|
+
const maxScore = entries[0]?.score ?? 1;
|
|
1302
|
+
const references = entries.flatMap(({ entry, score: entryScore }) => typeof entry.id === "string" && typeof entry.path === "string" ? [{ id: entry.id, uri: `doc-bridge://${entry.path}`, ...typeof entry.title === "string" ? { title: entry.title } : {}, contentHash: typeof entry.contentHash === "string" ? entry.contentHash : contentHash, relevance: entryScore / maxScore }] : []);
|
|
1265
1303
|
const telemetry = { status: "measured", durationMs: Date.now() - started, contextReferences: references.length, contextCostTokens: Math.max(1, Math.ceil(JSON.stringify(references).length / 4)) };
|
|
1266
1304
|
return { providerId: "doc-bridge", query, references, sourceHash: contentHash, snapshotHash: hashContextSnapshot({ providerId: "doc-bridge", query, references, sourceHash: contentHash }), resolvedAt: (/* @__PURE__ */ new Date()).toISOString(), assurance: "contract-tested", telemetry };
|
|
1267
1305
|
}
|
|
@@ -1970,7 +2008,7 @@ var digest4 = (value, label) => {
|
|
|
1970
2008
|
if (!/^[a-f0-9]{64}$/.test(result)) fail(`${label} must be a lowercase SHA-256 digest.`, "INVALID_INPUT");
|
|
1971
2009
|
return result;
|
|
1972
2010
|
};
|
|
1973
|
-
var
|
|
2011
|
+
var score2 = (value, label) => {
|
|
1974
2012
|
const numeric = typeof value === "number" ? value : Number.NaN;
|
|
1975
2013
|
if (!Number.isFinite(numeric) || numeric < 0 || numeric > 100) fail(`${label} must be a number between 0 and 100.`, "INVALID_INPUT");
|
|
1976
2014
|
return numeric;
|
|
@@ -1988,7 +2026,7 @@ var validateCase = (value, index2) => {
|
|
|
1988
2026
|
return component2;
|
|
1989
2027
|
});
|
|
1990
2028
|
if (new Set(normalizedComponents).size !== normalizedComponents.length) fail(`cases[${index2}].components must not contain duplicates.`, "INVALID_INPUT");
|
|
1991
|
-
const baselineScore = candidate["baselineScore"] === void 0 ? void 0 :
|
|
2029
|
+
const baselineScore = candidate["baselineScore"] === void 0 ? void 0 : score2(candidate["baselineScore"], `cases[${index2}].baselineScore`);
|
|
1992
2030
|
return {
|
|
1993
2031
|
id: nonEmpty4(candidate["id"], `cases[${index2}].id`),
|
|
1994
2032
|
layer,
|
|
@@ -2026,7 +2064,7 @@ var manifestBody2 = (value) => {
|
|
|
2026
2064
|
name: nonEmpty4(value["name"], "name"),
|
|
2027
2065
|
cases,
|
|
2028
2066
|
graders,
|
|
2029
|
-
thresholds: { subjectiveQuality:
|
|
2067
|
+
thresholds: { subjectiveQuality: score2(thresholds2["subjectiveQuality"] ?? 80, "thresholds.subjectiveQuality"), maxRegression: score2(thresholds2["maxRegression"] ?? 5, "thresholds.maxRegression") },
|
|
2030
2068
|
repetitions,
|
|
2031
2069
|
provider: nonEmpty4(value["provider"], "provider"),
|
|
2032
2070
|
model: nonEmpty4(value["model"], "model"),
|
|
@@ -2251,6 +2289,14 @@ var createKvMemoryAdapter = (store, options = {}) => {
|
|
|
2251
2289
|
const scopeMatch = record3.scope === "global" || (record3.scope === "issue" ? Boolean(issueId && record3.source.includes(issueId)) : Boolean(project && record3.source.includes(project)));
|
|
2252
2290
|
return scopeMatch && (!query || `${record3.summary} ${record3.source}`.toLowerCase().includes(query));
|
|
2253
2291
|
};
|
|
2292
|
+
let allRecordsCache = null;
|
|
2293
|
+
const allRecords = async () => {
|
|
2294
|
+
if (allRecordsCache) return allRecordsCache;
|
|
2295
|
+
const ids = await store.get(indexKey);
|
|
2296
|
+
const records = Array.isArray(ids) ? await Promise.all(ids.filter((id2) => typeof id2 === "string").map((id2) => store.get(`agentskit-harness:memory:${id2}`))) : [];
|
|
2297
|
+
allRecordsCache = records.filter((record3) => Boolean(record3 && typeof record3 === "object" && record3.approved === true));
|
|
2298
|
+
return allRecordsCache;
|
|
2299
|
+
};
|
|
2254
2300
|
return {
|
|
2255
2301
|
id: options.id ?? "agentskit-kv",
|
|
2256
2302
|
version: options.version ?? "1",
|
|
@@ -2262,13 +2308,13 @@ var createKvMemoryAdapter = (store, options = {}) => {
|
|
|
2262
2308
|
const index2 = Array.isArray(ids) ? ids.filter((id2) => typeof id2 === "string") : [];
|
|
2263
2309
|
if (!index2.includes(valid.id)) await store.set(indexKey, [...index2, valid.id].sort());
|
|
2264
2310
|
await store.set(`agentskit-harness:memory:${valid.id}`, valid);
|
|
2311
|
+
allRecordsCache = null;
|
|
2265
2312
|
writes += 1;
|
|
2266
2313
|
},
|
|
2267
2314
|
async recall({ query, issueId, project, sourceRevision }) {
|
|
2268
2315
|
reads += 1;
|
|
2269
|
-
const
|
|
2270
|
-
const
|
|
2271
|
-
const hits = records.filter((record3) => Boolean(record3 && typeof record3 === "object" && record3.approved === true)).filter((record3) => matches2(record3, query.trim().toLowerCase(), issueId, project)).map((record3) => ({ record: record3, relevant: true, stale: sourceRevision !== void 0 && record3.sourceRevision !== sourceRevision }));
|
|
2316
|
+
const records = await allRecords();
|
|
2317
|
+
const hits = records.filter((record3) => matches2(record3, query.trim().toLowerCase(), issueId, project)).map((record3) => ({ record: record3, relevant: true, stale: sourceRevision !== void 0 && record3.sourceRevision !== sourceRevision }));
|
|
2272
2318
|
relevantHits += hits.length;
|
|
2273
2319
|
staleHits += hits.filter((hit) => hit.stale).length;
|
|
2274
2320
|
return hits;
|
|
@@ -2708,12 +2754,12 @@ var validatePhaseTelemetry = (value) => {
|
|
|
2708
2754
|
...machine ? { machine } : {}
|
|
2709
2755
|
};
|
|
2710
2756
|
};
|
|
2711
|
-
var average = (values) => values.length ? Number((values.reduce((
|
|
2712
|
-
var
|
|
2757
|
+
var average = (values) => values.length ? Number((values.reduce((sum2, value) => sum2 + value, 0) / values.length).toFixed(2)) : null;
|
|
2758
|
+
var score3 = (value, source, baseline = null) => ({ score: value === null ? null : Math.max(0, Math.min(100, Number(value.toFixed(2)))), status: value === null ? "unknown" : "measured", baselineDelta: value === null || baseline === null ? null : Number((value - baseline).toFixed(2)), source });
|
|
2713
2759
|
var evaluateWatchdog = ({ phases, budget }) => {
|
|
2714
2760
|
const blockers = [];
|
|
2715
|
-
const duration5 = phases.every((phase2) => phase2.durationMs !== void 0) ? phases.reduce((
|
|
2716
|
-
const totalTokens = phases.every((phase2) => phase2.tokens?.inputTokens !== void 0 && phase2.tokens.outputTokens !== void 0) ? phases.reduce((
|
|
2761
|
+
const duration5 = phases.every((phase2) => phase2.durationMs !== void 0) ? phases.reduce((sum2, phase2) => sum2 + (phase2.durationMs ?? 0), 0) : void 0;
|
|
2762
|
+
const totalTokens = phases.every((phase2) => phase2.tokens?.inputTokens !== void 0 && phase2.tokens.outputTokens !== void 0) ? phases.reduce((sum2, phase2) => sum2 + (phase2.tokens?.inputTokens ?? 0) + (phase2.tokens?.outputTokens ?? 0), 0) : void 0;
|
|
2717
2763
|
if (budget.maxDurationMs !== void 0 && duration5 !== void 0 && duration5 > budget.maxDurationMs) blockers.push({ class: "budget", reason: `Duration budget exceeded: ${duration5}ms > ${budget.maxDurationMs}ms.` });
|
|
2718
2764
|
if (budget.maxTotalTokens !== void 0 && totalTokens !== void 0 && totalTokens > budget.maxTotalTokens) blockers.push({ class: "budget", reason: `Token budget exceeded: ${totalTokens} > ${budget.maxTotalTokens}.` });
|
|
2719
2765
|
for (const phase2 of phases) {
|
|
@@ -2729,16 +2775,16 @@ var createQualityMatrix = ({ phases, baseline, budget = {} }) => {
|
|
|
2729
2775
|
const priorDurations = prior.flatMap((phase2) => phase2.durationMs === void 0 ? [] : [phase2.durationMs]);
|
|
2730
2776
|
const currentTokens = current.flatMap((phase2) => phase2.tokens?.inputTokens !== void 0 && phase2.tokens.outputTokens !== void 0 ? [phase2.tokens.inputTokens + phase2.tokens.outputTokens] : []);
|
|
2731
2777
|
const priorTokens = prior.flatMap((phase2) => phase2.tokens?.inputTokens !== void 0 && phase2.tokens.outputTokens !== void 0 ? [phase2.tokens.inputTokens + phase2.tokens.outputTokens] : []);
|
|
2732
|
-
const correctness =
|
|
2733
|
-
const completeness =
|
|
2734
|
-
const speed =
|
|
2735
|
-
const cost =
|
|
2778
|
+
const correctness = score3(average(current.map((phase2) => phase2.evidenceCoverage === void 0 ? 0 : phase2.evidenceCoverage * 100)), "mean evidence coverage");
|
|
2779
|
+
const completeness = score3(current.length ? current.filter((phase2) => phase2.outcome === "pass").length / current.length * 100 : null, "passed phases / total phases");
|
|
2780
|
+
const speed = score3(currentDurations.length && priorDurations.length ? average(priorDurations) / Math.max(1, average(currentDurations)) * 100 : null, "baseline duration / current duration", 100);
|
|
2781
|
+
const cost = score3(currentTokens.length && priorTokens.length ? average(priorTokens) / Math.max(1, average(currentTokens)) * 100 : null, "baseline tokens / current tokens", 100);
|
|
2736
2782
|
const resourceValues = current.flatMap((phase2) => phase2.machine?.cpuPercent !== void 0 && phase2.machine.memoryUsedPercent !== void 0 ? [100 - Math.max(phase2.machine.cpuPercent, phase2.machine.memoryUsedPercent)] : []);
|
|
2737
|
-
const resource =
|
|
2738
|
-
const reliability =
|
|
2783
|
+
const resource = score3(average(resourceValues), "100 - max(cpu%, memory%)");
|
|
2784
|
+
const reliability = score3(current.length ? current.filter((phase2) => phase2.outcome === "pass").length / current.length * 100 : null, "passed phases / total phases");
|
|
2739
2785
|
const dimensions = { correctness, completeness, speed, cost, resource, reliability };
|
|
2740
2786
|
const measured = Object.values(dimensions).filter((item) => item.score !== null).map((item) => item.score);
|
|
2741
|
-
const overall =
|
|
2787
|
+
const overall = score3(average(measured), "mean of measured dimensions");
|
|
2742
2788
|
const unknownMetricCount = Object.values(dimensions).filter((item) => item.status === "unknown").length + current.filter((phase2) => phase2.durationMs === void 0 || phase2.tokens === void 0 || phase2.machine === void 0).length;
|
|
2743
2789
|
const blockers = evaluateWatchdog({ phases: current, budget }).blockers;
|
|
2744
2790
|
const body3 = { type: "agentskit-harness-quality-matrix", schemaVersion: 1, dimensions, overall, phaseCount: current.length, unknownMetricCount, blockers };
|
|
@@ -4179,6 +4225,21 @@ var orcaStatus = async (runner, options = {}) => parseOrcaStatus(await orcaJson(
|
|
|
4179
4225
|
var orcaWorktrees = async (runner, options = {}) => parseOrcaWorktrees(await orcaJson(runner, ["worktree", "ps"], options));
|
|
4180
4226
|
var orcaAgentHooks = async (runner, options = {}) => parseOrcaAgentHooks(await orcaJson(runner, ["agent", "hooks", "status"], options));
|
|
4181
4227
|
var orcaAccountList = async (runner, options = {}) => orcaJson(runner, ["account", "list"], options);
|
|
4228
|
+
var orcaDiagnosticsMemory = async (runner, options = {}) => {
|
|
4229
|
+
try {
|
|
4230
|
+
const result = await orcaJson(runner, ["diagnostics", "memory"], options);
|
|
4231
|
+
if (!isRecord8(result)) return null;
|
|
4232
|
+
const host = isRecord8(result["host"]) ? result["host"] : {};
|
|
4233
|
+
const availableBytes = host["availableMemory"];
|
|
4234
|
+
if (typeof availableBytes !== "number" || !Number.isFinite(availableBytes) || availableBytes <= 0) return null;
|
|
4235
|
+
const totalBytes = typeof host["totalMemory"] === "number" ? host["totalMemory"] : null;
|
|
4236
|
+
const worktrees = Array.isArray(result["worktrees"]) ? result["worktrees"] : [];
|
|
4237
|
+
const agentRssSamples = worktrees.filter(isRecord8).flatMap((worktree) => Array.isArray(worktree["sessions"]) ? worktree["sessions"] : []).filter(isRecord8).map((session) => session["memory"]).filter((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
|
|
4238
|
+
return { availableBytes, totalBytes, agentRssSamples };
|
|
4239
|
+
} catch {
|
|
4240
|
+
return null;
|
|
4241
|
+
}
|
|
4242
|
+
};
|
|
4182
4243
|
var parseOrcaWorktreeCreate = (result) => {
|
|
4183
4244
|
const record3 = isRecord8(result) ? result : {};
|
|
4184
4245
|
const nested = isRecord8(record3["worktree"]) ? record3["worktree"] : record3;
|
|
@@ -4236,10 +4297,16 @@ var orcaTerminalCreate = async (runner, input, options = {}) => {
|
|
|
4236
4297
|
};
|
|
4237
4298
|
var parseOrcaSendReceipt = (result) => {
|
|
4238
4299
|
const record3 = isRecord8(result) ? result : {};
|
|
4239
|
-
const
|
|
4240
|
-
const
|
|
4241
|
-
const
|
|
4242
|
-
|
|
4300
|
+
const send = isRecord8(record3["send"]) ? record3["send"] : null;
|
|
4301
|
+
const prompt = send && isRecord8(send["prompt"]) ? send["prompt"] : null;
|
|
4302
|
+
const receipt = isRecord8(record3["receipt"]) ? record3["receipt"] : send ?? record3;
|
|
4303
|
+
const rawStages = Array.isArray(receipt["stages"]) ? receipt["stages"] : prompt && Array.isArray(prompt["stages"]) ? prompt["stages"] : [];
|
|
4304
|
+
const stages = rawStages.map((stage) => isRecord8(stage) ? str(stage["stage"], str(stage["name"])) : str(stage)).filter(Boolean);
|
|
4305
|
+
const inputAccepted = stages.some((stage) => ["input_accepted", "input_queued", "prompt_accepted", "queued"].includes(stage.toLowerCase()));
|
|
4306
|
+
const acceptedValue = receipt["accepted"] ?? send?.["accepted"];
|
|
4307
|
+
const accepted = inputAccepted || acceptedValue === true || acceptedValue !== false && (result === null || result === void 0 || Object.keys(record3).length === 0);
|
|
4308
|
+
const warnings = Array.isArray(record3["warnings"]) ? record3["warnings"] : send && Array.isArray(send["warnings"]) ? send["warnings"] : [];
|
|
4309
|
+
return { accepted, requestId: str(receipt["requestId"], str(prompt?.["requestId"], str(record3["requestId"]))) || null, stages, warnings: warnings.map((warning) => isRecord8(warning) ? str(warning["message"], JSON.stringify(warning)) : str(warning)) };
|
|
4243
4310
|
};
|
|
4244
4311
|
var orcaTerminalSend = async (runner, input, options = {}) => parseOrcaSendReceipt(await orcaJson(runner, ["terminal", "send", "--terminal", input.terminal, "--text", input.text, ...input.enter === false ? [] : ["--enter"], ...input.waitSubmitSeconds ? ["--wait-submit", String(input.waitSubmitSeconds)] : []], { ...options, timeoutMs: options.timeoutMs ?? (input.waitSubmitSeconds ?? 0) * 1e3 + 3e4 }));
|
|
4245
4312
|
var orcaTerminalWait = async (runner, input, options = {}) => {
|
|
@@ -4499,6 +4566,8 @@ var LoopConfigSchema = z.object({
|
|
|
4499
4566
|
}).prefault({}),
|
|
4500
4567
|
catalog: z.object({
|
|
4501
4568
|
sources: z.array(z.enum(["cli", "artificial-analysis", "builtin"])).default(["cli", "builtin"]),
|
|
4569
|
+
/** How long a provider's CLI-discovered model list (e.g. `grok models`) is trusted before spawning the CLI again — it rarely changes between releases. */
|
|
4570
|
+
cliCacheHours: z.number().positive().default(6),
|
|
4502
4571
|
artificialAnalysis: z.object({
|
|
4503
4572
|
enabled: z.boolean().default(false),
|
|
4504
4573
|
apiKeyEnv: nonEmpty5.default("ARTIFICIAL_ANALYSIS_API_KEY"),
|
|
@@ -4917,8 +4986,8 @@ var isWsl = (platform = process.platform, osRelease = release(), env = process.e
|
|
|
4917
4986
|
var assessSlots = (input) => {
|
|
4918
4987
|
const platform = input.platform ?? process.platform;
|
|
4919
4988
|
const wsl = isWsl(platform, input.osRelease);
|
|
4920
|
-
const freeBytes = input.freeBytes ?? availableMemoryBytes(platform);
|
|
4921
|
-
const totalBytes = input.totalBytes ?? totalmem();
|
|
4989
|
+
const freeBytes = input.freeBytes ?? input.orcaMemory?.availableBytes ?? availableMemoryBytes(platform);
|
|
4990
|
+
const totalBytes = input.totalBytes ?? input.orcaMemory?.totalBytes ?? totalmem();
|
|
4922
4991
|
const sample = input.sample ?? { ...sampleMachine(), memoryUsedPercent: Number(Math.max(0, Math.min(100, (1 - freeBytes / Math.max(1, totalBytes)) * 100)).toFixed(2)) };
|
|
4923
4992
|
const freeRamGb = Number((freeBytes / 1024 ** 3).toFixed(2));
|
|
4924
4993
|
const reasons = [];
|
|
@@ -4926,9 +4995,11 @@ var assessSlots = (input) => {
|
|
|
4926
4995
|
const adaptive = adaptiveConcurrency(ceiling, sample, { warningPercent: input.machine.warningPercent, criticalPercent: input.machine.criticalPercent });
|
|
4927
4996
|
if (adaptive < ceiling) reasons.push(`machine pressure capped concurrency at ${adaptive} (load ${sample.load1PerCpuPercent}%, memory ${sample.memoryUsedPercent}%)`);
|
|
4928
4997
|
const reservedBytes = input.machine.minFreeRamGb * 1024 ** 3;
|
|
4929
|
-
const
|
|
4998
|
+
const measuredAgentBytes = input.orcaMemory?.agentRssSamples.length ? input.orcaMemory.agentRssSamples.reduce((total, value) => total + value, 0) / input.orcaMemory.agentRssSamples.length : null;
|
|
4999
|
+
const perAgentBytes = measuredAgentBytes ?? input.machine.agentRssMb * 1024 ** 2;
|
|
5000
|
+
const perAgentMb = Math.round(perAgentBytes / 1024 ** 2);
|
|
4930
5001
|
const ramBound = Math.max(0, Math.floor((freeBytes - reservedBytes) / perAgentBytes)) + input.running;
|
|
4931
|
-
if (ramBound < adaptive) reasons.push(`free RAM ${freeRamGb} GB minus ${input.machine.minFreeRamGb} GB reserve fits ${Math.max(0, ramBound - input.running)} more agent(s) at ${
|
|
5002
|
+
if (ramBound < adaptive) reasons.push(`free RAM ${freeRamGb} GB minus ${input.machine.minFreeRamGb} GB reserve fits ${Math.max(0, ramBound - input.running)} more agent(s) at ${perAgentMb} MB each${measuredAgentBytes ? " (measured)" : ""}`);
|
|
4932
5003
|
let maxAgents = Math.min(adaptive, ramBound);
|
|
4933
5004
|
if (wsl && maxAgents > input.machine.wslCap) {
|
|
4934
5005
|
maxAgents = input.machine.wslCap;
|
|
@@ -5069,7 +5140,12 @@ var selectModel = (config, role, availability, extraCandidates = []) => {
|
|
|
5069
5140
|
var routeAllRoles = (config, availability, extrasByRole = {}) => Object.fromEntries(MODEL_ROLES.map((role) => [role, selectModel(config, role, availability, extrasByRole[role] ?? [])]));
|
|
5070
5141
|
var rankModels = (config, role, availability, extraCandidates = []) => {
|
|
5071
5142
|
const byId = new Map(availability.map((item) => [item.id, item]));
|
|
5072
|
-
const { ranked } = availableFromTiers(config, role, availability);
|
|
5143
|
+
const { ranked, skipped } = availableFromTiers(config, role, availability);
|
|
5144
|
+
if (config.models.routing.pin[role]) {
|
|
5145
|
+
const pinned = applyPin(config, role, availability, skipped);
|
|
5146
|
+
if (pinned) return [pinned, ...ranked.filter((item) => !(item.provider === pinned.provider && item.model === pinned.model))];
|
|
5147
|
+
if (config.models.routing.pinStrict) return [];
|
|
5148
|
+
}
|
|
5073
5149
|
const extras = [];
|
|
5074
5150
|
let extraIndex = 1e4;
|
|
5075
5151
|
for (const ref of extraCandidates) {
|
|
@@ -5190,6 +5266,32 @@ ${outcome.stderr}`);
|
|
|
5190
5266
|
}
|
|
5191
5267
|
return [];
|
|
5192
5268
|
};
|
|
5269
|
+
var cliModelsCachePath = (stateDir, provider) => join(stateDir, "catalog", `cli-${provider}.json`);
|
|
5270
|
+
var readCliModelsCache = (stateDir, provider) => {
|
|
5271
|
+
const path = cliModelsCachePath(stateDir, provider);
|
|
5272
|
+
if (!existsSync(path)) return null;
|
|
5273
|
+
try {
|
|
5274
|
+
const raw = readJson2(path);
|
|
5275
|
+
return typeof raw.fetchedAt === "string" && Array.isArray(raw.ids) ? { fetchedAt: raw.fetchedAt, ids: raw.ids } : null;
|
|
5276
|
+
} catch {
|
|
5277
|
+
return null;
|
|
5278
|
+
}
|
|
5279
|
+
};
|
|
5280
|
+
var writeCliModelsCache = (stateDir, provider, ids, now4 = /* @__PURE__ */ new Date()) => {
|
|
5281
|
+
const path = cliModelsCachePath(stateDir, provider);
|
|
5282
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
5283
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
5284
|
+
writeFileSync(tmp, `${JSON.stringify({ fetchedAt: now4.toISOString(), ids }, null, 2)}
|
|
5285
|
+
`, "utf8");
|
|
5286
|
+
renameSync(tmp, path);
|
|
5287
|
+
};
|
|
5288
|
+
var listCliModelsCached = async (provider, bin, runner, stateDir, cacheHours, now4 = () => /* @__PURE__ */ new Date()) => {
|
|
5289
|
+
const cached = readCliModelsCache(stateDir, provider);
|
|
5290
|
+
if (cached && now4().getTime() - Date.parse(cached.fetchedAt) <= cacheHours * 36e5) return cached.ids;
|
|
5291
|
+
const ids = await listCliModels(provider, bin, runner);
|
|
5292
|
+
if (ids.length) writeCliModelsCache(stateDir, provider, ids, now4());
|
|
5293
|
+
return ids.length ? ids : cached?.ids ?? [];
|
|
5294
|
+
};
|
|
5193
5295
|
var parseArtificialAnalysisPayload = (payload) => {
|
|
5194
5296
|
const root = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
5195
5297
|
const data = Array.isArray(root["data"]) ? root["data"] : Array.isArray(payload) ? payload : [];
|
|
@@ -5274,7 +5376,7 @@ var resolveCatalogCandidates = async (input) => {
|
|
|
5274
5376
|
const settings = config.models.providers[provider];
|
|
5275
5377
|
if (settings) {
|
|
5276
5378
|
try {
|
|
5277
|
-
const ids = await listCliModels(provider, settings.bin, input.runner);
|
|
5379
|
+
const ids = input.stateDir ? await listCliModelsCached(provider, settings.bin, input.runner, input.stateDir, config.models.catalog.cliCacheHours, input.now) : await listCliModels(provider, settings.bin, input.runner);
|
|
5278
5380
|
for (const id2 of ids) {
|
|
5279
5381
|
const resolved = resolveAlias(provider, id2, aliases);
|
|
5280
5382
|
const existing = builtin[provider]?.models.find((model) => model.id === resolved);
|
|
@@ -5306,9 +5408,9 @@ var resolveCatalogCandidates = async (input) => {
|
|
|
5306
5408
|
const matches2 = models.models.filter((model) => model.creatorSlug === creator || model.creatorSlug.includes(creator));
|
|
5307
5409
|
for (const model of matches2) {
|
|
5308
5410
|
const id2 = resolveAlias(provider, model.slug, aliases);
|
|
5309
|
-
const
|
|
5310
|
-
const quality =
|
|
5311
|
-
push(provider, { id: id2, quality, codingScore:
|
|
5411
|
+
const score4 = model.codingIndex ?? model.intelligenceIndex ?? 50;
|
|
5412
|
+
const quality = score4 >= 80 ? "frontier" : score4 >= 60 ? "balanced" : "fast";
|
|
5413
|
+
push(provider, { id: id2, quality, codingScore: score4, source: "artificial-analysis", creator });
|
|
5312
5414
|
}
|
|
5313
5415
|
}
|
|
5314
5416
|
}
|
|
@@ -5366,6 +5468,16 @@ var clearProviderCooldown = (stateDir, provider) => {
|
|
|
5366
5468
|
writeCooldowns(stateDir, rest);
|
|
5367
5469
|
};
|
|
5368
5470
|
var rotationStatePath = (stateDir) => join(stateDir, "queue-owner.json");
|
|
5471
|
+
var countRotationBlockingLeases = (loaded, leases) => leases.filter((lease) => {
|
|
5472
|
+
const path = join(loaded.stateDir, "issues", lease.issue, "delivery.json");
|
|
5473
|
+
if (!existsSync(path)) return true;
|
|
5474
|
+
try {
|
|
5475
|
+
const delivery = JSON.parse(readFileSync(path, "utf8"));
|
|
5476
|
+
return delivery.prNumber == null && !delivery.heldFor && !delivery.finalOutcome;
|
|
5477
|
+
} catch {
|
|
5478
|
+
return true;
|
|
5479
|
+
}
|
|
5480
|
+
}).length;
|
|
5369
5481
|
var queueOwner = (loaded) => {
|
|
5370
5482
|
const { rotation } = loaded.config.linear;
|
|
5371
5483
|
if (!rotation.enabled || !rotation.owners.length) return loaded.config.linear.person;
|
|
@@ -5543,7 +5655,8 @@ var runLoopDoctor = async (input) => {
|
|
|
5543
5655
|
push("orca.worktrees", "warning", `worktree ps unavailable: ${workersError}`);
|
|
5544
5656
|
}
|
|
5545
5657
|
const running = countRunningWorkers(worktrees);
|
|
5546
|
-
const
|
|
5658
|
+
const orcaMemory = await orcaDiagnosticsMemory(input.runner, orcaOptions2);
|
|
5659
|
+
const machine = assessSlots({ machine: config.machine, running, platform: input.platform, orcaMemory });
|
|
5547
5660
|
push("machine.slots", machine.free > 0 ? "passed" : "warning", `${machine.free} free of ${machine.maxAgents} (running ${running}, cpus ${machine.sample.cpus}, load ${machine.sample.load1PerCpuPercent}%, free RAM ${machine.freeRamGb} GB)${machine.reasons.length ? `; ${machine.reasons.join("; ")}` : ""}`);
|
|
5548
5661
|
let queue = [];
|
|
5549
5662
|
let queueError = null;
|
|
@@ -5860,10 +5973,10 @@ var planMemoryContext = async (input) => {
|
|
|
5860
5973
|
hits = [];
|
|
5861
5974
|
}
|
|
5862
5975
|
const selected = selectMemoryForPrompt(hits, memory);
|
|
5863
|
-
const beforeChars = input.references.reduce((
|
|
5976
|
+
const beforeChars = input.references.reduce((sum2, ref) => sum2 + JSON.stringify(ref).length, 0) + issueBudgetDefault;
|
|
5864
5977
|
const preferred = memory.preferOverDocBridge ? preferMemoryOverDocBridge(input.references, selected.hits, memory.minDocBridgeWhenMemory) : { references: input.references};
|
|
5865
5978
|
const issueCharBudget = selected.hits.length && memory.shrinkIssueCharsWhenMemory ? Math.min(issueBudgetDefault, memory.issueCharsWithMemory) : issueBudgetDefault;
|
|
5866
|
-
const afterChars = preferred.references.reduce((
|
|
5979
|
+
const afterChars = preferred.references.reduce((sum2, ref) => sum2 + JSON.stringify(ref).length, 0) + issueCharBudget + selected.approxChars;
|
|
5867
5980
|
return {
|
|
5868
5981
|
hits: selected.hits,
|
|
5869
5982
|
references: preferred.references,
|
|
@@ -6420,9 +6533,14 @@ var writeDispatchRecord = (stateDir, record3) => {
|
|
|
6420
6533
|
writeJson2(path, record3);
|
|
6421
6534
|
return path;
|
|
6422
6535
|
};
|
|
6423
|
-
var
|
|
6536
|
+
var EVENTS_ROTATE_AT_BYTES = 10 * 1024 * 1024;
|
|
6537
|
+
var appendLoopEvent = (stateDir, event2, bus, now4 = () => /* @__PURE__ */ new Date()) => {
|
|
6424
6538
|
const path = join(stateDir, "events.ndjson");
|
|
6425
6539
|
mkdirSync(dirname(path), { recursive: true });
|
|
6540
|
+
try {
|
|
6541
|
+
if (statSync(path).size > EVENTS_ROTATE_AT_BYTES) renameSync(path, join(stateDir, `events-archive-${now4().getTime()}.ndjson`));
|
|
6542
|
+
} catch {
|
|
6543
|
+
}
|
|
6426
6544
|
appendFileSync(path, `${JSON.stringify(event2)}
|
|
6427
6545
|
`, "utf8");
|
|
6428
6546
|
if (bus && typeof event2["type"] === "string") bus.emit(event2);
|
|
@@ -6431,11 +6549,12 @@ var gatherLoopState = async (input) => {
|
|
|
6431
6549
|
const { config } = input.loaded;
|
|
6432
6550
|
const person = queueOwner(input.loaded);
|
|
6433
6551
|
const orca = { bin: config.orca.bin, timeoutMs: config.orca.timeoutMs };
|
|
6434
|
-
const [accountList, agentHooks, worktrees, queue] = await Promise.all([
|
|
6552
|
+
const [accountList, agentHooks, worktrees, queue, orcaMemory] = await Promise.all([
|
|
6435
6553
|
orcaAccountList(input.runner, orca).catch(() => ({})),
|
|
6436
6554
|
orcaAgentHooks(input.runner, orca).catch(() => ({})),
|
|
6437
6555
|
orcaWorktrees(input.runner, orca),
|
|
6438
|
-
fetchLinearQueue(input.runner, { bin: config.orca.bin, workspaceId: config.linear.workspaceId, teamKey: config.linear.teamKey, assignee: person, filter: config.linear, orca })
|
|
6556
|
+
fetchLinearQueue(input.runner, { bin: config.orca.bin, workspaceId: config.linear.workspaceId, teamKey: config.linear.teamKey, assignee: person, filter: config.linear, orca }),
|
|
6557
|
+
orcaDiagnosticsMemory(input.runner, orca)
|
|
6439
6558
|
]);
|
|
6440
6559
|
const providers = await detectProviders({ providers: providerSpecs(config), accountList, agentHooks, env: input.env, platform: input.platform, exhaustedPercent: config.models.cooldown.exhaustedPercent, cooldowns: activeCooldowns(readCooldowns(input.loaded.stateDir), input.now()), now: input.now });
|
|
6441
6560
|
const availableIds = providers.filter((provider) => provider.available).map((provider) => provider.id);
|
|
@@ -6450,11 +6569,11 @@ var gatherLoopState = async (input) => {
|
|
|
6450
6569
|
})]))) : {};
|
|
6451
6570
|
const routing = routeAllRoles(config, providers, extrasByRole);
|
|
6452
6571
|
const running = countRunningWorkers(worktrees);
|
|
6453
|
-
const slots = assessSlots({ machine: config.machine, running, platform: input.platform, ...input.machine });
|
|
6572
|
+
const slots = assessSlots({ machine: config.machine, running, platform: input.platform, orcaMemory, ...input.machine });
|
|
6454
6573
|
const leases = input.ledger.active();
|
|
6455
6574
|
const busy = busyIssues(queue, leases, worktrees, person);
|
|
6456
6575
|
const candidates = queue.filter((issue) => !busy.has(issue.identifier) && (!input.onlyIssue || issue.identifier === input.onlyIssue));
|
|
6457
|
-
return { person, providers, routing, worktrees, slots, queue, leases, busy, candidates };
|
|
6576
|
+
return { person, providers, routing, worktrees, slots, queue, leases, busy, candidates, extrasByRole };
|
|
6458
6577
|
};
|
|
6459
6578
|
var precheckTick = async (input) => {
|
|
6460
6579
|
const loaded = input.loaded ?? loadLoopConfig(input.configPath);
|
|
@@ -6495,16 +6614,7 @@ var runTick = async (input) => {
|
|
|
6495
6614
|
}
|
|
6496
6615
|
const state = await gatherLoopState({ loaded, runner: input.runner, ledger, env: input.env, platform: input.platform, now: now4, onlyIssue: input.onlyIssue, machine: input.machine });
|
|
6497
6616
|
const orchestrator = state.routing["orchestrator"] ?? { role: "orchestrator", selected: null, skipped: [] };
|
|
6498
|
-
const
|
|
6499
|
-
config,
|
|
6500
|
-
role: "orchestrator",
|
|
6501
|
-
availableProviderIds: state.providers.filter((provider) => provider.available).map((provider) => provider.id),
|
|
6502
|
-
runner: input.runner,
|
|
6503
|
-
stateDir: loaded.stateDir,
|
|
6504
|
-
env: input.env,
|
|
6505
|
-
now: now4
|
|
6506
|
-
}) : [];
|
|
6507
|
-
const orchestratorCandidates = rankModels(config, "orchestrator", state.providers, orchestratorExtras);
|
|
6617
|
+
const orchestratorCandidates = rankModels(config, "orchestrator", state.providers, state.extrasByRole["orchestrator"] ?? []);
|
|
6508
6618
|
const onProviderFailure = (failure) => {
|
|
6509
6619
|
if (dryRun) return;
|
|
6510
6620
|
const resetsAt = extractResetsAt(failure.detail, now4());
|
|
@@ -6524,7 +6634,7 @@ var runTick = async (input) => {
|
|
|
6524
6634
|
return { ...base, status: "idle", results, notes };
|
|
6525
6635
|
}
|
|
6526
6636
|
if (!state.candidates.length) {
|
|
6527
|
-
const rotation = dryRun ? { owner: state.person, advanced: false } : advanceQueueOwner(loaded, { queueEmpty: state.queue.length === 0, activeLeases: state.leases
|
|
6637
|
+
const rotation = dryRun ? { owner: state.person, advanced: false } : advanceQueueOwner(loaded, { queueEmpty: state.queue.length === 0, activeLeases: countRotationBlockingLeases(loaded, state.leases), now: now4() });
|
|
6528
6638
|
if (rotation.advanced) notes.push(`queue drained for ${state.person}; switched to ${rotation.owner}`);
|
|
6529
6639
|
else notes.push("queue has no dispatchable candidate");
|
|
6530
6640
|
return { ...base, status: "idle", results, notes };
|
|
@@ -6557,17 +6667,32 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
|
|
|
6557
6667
|
appendLoopEvent(loaded.stateDir, { at: now4().toISOString(), type: "issue.paused", issue, kind, consecutive: failureState.consecutive, reason }, bus);
|
|
6558
6668
|
await bus.runHook("onPause", { issue, kind, consecutive: failureState.consecutive, reason });
|
|
6559
6669
|
};
|
|
6670
|
+
let pinnedSkillsOnce;
|
|
6671
|
+
const getPinnedSkills = () => {
|
|
6672
|
+
if (pinnedSkillsOnce === void 0) {
|
|
6673
|
+
try {
|
|
6674
|
+
pinnedSkillsOnce = loadPinnedSkills(loaded.root, config.brief.skills, config.brief.maxSkillChars);
|
|
6675
|
+
} catch (error) {
|
|
6676
|
+
pinnedSkillsOnce = { error };
|
|
6677
|
+
throw error;
|
|
6678
|
+
}
|
|
6679
|
+
}
|
|
6680
|
+
if ("error" in pinnedSkillsOnce) throw pinnedSkillsOnce.error;
|
|
6681
|
+
return pinnedSkillsOnce;
|
|
6682
|
+
};
|
|
6560
6683
|
let dispatched = 0;
|
|
6561
6684
|
for (const candidate of state.candidates) {
|
|
6562
6685
|
if (dispatched >= budget) break;
|
|
6563
6686
|
const setupBudgetMs = config.project.setup.command ? Number.isFinite(timeBudgetMs) ? Math.min(config.project.setup.timeoutSec * 1e3, Math.max(0, timeBudgetMs - config.contract.timeoutMs - 125e3)) : config.project.setup.timeoutSec * 1e3 : 0;
|
|
6564
|
-
|
|
6687
|
+
const cachedContract = readStoredContract(loaded.stateDir, candidate.identifier);
|
|
6688
|
+
if (remainingMs() < config.contract.timeoutMs + setupBudgetMs + 12e4 && !cachedContract) {
|
|
6565
6689
|
notes.push(`time budget: ${candidate.identifier} left for the next tick (${Math.round(remainingMs() / 1e3)}s remaining)`);
|
|
6566
6690
|
continue;
|
|
6567
6691
|
}
|
|
6568
|
-
|
|
6692
|
+
const failureState = readIssueFailures(loaded.stateDir, candidate.identifier);
|
|
6693
|
+
if (failureState.pausedAt !== null) {
|
|
6569
6694
|
if (candidate.labels.includes(config.resilience.pausedLabel)) {
|
|
6570
|
-
results.push({ issue: candidate.identifier, outcome: "skipped", reason: `paused after ${
|
|
6695
|
+
results.push({ issue: candidate.identifier, outcome: "skipped", reason: `paused after ${failureState.consecutive} consecutive failures; remove the "${config.resilience.pausedLabel}" label or run "ak-harness loop resume ${candidate.identifier}" to retry` });
|
|
6571
6696
|
continue;
|
|
6572
6697
|
}
|
|
6573
6698
|
if (!dryRun) clearIssueFailures(loaded.stateDir, candidate.identifier);
|
|
@@ -6580,8 +6705,8 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
|
|
|
6580
6705
|
results.push({ issue: candidate.identifier, outcome: "failed", reason: `issue fetch failed: ${message2(error)}` });
|
|
6581
6706
|
continue;
|
|
6582
6707
|
}
|
|
6583
|
-
let stored =
|
|
6584
|
-
const
|
|
6708
|
+
let stored = cachedContract;
|
|
6709
|
+
const memoryPlan = memory ? await planMemoryContext({
|
|
6585
6710
|
adapter: memory,
|
|
6586
6711
|
config,
|
|
6587
6712
|
issueId: detail.identifier,
|
|
@@ -6589,7 +6714,7 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
|
|
|
6589
6714
|
project: config.project.name,
|
|
6590
6715
|
references: []
|
|
6591
6716
|
}) : null;
|
|
6592
|
-
if (stored && !contractIsFresh(stored, detail, config.contract.reuseHours, now4(),
|
|
6717
|
+
if (stored && !contractIsFresh(stored, detail, config.contract.reuseHours, now4(), memoryPlan?.memoryDigest)) stored = null;
|
|
6593
6718
|
if (!stored) {
|
|
6594
6719
|
if (input.skipContractGeneration) {
|
|
6595
6720
|
results.push({ issue: detail.identifier, outcome: "skipped", reason: "no cached contract; generation skipped" });
|
|
@@ -6689,16 +6814,9 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
|
|
|
6689
6814
|
}
|
|
6690
6815
|
if (setupFailed) notes.push(`${detail.identifier}: setup command failed but project.setup.required is false \u2014 continuing`);
|
|
6691
6816
|
}
|
|
6692
|
-
const briefMemory =
|
|
6693
|
-
adapter: memory,
|
|
6694
|
-
config,
|
|
6695
|
-
issueId: detail.identifier,
|
|
6696
|
-
issueTitle: detail.title,
|
|
6697
|
-
project: config.project.name,
|
|
6698
|
-
references: []
|
|
6699
|
-
}) : { memoryBlock: "", issueCharBudget: config.contract.maxIssueChars, hits: [] };
|
|
6817
|
+
const briefMemory = memoryPlan ?? { memoryBlock: "", issueCharBudget: config.contract.maxIssueChars, hits: [] };
|
|
6700
6818
|
const guidanceRefs = config.contract.maxBriefReferences > 0 && config.contract.briefScopes.length ? await resolveDocContext(loaded.root, `${detail.identifier} ${detail.title}`, config.contract.maxBriefReferences, config.contract.briefScopes) : [];
|
|
6701
|
-
const pinnedSkills =
|
|
6819
|
+
const pinnedSkills = getPinnedSkills();
|
|
6702
6820
|
const brief = renderWorkerBrief({
|
|
6703
6821
|
issue: detail,
|
|
6704
6822
|
contract: stored,
|
|
@@ -6963,14 +7081,34 @@ ${JSON.stringify(stored.contract, null, 2)}
|
|
|
6963
7081
|
return false;
|
|
6964
7082
|
}
|
|
6965
7083
|
};
|
|
7084
|
+
var captureWorkerOutput = async (ctx, terminal2) => {
|
|
7085
|
+
if (!terminal2) return null;
|
|
7086
|
+
try {
|
|
7087
|
+
const screen = (await orcaTerminalScreen(ctx.runner, { terminal: terminal2 }, orcaOptions(ctx.config))).trim();
|
|
7088
|
+
return screen ? screen.slice(-2e3) : null;
|
|
7089
|
+
} catch {
|
|
7090
|
+
return null;
|
|
7091
|
+
}
|
|
7092
|
+
};
|
|
6966
7093
|
var escalateLinear = async (ctx, record3, kind, body3, actions) => {
|
|
6967
7094
|
if (ctx.dryRun) {
|
|
6968
7095
|
actions.push(`would mark ${kind} in Linear and Orca`);
|
|
6969
7096
|
return;
|
|
6970
7097
|
}
|
|
7098
|
+
const workerOutput = await captureWorkerOutput(ctx, record3.terminal);
|
|
7099
|
+
const fullBody = workerOutput ? `${body3}
|
|
7100
|
+
|
|
7101
|
+
<details><summary>Worker's last terminal output</summary>
|
|
7102
|
+
|
|
7103
|
+
\`\`\`
|
|
7104
|
+
${workerOutput}
|
|
7105
|
+
\`\`\`
|
|
7106
|
+
|
|
7107
|
+
</details>` : body3;
|
|
7108
|
+
if (workerOutput) actions.push("captured worker terminal output for the escalation");
|
|
6971
7109
|
const linear = linearOptions(ctx.config);
|
|
6972
7110
|
try {
|
|
6973
|
-
await linearCommentAdd(ctx.runner, { issue: record3.issue, body: `${
|
|
7111
|
+
await linearCommentAdd(ctx.runner, { issue: record3.issue, body: `${fullBody}
|
|
6974
7112
|
|
|
6975
7113
|
<!-- loop:${kind}:${record3.leaseId} -->`, dedupeKey: `${kind}:${record3.issue}:${record3.leaseId}` }, linear);
|
|
6976
7114
|
await linearLabelAdd(ctx.runner, { issue: record3.issue, labels: [ctx.config.linear.blockedLabel] }, linear);
|
|
@@ -7028,7 +7166,7 @@ var providerUnavailable = (ctx, providerId) => {
|
|
|
7028
7166
|
return !match || !match.available;
|
|
7029
7167
|
};
|
|
7030
7168
|
var pickHandoffBuilder = (ctx, record3) => {
|
|
7031
|
-
const ranked = rankModels(ctx.config, "builder", ctx.providers);
|
|
7169
|
+
const ranked = rankModels(ctx.config, "builder", ctx.providers, ctx.builderExtras);
|
|
7032
7170
|
const different = ranked.find((candidate) => candidate.provider !== record3.provider || candidate.model !== record3.model);
|
|
7033
7171
|
return different ?? null;
|
|
7034
7172
|
};
|
|
@@ -7469,7 +7607,8 @@ var runDeliver = async (input) => {
|
|
|
7469
7607
|
const availableIds = providers.filter((provider) => provider.available).map((provider) => provider.id);
|
|
7470
7608
|
const catalogExtras = async (role) => config.models.routing.mode === "catalog" ? resolveCatalogCandidates({ config, role, availableProviderIds: availableIds, runner: input.runner, stateDir: loaded.stateDir, env: input.env, now: now4 }) : Promise.resolve([]);
|
|
7471
7609
|
const reviewer = rankModels(config, "reviewer", providers, await catalogExtras("reviewer"))[0] ?? null;
|
|
7472
|
-
const
|
|
7610
|
+
const builderExtras = await catalogExtras("builder");
|
|
7611
|
+
const builder = rankModels(config, "builder", providers, builderExtras)[0] ?? null;
|
|
7473
7612
|
let env = input.env ?? process.env;
|
|
7474
7613
|
if (!env["GITHUB_TOKEN"] && !env["GH_TOKEN"]) {
|
|
7475
7614
|
try {
|
|
@@ -7485,13 +7624,14 @@ var runDeliver = async (input) => {
|
|
|
7485
7624
|
const { errors } = await loadLoopPlugins(loaded.root, config.plugins.modules, bus);
|
|
7486
7625
|
for (const failure of errors) notes.push(`plugin ${failure.path} failed to load: ${failure.error}`);
|
|
7487
7626
|
}
|
|
7488
|
-
const ctx = { loaded, config, runner: input.runner, now: now4, dryRun, reviewer, builder, providers, env, ...input.assumeIdle === void 0 ? {} : { assumeIdle: input.assumeIdle }, notes, reviewDeadlineMs, bus };
|
|
7627
|
+
const ctx = { loaded, config, runner: input.runner, now: now4, dryRun, reviewer, builder, providers, env, ...input.assumeIdle === void 0 ? {} : { assumeIdle: input.assumeIdle }, notes, reviewDeadlineMs, bus, builderExtras };
|
|
7489
7628
|
const ledger = createDispatchLedger(loaded.stateDir);
|
|
7490
7629
|
const leases = new Map(ledger.active().map((lease) => [lease.issue, lease]));
|
|
7491
7630
|
const results = [];
|
|
7492
7631
|
for (const record3 of listDispatched(loaded.stateDir)) {
|
|
7493
7632
|
if (input.onlyIssue && record3.issue !== input.onlyIssue) continue;
|
|
7494
7633
|
let state = readDeliveryState(loaded.stateDir, record3.issue);
|
|
7634
|
+
if (state.finishedAt && state.finalOutcome === "merged") continue;
|
|
7495
7635
|
const lease = leases.get(record3.issue);
|
|
7496
7636
|
if (!state.finishedAt) {
|
|
7497
7637
|
const ageMinutes = minutesBetween(now4(), record3.dispatchedAt);
|
|
@@ -7530,7 +7670,6 @@ var runDeliver = async (input) => {
|
|
|
7530
7670
|
results.push(await handlePullRequest(ctx, record3, lease, state, pr));
|
|
7531
7671
|
continue;
|
|
7532
7672
|
}
|
|
7533
|
-
if (state.finishedAt && state.finalOutcome === "merged") continue;
|
|
7534
7673
|
const recordedMerge = readMergedEvent(loaded.stateDir, record3.issue);
|
|
7535
7674
|
if (recordedMerge) {
|
|
7536
7675
|
try {
|
|
@@ -8091,10 +8230,19 @@ ${step && total ? `${step}/${total} ` : ""}${title}`),
|
|
|
8091
8230
|
] }))
|
|
8092
8231
|
};
|
|
8093
8232
|
};
|
|
8233
|
+
var newestIssueMtimeMs = (stateDir, issue) => {
|
|
8234
|
+
const mtimes = [dispatchRecordPath(stateDir, issue), deliveryStatePath(stateDir, issue), contractPath(stateDir, issue)].map((path) => {
|
|
8235
|
+
try {
|
|
8236
|
+
return statSync(path).mtimeMs;
|
|
8237
|
+
} catch {
|
|
8238
|
+
return null;
|
|
8239
|
+
}
|
|
8240
|
+
}).filter((value) => value !== null);
|
|
8241
|
+
return mtimes.length ? Math.max(...mtimes) : null;
|
|
8242
|
+
};
|
|
8094
8243
|
var HARNESS_REPO_URL = "https://github.com/AgentsKit-io/harness";
|
|
8095
8244
|
var isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8096
|
-
var
|
|
8097
|
-
const path = join(stateDir, "events.ndjson");
|
|
8245
|
+
var parseEventsFile = (path) => {
|
|
8098
8246
|
if (!existsSync(path)) return [];
|
|
8099
8247
|
return readFileSync(path, "utf8").split(/\r?\n/).filter(Boolean).flatMap((line2) => {
|
|
8100
8248
|
try {
|
|
@@ -8105,6 +8253,11 @@ var readLoopEvents = (stateDir) => {
|
|
|
8105
8253
|
}
|
|
8106
8254
|
});
|
|
8107
8255
|
};
|
|
8256
|
+
var eventsArchivePattern = /^events-archive-(\d+)\.ndjson$/;
|
|
8257
|
+
var readLoopEvents = (stateDir, sinceMs) => {
|
|
8258
|
+
const archives = existsSync(stateDir) ? readdirSync(stateDir).map((name2) => name2.match(eventsArchivePattern)).filter((match) => match !== null).map((match) => ({ path: join(stateDir, match[0]), rotatedAtMs: Number(match[1]) })).filter((archive) => sinceMs === void 0 || archive.rotatedAtMs >= sinceMs).sort((a, b) => a.rotatedAtMs - b.rotatedAtMs) : [];
|
|
8259
|
+
return [...archives.flatMap((archive) => parseEventsFile(archive.path)), ...parseEventsFile(join(stateDir, "events.ndjson"))];
|
|
8260
|
+
};
|
|
8108
8261
|
var parseSince = (value, now4) => {
|
|
8109
8262
|
if (!value) return new Date(now4.getTime() - 7 * 864e5);
|
|
8110
8263
|
const match = value.match(/^(\d+)([dhm])$/);
|
|
@@ -8151,10 +8304,11 @@ var buildSuggestions = (input) => {
|
|
|
8151
8304
|
var buildRetroReport = async (input) => {
|
|
8152
8305
|
const loaded = input.loaded ?? loadLoopConfig(input.configPath);
|
|
8153
8306
|
const { config } = loaded;
|
|
8307
|
+
const person = queueOwner(loaded);
|
|
8154
8308
|
const now4 = (input.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
8155
8309
|
const since = parseSince(input.since, now4);
|
|
8156
8310
|
const inWindow = (at) => typeof at === "string" && Date.parse(at) >= since.getTime() && Date.parse(at) <= now4.getTime();
|
|
8157
|
-
const events = readLoopEvents(loaded.stateDir).filter((event2) => inWindow(event2.at));
|
|
8311
|
+
const events = readLoopEvents(loaded.stateDir, since.getTime()).filter((event2) => inWindow(event2.at));
|
|
8158
8312
|
const counts = {};
|
|
8159
8313
|
for (const event2 of events) counts[event2.type] = (counts[event2.type] ?? 0) + 1;
|
|
8160
8314
|
const escalations = events.filter((event2) => event2.type === "contract.escalated");
|
|
@@ -8176,6 +8330,8 @@ var buildRetroReport = async (input) => {
|
|
|
8176
8330
|
if (existsSync(issuesDir)) for (const entry of readdirSync(issuesDir, { withFileTypes: true })) {
|
|
8177
8331
|
if (!entry.isDirectory()) continue;
|
|
8178
8332
|
const issue = entry.name;
|
|
8333
|
+
const newestMtime = newestIssueMtimeMs(loaded.stateDir, issue);
|
|
8334
|
+
if (newestMtime !== null && newestMtime < since.getTime()) continue;
|
|
8179
8335
|
const dispatch = readDispatchRecord(loaded.stateDir, issue);
|
|
8180
8336
|
const delivery = readDeliveryState(loaded.stateDir, issue);
|
|
8181
8337
|
const contract = readStoredContract(loaded.stateDir, issue);
|
|
@@ -8233,7 +8389,7 @@ var buildRetroReport = async (input) => {
|
|
|
8233
8389
|
else if (status === "ok") work += 1;
|
|
8234
8390
|
}
|
|
8235
8391
|
}
|
|
8236
|
-
orca = { runs, idle, work, timedOut, avgDurationSec: durations.length ? Math.round(durations.reduce((
|
|
8392
|
+
orca = { runs, idle, work, timedOut, avgDurationSec: durations.length ? Math.round(durations.reduce((sum2, value) => sum2 + value, 0) / durations.length) : null, maxDurationSec: durations.length ? Math.round(Math.max(...durations)) : null };
|
|
8237
8393
|
} catch {
|
|
8238
8394
|
orca = null;
|
|
8239
8395
|
}
|
|
@@ -8242,9 +8398,9 @@ var buildRetroReport = async (input) => {
|
|
|
8242
8398
|
generatedAt: now4.toISOString(),
|
|
8243
8399
|
window: { since: since.toISOString(), until: now4.toISOString(), days: Number(((now4.getTime() - since.getTime()) / 864e5).toFixed(2)) },
|
|
8244
8400
|
project: config.project.repo,
|
|
8245
|
-
person
|
|
8401
|
+
person,
|
|
8246
8402
|
counts,
|
|
8247
|
-
escalations: { total: escalations.length, issues: [...new Set(escalations.map((event2) => String(event2.issue ?? "?")))], reasons: [...reasonCounts.entries()].map(([reason2,
|
|
8403
|
+
escalations: { total: escalations.length, issues: [...new Set(escalations.map((event2) => String(event2.issue ?? "?")))], reasons: [...reasonCounts.entries()].map(([reason2, count3]) => ({ reason: reason2, count: count3 })).sort((left, right) => right.count - left.count) },
|
|
8248
8404
|
dispatches: { total: dispatchEvents.length, failed: counts["worker.dispatch-failed"] ?? 0, byProvider },
|
|
8249
8405
|
delivery: { merged: tally("merged"), blocked: tally("blocked"), stuck: tally("stuck"), abandoned: tally("abandoned"), inFlight: tally("in-flight"), fixRounds, reviewsClean, reviewsFindings, reviewsIncomplete, medianLeadTimeMin: median3(rows.map((row) => row.leadTimeMin).filter((value) => value !== null)) },
|
|
8250
8406
|
providers: { cooldowns, cooldownEvents: counts["provider.cooldown"] ?? 0 },
|
|
@@ -8271,7 +8427,7 @@ var renderRetroMarkdown = (report) => {
|
|
|
8271
8427
|
if (report.orca) lines.push(`| Orca runs (idle / work / timed out) | ${report.orca.runs} (${report.orca.idle} / ${report.orca.work} / ${report.orca.timedOut}) \xB7 avg ${report.orca.avgDurationSec ?? "\u2014"} s \xB7 max ${report.orca.maxDurationSec ?? "\u2014"} s |`);
|
|
8272
8428
|
lines.push("");
|
|
8273
8429
|
if (Object.keys(report.dispatches.byProvider).length) {
|
|
8274
|
-
lines.push("## Providers", "", ...Object.entries(report.dispatches.byProvider).map(([key,
|
|
8430
|
+
lines.push("## Providers", "", ...Object.entries(report.dispatches.byProvider).map(([key, count3]) => `- ${key}: ${count3} dispatch(es)`), ...report.providers.cooldowns.map((row) => `- cooldown ${row.provider} until ${row.until.slice(0, 16)}Z \u2014 ${row.reason}`), "");
|
|
8275
8431
|
}
|
|
8276
8432
|
if (report.escalations.reasons.length) {
|
|
8277
8433
|
lines.push("## Problems", "", ...report.escalations.reasons.map((row) => `- ${row.count}\xD7 ${row.reason}`), ...report.issues.filter((row) => ["blocked", "stuck", "abandoned"].includes(row.outcome)).map((row) => `- ${row.issue} ${row.outcome}${row.pr ? ` (PR #${row.pr})` : ""} after ${row.fixRounds} fix round(s), ${row.nudges} nudge(s)`), "");
|
|
@@ -8452,7 +8608,7 @@ var buildDebriefReport = (input) => {
|
|
|
8452
8608
|
}
|
|
8453
8609
|
const inFlight = rows.filter((row) => !row.finalOutcome && row.phase !== "escalated");
|
|
8454
8610
|
const held = rows.filter((row) => row.phase === "held" || row.phase === "held-incomplete-review" || row.heldFor);
|
|
8455
|
-
const events = readLoopEvents(stateDir).filter((event2) => Date.parse(event2.at) >= since.getTime());
|
|
8611
|
+
const events = readLoopEvents(stateDir, since.getTime()).filter((event2) => Date.parse(event2.at) >= since.getTime());
|
|
8456
8612
|
const recentEscalations = events.filter((event2) => event2.type === "contract.escalated").slice(-10).map((event2) => ({
|
|
8457
8613
|
issue: typeof event2.issue === "string" ? event2.issue : "?",
|
|
8458
8614
|
at: event2.at,
|
|
@@ -8534,6 +8690,138 @@ var renderDebriefMarkdown = (report) => {
|
|
|
8534
8690
|
lines.push("_Read-only. Run `ak-harness loop deliver` / `tick` to act; `loop retro` for the weekly digest._");
|
|
8535
8691
|
return lines.join("\n");
|
|
8536
8692
|
};
|
|
8693
|
+
var connectedStatuses = /* @__PURE__ */ new Set(["connected", "running", "active", "idle"]);
|
|
8694
|
+
var stalledPhases = /* @__PURE__ */ new Set(["waiting-for-pr", "awaiting-review", "review-incomplete", "fix-round"]);
|
|
8695
|
+
var heldRow = (row) => Boolean(row.heldFor) || row.phase === "held" || row.phase === "held-incomplete-review";
|
|
8696
|
+
var count2 = (events, type) => events.filter((event2) => event2.type === type).length;
|
|
8697
|
+
var sum = (events, key) => events.reduce((total, event2) => total + (typeof event2[key] === "number" && Number.isFinite(event2[key]) ? Number(event2[key]) : 0), 0);
|
|
8698
|
+
var uniqueIssues = (events, types) => new Set(events.filter((event2) => types.includes(event2.type) && typeof event2.issue === "string").map((event2) => event2.issue)).size;
|
|
8699
|
+
var assessObservability = (input) => {
|
|
8700
|
+
const anomalies = [];
|
|
8701
|
+
for (const issue of input.missingDeliveryIssues) anomalies.push({ id: "claim-without-delivery", severity: "action_required", issue, message: `${issue} has an active claim but no delivery.json`, evidence: { issue } });
|
|
8702
|
+
for (const terminal2 of input.terminals) {
|
|
8703
|
+
if (terminal2.worktreeId && connectedStatuses.has(terminal2.status.toLowerCase()) && terminal2.lastOutputAt === null && !terminal2.preview.trim()) anomalies.push({ id: "connected-without-output", severity: "warning", issue: null, message: `terminal ${terminal2.handle} is connected but has not emitted output`, evidence: { handle: terminal2.handle, worktreeId: terminal2.worktreeId, status: terminal2.status } });
|
|
8704
|
+
}
|
|
8705
|
+
for (const worktree of input.finalizedDirtyWorktrees) anomalies.push({ id: "finalized-dirty-worktree", severity: "action_required", issue: worktree.issue, message: `finalized worktree ${worktree.worktreeId} still has ${worktree.files} uncommitted file(s)`, evidence: { ...worktree } });
|
|
8706
|
+
const latestDispatch = input.events.filter((event2) => event2.type === "worker.dispatched").map((event2) => Date.parse(event2.at)).filter(Number.isFinite).sort((a, b) => b - a)[0];
|
|
8707
|
+
const quietForMin = latestDispatch === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, Math.round((Date.parse(input.generatedAt) - latestDispatch) / 6e4));
|
|
8708
|
+
if (input.queueReady > 0 && input.freeSlots > 0 && quietForMin >= 15) anomalies.push({ id: "queue-ready-no-dispatch", severity: "action_required", issue: null, message: `${input.queueReady} ready issue(s) and ${input.freeSlots} free slot(s), but no dispatch in ${Number.isFinite(quietForMin) ? `${quietForMin} min` : "the observation window"}`, evidence: { queueReady: input.queueReady, freeSlots: input.freeSlots, quietForMin } });
|
|
8709
|
+
for (const row of input.issues) {
|
|
8710
|
+
if (row.heldFor || !stalledPhases.has(row.phase) || row.ageMin === null || row.ageMin < input.workerIdleTimeoutMin) continue;
|
|
8711
|
+
anomalies.push({ id: "stalled-delivery", severity: "action_required", issue: row.issue, message: `${row.issue} is in ${row.phase} for ${row.ageMin} min (threshold ${input.workerIdleTimeoutMin} min)`, evidence: { issue: row.issue, phase: row.phase, ageMin: row.ageMin, thresholdMin: input.workerIdleTimeoutMin } });
|
|
8712
|
+
}
|
|
8713
|
+
const events = {};
|
|
8714
|
+
for (const event2 of input.events) events[event2.type] = (events[event2.type] ?? 0) + 1;
|
|
8715
|
+
const report = {
|
|
8716
|
+
status: anomalies.some((item) => item.severity === "action_required") ? "action_required" : "healthy",
|
|
8717
|
+
generatedAt: input.generatedAt,
|
|
8718
|
+
project: input.project,
|
|
8719
|
+
person: input.person,
|
|
8720
|
+
windowHours: input.windowHours,
|
|
8721
|
+
anomalies,
|
|
8722
|
+
metrics: {
|
|
8723
|
+
queueReady: input.queueReady,
|
|
8724
|
+
freeSlots: input.freeSlots,
|
|
8725
|
+
runningWorkers: input.runningWorkers,
|
|
8726
|
+
maxAgents: input.maxAgents,
|
|
8727
|
+
activeClaims: input.activeClaims,
|
|
8728
|
+
inFlight: input.issues.filter((row) => !heldRow(row)).length,
|
|
8729
|
+
held: input.issues.filter(heldRow).length,
|
|
8730
|
+
merged: input.merged,
|
|
8731
|
+
blocked: input.blocked,
|
|
8732
|
+
fixRounds: input.fixRounds,
|
|
8733
|
+
reviewFindings: input.reviewFindings,
|
|
8734
|
+
reviewIncomplete: input.reviewIncomplete,
|
|
8735
|
+
medianLeadTimeMin: input.medianLeadTimeMin,
|
|
8736
|
+
providerRemainingPercent: input.providerRemainingPercent,
|
|
8737
|
+
machine: input.machine,
|
|
8738
|
+
memory: input.memory,
|
|
8739
|
+
cache: input.cache,
|
|
8740
|
+
tokens: input.tokens,
|
|
8741
|
+
events
|
|
8742
|
+
}
|
|
8743
|
+
};
|
|
8744
|
+
return report;
|
|
8745
|
+
};
|
|
8746
|
+
var compactTerminal = (terminal2) => ({ handle: terminal2.handle, status: terminal2.status, worktreeId: terminal2.worktreeId, lastOutputAt: terminal2.lastOutputAt, preview: terminal2.preview });
|
|
8747
|
+
var dirtyFinalizedWorktrees = async (runner, worktrees) => {
|
|
8748
|
+
const out = [];
|
|
8749
|
+
for (const worktree of worktrees) {
|
|
8750
|
+
if (worktree.workspaceStatus.trim().toLowerCase() !== "completed" || !worktree.path) continue;
|
|
8751
|
+
try {
|
|
8752
|
+
const result = await runner.run(["git", "-C", worktree.path, "status", "--porcelain"], { timeoutMs: 1e4 });
|
|
8753
|
+
if (result.code === 0 && result.stdout.trim()) out.push({ worktreeId: worktree.id, issue: worktree.linkedLinearIssue, files: result.stdout.trim().split(/\r?\n/).length });
|
|
8754
|
+
} catch {
|
|
8755
|
+
}
|
|
8756
|
+
}
|
|
8757
|
+
return out;
|
|
8758
|
+
};
|
|
8759
|
+
var runObservability = async (input) => {
|
|
8760
|
+
const loaded = input.loaded ?? loadLoopConfig(input.configPath ?? "loop.config.yaml");
|
|
8761
|
+
const now4 = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
8762
|
+
const at = now4();
|
|
8763
|
+
const since = parseSince(input.since ?? "24h", at);
|
|
8764
|
+
const [doctor, debrief, worktrees, terminals] = await Promise.all([
|
|
8765
|
+
runLoopDoctor({ loaded, runner: input.runner, env: input.env, platform: input.platform, now: () => at, probe: false }),
|
|
8766
|
+
Promise.resolve(buildDebriefReport({ loaded, since: input.since ?? "24h", now: () => at })),
|
|
8767
|
+
orcaWorktrees(input.runner, { bin: loaded.config.orca.bin, timeoutMs: loaded.config.orca.timeoutMs }).catch(() => []),
|
|
8768
|
+
orcaTerminalList(input.runner, {}, { bin: loaded.config.orca.bin, timeoutMs: loaded.config.orca.timeoutMs }).catch(() => [])
|
|
8769
|
+
]);
|
|
8770
|
+
const events = readLoopEvents(loaded.stateDir).filter((event2) => Date.parse(event2.at) >= since.getTime() && Date.parse(event2.at) <= at.getTime());
|
|
8771
|
+
const ledger = createDispatchLedger(loaded.stateDir);
|
|
8772
|
+
const active = ledger.active();
|
|
8773
|
+
const missingDeliveryIssues = active.filter((lease) => !existsSync(deliveryStatePath(loaded.stateDir, lease.issue))).map((lease) => lease.issue);
|
|
8774
|
+
const records = listDispatched(loaded.stateDir);
|
|
8775
|
+
const completed = records.map((record3) => ({ record: record3, state: readDeliveryState(loaded.stateDir, record3.issue) })).filter(({ state }) => state.finishedAt && Date.parse(state.finishedAt) >= since.getTime());
|
|
8776
|
+
const leadTimes = completed.map(({ record: record3, state }) => state.finishedAt ? (Date.parse(state.finishedAt) - Date.parse(record3.dispatchedAt)) / 6e4 : null).filter((value) => value !== null && Number.isFinite(value)).sort((a, b) => a - b);
|
|
8777
|
+
const medianLeadTimeMin = leadTimes.length ? leadTimes.length % 2 ? leadTimes[Math.floor(leadTimes.length / 2)] : (leadTimes[leadTimes.length / 2 - 1] + leadTimes[leadTimes.length / 2]) / 2 : null;
|
|
8778
|
+
const providerRemainingPercent = Object.fromEntries(doctor.providers.map((provider) => [provider.id, remainingUsagePercent(provider.usage, loaded.config.models.routing.usageMetric)]));
|
|
8779
|
+
const cachedContracts = records.filter((record3) => existsSync(contractPath(loaded.stateDir, record3.issue))).length;
|
|
8780
|
+
const memoryEvents = events.filter((event2) => event2.type === "memory.recalled");
|
|
8781
|
+
const tokens = { input: sum(events, "inputTokens"), output: sum(events, "outputTokens"), total: sum(events, "totalTokens"), cacheRead: sum(events, "cacheReadTokens"), cacheWrite: sum(events, "cacheWriteTokens") };
|
|
8782
|
+
const machine = { cpuCount: doctor.machine.sample.cpus, load1PerCpuPercent: doctor.machine.sample.load1PerCpuPercent, memoryUsedPercent: doctor.machine.sample.memoryUsedPercent, freeRamGb: doctor.machine.freeRamGb };
|
|
8783
|
+
const snapshot = {
|
|
8784
|
+
generatedAt: at.toISOString(),
|
|
8785
|
+
project: doctor.config.project,
|
|
8786
|
+
person: doctor.config.person,
|
|
8787
|
+
windowHours: Math.max(1, Math.round((at.getTime() - since.getTime()) / 36e5)),
|
|
8788
|
+
workerIdleTimeoutMin: loaded.config.delivery.workerIdleTimeoutMin,
|
|
8789
|
+
queueReady: doctor.queue.count,
|
|
8790
|
+
freeSlots: doctor.machine.free,
|
|
8791
|
+
runningWorkers: doctor.workers.running,
|
|
8792
|
+
maxAgents: doctor.machine.maxAgents,
|
|
8793
|
+
activeClaims: active.length,
|
|
8794
|
+
missingDeliveryIssues,
|
|
8795
|
+
terminals: terminals.map(compactTerminal),
|
|
8796
|
+
finalizedDirtyWorktrees: await dirtyFinalizedWorktrees(input.runner, worktrees),
|
|
8797
|
+
issues: debrief.inFlight.map(({ issue, phase: phase2, ageMin, heldFor }) => ({ issue, phase: phase2, ageMin, heldFor })),
|
|
8798
|
+
events,
|
|
8799
|
+
merged: uniqueIssues(events, ["pr.merged", "worker.merged"]),
|
|
8800
|
+
blocked: Math.max(records.filter((record3) => readDeliveryState(loaded.stateDir, record3.issue).finalOutcome === "blocked").length, uniqueIssues(events, ["worker.blocked"])),
|
|
8801
|
+
fixRounds: records.reduce((total, record3) => total + readDeliveryState(loaded.stateDir, record3.issue).fixRounds, 0),
|
|
8802
|
+
reviewFindings: count2(events, "pr.reviewed") - count2(events.filter((event2) => event2["status"] !== "findings"), "pr.reviewed"),
|
|
8803
|
+
reviewIncomplete: events.filter((event2) => event2.type === "pr.reviewed" && event2["status"] === "incomplete").length,
|
|
8804
|
+
medianLeadTimeMin,
|
|
8805
|
+
providerRemainingPercent,
|
|
8806
|
+
machine,
|
|
8807
|
+
memory: { recalls: memoryEvents.length, hits: sum(memoryEvents, "hits"), approxCharsSaved: sum(memoryEvents, "approxCharsSaved") },
|
|
8808
|
+
cache: { cachedContracts },
|
|
8809
|
+
tokens
|
|
8810
|
+
};
|
|
8811
|
+
return assessObservability(snapshot);
|
|
8812
|
+
};
|
|
8813
|
+
var renderObservabilityMarkdown = (report) => {
|
|
8814
|
+
const m = report.metrics;
|
|
8815
|
+
const headroom = Object.entries(m.providerRemainingPercent).map(([provider, remaining]) => `${provider} ${remaining === null ? "?" : `${remaining}%`}`).join(", ");
|
|
8816
|
+
const lines = [`# Loop observability \u2014 ${report.project} \xB7 ${report.person}`, "", `_${report.status}_ \xB7 generated ${report.generatedAt.slice(0, 19)}Z \xB7 last ${report.windowHours}h`, "", "## Metrics", "", `- Queue: ${m.queueReady} ready \xB7 ${m.freeSlots} free slot(s) \xB7 ${m.runningWorkers}/${m.maxAgents} workers`, `- Delivery: ${m.inFlight} in flight \xB7 ${m.held} held \xB7 ${m.merged} merged \xB7 ${m.blocked} blocked \xB7 ${m.fixRounds} fix round(s)`, `- Reviews: ${m.reviewFindings} findings \xB7 ${m.reviewIncomplete} incomplete`, `- Machine: ${m.machine.cpuCount} CPU \xB7 ${m.machine.load1PerCpuPercent}% load \xB7 ${m.machine.memoryUsedPercent}% memory \xB7 ${m.machine.freeRamGb} GB free`, `- Providers: ${headroom || "n/a"}`, `- Memory/cache: ${m.memory.recalls} recall(s), ${m.memory.hits} hit(s), ${m.memory.approxCharsSaved} chars saved \xB7 ${m.cache.cachedContracts} cached contract(s)`, `- Tokens observed: ${m.tokens.total || m.tokens.input + m.tokens.output || "n/a"}`, ""];
|
|
8817
|
+
if (report.anomalies.length) {
|
|
8818
|
+
lines.push("## Anomalies", "");
|
|
8819
|
+
for (const anomaly of report.anomalies) lines.push(`- **${anomaly.severity}**${anomaly.issue ? ` \xB7 ${anomaly.issue}` : ""}: ${anomaly.message}`);
|
|
8820
|
+
lines.push("");
|
|
8821
|
+
} else lines.push("## Anomalies", "", "_None detected._", "");
|
|
8822
|
+
lines.push("_Read-only. Run `ak-harness loop tick` or `deliver` to act on the queue._");
|
|
8823
|
+
return lines.join("\n");
|
|
8824
|
+
};
|
|
8537
8825
|
|
|
8538
8826
|
// src/loop/watch.ts
|
|
8539
8827
|
var defaultSleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
@@ -8661,6 +8949,6 @@ var watchDeliveries = async (input) => {
|
|
|
8661
8949
|
};
|
|
8662
8950
|
var formatWatchEvent = (event2) => `${event2.kind}: ${event2.issue} \xB7 ${event2.message}`;
|
|
8663
8951
|
|
|
8664
|
-
export { AGENT_REGISTRY_SCHEMA_VERSION, ARTIFACT_SCHEMA_VERSION, ARTIFACT_TYPES, ASSURANCE_LEVELS, AgentRegistryEntrySchema, AgentRegistrySchema, BENCHMARK_SCHEMA_VERSION, BLOCK_STATUSES, CAPABILITY_KINDS, CAPABILITY_MANIFEST_SCHEMA_VERSION, COMPATIBILITY_COMPONENTS, COMPATIBILITY_SCHEMA_VERSION, CONTEXT_PROVIDER_SLOT, CONTRACT_CLOSE, CONTRACT_OPEN, CONTRACT_SCHEMA_VERSION, ContractOutcomeSchema, EVAL_COMPONENTS, EVAL_LAYERS, EVAL_MANIFEST_SCHEMA_VERSION, EVENT_LOG_GENESIS, EVIDENCE_BUNDLE_SCHEMA_VERSION, FileArtifactStore, FileEventStore, HARNESS_ERROR_CATALOG, HARNESS_ERROR_CODES, HARNESS_EVENT_ENVELOPE_SCHEMA_VERSION, HARNESS_EVENT_SCHEMA_VERSION, HARNESS_EVENT_TYPES, HARNESS_PLUGIN_API_VERSION, HARNESS_REPO_URL, HarnessError, IMPROVEMENT_CYCLE_STEPS, LEARNING_STATUSES, LEGAL_TRANSITIONS, LOOP_CONFIG_FILE, LOOP_CONFIG_SCHEMA_VERSION, LOOP_LOCAL_CONFIG_FILE, LOOP_STAGES, LoopConfigSchema, MEMORY_SCOPES, MODEL_ROLES, PHASE_DECISIONS, PHASE_EFFECTS, PHASE_EFFECT_ACTIONS, PHASE_MODES, PR_FIELDS, QUALITY_DIMENSIONS, REVIEW_SEVERITIES, STATES, TaskContractSchema, WIP_STATES, activeCooldowns, adaptiveConcurrency, advanceQueueOwner, appendLoopEvent, approveRun, approvedDecision, artifactDigest, artifactFilePath, artifactIsFresh, artifactMarkdownPath, assertHuman, assessAcceptance, assessAgentEval, assessBlock, assessChecks, assessCompatibility, assessContract, assessDiscovery, assessImprovementCycle, assessIntegration, assessPilot, assessPreflight, assessProduction, assessQaTransition, assessSlots, assessWip, assessWorktreeCleanup, atLeast, authStatusFor, authorizeRun, automationName, automationPrompt, automationSpecs, availableMemoryBytes, benchmarkRuns, branchFor, briefPath, buildDebriefReport, buildListIssuesArgv, buildRetroReport, buildReviewArgv, buildSuggestions, busyIssues, cancelRun, classifyFailure, classifyHarnessError, classifyProviderFailure, classifyWatchEvent, classifyWatchPhase, cleanTaskArtifacts, clearIssueFailures, clearProviderCooldown, compareOptimization, compareVersions, composePullRequest, contractIsFresh, contractPath, cooldownPath, cooldownUntil, countRunningWorkers, createArgvRagContextProvider, createArtifactEnvelope, createCapabilityManifest, createCodingAgentAdapter, createCompatibilityManifest, createConfiguredToolRuntime, createDispatchLedger, createDocBridgeContextProvider, createDockerToolRuntime, createEvalManifest, createFileMemoryAdapter, createFileMemoryKvStore, createHarnessEventEnvelope, createInMemoryMemoryAdapter, createKvMemoryAdapter, createLinearTrackingAdapter, createLlmCache, createLlmCacheKey, createLoopEventBus, createMachineMonitor, createMcpToolBridge, createModelPolicy, createOrcaDispatchPlan, createOrcaLifecycleProjection, createPhaseArtifact, createPhaseProfile, createPluginRegistry, createPluginSlot, createPolicyGate, createProcessRunner, createProcessToolRuntime, createPullRequestApproval, createQualityMatrix, createRagContextProvider, createRichIO, createSessionRecorder, createStatusSnapshot, createToolRuntime, createTrackingAdapter, createTrackingTransition, deliveryStatePath, detectProviders, discoverIntake, dispatchRecordPath, evaluateWatchdog, executePhaseProfile, exportEvidenceBundle, extractResetsAt, fetchArtificialAnalysisModels, fetchLinearIssue, fetchLinearQueue, fetchTeamMembers, filterAndOrderQueue, findExecutable, formatWatchEvent, gatherLoopState, generateContract, githubComment, githubCommentArgv, githubCommentExists, githubLabelRemove, githubMerge, githubMergeArgv, githubOpenPullRequests, githubPullRequest, githubPullRequestsForBranch, hasLocalConfig, hashContextSnapshot, hashContextSnapshots, hashMcpArgs, inspectDocBridgeIndex, inspectEventLogLock, installLoopAutomations, installPreflight, intakeIssueId, intakePath, isDiscoveryCurrent, isIssuePaused, isStagePaused, isWsl, issueFailurePath, launchWorkerTerminal, learningToMemoryRecord, learningsPath, linearAttach, linearAttachArgv, linearCommentAdd, linearCommentAddArgv, linearLabelAdd, linearLabelArgv, linearLabelRemove, linearStatusSet, linearStatusSetArgv, listCliModels, listDispatched, listIntake, listPausedIssues, loadAgentRegistry, loadAliases, loadBenchmarkManifest, loadBuiltinCatalog, loadConfig, loadLatestRun, loadLoopConfig, loadLoopPlugins, loadPinnedSkills, localConfigPath, loopStatus, markProviderExhausted, memoryDigestOf, mergeLoopConfig, modelFor, normalizeReason, openLoopMemory, orcaAccountList, orcaAgentHooks, orcaAutomationCreateArgv, orcaAutomationEditArgv, orcaAutomationRemove, orcaAutomationRun, orcaAutomationRuns, orcaAutomationsList, orcaJson, orcaStatus, orcaTerminalCreate, orcaTerminalList, orcaTerminalScreen, orcaTerminalSend, orcaTerminalWait, orcaVersion, orcaWorktreeCreate, orcaWorktreeRemove, orcaWorktreeSet, orcaWorktreeSetArgv, orcaWorktrees, parseAgentRegistryText, parseArtificialAnalysisPayload, parseAutomationRuns, parseContractOutput, parseGrokModelsOutput, parseJsonEnvelope, parseLinearIssueDetail, parseLinearIssues, parseLoopConfigText, parseMemInfo, parseModelRef, parseOrcaAgentHooks, parseOrcaAutomations, parseOrcaSendReceipt, parseOrcaStatus, parseOrcaTerminals, parseOrcaVersion, parseOrcaWorktreeCreate, parseOrcaWorktrees, parseProviderUsage, parsePullRequest, parseRagQueryOutput, parseRetro, parseReviewResult, parseSince, parseTeamMembers, parseUsageWindows, parseVmStat, pauseIssue, planFilePreflight, planMemoryContext, planPhaseProfile, planRun, precheckCommand, precheckDeliver, precheckTick, preferMemoryOverDocBridge, promoteLearnings, promoteLearningsToMemory, promptLocalConfig, providerIdentity, providerSpecs, queueOwner, rankModels, readAaCache, readArtifactFile, readContextSnapshots, readCooldowns, readDeliveryState, readDispatchRecord, readEvidenceTrustStore, readIntake, readIssueFailures, readLearningsLedger, readLoopEvents, readOutcomeProgress, readStagePause, readStoredContract, reconcileRun, recordBenchmarkObservation, recordIssueFailure, recordStageRunResult, recoverEventLogLock, recoveryDelayMs, remainingUsagePercent, renderArtifactMarkdown, renderContractPrompt, renderDebriefMarkdown, renderFindingsForWorker, renderHandoffBrief, renderHeadlessArgv, renderLocalConfig, renderPinnedSkills, renderRetroMarkdown, renderTuiCommand, renderWorkerBrief, resolveAgentForRole, resolveAlias, resolveCatalogCandidates, resolveDocContext, resumeIssue, resumeStage, resumeStateFromArtifacts, retroLearnings, retryRun, rotationStatePath, routeAllRoles, runAdversarialReview, runAgentEval, runCodeReview, runDeliver, runEvalBattery, runGuidedInstall, runLoopDoctor, runRetroStage, runTick, runWithRecovery, runWorkflow, sampleMachine, scanForPii, selectMemoryForPrompt, selectModel, selectRuntime, severityRank, shellQuote, skillDigest, skillRefs, snapshotWatchTargets, stageEntry, stagePausePath, startRun, summarizeMachine, tiersFor, touchesProtectedPaths, transition, undeclaredOrcaProviders, uninstallLoopAutomations, unknownTelemetry, untrusted, upsertProposedLearnings, usageRankTuple, validateAdapterMetadata, validateArtifactEnvelope, validateBenchmarkManifest, validateBlockManifest, validateCacheableOperation, validateCapabilityManifest, validateCompatibilityManifest, validateConfig, validateContextSnapshot, validateContextSnapshots, validateEvalManifest, validateHarnessErrorClassification, validateHarnessEventEnvelope, validateLoopConfig, validateMemoryRecord, validateOptimizationObservation, validatePhaseTelemetry, validateSafeCommand, validateStatusSnapshot, verifyEvidenceBundle, verifyPullRequestApproval, verifyRun, watchDeliveries, worktreeNameFor, writeAaCache, writeDispatchRecord, writeIdFor, writeLearningsLedger, writeLocalConfig, writeStoredContract };
|
|
8952
|
+
export { AGENT_REGISTRY_SCHEMA_VERSION, ARTIFACT_SCHEMA_VERSION, ARTIFACT_TYPES, ASSURANCE_LEVELS, AgentRegistryEntrySchema, AgentRegistrySchema, BENCHMARK_SCHEMA_VERSION, BLOCK_STATUSES, CAPABILITY_KINDS, CAPABILITY_MANIFEST_SCHEMA_VERSION, COMPATIBILITY_COMPONENTS, COMPATIBILITY_SCHEMA_VERSION, CONTEXT_PROVIDER_SLOT, CONTRACT_CLOSE, CONTRACT_OPEN, CONTRACT_SCHEMA_VERSION, ContractOutcomeSchema, EVAL_COMPONENTS, EVAL_LAYERS, EVAL_MANIFEST_SCHEMA_VERSION, EVENT_LOG_GENESIS, EVIDENCE_BUNDLE_SCHEMA_VERSION, FileArtifactStore, FileEventStore, HARNESS_ERROR_CATALOG, HARNESS_ERROR_CODES, HARNESS_EVENT_ENVELOPE_SCHEMA_VERSION, HARNESS_EVENT_SCHEMA_VERSION, HARNESS_EVENT_TYPES, HARNESS_PLUGIN_API_VERSION, HARNESS_REPO_URL, HarnessError, IMPROVEMENT_CYCLE_STEPS, LEARNING_STATUSES, LEGAL_TRANSITIONS, LOOP_CONFIG_FILE, LOOP_CONFIG_SCHEMA_VERSION, LOOP_LOCAL_CONFIG_FILE, LOOP_STAGES, LoopConfigSchema, MEMORY_SCOPES, MODEL_ROLES, PHASE_DECISIONS, PHASE_EFFECTS, PHASE_EFFECT_ACTIONS, PHASE_MODES, PR_FIELDS, QUALITY_DIMENSIONS, REVIEW_SEVERITIES, STATES, TaskContractSchema, WIP_STATES, activeCooldowns, adaptiveConcurrency, advanceQueueOwner, appendLoopEvent, approveRun, approvedDecision, artifactDigest, artifactFilePath, artifactIsFresh, artifactMarkdownPath, assertHuman, assessAcceptance, assessAgentEval, assessBlock, assessChecks, assessCompatibility, assessContract, assessDiscovery, assessImprovementCycle, assessIntegration, assessObservability, assessPilot, assessPreflight, assessProduction, assessQaTransition, assessSlots, assessWip, assessWorktreeCleanup, atLeast, authStatusFor, authorizeRun, automationName, automationPrompt, automationSpecs, availableMemoryBytes, benchmarkRuns, branchFor, briefPath, buildDebriefReport, buildListIssuesArgv, buildRetroReport, buildReviewArgv, buildSuggestions, busyIssues, cancelRun, classifyFailure, classifyHarnessError, classifyProviderFailure, classifyWatchEvent, classifyWatchPhase, cleanTaskArtifacts, clearIssueFailures, clearProviderCooldown, compareOptimization, compareVersions, composePullRequest, contractIsFresh, contractPath, cooldownPath, cooldownUntil, countRotationBlockingLeases, countRunningWorkers, createArgvRagContextProvider, createArtifactEnvelope, createCapabilityManifest, createCodingAgentAdapter, createCompatibilityManifest, createConfiguredToolRuntime, createDispatchLedger, createDocBridgeContextProvider, createDockerToolRuntime, createEvalManifest, createFileMemoryAdapter, createFileMemoryKvStore, createHarnessEventEnvelope, createInMemoryMemoryAdapter, createKvMemoryAdapter, createLinearTrackingAdapter, createLlmCache, createLlmCacheKey, createLoopEventBus, createMachineMonitor, createMcpToolBridge, createModelPolicy, createOrcaDispatchPlan, createOrcaLifecycleProjection, createPhaseArtifact, createPhaseProfile, createPluginRegistry, createPluginSlot, createPolicyGate, createProcessRunner, createProcessToolRuntime, createPullRequestApproval, createQualityMatrix, createRagContextProvider, createRichIO, createSessionRecorder, createStatusSnapshot, createToolRuntime, createTrackingAdapter, createTrackingTransition, deliveryStatePath, detectProviders, discoverIntake, dispatchRecordPath, evaluateWatchdog, executePhaseProfile, exportEvidenceBundle, extractResetsAt, fetchArtificialAnalysisModels, fetchLinearIssue, fetchLinearQueue, fetchTeamMembers, filterAndOrderQueue, findExecutable, formatWatchEvent, gatherLoopState, generateContract, githubComment, githubCommentArgv, githubCommentExists, githubLabelRemove, githubMerge, githubMergeArgv, githubOpenPullRequests, githubPullRequest, githubPullRequestsForBranch, hasLocalConfig, hashContextSnapshot, hashContextSnapshots, hashMcpArgs, inspectDocBridgeIndex, inspectEventLogLock, installLoopAutomations, installPreflight, intakeIssueId, intakePath, isDiscoveryCurrent, isIssuePaused, isStagePaused, isWsl, issueFailurePath, launchWorkerTerminal, learningToMemoryRecord, learningsPath, linearAttach, linearAttachArgv, linearCommentAdd, linearCommentAddArgv, linearLabelAdd, linearLabelArgv, linearLabelRemove, linearStatusSet, linearStatusSetArgv, listCliModels, listCliModelsCached, listDispatched, listIntake, listPausedIssues, loadAgentRegistry, loadAliases, loadBenchmarkManifest, loadBuiltinCatalog, loadConfig, loadLatestRun, loadLoopConfig, loadLoopPlugins, loadPinnedSkills, localConfigPath, loopStatus, markProviderExhausted, memoryDigestOf, mergeLoopConfig, modelFor, normalizeReason, openLoopMemory, orcaAccountList, orcaAgentHooks, orcaAutomationCreateArgv, orcaAutomationEditArgv, orcaAutomationRemove, orcaAutomationRun, orcaAutomationRuns, orcaAutomationsList, orcaDiagnosticsMemory, orcaJson, orcaStatus, orcaTerminalCreate, orcaTerminalList, orcaTerminalScreen, orcaTerminalSend, orcaTerminalWait, orcaVersion, orcaWorktreeCreate, orcaWorktreeRemove, orcaWorktreeSet, orcaWorktreeSetArgv, orcaWorktrees, parseAgentRegistryText, parseArtificialAnalysisPayload, parseAutomationRuns, parseContractOutput, parseGrokModelsOutput, parseJsonEnvelope, parseLinearIssueDetail, parseLinearIssues, parseLoopConfigText, parseMemInfo, parseModelRef, parseOrcaAgentHooks, parseOrcaAutomations, parseOrcaSendReceipt, parseOrcaStatus, parseOrcaTerminals, parseOrcaVersion, parseOrcaWorktreeCreate, parseOrcaWorktrees, parseProviderUsage, parsePullRequest, parseRagQueryOutput, parseRetro, parseReviewResult, parseSince, parseTeamMembers, parseUsageWindows, parseVmStat, pauseIssue, planFilePreflight, planMemoryContext, planPhaseProfile, planRun, precheckCommand, precheckDeliver, precheckTick, preferMemoryOverDocBridge, promoteLearnings, promoteLearningsToMemory, promptLocalConfig, providerIdentity, providerSpecs, queueOwner, rankModels, readAaCache, readArtifactFile, readCliModelsCache, readContextSnapshots, readCooldowns, readDeliveryState, readDispatchRecord, readEvidenceTrustStore, readIntake, readIssueFailures, readLearningsLedger, readLoopEvents, readOutcomeProgress, readStagePause, readStoredContract, reconcileRun, recordBenchmarkObservation, recordIssueFailure, recordStageRunResult, recoverEventLogLock, recoveryDelayMs, remainingUsagePercent, renderArtifactMarkdown, renderContractPrompt, renderDebriefMarkdown, renderFindingsForWorker, renderHandoffBrief, renderHeadlessArgv, renderLocalConfig, renderObservabilityMarkdown, renderPinnedSkills, renderRetroMarkdown, renderTuiCommand, renderWorkerBrief, resolveAgentForRole, resolveAlias, resolveCatalogCandidates, resolveDocContext, resumeIssue, resumeStage, resumeStateFromArtifacts, retroLearnings, retryRun, rotationStatePath, routeAllRoles, runAdversarialReview, runAgentEval, runCodeReview, runDeliver, runEvalBattery, runGuidedInstall, runLoopDoctor, runObservability, runRetroStage, runTick, runWithRecovery, runWorkflow, sampleMachine, scanForPii, selectMemoryForPrompt, selectModel, selectRuntime, severityRank, shellQuote, skillDigest, skillRefs, snapshotWatchTargets, stageEntry, stagePausePath, startRun, summarizeMachine, tiersFor, touchesProtectedPaths, transition, undeclaredOrcaProviders, uninstallLoopAutomations, unknownTelemetry, untrusted, upsertProposedLearnings, usageRankTuple, validateAdapterMetadata, validateArtifactEnvelope, validateBenchmarkManifest, validateBlockManifest, validateCacheableOperation, validateCapabilityManifest, validateCompatibilityManifest, validateConfig, validateContextSnapshot, validateContextSnapshots, validateEvalManifest, validateHarnessErrorClassification, validateHarnessEventEnvelope, validateLoopConfig, validateMemoryRecord, validateOptimizationObservation, validatePhaseTelemetry, validateSafeCommand, validateStatusSnapshot, verifyEvidenceBundle, verifyPullRequestApproval, verifyRun, watchDeliveries, worktreeNameFor, writeAaCache, writeCliModelsCache, writeDispatchRecord, writeIdFor, writeLearningsLedger, writeLocalConfig, writeStoredContract };
|
|
8665
8953
|
//# sourceMappingURL=index.js.map
|
|
8666
8954
|
//# sourceMappingURL=index.js.map
|