@agentskit/harness 0.10.0 → 0.11.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/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().toLowerCase();
1239
- const scopes = query.scope?.map((scope) => scope.toLowerCase()) ?? [];
1246
+ const needle = query.query.trim();
1247
+ if (!needle) return 0;
1240
1248
  const value = text(entry);
1241
- return Boolean(needle && value.includes(needle) && (scopes.length === 0 || scopes.some((scope) => value.includes(scope))));
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.0.0",
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 entries = Array.isArray(document.knowledge) ? document.knowledge.filter((value) => typeof value === "object" && value !== null && !Array.isArray(value)).filter((entry) => matches(entry, query)).sort((left, right) => String(left.id ?? "").localeCompare(String(right.id ?? ""))).slice(0, 8) : [];
1264
- const references = entries.flatMap((entry) => 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: 1 }] : []);
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 score = (value, label) => {
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 : score(candidate["baselineScore"], `cases[${index2}].baselineScore`);
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: score(thresholds2["subjectiveQuality"] ?? 80, "thresholds.subjectiveQuality"), maxRegression: score(thresholds2["maxRegression"] ?? 5, "thresholds.maxRegression") },
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 ids = await store.get(indexKey);
2270
- const records = Array.isArray(ids) ? await Promise.all(ids.filter((id2) => typeof id2 === "string").map((id2) => store.get(`agentskit-harness:memory:${id2}`))) : [];
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((sum, value) => sum + value, 0) / values.length).toFixed(2)) : null;
2712
- var score2 = (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 });
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((sum, phase2) => sum + (phase2.durationMs ?? 0), 0) : void 0;
2716
- const totalTokens = phases.every((phase2) => phase2.tokens?.inputTokens !== void 0 && phase2.tokens.outputTokens !== void 0) ? phases.reduce((sum, phase2) => sum + (phase2.tokens?.inputTokens ?? 0) + (phase2.tokens?.outputTokens ?? 0), 0) : void 0;
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 = score2(average(current.map((phase2) => phase2.evidenceCoverage === void 0 ? 0 : phase2.evidenceCoverage * 100)), "mean evidence coverage");
2733
- const completeness = score2(current.length ? current.filter((phase2) => phase2.outcome === "pass").length / current.length * 100 : null, "passed phases / total phases");
2734
- const speed = score2(currentDurations.length && priorDurations.length ? average(priorDurations) / Math.max(1, average(currentDurations)) * 100 : null, "baseline duration / current duration", 100);
2735
- const cost = score2(currentTokens.length && priorTokens.length ? average(priorTokens) / Math.max(1, average(currentTokens)) * 100 : null, "baseline tokens / current tokens", 100);
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 = score2(average(resourceValues), "100 - max(cpu%, memory%)");
2738
- const reliability = score2(current.length ? current.filter((phase2) => phase2.outcome === "pass").length / current.length * 100 : null, "passed phases / total phases");
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 = score2(average(measured), "mean of measured dimensions");
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 };
@@ -4236,10 +4282,16 @@ var orcaTerminalCreate = async (runner, input, options = {}) => {
4236
4282
  };
4237
4283
  var parseOrcaSendReceipt = (result) => {
4238
4284
  const record3 = isRecord8(result) ? result : {};
4239
- const receipt = isRecord8(record3["receipt"]) ? record3["receipt"] : record3;
4240
- const stages = Array.isArray(receipt["stages"]) ? receipt["stages"].map((stage) => isRecord8(stage) ? str(stage["stage"], str(stage["name"])) : str(stage)).filter(Boolean) : [];
4241
- const accepted = receipt["accepted"] === false ? false : receipt["accepted"] === true || stages.includes("input_accepted") || (result === null || result === void 0 || Object.keys(record3).length === 0);
4242
- return { accepted, requestId: str(receipt["requestId"], str(record3["requestId"])) || null, stages, warnings: Array.isArray(record3["warnings"]) ? record3["warnings"].map((warning) => isRecord8(warning) ? str(warning["message"], JSON.stringify(warning)) : str(warning)) : [] };
4285
+ const send = isRecord8(record3["send"]) ? record3["send"] : null;
4286
+ const prompt = send && isRecord8(send["prompt"]) ? send["prompt"] : null;
4287
+ const receipt = isRecord8(record3["receipt"]) ? record3["receipt"] : send ?? record3;
4288
+ const rawStages = Array.isArray(receipt["stages"]) ? receipt["stages"] : prompt && Array.isArray(prompt["stages"]) ? prompt["stages"] : [];
4289
+ const stages = rawStages.map((stage) => isRecord8(stage) ? str(stage["stage"], str(stage["name"])) : str(stage)).filter(Boolean);
4290
+ const inputAccepted = stages.some((stage) => ["input_accepted", "input_queued", "prompt_accepted", "queued"].includes(stage.toLowerCase()));
4291
+ const acceptedValue = receipt["accepted"] ?? send?.["accepted"];
4292
+ const accepted = inputAccepted || acceptedValue === true || acceptedValue !== false && (result === null || result === void 0 || Object.keys(record3).length === 0);
4293
+ const warnings = Array.isArray(record3["warnings"]) ? record3["warnings"] : send && Array.isArray(send["warnings"]) ? send["warnings"] : [];
4294
+ 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
4295
  };
4244
4296
  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
4297
  var orcaTerminalWait = async (runner, input, options = {}) => {
@@ -4499,6 +4551,8 @@ var LoopConfigSchema = z.object({
4499
4551
  }).prefault({}),
4500
4552
  catalog: z.object({
4501
4553
  sources: z.array(z.enum(["cli", "artificial-analysis", "builtin"])).default(["cli", "builtin"]),
4554
+ /** 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. */
4555
+ cliCacheHours: z.number().positive().default(6),
4502
4556
  artificialAnalysis: z.object({
4503
4557
  enabled: z.boolean().default(false),
4504
4558
  apiKeyEnv: nonEmpty5.default("ARTIFICIAL_ANALYSIS_API_KEY"),
@@ -5069,7 +5123,12 @@ var selectModel = (config, role, availability, extraCandidates = []) => {
5069
5123
  var routeAllRoles = (config, availability, extrasByRole = {}) => Object.fromEntries(MODEL_ROLES.map((role) => [role, selectModel(config, role, availability, extrasByRole[role] ?? [])]));
5070
5124
  var rankModels = (config, role, availability, extraCandidates = []) => {
5071
5125
  const byId = new Map(availability.map((item) => [item.id, item]));
5072
- const { ranked } = availableFromTiers(config, role, availability);
5126
+ const { ranked, skipped } = availableFromTiers(config, role, availability);
5127
+ if (config.models.routing.pin[role]) {
5128
+ const pinned = applyPin(config, role, availability, skipped);
5129
+ if (pinned) return [pinned, ...ranked.filter((item) => !(item.provider === pinned.provider && item.model === pinned.model))];
5130
+ if (config.models.routing.pinStrict) return [];
5131
+ }
5073
5132
  const extras = [];
5074
5133
  let extraIndex = 1e4;
5075
5134
  for (const ref of extraCandidates) {
@@ -5190,6 +5249,32 @@ ${outcome.stderr}`);
5190
5249
  }
5191
5250
  return [];
5192
5251
  };
5252
+ var cliModelsCachePath = (stateDir, provider) => join(stateDir, "catalog", `cli-${provider}.json`);
5253
+ var readCliModelsCache = (stateDir, provider) => {
5254
+ const path = cliModelsCachePath(stateDir, provider);
5255
+ if (!existsSync(path)) return null;
5256
+ try {
5257
+ const raw = readJson2(path);
5258
+ return typeof raw.fetchedAt === "string" && Array.isArray(raw.ids) ? { fetchedAt: raw.fetchedAt, ids: raw.ids } : null;
5259
+ } catch {
5260
+ return null;
5261
+ }
5262
+ };
5263
+ var writeCliModelsCache = (stateDir, provider, ids, now4 = /* @__PURE__ */ new Date()) => {
5264
+ const path = cliModelsCachePath(stateDir, provider);
5265
+ mkdirSync(dirname(path), { recursive: true });
5266
+ const tmp = `${path}.${process.pid}.tmp`;
5267
+ writeFileSync(tmp, `${JSON.stringify({ fetchedAt: now4.toISOString(), ids }, null, 2)}
5268
+ `, "utf8");
5269
+ renameSync(tmp, path);
5270
+ };
5271
+ var listCliModelsCached = async (provider, bin, runner, stateDir, cacheHours, now4 = () => /* @__PURE__ */ new Date()) => {
5272
+ const cached = readCliModelsCache(stateDir, provider);
5273
+ if (cached && now4().getTime() - Date.parse(cached.fetchedAt) <= cacheHours * 36e5) return cached.ids;
5274
+ const ids = await listCliModels(provider, bin, runner);
5275
+ if (ids.length) writeCliModelsCache(stateDir, provider, ids, now4());
5276
+ return ids.length ? ids : cached?.ids ?? [];
5277
+ };
5193
5278
  var parseArtificialAnalysisPayload = (payload) => {
5194
5279
  const root = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
5195
5280
  const data = Array.isArray(root["data"]) ? root["data"] : Array.isArray(payload) ? payload : [];
@@ -5274,7 +5359,7 @@ var resolveCatalogCandidates = async (input) => {
5274
5359
  const settings = config.models.providers[provider];
5275
5360
  if (settings) {
5276
5361
  try {
5277
- const ids = await listCliModels(provider, settings.bin, input.runner);
5362
+ 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
5363
  for (const id2 of ids) {
5279
5364
  const resolved = resolveAlias(provider, id2, aliases);
5280
5365
  const existing = builtin[provider]?.models.find((model) => model.id === resolved);
@@ -5306,9 +5391,9 @@ var resolveCatalogCandidates = async (input) => {
5306
5391
  const matches2 = models.models.filter((model) => model.creatorSlug === creator || model.creatorSlug.includes(creator));
5307
5392
  for (const model of matches2) {
5308
5393
  const id2 = resolveAlias(provider, model.slug, aliases);
5309
- const score3 = model.codingIndex ?? model.intelligenceIndex ?? 50;
5310
- const quality = score3 >= 80 ? "frontier" : score3 >= 60 ? "balanced" : "fast";
5311
- push(provider, { id: id2, quality, codingScore: score3, source: "artificial-analysis", creator });
5394
+ const score4 = model.codingIndex ?? model.intelligenceIndex ?? 50;
5395
+ const quality = score4 >= 80 ? "frontier" : score4 >= 60 ? "balanced" : "fast";
5396
+ push(provider, { id: id2, quality, codingScore: score4, source: "artificial-analysis", creator });
5312
5397
  }
5313
5398
  }
5314
5399
  }
@@ -5366,6 +5451,16 @@ var clearProviderCooldown = (stateDir, provider) => {
5366
5451
  writeCooldowns(stateDir, rest);
5367
5452
  };
5368
5453
  var rotationStatePath = (stateDir) => join(stateDir, "queue-owner.json");
5454
+ var countRotationBlockingLeases = (loaded, leases) => leases.filter((lease) => {
5455
+ const path = join(loaded.stateDir, "issues", lease.issue, "delivery.json");
5456
+ if (!existsSync(path)) return true;
5457
+ try {
5458
+ const delivery = JSON.parse(readFileSync(path, "utf8"));
5459
+ return delivery.prNumber == null && !delivery.heldFor && !delivery.finalOutcome;
5460
+ } catch {
5461
+ return true;
5462
+ }
5463
+ }).length;
5369
5464
  var queueOwner = (loaded) => {
5370
5465
  const { rotation } = loaded.config.linear;
5371
5466
  if (!rotation.enabled || !rotation.owners.length) return loaded.config.linear.person;
@@ -5860,10 +5955,10 @@ var planMemoryContext = async (input) => {
5860
5955
  hits = [];
5861
5956
  }
5862
5957
  const selected = selectMemoryForPrompt(hits, memory);
5863
- const beforeChars = input.references.reduce((sum, ref) => sum + JSON.stringify(ref).length, 0) + issueBudgetDefault;
5958
+ const beforeChars = input.references.reduce((sum2, ref) => sum2 + JSON.stringify(ref).length, 0) + issueBudgetDefault;
5864
5959
  const preferred = memory.preferOverDocBridge ? preferMemoryOverDocBridge(input.references, selected.hits, memory.minDocBridgeWhenMemory) : { references: input.references};
5865
5960
  const issueCharBudget = selected.hits.length && memory.shrinkIssueCharsWhenMemory ? Math.min(issueBudgetDefault, memory.issueCharsWithMemory) : issueBudgetDefault;
5866
- const afterChars = preferred.references.reduce((sum, ref) => sum + JSON.stringify(ref).length, 0) + issueCharBudget + selected.approxChars;
5961
+ const afterChars = preferred.references.reduce((sum2, ref) => sum2 + JSON.stringify(ref).length, 0) + issueCharBudget + selected.approxChars;
5867
5962
  return {
5868
5963
  hits: selected.hits,
5869
5964
  references: preferred.references,
@@ -6420,9 +6515,14 @@ var writeDispatchRecord = (stateDir, record3) => {
6420
6515
  writeJson2(path, record3);
6421
6516
  return path;
6422
6517
  };
6423
- var appendLoopEvent = (stateDir, event2, bus) => {
6518
+ var EVENTS_ROTATE_AT_BYTES = 10 * 1024 * 1024;
6519
+ var appendLoopEvent = (stateDir, event2, bus, now4 = () => /* @__PURE__ */ new Date()) => {
6424
6520
  const path = join(stateDir, "events.ndjson");
6425
6521
  mkdirSync(dirname(path), { recursive: true });
6522
+ try {
6523
+ if (statSync(path).size > EVENTS_ROTATE_AT_BYTES) renameSync(path, join(stateDir, `events-archive-${now4().getTime()}.ndjson`));
6524
+ } catch {
6525
+ }
6426
6526
  appendFileSync(path, `${JSON.stringify(event2)}
6427
6527
  `, "utf8");
6428
6528
  if (bus && typeof event2["type"] === "string") bus.emit(event2);
@@ -6454,7 +6554,7 @@ var gatherLoopState = async (input) => {
6454
6554
  const leases = input.ledger.active();
6455
6555
  const busy = busyIssues(queue, leases, worktrees, person);
6456
6556
  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 };
6557
+ return { person, providers, routing, worktrees, slots, queue, leases, busy, candidates, extrasByRole };
6458
6558
  };
6459
6559
  var precheckTick = async (input) => {
6460
6560
  const loaded = input.loaded ?? loadLoopConfig(input.configPath);
@@ -6495,16 +6595,7 @@ var runTick = async (input) => {
6495
6595
  }
6496
6596
  const state = await gatherLoopState({ loaded, runner: input.runner, ledger, env: input.env, platform: input.platform, now: now4, onlyIssue: input.onlyIssue, machine: input.machine });
6497
6597
  const orchestrator = state.routing["orchestrator"] ?? { role: "orchestrator", selected: null, skipped: [] };
6498
- const orchestratorExtras = config.models.routing.mode === "catalog" ? await resolveCatalogCandidates({
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);
6598
+ const orchestratorCandidates = rankModels(config, "orchestrator", state.providers, state.extrasByRole["orchestrator"] ?? []);
6508
6599
  const onProviderFailure = (failure) => {
6509
6600
  if (dryRun) return;
6510
6601
  const resetsAt = extractResetsAt(failure.detail, now4());
@@ -6524,7 +6615,7 @@ var runTick = async (input) => {
6524
6615
  return { ...base, status: "idle", results, notes };
6525
6616
  }
6526
6617
  if (!state.candidates.length) {
6527
- const rotation = dryRun ? { owner: state.person, advanced: false } : advanceQueueOwner(loaded, { queueEmpty: state.queue.length === 0, activeLeases: state.leases.length, now: now4() });
6618
+ const rotation = dryRun ? { owner: state.person, advanced: false } : advanceQueueOwner(loaded, { queueEmpty: state.queue.length === 0, activeLeases: countRotationBlockingLeases(loaded, state.leases), now: now4() });
6528
6619
  if (rotation.advanced) notes.push(`queue drained for ${state.person}; switched to ${rotation.owner}`);
6529
6620
  else notes.push("queue has no dispatchable candidate");
6530
6621
  return { ...base, status: "idle", results, notes };
@@ -6557,17 +6648,32 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
6557
6648
  appendLoopEvent(loaded.stateDir, { at: now4().toISOString(), type: "issue.paused", issue, kind, consecutive: failureState.consecutive, reason }, bus);
6558
6649
  await bus.runHook("onPause", { issue, kind, consecutive: failureState.consecutive, reason });
6559
6650
  };
6651
+ let pinnedSkillsOnce;
6652
+ const getPinnedSkills = () => {
6653
+ if (pinnedSkillsOnce === void 0) {
6654
+ try {
6655
+ pinnedSkillsOnce = loadPinnedSkills(loaded.root, config.brief.skills, config.brief.maxSkillChars);
6656
+ } catch (error) {
6657
+ pinnedSkillsOnce = { error };
6658
+ throw error;
6659
+ }
6660
+ }
6661
+ if ("error" in pinnedSkillsOnce) throw pinnedSkillsOnce.error;
6662
+ return pinnedSkillsOnce;
6663
+ };
6560
6664
  let dispatched = 0;
6561
6665
  for (const candidate of state.candidates) {
6562
6666
  if (dispatched >= budget) break;
6563
6667
  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
- if (remainingMs() < config.contract.timeoutMs + setupBudgetMs + 12e4 && !readStoredContract(loaded.stateDir, candidate.identifier)) {
6668
+ const cachedContract = readStoredContract(loaded.stateDir, candidate.identifier);
6669
+ if (remainingMs() < config.contract.timeoutMs + setupBudgetMs + 12e4 && !cachedContract) {
6565
6670
  notes.push(`time budget: ${candidate.identifier} left for the next tick (${Math.round(remainingMs() / 1e3)}s remaining)`);
6566
6671
  continue;
6567
6672
  }
6568
- if (isIssuePaused(loaded.stateDir, candidate.identifier)) {
6673
+ const failureState = readIssueFailures(loaded.stateDir, candidate.identifier);
6674
+ if (failureState.pausedAt !== null) {
6569
6675
  if (candidate.labels.includes(config.resilience.pausedLabel)) {
6570
- results.push({ issue: candidate.identifier, outcome: "skipped", reason: `paused after ${readIssueFailures(loaded.stateDir, candidate.identifier).consecutive} consecutive failures; remove the "${config.resilience.pausedLabel}" label or run "ak-harness loop resume ${candidate.identifier}" to retry` });
6676
+ 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
6677
  continue;
6572
6678
  }
6573
6679
  if (!dryRun) clearIssueFailures(loaded.stateDir, candidate.identifier);
@@ -6580,8 +6686,8 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
6580
6686
  results.push({ issue: candidate.identifier, outcome: "failed", reason: `issue fetch failed: ${message2(error)}` });
6581
6687
  continue;
6582
6688
  }
6583
- let stored = readStoredContract(loaded.stateDir, detail.identifier);
6584
- const memoryProbe = memory ? await planMemoryContext({
6689
+ let stored = cachedContract;
6690
+ const memoryPlan = memory ? await planMemoryContext({
6585
6691
  adapter: memory,
6586
6692
  config,
6587
6693
  issueId: detail.identifier,
@@ -6589,7 +6695,7 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
6589
6695
  project: config.project.name,
6590
6696
  references: []
6591
6697
  }) : null;
6592
- if (stored && !contractIsFresh(stored, detail, config.contract.reuseHours, now4(), memoryProbe?.memoryDigest)) stored = null;
6698
+ if (stored && !contractIsFresh(stored, detail, config.contract.reuseHours, now4(), memoryPlan?.memoryDigest)) stored = null;
6593
6699
  if (!stored) {
6594
6700
  if (input.skipContractGeneration) {
6595
6701
  results.push({ issue: detail.identifier, outcome: "skipped", reason: "no cached contract; generation skipped" });
@@ -6689,16 +6795,9 @@ The loop will not retry this issue until you remove the \`${config.resilience.pa
6689
6795
  }
6690
6796
  if (setupFailed) notes.push(`${detail.identifier}: setup command failed but project.setup.required is false \u2014 continuing`);
6691
6797
  }
6692
- const briefMemory = memory ? await planMemoryContext({
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: [] };
6798
+ const briefMemory = memoryPlan ?? { memoryBlock: "", issueCharBudget: config.contract.maxIssueChars, hits: [] };
6700
6799
  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 = loadPinnedSkills(loaded.root, config.brief.skills, config.brief.maxSkillChars);
6800
+ const pinnedSkills = getPinnedSkills();
6702
6801
  const brief = renderWorkerBrief({
6703
6802
  issue: detail,
6704
6803
  contract: stored,
@@ -7028,7 +7127,7 @@ var providerUnavailable = (ctx, providerId) => {
7028
7127
  return !match || !match.available;
7029
7128
  };
7030
7129
  var pickHandoffBuilder = (ctx, record3) => {
7031
- const ranked = rankModels(ctx.config, "builder", ctx.providers);
7130
+ const ranked = rankModels(ctx.config, "builder", ctx.providers, ctx.builderExtras);
7032
7131
  const different = ranked.find((candidate) => candidate.provider !== record3.provider || candidate.model !== record3.model);
7033
7132
  return different ?? null;
7034
7133
  };
@@ -7469,7 +7568,8 @@ var runDeliver = async (input) => {
7469
7568
  const availableIds = providers.filter((provider) => provider.available).map((provider) => provider.id);
7470
7569
  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
7570
  const reviewer = rankModels(config, "reviewer", providers, await catalogExtras("reviewer"))[0] ?? null;
7472
- const builder = rankModels(config, "builder", providers, await catalogExtras("builder"))[0] ?? null;
7571
+ const builderExtras = await catalogExtras("builder");
7572
+ const builder = rankModels(config, "builder", providers, builderExtras)[0] ?? null;
7473
7573
  let env = input.env ?? process.env;
7474
7574
  if (!env["GITHUB_TOKEN"] && !env["GH_TOKEN"]) {
7475
7575
  try {
@@ -7485,13 +7585,14 @@ var runDeliver = async (input) => {
7485
7585
  const { errors } = await loadLoopPlugins(loaded.root, config.plugins.modules, bus);
7486
7586
  for (const failure of errors) notes.push(`plugin ${failure.path} failed to load: ${failure.error}`);
7487
7587
  }
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 };
7588
+ 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
7589
  const ledger = createDispatchLedger(loaded.stateDir);
7490
7590
  const leases = new Map(ledger.active().map((lease) => [lease.issue, lease]));
7491
7591
  const results = [];
7492
7592
  for (const record3 of listDispatched(loaded.stateDir)) {
7493
7593
  if (input.onlyIssue && record3.issue !== input.onlyIssue) continue;
7494
7594
  let state = readDeliveryState(loaded.stateDir, record3.issue);
7595
+ if (state.finishedAt && state.finalOutcome === "merged") continue;
7495
7596
  const lease = leases.get(record3.issue);
7496
7597
  if (!state.finishedAt) {
7497
7598
  const ageMinutes = minutesBetween(now4(), record3.dispatchedAt);
@@ -7530,7 +7631,6 @@ var runDeliver = async (input) => {
7530
7631
  results.push(await handlePullRequest(ctx, record3, lease, state, pr));
7531
7632
  continue;
7532
7633
  }
7533
- if (state.finishedAt && state.finalOutcome === "merged") continue;
7534
7634
  const recordedMerge = readMergedEvent(loaded.stateDir, record3.issue);
7535
7635
  if (recordedMerge) {
7536
7636
  try {
@@ -8091,10 +8191,19 @@ ${step && total ? `${step}/${total} ` : ""}${title}`),
8091
8191
  ] }))
8092
8192
  };
8093
8193
  };
8194
+ var newestIssueMtimeMs = (stateDir, issue) => {
8195
+ const mtimes = [dispatchRecordPath(stateDir, issue), deliveryStatePath(stateDir, issue), contractPath(stateDir, issue)].map((path) => {
8196
+ try {
8197
+ return statSync(path).mtimeMs;
8198
+ } catch {
8199
+ return null;
8200
+ }
8201
+ }).filter((value) => value !== null);
8202
+ return mtimes.length ? Math.max(...mtimes) : null;
8203
+ };
8094
8204
  var HARNESS_REPO_URL = "https://github.com/AgentsKit-io/harness";
8095
8205
  var isRecord14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8096
- var readLoopEvents = (stateDir) => {
8097
- const path = join(stateDir, "events.ndjson");
8206
+ var parseEventsFile = (path) => {
8098
8207
  if (!existsSync(path)) return [];
8099
8208
  return readFileSync(path, "utf8").split(/\r?\n/).filter(Boolean).flatMap((line2) => {
8100
8209
  try {
@@ -8105,6 +8214,11 @@ var readLoopEvents = (stateDir) => {
8105
8214
  }
8106
8215
  });
8107
8216
  };
8217
+ var eventsArchivePattern = /^events-archive-(\d+)\.ndjson$/;
8218
+ var readLoopEvents = (stateDir, sinceMs) => {
8219
+ 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) : [];
8220
+ return [...archives.flatMap((archive) => parseEventsFile(archive.path)), ...parseEventsFile(join(stateDir, "events.ndjson"))];
8221
+ };
8108
8222
  var parseSince = (value, now4) => {
8109
8223
  if (!value) return new Date(now4.getTime() - 7 * 864e5);
8110
8224
  const match = value.match(/^(\d+)([dhm])$/);
@@ -8151,10 +8265,11 @@ var buildSuggestions = (input) => {
8151
8265
  var buildRetroReport = async (input) => {
8152
8266
  const loaded = input.loaded ?? loadLoopConfig(input.configPath);
8153
8267
  const { config } = loaded;
8268
+ const person = queueOwner(loaded);
8154
8269
  const now4 = (input.now ?? (() => /* @__PURE__ */ new Date()))();
8155
8270
  const since = parseSince(input.since, now4);
8156
8271
  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));
8272
+ const events = readLoopEvents(loaded.stateDir, since.getTime()).filter((event2) => inWindow(event2.at));
8158
8273
  const counts = {};
8159
8274
  for (const event2 of events) counts[event2.type] = (counts[event2.type] ?? 0) + 1;
8160
8275
  const escalations = events.filter((event2) => event2.type === "contract.escalated");
@@ -8176,6 +8291,8 @@ var buildRetroReport = async (input) => {
8176
8291
  if (existsSync(issuesDir)) for (const entry of readdirSync(issuesDir, { withFileTypes: true })) {
8177
8292
  if (!entry.isDirectory()) continue;
8178
8293
  const issue = entry.name;
8294
+ const newestMtime = newestIssueMtimeMs(loaded.stateDir, issue);
8295
+ if (newestMtime !== null && newestMtime < since.getTime()) continue;
8179
8296
  const dispatch = readDispatchRecord(loaded.stateDir, issue);
8180
8297
  const delivery = readDeliveryState(loaded.stateDir, issue);
8181
8298
  const contract = readStoredContract(loaded.stateDir, issue);
@@ -8233,7 +8350,7 @@ var buildRetroReport = async (input) => {
8233
8350
  else if (status === "ok") work += 1;
8234
8351
  }
8235
8352
  }
8236
- orca = { runs, idle, work, timedOut, avgDurationSec: durations.length ? Math.round(durations.reduce((sum, value) => sum + value, 0) / durations.length) : null, maxDurationSec: durations.length ? Math.round(Math.max(...durations)) : null };
8353
+ 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
8354
  } catch {
8238
8355
  orca = null;
8239
8356
  }
@@ -8242,9 +8359,9 @@ var buildRetroReport = async (input) => {
8242
8359
  generatedAt: now4.toISOString(),
8243
8360
  window: { since: since.toISOString(), until: now4.toISOString(), days: Number(((now4.getTime() - since.getTime()) / 864e5).toFixed(2)) },
8244
8361
  project: config.project.repo,
8245
- person: config.linear.person,
8362
+ person,
8246
8363
  counts,
8247
- escalations: { total: escalations.length, issues: [...new Set(escalations.map((event2) => String(event2.issue ?? "?")))], reasons: [...reasonCounts.entries()].map(([reason2, count2]) => ({ reason: reason2, count: count2 })).sort((left, right) => right.count - left.count) },
8364
+ 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
8365
  dispatches: { total: dispatchEvents.length, failed: counts["worker.dispatch-failed"] ?? 0, byProvider },
8249
8366
  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
8367
  providers: { cooldowns, cooldownEvents: counts["provider.cooldown"] ?? 0 },
@@ -8271,7 +8388,7 @@ var renderRetroMarkdown = (report) => {
8271
8388
  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
8389
  lines.push("");
8273
8390
  if (Object.keys(report.dispatches.byProvider).length) {
8274
- lines.push("## Providers", "", ...Object.entries(report.dispatches.byProvider).map(([key, count2]) => `- ${key}: ${count2} dispatch(es)`), ...report.providers.cooldowns.map((row) => `- cooldown ${row.provider} until ${row.until.slice(0, 16)}Z \u2014 ${row.reason}`), "");
8391
+ 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
8392
  }
8276
8393
  if (report.escalations.reasons.length) {
8277
8394
  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 +8569,7 @@ var buildDebriefReport = (input) => {
8452
8569
  }
8453
8570
  const inFlight = rows.filter((row) => !row.finalOutcome && row.phase !== "escalated");
8454
8571
  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());
8572
+ const events = readLoopEvents(stateDir, since.getTime()).filter((event2) => Date.parse(event2.at) >= since.getTime());
8456
8573
  const recentEscalations = events.filter((event2) => event2.type === "contract.escalated").slice(-10).map((event2) => ({
8457
8574
  issue: typeof event2.issue === "string" ? event2.issue : "?",
8458
8575
  at: event2.at,
@@ -8534,6 +8651,138 @@ var renderDebriefMarkdown = (report) => {
8534
8651
  lines.push("_Read-only. Run `ak-harness loop deliver` / `tick` to act; `loop retro` for the weekly digest._");
8535
8652
  return lines.join("\n");
8536
8653
  };
8654
+ var connectedStatuses = /* @__PURE__ */ new Set(["connected", "running", "active", "idle"]);
8655
+ var stalledPhases = /* @__PURE__ */ new Set(["waiting-for-pr", "awaiting-review", "review-incomplete", "fix-round"]);
8656
+ var heldRow = (row) => Boolean(row.heldFor) || row.phase === "held" || row.phase === "held-incomplete-review";
8657
+ var count2 = (events, type) => events.filter((event2) => event2.type === type).length;
8658
+ var sum = (events, key) => events.reduce((total, event2) => total + (typeof event2[key] === "number" && Number.isFinite(event2[key]) ? Number(event2[key]) : 0), 0);
8659
+ var uniqueIssues = (events, types) => new Set(events.filter((event2) => types.includes(event2.type) && typeof event2.issue === "string").map((event2) => event2.issue)).size;
8660
+ var assessObservability = (input) => {
8661
+ const anomalies = [];
8662
+ 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 } });
8663
+ for (const terminal2 of input.terminals) {
8664
+ 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 } });
8665
+ }
8666
+ 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 } });
8667
+ 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];
8668
+ const quietForMin = latestDispatch === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, Math.round((Date.parse(input.generatedAt) - latestDispatch) / 6e4));
8669
+ 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 } });
8670
+ for (const row of input.issues) {
8671
+ if (row.heldFor || !stalledPhases.has(row.phase) || row.ageMin === null || row.ageMin < input.workerIdleTimeoutMin) continue;
8672
+ 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 } });
8673
+ }
8674
+ const events = {};
8675
+ for (const event2 of input.events) events[event2.type] = (events[event2.type] ?? 0) + 1;
8676
+ const report = {
8677
+ status: anomalies.some((item) => item.severity === "action_required") ? "action_required" : "healthy",
8678
+ generatedAt: input.generatedAt,
8679
+ project: input.project,
8680
+ person: input.person,
8681
+ windowHours: input.windowHours,
8682
+ anomalies,
8683
+ metrics: {
8684
+ queueReady: input.queueReady,
8685
+ freeSlots: input.freeSlots,
8686
+ runningWorkers: input.runningWorkers,
8687
+ maxAgents: input.maxAgents,
8688
+ activeClaims: input.activeClaims,
8689
+ inFlight: input.issues.filter((row) => !heldRow(row)).length,
8690
+ held: input.issues.filter(heldRow).length,
8691
+ merged: input.merged,
8692
+ blocked: input.blocked,
8693
+ fixRounds: input.fixRounds,
8694
+ reviewFindings: input.reviewFindings,
8695
+ reviewIncomplete: input.reviewIncomplete,
8696
+ medianLeadTimeMin: input.medianLeadTimeMin,
8697
+ providerRemainingPercent: input.providerRemainingPercent,
8698
+ machine: input.machine,
8699
+ memory: input.memory,
8700
+ cache: input.cache,
8701
+ tokens: input.tokens,
8702
+ events
8703
+ }
8704
+ };
8705
+ return report;
8706
+ };
8707
+ var compactTerminal = (terminal2) => ({ handle: terminal2.handle, status: terminal2.status, worktreeId: terminal2.worktreeId, lastOutputAt: terminal2.lastOutputAt, preview: terminal2.preview });
8708
+ var dirtyFinalizedWorktrees = async (runner, worktrees) => {
8709
+ const out = [];
8710
+ for (const worktree of worktrees) {
8711
+ if (worktree.workspaceStatus.trim().toLowerCase() !== "completed" || !worktree.path) continue;
8712
+ try {
8713
+ const result = await runner.run(["git", "-C", worktree.path, "status", "--porcelain"], { timeoutMs: 1e4 });
8714
+ if (result.code === 0 && result.stdout.trim()) out.push({ worktreeId: worktree.id, issue: worktree.linkedLinearIssue, files: result.stdout.trim().split(/\r?\n/).length });
8715
+ } catch {
8716
+ }
8717
+ }
8718
+ return out;
8719
+ };
8720
+ var runObservability = async (input) => {
8721
+ const loaded = input.loaded ?? loadLoopConfig(input.configPath ?? "loop.config.yaml");
8722
+ const now4 = input.now ?? (() => /* @__PURE__ */ new Date());
8723
+ const at = now4();
8724
+ const since = parseSince(input.since ?? "24h", at);
8725
+ const [doctor, debrief, worktrees, terminals] = await Promise.all([
8726
+ runLoopDoctor({ loaded, runner: input.runner, env: input.env, platform: input.platform, now: () => at, probe: false }),
8727
+ Promise.resolve(buildDebriefReport({ loaded, since: input.since ?? "24h", now: () => at })),
8728
+ orcaWorktrees(input.runner, { bin: loaded.config.orca.bin, timeoutMs: loaded.config.orca.timeoutMs }).catch(() => []),
8729
+ orcaTerminalList(input.runner, {}, { bin: loaded.config.orca.bin, timeoutMs: loaded.config.orca.timeoutMs }).catch(() => [])
8730
+ ]);
8731
+ const events = readLoopEvents(loaded.stateDir).filter((event2) => Date.parse(event2.at) >= since.getTime() && Date.parse(event2.at) <= at.getTime());
8732
+ const ledger = createDispatchLedger(loaded.stateDir);
8733
+ const active = ledger.active();
8734
+ const missingDeliveryIssues = active.filter((lease) => !existsSync(deliveryStatePath(loaded.stateDir, lease.issue))).map((lease) => lease.issue);
8735
+ const records = listDispatched(loaded.stateDir);
8736
+ const completed = records.map((record3) => ({ record: record3, state: readDeliveryState(loaded.stateDir, record3.issue) })).filter(({ state }) => state.finishedAt && Date.parse(state.finishedAt) >= since.getTime());
8737
+ 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);
8738
+ const medianLeadTimeMin = leadTimes.length ? leadTimes.length % 2 ? leadTimes[Math.floor(leadTimes.length / 2)] : (leadTimes[leadTimes.length / 2 - 1] + leadTimes[leadTimes.length / 2]) / 2 : null;
8739
+ const providerRemainingPercent = Object.fromEntries(doctor.providers.map((provider) => [provider.id, remainingUsagePercent(provider.usage, loaded.config.models.routing.usageMetric)]));
8740
+ const cachedContracts = records.filter((record3) => existsSync(contractPath(loaded.stateDir, record3.issue))).length;
8741
+ const memoryEvents = events.filter((event2) => event2.type === "memory.recalled");
8742
+ const tokens = { input: sum(events, "inputTokens"), output: sum(events, "outputTokens"), total: sum(events, "totalTokens"), cacheRead: sum(events, "cacheReadTokens"), cacheWrite: sum(events, "cacheWriteTokens") };
8743
+ const machine = { cpuCount: doctor.machine.sample.cpus, load1PerCpuPercent: doctor.machine.sample.load1PerCpuPercent, memoryUsedPercent: doctor.machine.sample.memoryUsedPercent, freeRamGb: doctor.machine.freeRamGb };
8744
+ const snapshot = {
8745
+ generatedAt: at.toISOString(),
8746
+ project: doctor.config.project,
8747
+ person: doctor.config.person,
8748
+ windowHours: Math.max(1, Math.round((at.getTime() - since.getTime()) / 36e5)),
8749
+ workerIdleTimeoutMin: loaded.config.delivery.workerIdleTimeoutMin,
8750
+ queueReady: doctor.queue.count,
8751
+ freeSlots: doctor.machine.free,
8752
+ runningWorkers: doctor.workers.running,
8753
+ maxAgents: doctor.machine.maxAgents,
8754
+ activeClaims: active.length,
8755
+ missingDeliveryIssues,
8756
+ terminals: terminals.map(compactTerminal),
8757
+ finalizedDirtyWorktrees: await dirtyFinalizedWorktrees(input.runner, worktrees),
8758
+ issues: debrief.inFlight.map(({ issue, phase: phase2, ageMin, heldFor }) => ({ issue, phase: phase2, ageMin, heldFor })),
8759
+ events,
8760
+ merged: uniqueIssues(events, ["pr.merged", "worker.merged"]),
8761
+ blocked: Math.max(records.filter((record3) => readDeliveryState(loaded.stateDir, record3.issue).finalOutcome === "blocked").length, uniqueIssues(events, ["worker.blocked"])),
8762
+ fixRounds: records.reduce((total, record3) => total + readDeliveryState(loaded.stateDir, record3.issue).fixRounds, 0),
8763
+ reviewFindings: count2(events, "pr.reviewed") - count2(events.filter((event2) => event2["status"] !== "findings"), "pr.reviewed"),
8764
+ reviewIncomplete: events.filter((event2) => event2.type === "pr.reviewed" && event2["status"] === "incomplete").length,
8765
+ medianLeadTimeMin,
8766
+ providerRemainingPercent,
8767
+ machine,
8768
+ memory: { recalls: memoryEvents.length, hits: sum(memoryEvents, "hits"), approxCharsSaved: sum(memoryEvents, "approxCharsSaved") },
8769
+ cache: { cachedContracts },
8770
+ tokens
8771
+ };
8772
+ return assessObservability(snapshot);
8773
+ };
8774
+ var renderObservabilityMarkdown = (report) => {
8775
+ const m = report.metrics;
8776
+ const headroom = Object.entries(m.providerRemainingPercent).map(([provider, remaining]) => `${provider} ${remaining === null ? "?" : `${remaining}%`}`).join(", ");
8777
+ 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"}`, ""];
8778
+ if (report.anomalies.length) {
8779
+ lines.push("## Anomalies", "");
8780
+ for (const anomaly of report.anomalies) lines.push(`- **${anomaly.severity}**${anomaly.issue ? ` \xB7 ${anomaly.issue}` : ""}: ${anomaly.message}`);
8781
+ lines.push("");
8782
+ } else lines.push("## Anomalies", "", "_None detected._", "");
8783
+ lines.push("_Read-only. Run `ak-harness loop tick` or `deliver` to act on the queue._");
8784
+ return lines.join("\n");
8785
+ };
8537
8786
 
8538
8787
  // src/loop/watch.ts
8539
8788
  var defaultSleep = (ms) => new Promise((resolve10) => setTimeout(resolve10, ms));
@@ -8661,6 +8910,6 @@ var watchDeliveries = async (input) => {
8661
8910
  };
8662
8911
  var formatWatchEvent = (event2) => `${event2.kind}: ${event2.issue} \xB7 ${event2.message}`;
8663
8912
 
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 };
8913
+ 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, 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
8914
  //# sourceMappingURL=index.js.map
8666
8915
  //# sourceMappingURL=index.js.map