@oxagen/cli 2.1.4-684 → 2.1.4-699

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/oxagen.mjs +2219 -1459
  2. package/package.json +1 -1
package/oxagen.mjs CHANGED
@@ -5253,6 +5253,78 @@ var init_envelope = __esm({
5253
5253
  }
5254
5254
  });
5255
5255
 
5256
+ // ../../packages/tacho/src/harness-limits.ts
5257
+ function isLimitedHarness(harness) {
5258
+ return harness !== void 0 && LIMITED_HARNESSES.includes(harness);
5259
+ }
5260
+ function harnessHookLimitChars(harness) {
5261
+ return HARNESS_HOOK_LIMITS[isLimitedHarness(harness) ? harness : SMALLEST_LIMIT_HARNESS].chars;
5262
+ }
5263
+ function hookAnswerMaxChars(harness) {
5264
+ return harnessHookLimitChars(harness) - HOOK_ANSWER_RESERVE_CHARS;
5265
+ }
5266
+ function prefixBudgetTokens(harness) {
5267
+ return Math.floor(
5268
+ (hookAnswerMaxChars(harness) - STEER_ROOM_CHARS) / 4
5269
+ );
5270
+ }
5271
+ function harnessesAtLargestBudget() {
5272
+ return LIMITED_HARNESSES.filter(
5273
+ (harness) => prefixBudgetTokens(harness) === LARGEST_PREFIX_BUDGET_TOKENS
5274
+ );
5275
+ }
5276
+ var CONTEXT_SYSTEM_MAX_CHARS, CODEX_ADDITIONAL_CONTEXT_LIMIT, LIMITED_HARNESSES, HARNESS_HOOK_LIMITS, HOOK_ANSWER_RESERVE_CHARS, STEER_ROOM_CHARS, SMALLEST_LIMIT_HARNESS, SMALLEST_PREFIX_BUDGET_TOKENS, LARGEST_PREFIX_BUDGET_TOKENS;
5277
+ var init_harness_limits = __esm({
5278
+ "../../packages/tacho/src/harness-limits.ts"() {
5279
+ "use strict";
5280
+ CONTEXT_SYSTEM_MAX_CHARS = 16384;
5281
+ CODEX_ADDITIONAL_CONTEXT_LIMIT = 16384;
5282
+ LIMITED_HARNESSES = [
5283
+ "claude-code",
5284
+ "codex",
5285
+ "cursor",
5286
+ "stella"
5287
+ ];
5288
+ HARNESS_HOOK_LIMITS = {
5289
+ "claude-code": {
5290
+ documented: 1e4,
5291
+ chars: 1e4,
5292
+ source: "https://code.claude.com/docs/en/hooks",
5293
+ note: "A hook's additionalContext is capped at 10,000 characters. Past the cap Claude Code saves the text to a file and passes a path with a 2,000-character preview. No setting raises the cap."
5294
+ },
5295
+ codex: {
5296
+ documented: CODEX_ADDITIONAL_CONTEXT_LIMIT,
5297
+ chars: Math.min(CODEX_ADDITIONAL_CONTEXT_LIMIT, CONTEXT_SYSTEM_MAX_CHARS),
5298
+ source: "https://developers.openai.com/codex/hooks",
5299
+ note: "Codex spills additionalContext past about 2,500 approximate tokens unless the hook sets additionalContextLimit. Oxagen writes that setting on every hook that answers with text, and a string never has fewer characters than tokens."
5300
+ },
5301
+ cursor: {
5302
+ documented: null,
5303
+ chars: CONTEXT_SYSTEM_MAX_CHARS,
5304
+ source: "https://cursor.com/docs/agent/hooks",
5305
+ note: "The sessionStart hook's additional_context has no documented limit, so the host's context.system cap binds."
5306
+ },
5307
+ stella: {
5308
+ documented: null,
5309
+ chars: CONTEXT_SYSTEM_MAX_CHARS,
5310
+ source: "crates/stella-core/src/hooks.rs in macanderson/stella",
5311
+ note: "Stella appends a SessionStart hook's whole stdout to the system prompt and caps nothing, so the host's context.system cap binds."
5312
+ }
5313
+ };
5314
+ HOOK_ANSWER_RESERVE_CHARS = 500;
5315
+ STEER_ROOM_CHARS = 1500;
5316
+ SMALLEST_LIMIT_HARNESS = [...LIMITED_HARNESSES].sort(
5317
+ (a, b5) => HARNESS_HOOK_LIMITS[a].chars - HARNESS_HOOK_LIMITS[b5].chars
5318
+ )[0];
5319
+ SMALLEST_PREFIX_BUDGET_TOKENS = prefixBudgetTokens(
5320
+ SMALLEST_LIMIT_HARNESS
5321
+ );
5322
+ LARGEST_PREFIX_BUDGET_TOKENS = Math.max(
5323
+ ...LIMITED_HARNESSES.map(prefixBudgetTokens)
5324
+ );
5325
+ }
5326
+ });
5327
+
5256
5328
  // ../../packages/tacho/src/policy/context.ts
5257
5329
  function clockContext(now) {
5258
5330
  const date = new Date(now);
@@ -5377,6 +5449,7 @@ var init_wire = __esm({
5377
5449
  init_zod();
5378
5450
  init_digest();
5379
5451
  init_envelope();
5452
+ init_harness_limits();
5380
5453
  init_context();
5381
5454
  TACHO_BATCH_SCHEMA = "tacho.batch.v1";
5382
5455
  TACHO_BUNDLE_SCHEMA = "tacho.bundle.v1";
@@ -5763,7 +5836,7 @@ var init_wire = __esm({
5763
5836
  mode: external_exports.enum(["observed", "enforced"])
5764
5837
  }).strict(),
5765
5838
  context: external_exports.object({
5766
- system: external_exports.string().max(16384).nullable(),
5839
+ system: external_exports.string().max(CONTEXT_SYSTEM_MAX_CHARS).nullable(),
5767
5840
  /**
5768
5841
  * Emitted only to a host that advertised
5769
5842
  * `BUNDLE_FEATURE_STEERING_MANIFEST`; see that constant.
@@ -7343,13 +7416,13 @@ function candidatePaths(path2, context) {
7343
7416
  cwd !== void 0 && lib.isAbsolute(cwd) ? lib.resolve(cwd, expanded) : lib.normalize(expanded)
7344
7417
  );
7345
7418
  const out = [resolved];
7346
- const under = (root) => {
7419
+ const under2 = (root) => {
7347
7420
  const base2 = fold(lib.normalize(root)).replace(/\/+$/, "");
7348
7421
  return resolved.startsWith(`${base2}/`) ? resolved.slice(base2.length + 1) : void 0;
7349
7422
  };
7350
- const relative10 = cwd !== void 0 ? under(cwd) : void 0;
7351
- if (relative10 !== void 0) out.push(relative10);
7352
- const fromHome = home !== void 0 ? under(home) : void 0;
7423
+ const relative11 = cwd !== void 0 ? under2(cwd) : void 0;
7424
+ if (relative11 !== void 0) out.push(relative11);
7425
+ const fromHome = home !== void 0 ? under2(home) : void 0;
7353
7426
  if (fromHome !== void 0) out.push(`~/${fromHome}`);
7354
7427
  return out;
7355
7428
  }
@@ -9519,11 +9592,12 @@ function stripCodexHooks(existing, enrollmentId) {
9519
9592
  function codexHookPresence(existing, enrollmentId) {
9520
9593
  return hookGroupPresence(existing, CODEX_HOOK_EVENTS, enrollmentId);
9521
9594
  }
9522
- var CODEX_TELEMETRY_EVENTS, CODEX_HOOK_EVENTS, TELEMETRY_TIMEOUT_S2, CODEX_ADDITIONAL_CONTEXT_LIMIT, CONTEXT_EVENTS;
9595
+ var CODEX_TELEMETRY_EVENTS, CODEX_HOOK_EVENTS, TELEMETRY_TIMEOUT_S2, CONTEXT_EVENTS;
9523
9596
  var init_codex_writer = __esm({
9524
9597
  "../../packages/tacho/src/host/codex-writer.ts"() {
9525
9598
  "use strict";
9526
9599
  init_settings_writer();
9600
+ init_harness_limits();
9527
9601
  CODEX_TELEMETRY_EVENTS = [
9528
9602
  "PostToolUse",
9529
9603
  "SubagentStart",
@@ -9538,7 +9612,6 @@ var init_codex_writer = __esm({
9538
9612
  ...CODEX_TELEMETRY_EVENTS
9539
9613
  ];
9540
9614
  TELEMETRY_TIMEOUT_S2 = 5;
9541
- CODEX_ADDITIONAL_CONTEXT_LIMIT = 1e4;
9542
9615
  CONTEXT_EVENTS = /* @__PURE__ */ new Set([
9543
9616
  "SessionStart",
9544
9617
  "UserPromptSubmit",
@@ -24024,7 +24097,7 @@ import { readFileSync as readFileSync11 } from "node:fs";
24024
24097
  import { dirname as dirname9, resolve as resolve3 } from "node:path";
24025
24098
  import { fileURLToPath } from "node:url";
24026
24099
  function readVersion() {
24027
- if (true) return "2.1.4-684";
24100
+ if (true) return "2.1.4-699";
24028
24101
  try {
24029
24102
  const here = dirname9(fileURLToPath(import.meta.url));
24030
24103
  const pkg = JSON.parse(
@@ -24284,11 +24357,11 @@ function harnessFacts(exec4, name, platform = process.platform, env = process.en
24284
24357
  path2 ??= shellExecutable(exec4("sh", ["-lc", `command -v ${name}`]));
24285
24358
  }
24286
24359
  if (path2 === void 0) {
24287
- const sep12 = platform === "win32" ? "\\" : "/";
24360
+ const sep13 = platform === "win32" ? "\\" : "/";
24288
24361
  const names2 = platform === "win32" ? [`${name}.exe`, `${name}.cmd`] : [name];
24289
24362
  outer: for (const dir of wellKnownBinDirs(home, platform, env)) {
24290
24363
  for (const file of names2) {
24291
- const candidate = `${dir}${sep12}${file}`;
24364
+ const candidate = `${dir}${sep13}${file}`;
24292
24365
  if (exists(candidate)) {
24293
24366
  path2 = candidate;
24294
24367
  break outer;
@@ -25029,10 +25102,12 @@ function createControlClient(options) {
25029
25102
  ingestTimeoutMs
25030
25103
  )
25031
25104
  ),
25032
- bundle: async (etag) => bundleResponseSchema.parse(
25105
+ bundle: async (etag, run3) => bundleResponseSchema.parse(
25033
25106
  await post2(options.endpoints.bundle, {
25034
25107
  host_enrollment_id: options.hostEnrollmentId,
25035
- ...etag !== void 0 ? { etag } : {}
25108
+ ...etag !== void 0 ? { etag } : {},
25109
+ ...run3?.remote !== void 0 ? { remote: run3.remote } : {},
25110
+ ...run3?.harness !== void 0 ? { harness: run3.harness } : {}
25036
25111
  })
25037
25112
  ),
25038
25113
  commands: async (acknowledgements = [], daemon) => commandsResponseSchema.parse(
@@ -29171,8 +29246,8 @@ function harnessFileProblems(harnesses, deps) {
29171
29246
  if (harnesses.includes("codex"))
29172
29247
  check2(deps.paths.codexHooks, deps.readCodexHooks, hooksShapeProblem);
29173
29248
  if (harnesses.includes("cursor")) {
29174
- const relative10 = absoluteHookCommandProblem(deps.runtime.hookCommand);
29175
- if (relative10 !== void 0) problems.push(relative10);
29249
+ const relative11 = absoluteHookCommandProblem(deps.runtime.hookCommand);
29250
+ if (relative11 !== void 0) problems.push(relative11);
29176
29251
  for (const path2 of deps.paths.cursorHooks)
29177
29252
  check2(path2, () => deps.readCursorHooks(path2), cursorHooksShapeProblem);
29178
29253
  }
@@ -38218,6 +38293,7 @@ async function readRepositoryRemote(exec4, cwd) {
38218
38293
  const slash = canonical3.lastIndexOf("/");
38219
38294
  const name = slash === -1 ? "" : canonical3.slice(slash + 1);
38220
38295
  return {
38296
+ canonical: canonical3,
38221
38297
  remote_digest: digestBytes(canonical3),
38222
38298
  remote_digest_folded: digestBytes(foldedRemote(canonical3)),
38223
38299
  ...name.length > 0 ? { name } : {},
@@ -40608,6 +40684,7 @@ function deliversMessages(harness, hookEventName) {
40608
40684
  function drainMessages(record, deps, events, used = 0) {
40609
40685
  const delivered = [];
40610
40686
  const now = deps.now();
40687
+ const max2 = hookAnswerMaxChars(record.harness);
40611
40688
  const queue = record.control.messages.splice(0);
40612
40689
  for (const [index, message] of queue.entries()) {
40613
40690
  if (message.expiresAt !== null && Date.parse(message.expiresAt) < now) {
@@ -40619,17 +40696,17 @@ function drainMessages(record, deps, events, used = 0) {
40619
40696
  });
40620
40697
  continue;
40621
40698
  }
40622
- if (message.text.length > ADDITIONAL_CONTEXT_MAX_CHARS) {
40699
+ if (message.text.length > max2) {
40623
40700
  deps.acknowledge?.({
40624
40701
  command_id: message.id,
40625
40702
  status: "failed",
40626
40703
  session_uuid: record.recorder.sessionUuid,
40627
- detail: `longer than the ${ADDITIONAL_CONTEXT_MAX_CHARS} characters a hook delivers`
40704
+ detail: `longer than the ${max2} characters a hook delivers`
40628
40705
  });
40629
40706
  continue;
40630
40707
  }
40631
40708
  const size = (used > 0 ? CONTEXT_JOINER.length : 0) + message.text.length;
40632
- if (used + size > ADDITIONAL_CONTEXT_MAX_CHARS) {
40709
+ if (used + size > max2) {
40633
40710
  record.control.messages.unshift(...queue.slice(index));
40634
40711
  break;
40635
40712
  }
@@ -40812,8 +40889,8 @@ function promptText(input) {
40812
40889
  const userInput = input["user_input"];
40813
40890
  return typeof userInput === "string" ? userInput : void 0;
40814
40891
  }
40815
- function recallContext(memories, used) {
40816
- const room = ADDITIONAL_CONTEXT_MAX_CHARS - used - (used > 0 ? CONTEXT_JOINER.length : 0);
40892
+ function recallContext(memories, used, max2 = ADDITIONAL_CONTEXT_MAX_CHARS) {
40893
+ const room = max2 - used - (used > 0 ? CONTEXT_JOINER.length : 0);
40817
40894
  let text5 = RECALL_HEADING;
40818
40895
  let count12 = 0;
40819
40896
  for (const memory of memories) {
@@ -40827,6 +40904,19 @@ function recallContext(memories, used) {
40827
40904
  }
40828
40905
  return count12 > 0 ? { text: text5, count: count12 } : void 0;
40829
40906
  }
40907
+ async function runSteeringBundle(record, deps) {
40908
+ if (deps.runSteering === void 0) return void 0;
40909
+ const named = record.harness ?? "claude-code";
40910
+ const harness = WRAPPED_HARNESSES.includes(named) ? named : void 0;
40911
+ const remote = Promise.resolve(
40912
+ deps.repositoryRemote === void 0 ? void 0 : readRepository(recallView(record), deps.repositoryRemote)
40913
+ ).then((repository) => repository?.canonical);
40914
+ try {
40915
+ return await deps.runSteering(remote, harness);
40916
+ } catch {
40917
+ return void 0;
40918
+ }
40919
+ }
40830
40920
  function skillsHarness(record) {
40831
40921
  if (record.customAgent !== void 0) return void 0;
40832
40922
  return record.harness ?? "claude-code";
@@ -40836,7 +40926,13 @@ async function placeSessionSkills(view, record, deps, env) {
40836
40926
  const harness = skillsHarness(record);
40837
40927
  if (deps.skills === void 0 || harness === void 0 || !view.verified || skills === void 0 || skills.length === 0)
40838
40928
  return;
40839
- await deps.skills.place(harness, record.harnessSessionId, skills, env);
40929
+ await deps.skills.place(
40930
+ harness,
40931
+ record.harnessSessionId,
40932
+ skills,
40933
+ env,
40934
+ view.bundle.cedar?.policies
40935
+ );
40840
40936
  }
40841
40937
  async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
40842
40938
  const input = hookInputSchema.parse(raw);
@@ -40906,7 +41002,8 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
40906
41002
  switch (input.hook_event_name) {
40907
41003
  case "SessionStart": {
40908
41004
  const block = operatorBlock(view, record);
40909
- const context = view.bundle.context.system;
41005
+ const steering = block === void 0 && replay === void 0 ? await runSteeringBundle(record, deps) ?? view.bundle : view.bundle;
41006
+ const context = steering.context.system;
40910
41007
  const messages = block === void 0 && replay === void 0 ? drainMessages(record, deps, events, context?.length ?? 0) : [];
40911
41008
  const additional = block === void 0 ? [context ?? "", ...messages.map((m) => m.text)].filter((s4) => s4.length > 0).join(CONTEXT_JOINER) : "";
40912
41009
  const delivered = replay === void 0 ? void 0 : readDeliveredContext(replay.deliveredContext);
@@ -40958,12 +41055,12 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
40958
41055
  }
40959
41056
  if (replay === void 0)
40960
41057
  await placeSessionSkills(view, record, deps, env);
40961
- const manifest = view.bundle.context.manifest;
40962
- if (manifest !== void 0 && (replay === void 0 || delivered?.bundle_etag === view.bundle.etag && manifest.text_digest === (delivered.digest ?? null))) {
41058
+ const manifest = steering.context.manifest;
41059
+ if (manifest !== void 0 && (replay === void 0 || delivered?.bundle_etag === steering.etag && manifest.text_digest === (delivered.digest ?? null))) {
40963
41060
  events.push(
40964
41061
  record.recorder.sealCollectorEvent(
40965
41062
  "steering.manifest",
40966
- steeringManifestFrame(manifest, view.bundle, messages),
41063
+ steeringManifestFrame(manifest, steering, messages),
40967
41064
  { hook_event_name: "SessionStart", attrs: replayed }
40968
41065
  )
40969
41066
  );
@@ -41006,7 +41103,8 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
41006
41103
  ...recallScope(recallView(record)),
41007
41104
  text: promptText(input) ?? ""
41008
41105
  }),
41009
- delivered.join(CONTEXT_JOINER).length
41106
+ delivered.join(CONTEXT_JOINER).length,
41107
+ hookAnswerMaxChars(record.harness)
41010
41108
  ) : void 0;
41011
41109
  if (block === void 0) record.control.resumeOwed = void 0;
41012
41110
  if (block === void 0) notePrompt(record, promptText(input));
@@ -41452,6 +41550,7 @@ var init_hook_handler = __esm({
41452
41550
  init_context2();
41453
41551
  init_tools();
41454
41552
  init_steering_manifest();
41553
+ init_harness_limits();
41455
41554
  init_timestamp();
41456
41555
  init_wire();
41457
41556
  init_bundle();
@@ -41471,7 +41570,7 @@ var init_hook_handler = __esm({
41471
41570
  "Stop"
41472
41571
  ]);
41473
41572
  RESUMED_TEXT = "Resumed by the operator. Continue the task.";
41474
- ADDITIONAL_CONTEXT_MAX_CHARS = 9500;
41573
+ ADDITIONAL_CONTEXT_MAX_CHARS = hookAnswerMaxChars(void 0);
41475
41574
  CONTEXT_JOINER = "\n\n";
41476
41575
  TOOL_CALL_HOOK_EVENTS = /* @__PURE__ */ new Set([
41477
41576
  "PreToolUse",
@@ -45570,6 +45669,37 @@ import { createHash as createHash13 } from "node:crypto";
45570
45669
  import { mkdir as mkdir2, readdir as readdir2, readFile as readFile2, rm as rm2, writeFile } from "node:fs/promises";
45571
45670
  import { homedir as homedir5 } from "node:os";
45572
45671
  import { dirname as dirname20, join as join36 } from "node:path";
45672
+ function skillToolLimits(policies) {
45673
+ const limits = /* @__PURE__ */ new Map();
45674
+ for (const text5 of Object.values(policies)) {
45675
+ const lineage = SKILL_POLICY_ANNOTATION.exec(text5)?.[1];
45676
+ if (lineage === void 0) continue;
45677
+ const list = UNLESS_ACTIONS.exec(text5)?.[1] ?? "";
45678
+ const actions = [...list.matchAll(ACTION_ID)].map((m) => m[1]);
45679
+ const held = limits.get(lineage);
45680
+ const permitted = held === void 0 ? actions : held.filter((action) => actions.includes(action));
45681
+ limits.set(lineage, [...new Set(permitted)].sort());
45682
+ }
45683
+ return limits;
45684
+ }
45685
+ function harnessToolNames(harness, actions) {
45686
+ if (harness !== "claude-code") return null;
45687
+ const names2 = /* @__PURE__ */ new Set();
45688
+ for (const action of actions) {
45689
+ for (const name of CLAUDE_CODE_TOOL_NAMES[action] ?? []) names2.add(name);
45690
+ }
45691
+ return CLAUDE_CODE_TOOL_ORDER.filter((name) => names2.has(name));
45692
+ }
45693
+ function withToolLimits(skills, limits) {
45694
+ if (limits === void 0) return [...skills];
45695
+ const byLineage = skillToolLimits(limits.policies);
45696
+ return skills.map((skill) => {
45697
+ const actions = byLineage.get(skill.lineage);
45698
+ if (actions === void 0) return skill;
45699
+ const names2 = harnessToolNames(limits.harness, actions);
45700
+ return names2 === null ? skill : { ...skill, allowedTools: names2 };
45701
+ });
45702
+ }
45573
45703
  function envDir(env, key) {
45574
45704
  const value = env[key];
45575
45705
  return value === void 0 || value.trim() === "" ? null : value;
@@ -45610,10 +45740,12 @@ function skillFileRefusal(path2) {
45610
45740
  return null;
45611
45741
  }
45612
45742
  function skillMarkdown(skill) {
45743
+ const tools = skill.allowedTools !== void 0 && skill.allowedTools.length > 0 ? `allowed-tools: ${skill.allowedTools.join(", ")}
45744
+ ` : "";
45613
45745
  return `---
45614
45746
  name: ${skill.name}
45615
45747
  description: ${JSON.stringify(skill.description)}
45616
- ---
45748
+ ${tools}---
45617
45749
 
45618
45750
  ${skill.body.replace(/^\n+/, "")}`;
45619
45751
  }
@@ -45691,11 +45823,11 @@ function skillRefusal(skill) {
45691
45823
  }
45692
45824
  return null;
45693
45825
  }
45694
- async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Date()) {
45826
+ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Date(), limits) {
45695
45827
  const result2 = { placed: [], skipped: [], warnings: [] };
45696
45828
  await mkdir2(root, { recursive: true });
45697
45829
  const taken = /* @__PURE__ */ new Set();
45698
- for (const skill of skills) {
45830
+ for (const skill of withToolLimits(skills, limits)) {
45699
45831
  const refusal = skillRefusal(skill);
45700
45832
  if (refusal !== null) {
45701
45833
  result2.skipped.push(skill.name);
@@ -45785,13 +45917,36 @@ async function removeSkills(root, sessionId, now = /* @__PURE__ */ new Date()) {
45785
45917
  }
45786
45918
  return result2;
45787
45919
  }
45788
- var SESSION_MARKER, SESSION_TTL_MS, SKILL_NAME_PATTERN;
45920
+ var SESSION_MARKER, SESSION_TTL_MS, SKILL_NAME_PATTERN, SKILL_POLICY_ANNOTATION, UNLESS_ACTIONS, ACTION_ID, CLAUDE_CODE_TOOL_NAMES, CLAUDE_CODE_TOOL_ORDER;
45789
45921
  var init_place = __esm({
45790
45922
  "../../packages/tacho/src/skills/place.ts"() {
45791
45923
  "use strict";
45792
45924
  SESSION_MARKER = ".oxagen-session";
45793
45925
  SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
45794
45926
  SKILL_NAME_PATTERN = /^[a-z0-9-]{1,64}$/;
45927
+ SKILL_POLICY_ANNOTATION = /@skill\s*\(\s*"((?:[^"\\]|\\.)*)"\s*\)/;
45928
+ UNLESS_ACTIONS = /unless\s*\{\s*action\s+in\s*\[([^\]]*)\]\s*\}/;
45929
+ ACTION_ID = /Action::"((?:[^"\\]|\\.)*)"/g;
45930
+ CLAUDE_CODE_TOOL_NAMES = {
45931
+ builtin__read_file: ["Read"],
45932
+ builtin__search_files: ["Grep", "Glob"],
45933
+ builtin__shell: ["Bash"],
45934
+ builtin__write_file: ["Edit", "Write"],
45935
+ builtin__web_fetch: ["WebFetch"],
45936
+ builtin__web_search: ["WebSearch"],
45937
+ builtin__start_subagent: ["Agent"]
45938
+ };
45939
+ CLAUDE_CODE_TOOL_ORDER = [
45940
+ "Read",
45941
+ "Grep",
45942
+ "Glob",
45943
+ "Bash",
45944
+ "Edit",
45945
+ "Write",
45946
+ "WebFetch",
45947
+ "WebSearch",
45948
+ "Agent"
45949
+ ];
45795
45950
  }
45796
45951
  });
45797
45952
 
@@ -45839,7 +45994,7 @@ function sessionSkills(options) {
45839
45994
  }
45840
45995
  }
45841
45996
  return {
45842
- async place(harness, sessionId, skills, env) {
45997
+ async place(harness, sessionId, skills, env, policies) {
45843
45998
  const root = skillsRoot(harness, env, home);
45844
45999
  if (root === null || skills.length === 0) return;
45845
46000
  placedRoots.set(sessionId, root);
@@ -45849,7 +46004,8 @@ function sessionSkills(options) {
45849
46004
  root,
45850
46005
  sessionId,
45851
46006
  skills.map(decodeSkill),
45852
- now()
46007
+ now(),
46008
+ policies === void 0 ? void 0 : { harness, policies }
45853
46009
  );
45854
46010
  for (const warning of result2.warnings) log(`skills: ${warning}`);
45855
46011
  } catch (error) {
@@ -46604,8 +46760,8 @@ function resolveModelRoute(rawUrl, headers) {
46604
46760
  const mark = rawUrl.indexOf("?");
46605
46761
  const pathname = mark === -1 ? rawUrl : rawUrl.slice(0, mark);
46606
46762
  const search = mark === -1 ? "" : rawUrl.slice(mark);
46607
- const under = (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`) ? pathname.slice(prefix.length) || "/" : void 0;
46608
- const stella = under("/stella/anthropic");
46763
+ const under2 = (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`) ? pathname.slice(prefix.length) || "/" : void 0;
46764
+ const stella = under2("/stella/anthropic");
46609
46765
  if (stella !== void 0) {
46610
46766
  return {
46611
46767
  provider: "anthropic",
@@ -46615,7 +46771,7 @@ function resolveModelRoute(rawUrl, headers) {
46615
46771
  harness: "stella"
46616
46772
  };
46617
46773
  }
46618
- const anthropic = under("/anthropic");
46774
+ const anthropic = under2("/anthropic");
46619
46775
  if (anthropic !== void 0) {
46620
46776
  return {
46621
46777
  provider: "anthropic",
@@ -46624,11 +46780,11 @@ function resolveModelRoute(rawUrl, headers) {
46624
46780
  path: `${anthropic}${search}`
46625
46781
  };
46626
46782
  }
46627
- const codex = under("/backend-api/codex");
46783
+ const codex = under2("/backend-api/codex");
46628
46784
  if (codex !== void 0) return openAiRoute(codex, search, headers);
46629
- const openai = under("/openai/v1");
46785
+ const openai = under2("/openai/v1");
46630
46786
  if (openai !== void 0) return openAiRoute(openai, search, headers);
46631
- const bare = under("/v1");
46787
+ const bare = under2("/v1");
46632
46788
  if (bare !== void 0) {
46633
46789
  const isAnthropic = bare === "/messages" || bare.startsWith("/messages/") || bare !== "/responses" && bare !== "/chat/completions" && looksAnthropic(headers);
46634
46790
  if (isAnthropic) {
@@ -49925,6 +50081,22 @@ function settleWithin(work, ms) {
49925
50081
  work.then(done, done);
49926
50082
  });
49927
50083
  }
50084
+ function valueWithin(work, ms) {
50085
+ return new Promise((resolve23) => {
50086
+ const timer = setTimeout(() => resolve23(void 0), ms);
50087
+ timer.unref();
50088
+ work.then(
50089
+ (value) => {
50090
+ clearTimeout(timer);
50091
+ resolve23(value);
50092
+ },
50093
+ () => {
50094
+ clearTimeout(timer);
50095
+ resolve23(void 0);
50096
+ }
50097
+ );
50098
+ });
50099
+ }
49928
50100
  function olderBundle(candidate, held) {
49929
50101
  return candidate.version < held.version && !(Date.parse(candidate.issued_at) > Date.parse(held.issued_at));
49930
50102
  }
@@ -50656,6 +50828,43 @@ async function initializeDaemon(options, server, port, ready) {
50656
50828
  bundleFetch = run3;
50657
50829
  return run3;
50658
50830
  }
50831
+ const RUN_BUNDLES_MAX = 64;
50832
+ const runBundles = /* @__PURE__ */ new Map();
50833
+ async function runBundle(remote, harness) {
50834
+ if (remote === void 0 && harness === void 0) return void 0;
50835
+ const key = `${harness ?? ""}\0${remote ?? ""}`;
50836
+ const held = runBundles.get(key);
50837
+ try {
50838
+ const response = await client.bundle(held?.etag, { remote, harness });
50839
+ lastControlAt = now();
50840
+ if (response.not_modified) return held;
50841
+ if (response.bundle === null) return void 0;
50842
+ const verification = verifyBundle(
50843
+ response.bundle,
50844
+ host.bundle_public_key_pem,
50845
+ host.host_enrollment_id
50846
+ );
50847
+ if (!verification.ok) {
50848
+ log(
50849
+ `refused a run bundle that does not verify: ${verification.reason ?? "unknown"}`
50850
+ );
50851
+ return void 0;
50852
+ }
50853
+ runBundles.delete(key);
50854
+ runBundles.set(key, response.bundle);
50855
+ while (runBundles.size > RUN_BUNDLES_MAX) {
50856
+ const oldest = runBundles.keys().next().value;
50857
+ if (oldest === void 0) break;
50858
+ runBundles.delete(oldest);
50859
+ }
50860
+ return response.bundle;
50861
+ } catch (error) {
50862
+ log(
50863
+ `run bundle fetch failed: ${error instanceof Error ? error.message : String(error)}`
50864
+ );
50865
+ return void 0;
50866
+ }
50867
+ }
50659
50868
  async function onControl(control) {
50660
50869
  lastControlAt = now();
50661
50870
  if (control.agent_day_spend !== void 0)
@@ -51257,6 +51466,12 @@ async function initializeDaemon(options, server, port, ready) {
51257
51466
  refreshBundle: async () => {
51258
51467
  await settleWithin(refreshBundle(), timers.hookBundleWaitMs);
51259
51468
  },
51469
+ // One wait covers the repository read and the run's bundle fetch.
51470
+ // Past it, the start hands the agent the host's bundle (ADR-350).
51471
+ runSteering: (remote, harness) => valueWithin(
51472
+ remote.then((canonical3) => runBundle(canonical3, harness)),
51473
+ timers.hookBundleWaitMs
51474
+ ),
51260
51475
  acknowledge: (ack) => {
51261
51476
  acks.push(ack);
51262
51477
  },
@@ -53116,7 +53331,7 @@ import {
53116
53331
  writeFileSync as writeFileSync5
53117
53332
  } from "node:fs";
53118
53333
  import { dirname as dirname22, join as join39, resolve as resolve15 } from "node:path";
53119
- function bundlePath(root, relative10, create2 = false) {
53334
+ function bundlePath(root, relative11, create2 = false) {
53120
53335
  const absolute = resolve15(root);
53121
53336
  if (create2) mkdirSync8(absolute, { recursive: true, mode: 448 });
53122
53337
  if (lstatSync7(absolute).isSymbolicLink() || !lstatSync7(absolute).isDirectory()) {
@@ -53124,7 +53339,7 @@ function bundlePath(root, relative10, create2 = false) {
53124
53339
  }
53125
53340
  const base2 = realpathSync5(absolute);
53126
53341
  let current = base2;
53127
- const parts = relative10.split("/");
53342
+ const parts = relative11.split("/");
53128
53343
  for (let i2 = 0; i2 < parts.length; i2++) {
53129
53344
  current = join39(current, parts[i2]);
53130
53345
  try {
@@ -53143,8 +53358,8 @@ function bundlePath(root, relative10, create2 = false) {
53143
53358
  }
53144
53359
  return current;
53145
53360
  }
53146
- function readBounded(root, relative10, limit = ARP_MAX_BLOB_BYTES) {
53147
- const path2 = bundlePath(root, relative10);
53361
+ function readBounded(root, relative11, limit = ARP_MAX_BLOB_BYTES) {
53362
+ const path2 = bundlePath(root, relative11);
53148
53363
  const fd2 = openSync7(path2, constants3.O_RDONLY | constants3.O_NOFOLLOW);
53149
53364
  try {
53150
53365
  const stat6 = fstatSync2(fd2);
@@ -53166,8 +53381,8 @@ function readBounded(root, relative10, limit = ARP_MAX_BLOB_BYTES) {
53166
53381
  closeSync7(fd2);
53167
53382
  }
53168
53383
  }
53169
- function writeNew(root, relative10, bytes) {
53170
- const path2 = bundlePath(root, relative10, true);
53384
+ function writeNew(root, relative11, bytes) {
53385
+ const path2 = bundlePath(root, relative11, true);
53171
53386
  const fd2 = openSync7(
53172
53387
  path2,
53173
53388
  constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW,
@@ -54937,7 +55152,7 @@ var init_package = __esm({
54937
55152
  "package.json"() {
54938
55153
  package_default = {
54939
55154
  name: "@oxagen/cli",
54940
- version: "2.1.4-684",
55155
+ version: "2.1.4-699",
54941
55156
  description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
54942
55157
  type: "module",
54943
55158
  main: "./dist/index.js",
@@ -61331,15 +61546,305 @@ var init_record_force = __esm({
61331
61546
  }
61332
61547
  });
61333
61548
 
61549
+ // ../../packages/oxagen/src/steering-repo/harness-files.ts
61550
+ function nameOf(path2) {
61551
+ const cut2 = path2.lastIndexOf("/");
61552
+ return cut2 < 0 ? path2 : path2.slice(cut2 + 1);
61553
+ }
61554
+ function isMarkdown(name) {
61555
+ return name.endsWith(".md") || name.endsWith(".mdc");
61556
+ }
61557
+ function instructionEntryOf(path2) {
61558
+ const name = nameOf(path2);
61559
+ const nested2 = NESTED.get(name) ?? SINGLE.get(name);
61560
+ if (nested2) return nested2;
61561
+ if (path2 === ".github/copilot-instructions.md")
61562
+ return ROOT_FILES.get(path2) ?? null;
61563
+ if (path2.startsWith(".github/instructions/") && name.endsWith(".instructions.md"))
61564
+ return COPILOT_RULES;
61565
+ if (!isMarkdown(name)) return null;
61566
+ const slashed = `/${path2}`;
61567
+ return RULE_FOLDERS.find(({ folder }) => slashed.includes(`/${folder}`))?.entry ?? null;
61568
+ }
61569
+ function classifyHarnessFile(path2) {
61570
+ for (const { folder, entry: entry2 } of SKILL_FOLDERS) {
61571
+ if (!path2.startsWith(folder)) continue;
61572
+ const rest = path2.slice(folder.length);
61573
+ const cut2 = rest.indexOf("/");
61574
+ if (cut2 <= 0) return null;
61575
+ return { ...entry2, path: path2, skillFolder: folder + rest.slice(0, cut2) };
61576
+ }
61577
+ const instruction = instructionEntryOf(path2);
61578
+ if (instruction) return { ...instruction, path: path2, skillFolder: null };
61579
+ const root = ROOT_FILES.get(path2);
61580
+ if (root) return { ...root, path: path2, skillFolder: null };
61581
+ for (const { folder, entry: entry2 } of MARKDOWN_FOLDERS) {
61582
+ if (path2.startsWith(folder) && nameOf(path2).endsWith(".md"))
61583
+ return { ...entry2, path: path2, skillFolder: null };
61584
+ }
61585
+ return null;
61586
+ }
61587
+ var HARNESSES2, HARNESS_FILE_KINDS, CLAUDE_MD, NESTED, SINGLE, RULE_FOLDERS, ROOT_FILES, COPILOT_RULES, MARKDOWN_FOLDERS, SKILL_FOLDERS, SKILL_FILE, HARNESS_FILE_CATALOGUE, WELL_KNOWN_FOLDERS;
61588
+ var init_harness_files = __esm({
61589
+ "../../packages/oxagen/src/steering-repo/harness-files.ts"() {
61590
+ "use strict";
61591
+ HARNESSES2 = [
61592
+ "claude-code",
61593
+ "codex",
61594
+ "cursor",
61595
+ "copilot",
61596
+ "windsurf",
61597
+ "cline",
61598
+ "gemini",
61599
+ "stella"
61600
+ ];
61601
+ HARNESS_FILE_KINDS = [
61602
+ "instructions",
61603
+ "personal",
61604
+ "rule",
61605
+ "skill",
61606
+ "command",
61607
+ "subagent",
61608
+ "settings",
61609
+ "mcp-config"
61610
+ ];
61611
+ CLAUDE_MD = {
61612
+ pattern: "CLAUDE.md",
61613
+ harnesses: ["claude-code", "stella"],
61614
+ kind: "instructions"
61615
+ };
61616
+ NESTED = /* @__PURE__ */ new Map([
61617
+ ["CLAUDE.md", CLAUDE_MD],
61618
+ [
61619
+ "AGENTS.md",
61620
+ { pattern: "AGENTS.md", harnesses: ["codex", "stella"], kind: "instructions" }
61621
+ ],
61622
+ [
61623
+ "AGENTS.override.md",
61624
+ { pattern: "AGENTS.override.md", harnesses: ["codex"], kind: "instructions" }
61625
+ ],
61626
+ [
61627
+ "GEMINI.md",
61628
+ { pattern: "GEMINI.md", harnesses: ["gemini"], kind: "instructions" }
61629
+ ],
61630
+ [
61631
+ "CLAUDE.local.md",
61632
+ { pattern: "CLAUDE.local.md", harnesses: ["claude-code"], kind: "personal" }
61633
+ ]
61634
+ ]);
61635
+ SINGLE = /* @__PURE__ */ new Map([
61636
+ [
61637
+ ".cursorrules",
61638
+ { pattern: ".cursorrules", harnesses: ["cursor"], kind: "instructions" }
61639
+ ],
61640
+ [
61641
+ ".windsurfrules",
61642
+ { pattern: ".windsurfrules", harnesses: ["windsurf"], kind: "instructions" }
61643
+ ],
61644
+ [
61645
+ ".clinerules",
61646
+ { pattern: ".clinerules", harnesses: ["cline"], kind: "instructions" }
61647
+ ]
61648
+ ]);
61649
+ RULE_FOLDERS = [
61650
+ {
61651
+ folder: ".cursor/rules/",
61652
+ entry: {
61653
+ pattern: ".cursor/rules/*.md, .cursor/rules/*.mdc",
61654
+ harnesses: ["cursor"],
61655
+ kind: "rule"
61656
+ }
61657
+ },
61658
+ {
61659
+ folder: ".windsurf/rules/",
61660
+ entry: {
61661
+ pattern: ".windsurf/rules/*.md",
61662
+ harnesses: ["windsurf"],
61663
+ kind: "rule"
61664
+ }
61665
+ },
61666
+ {
61667
+ folder: ".clinerules/",
61668
+ entry: { pattern: ".clinerules/*.md", harnesses: ["cline"], kind: "rule" }
61669
+ }
61670
+ ];
61671
+ ROOT_FILES = /* @__PURE__ */ new Map([
61672
+ [
61673
+ ".github/copilot-instructions.md",
61674
+ {
61675
+ pattern: ".github/copilot-instructions.md",
61676
+ harnesses: ["copilot"],
61677
+ kind: "instructions"
61678
+ }
61679
+ ],
61680
+ [
61681
+ ".claude/settings.json",
61682
+ {
61683
+ pattern: ".claude/settings.json",
61684
+ harnesses: ["claude-code"],
61685
+ kind: "settings"
61686
+ }
61687
+ ],
61688
+ [
61689
+ ".codex/config.toml",
61690
+ {
61691
+ pattern: ".codex/config.toml",
61692
+ harnesses: ["codex"],
61693
+ kind: "settings"
61694
+ }
61695
+ ],
61696
+ [
61697
+ ".mcp.json",
61698
+ { pattern: ".mcp.json", harnesses: ["claude-code"], kind: "mcp-config" }
61699
+ ],
61700
+ [
61701
+ ".cursor/mcp.json",
61702
+ {
61703
+ pattern: ".cursor/mcp.json",
61704
+ harnesses: ["cursor"],
61705
+ kind: "mcp-config"
61706
+ }
61707
+ ]
61708
+ ]);
61709
+ COPILOT_RULES = {
61710
+ pattern: ".github/instructions/*.instructions.md",
61711
+ harnesses: ["copilot"],
61712
+ kind: "rule"
61713
+ };
61714
+ MARKDOWN_FOLDERS = [
61715
+ {
61716
+ folder: ".claude/commands/",
61717
+ entry: {
61718
+ pattern: ".claude/commands/*.md",
61719
+ harnesses: ["claude-code", "stella"],
61720
+ kind: "command"
61721
+ }
61722
+ },
61723
+ {
61724
+ folder: ".cursor/commands/",
61725
+ entry: {
61726
+ pattern: ".cursor/commands/*.md",
61727
+ harnesses: ["cursor"],
61728
+ kind: "command"
61729
+ }
61730
+ },
61731
+ {
61732
+ folder: ".claude/agents/",
61733
+ entry: {
61734
+ pattern: ".claude/agents/*.md",
61735
+ harnesses: ["claude-code", "cursor", "stella"],
61736
+ kind: "subagent"
61737
+ }
61738
+ }
61739
+ ];
61740
+ SKILL_FOLDERS = [
61741
+ {
61742
+ folder: ".claude/skills/",
61743
+ entry: {
61744
+ pattern: ".claude/skills/<name>/",
61745
+ harnesses: ["claude-code", "cursor", "stella"],
61746
+ kind: "skill"
61747
+ }
61748
+ },
61749
+ {
61750
+ folder: ".agents/skills/",
61751
+ entry: {
61752
+ pattern: ".agents/skills/<name>/",
61753
+ harnesses: ["codex"],
61754
+ kind: "skill"
61755
+ }
61756
+ },
61757
+ {
61758
+ folder: ".cursor/skills/",
61759
+ entry: {
61760
+ pattern: ".cursor/skills/<name>/",
61761
+ harnesses: ["cursor"],
61762
+ kind: "skill"
61763
+ }
61764
+ }
61765
+ ];
61766
+ SKILL_FILE = "SKILL.md";
61767
+ HARNESS_FILE_CATALOGUE = [
61768
+ ...NESTED.values(),
61769
+ ...SINGLE.values(),
61770
+ ...RULE_FOLDERS.map((r) => r.entry),
61771
+ COPILOT_RULES,
61772
+ ...SKILL_FOLDERS.map((s4) => s4.entry),
61773
+ ...MARKDOWN_FOLDERS.map((m) => m.entry),
61774
+ ...ROOT_FILES.values()
61775
+ ];
61776
+ WELL_KNOWN_FOLDERS = [
61777
+ "",
61778
+ ".github",
61779
+ ".github/instructions",
61780
+ ".claude",
61781
+ ".claude/skills",
61782
+ ".claude/commands",
61783
+ ".claude/agents",
61784
+ ".codex",
61785
+ ".agents",
61786
+ ".agents/skills",
61787
+ ".cursor",
61788
+ ".cursor/rules",
61789
+ ".cursor/skills",
61790
+ ".cursor/commands",
61791
+ ".windsurf",
61792
+ ".windsurf/rules",
61793
+ ".clinerules"
61794
+ ];
61795
+ }
61796
+ });
61797
+
61798
+ // ../../packages/oxagen/src/steering-repo/record-scope.ts
61799
+ var recordScopeSchema, recordLoadSchema;
61800
+ var init_record_scope = __esm({
61801
+ "../../packages/oxagen/src/steering-repo/record-scope.ts"() {
61802
+ "use strict";
61803
+ init_zod();
61804
+ recordScopeSchema = external_exports.enum([
61805
+ "workspace",
61806
+ "repository",
61807
+ "organization"
61808
+ ]);
61809
+ recordLoadSchema = external_exports.enum([
61810
+ "always",
61811
+ "match",
61812
+ "relevant",
61813
+ "mention"
61814
+ ]);
61815
+ }
61816
+ });
61817
+
61334
61818
  // ../../packages/oxagen/src/contracts/steering.markdown_import.shared.ts
61335
61819
  function markdownImportFileCount(rows) {
61336
- return rows.records.filter((row) => row.action === "add").length + rows.policies.filter((policy) => policy.action === "add").length;
61820
+ let count12 = rows.policies.filter((policy) => policy.action === "add").length;
61821
+ for (const row of rows.records) {
61822
+ if (row.action === "add") count12 += 1 + (row.files?.length ?? 0);
61823
+ }
61824
+ return count12;
61337
61825
  }
61338
61826
  function markdownImportTooManyFiles(count12) {
61339
61827
  if (count12 <= STEERING_PR_MAX_FILES) return null;
61340
61828
  return `The import marks ${count12} records and policy files add, and one steering PR holds at most ${STEERING_PR_MAX_FILES} files. Mark ${count12 - STEERING_PR_MAX_FILES} of them skip, or import the files in smaller sets.`;
61341
61829
  }
61342
- var MARKDOWN_IMPORT_FILES_MAX, MARKDOWN_IMPORT_FILE_CHARS_MAX, MARKDOWN_IMPORT_STATEMENTS_MAX, MARKDOWN_IMPORT_KIND_REASON_MAX, MARKDOWN_IMPORT_FORCE_WORDS_MAX, MARKDOWN_IMPORT_ROWS_MAX, markdownImportPullRequestFilesSchema, markdownImportTargetSchema, markdownImportDocumentSchema, markdownImportMatchSchema, markdownImportOriginSchema, markdownImportRecordSchema, markdownImportMemoryMatchReasonSchema, markdownImportMemoryMatchSchema, markdownImportMemorySchema, markdownImportPolicyStatementSchema, markdownImportPolicyIssueSchema, markdownImportPolicySchema, markdownImportFileSchema;
61830
+ function markdownImportSourceOf(path2) {
61831
+ const clean = path2.replace(/\\/g, "/").replace(/^\.?\//, "");
61832
+ const segments = clean.split("/");
61833
+ const starts = segments.map((segment, at) => segment.startsWith(".") ? at : -1).filter((at) => at >= 0);
61834
+ if (!starts.includes(0)) starts.push(0);
61835
+ for (const at of starts) {
61836
+ const rest = segments.slice(at).join("/");
61837
+ const file = classifyHarnessFile(rest);
61838
+ if (file === null) continue;
61839
+ if (file.kind === "skill" && rest !== `${file.skillFolder}/${SKILL_FILE}`)
61840
+ return null;
61841
+ const kind = markdownImportFileKindSchema.safeParse(file.kind);
61842
+ const harness = markdownImportHarnessSchema.safeParse(file.harnesses[0]);
61843
+ return kind.success && harness.success ? { harness: harness.data, kind: kind.data } : null;
61844
+ }
61845
+ return null;
61846
+ }
61847
+ var MARKDOWN_IMPORT_FILES_MAX, MARKDOWN_IMPORT_FILE_CHARS_MAX, MARKDOWN_IMPORT_STATEMENTS_MAX, MARKDOWN_IMPORT_KIND_REASON_MAX, MARKDOWN_IMPORT_FORCE_WORDS_MAX, MARKDOWN_IMPORT_ROWS_MAX, markdownImportPullRequestFilesSchema, markdownImportTargetSchema, markdownImportHarnessSchema, markdownImportFileKindSchema, markdownImportSourceSchema, MARKDOWN_IMPORT_SKILL_FILES_MAX, markdownImportSkillFileSchema, markdownImportDocumentSchema, markdownImportMatchSchema, markdownImportOriginSchema, markdownImportRecordSchema, markdownImportMemoryMatchReasonSchema, markdownImportMemoryMatchSchema, markdownImportMemorySchema, markdownImportPolicyStatementSchema, markdownImportPolicyIssueSchema, markdownImportPolicySchema, markdownImportFileSchema;
61343
61848
  var init_steering_markdown_import_shared = __esm({
61344
61849
  "../../packages/oxagen/src/contracts/steering.markdown_import.shared.ts"() {
61345
61850
  "use strict";
@@ -61350,7 +61855,9 @@ var init_steering_markdown_import_shared = __esm({
61350
61855
  init_names();
61351
61856
  init_record_effect();
61352
61857
  init_record_force();
61858
+ init_harness_files();
61353
61859
  init_record_kind();
61860
+ init_record_scope();
61354
61861
  MARKDOWN_IMPORT_FILES_MAX = 25;
61355
61862
  MARKDOWN_IMPORT_FILE_CHARS_MAX = 1e5;
61356
61863
  MARKDOWN_IMPORT_STATEMENTS_MAX = 50;
@@ -61370,6 +61877,38 @@ var init_steering_markdown_import_shared = __esm({
61370
61877
  "memories",
61371
61878
  "skip"
61372
61879
  ]);
61880
+ markdownImportHarnessSchema = external_exports.enum(HARNESSES2).exclude([
61881
+ "stella"
61882
+ ]);
61883
+ markdownImportFileKindSchema = external_exports.enum(HARNESS_FILE_KINDS).extract([
61884
+ "instructions",
61885
+ "rule",
61886
+ "skill",
61887
+ "command",
61888
+ "subagent"
61889
+ ]);
61890
+ markdownImportSourceSchema = external_exports.object({
61891
+ harness: markdownImportHarnessSchema.describe(
61892
+ "The harness whose format the file is written in"
61893
+ ),
61894
+ kind: markdownImportFileKindSchema.describe(
61895
+ "The file's kind in the harness file catalogue"
61896
+ ),
61897
+ path: repoPathSchema.max(1024).describe(
61898
+ "The file's path in the repository, such as apps/app/CLAUDE.md. For a skill folder, the path of its SKILL.md."
61899
+ ),
61900
+ repository: repoRefSchema.optional().describe(
61901
+ "The linked repository, as <host>/<owner>/<name>. With it, every record gets scope repository and repos set to it."
61902
+ )
61903
+ }).strict();
61904
+ MARKDOWN_IMPORT_SKILL_FILES_MAX = 64;
61905
+ markdownImportSkillFileSchema = external_exports.object({
61906
+ path: external_exports.string().min(1).max(512).regex(
61907
+ /^(?!\/)(?!.*\/\/)(?!(?:.*\/)?\.\.?(?:\/|$))[^\0\\]+$/,
61908
+ "a skill file path is relative, uses /, and names no . or .. segment"
61909
+ ).describe("The file's path inside the skill folder, such as scripts/run.sh"),
61910
+ content: external_exports.string().max(MARKDOWN_IMPORT_FILE_CHARS_MAX).describe("The file's text")
61911
+ }).strict();
61373
61912
  markdownImportDocumentSchema = external_exports.object({
61374
61913
  filename: external_exports.string().min(1).max(256).describe(
61375
61914
  "The file's name, or its path relative to the folder imported, such as docs/release.md"
@@ -61377,8 +61916,40 @@ var init_steering_markdown_import_shared = __esm({
61377
61916
  content: external_exports.string().min(1).max(MARKDOWN_IMPORT_FILE_CHARS_MAX).describe("The file's Markdown text"),
61378
61917
  target: markdownImportTargetSchema.optional().describe(
61379
61918
  "records, policies, memories, or skip. Omit it to take the target the file's text implies."
61919
+ ),
61920
+ source: markdownImportSourceSchema.optional().describe(
61921
+ "Where the file came from: its harness, its catalogue kind, its path, and the repository. Omit it to read the file as plain Markdown."
61922
+ ),
61923
+ files: external_exports.array(markdownImportSkillFileSchema).max(MARKDOWN_IMPORT_SKILL_FILES_MAX).optional().describe(
61924
+ "A skill folder's other text files, by their path inside the folder. Only a source of kind skill carries them."
61380
61925
  )
61381
- }).strict();
61926
+ }).strict().superRefine((document, ctx) => {
61927
+ if (document.files !== void 0 && document.files.length > 0 && document.source?.kind !== "skill") {
61928
+ ctx.addIssue({
61929
+ code: external_exports.ZodIssueCode.custom,
61930
+ path: ["files"],
61931
+ message: "only a document whose source is a skill carries files"
61932
+ });
61933
+ }
61934
+ const paths = /* @__PURE__ */ new Set();
61935
+ for (const file of document.files ?? []) {
61936
+ if (paths.has(file.path)) {
61937
+ ctx.addIssue({
61938
+ code: external_exports.ZodIssueCode.custom,
61939
+ path: ["files"],
61940
+ message: `the skill names ${file.path} twice`
61941
+ });
61942
+ }
61943
+ paths.add(file.path);
61944
+ }
61945
+ if (paths.has(SKILL_FILE)) {
61946
+ ctx.addIssue({
61947
+ code: external_exports.ZodIssueCode.custom,
61948
+ path: ["files"],
61949
+ message: `${SKILL_FILE} is the document's content, not one of its files`
61950
+ });
61951
+ }
61952
+ });
61382
61953
  markdownImportMatchSchema = external_exports.object({
61383
61954
  lineage: external_exports.string().min(1),
61384
61955
  /** Where the matched record lives, or null for a published record with no known path. */
@@ -61386,7 +61957,12 @@ var init_steering_markdown_import_shared = __esm({
61386
61957
  /** True for a record already published, false for another row of this import. */
61387
61958
  published: external_exports.boolean()
61388
61959
  }).strict();
61389
- markdownImportOriginSchema = external_exports.enum(["frontmatter", "split"]);
61960
+ markdownImportOriginSchema = external_exports.enum([
61961
+ "frontmatter",
61962
+ "split",
61963
+ "rule",
61964
+ "skill"
61965
+ ]);
61390
61966
  markdownImportRecordSchema = external_exports.object({
61391
61967
  file: external_exports.string().min(1).max(256).describe("The file the statement came from"),
61392
61968
  line: external_exports.number().int().min(1).describe("The line of the file the statement starts on"),
@@ -61416,7 +61992,29 @@ var init_steering_markdown_import_shared = __esm({
61416
61992
  "add or skip. A duplicate defaults to skip. A conflict is null until a person chooses."
61417
61993
  ),
61418
61994
  frontmatter: external_exports.string().max(MARKDOWN_IMPORT_FILE_CHARS_MAX).nullable().describe(
61419
- "The file's frontmatter, kept for a frontmatter record so the commit keeps its other fields. Null for a split statement."
61995
+ "The file's frontmatter YAML: kept for a frontmatter record so the commit keeps its other fields, and shown for a rule or a skill so a person sees what the source said. Null for a split statement, and for a rule or a skill whose file had none."
61996
+ ),
61997
+ // The fields below are set only when the document named a source. A row
61998
+ // without them commits as every row did before: workspace scope, no
61999
+ // paths, and the load its force implies.
62000
+ scope: recordScopeSchema.optional().describe(
62001
+ "The record's scope. repository when the source named a repository, else absent, which commits as workspace."
62002
+ ),
62003
+ repos: external_exports.array(repoRefSchema).min(1).max(16).optional().describe("The repositories a repository-scoped record reaches."),
62004
+ applies_to: external_exports.array(external_exports.string().min(1).max(512)).min(1).max(64).optional().describe(
62005
+ "The path globs the record is about: a nested file's folder, a Cursor rule's globs, a Copilot rule's applyTo, or a skill's paths."
62006
+ ),
62007
+ load: recordLoadSchema.optional().describe(
62008
+ "When the record reaches a request: always, match, relevant, or mention. Absent, the record's force decides."
62009
+ ),
62010
+ name: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*$/).max(64).optional().describe(
62011
+ "A skill's folder name, from the source's name field or its file name. Set on a skill row only."
62012
+ ),
62013
+ files: external_exports.array(markdownImportSkillFileSchema).max(MARKDOWN_IMPORT_SKILL_FILES_MAX).optional().describe(
62014
+ "A skill folder's other files, written beside its SKILL.md. Set on a skill row only."
62015
+ ),
62016
+ dropped: external_exports.array(external_exports.string().min(1).max(200)).max(64).optional().describe(
62017
+ "What the source said that the record cannot hold, each as one line: a frontmatter field the record schema has no place for, a tools list moved to a Cedar policy, or a binary file left out."
61420
62018
  )
61421
62019
  }).strict().superRefine((row, ctx) => {
61422
62020
  if (!forceAllowed(row.kind, row.force)) {
@@ -61440,11 +62038,46 @@ var init_steering_markdown_import_shared = __esm({
61440
62038
  message: "only a constraint carries an effect"
61441
62039
  });
61442
62040
  }
61443
- if (row.origin === "frontmatter" !== (row.frontmatter !== null)) {
62041
+ if (row.origin === "frontmatter" && row.frontmatter === null) {
62042
+ ctx.addIssue({
62043
+ code: external_exports.ZodIssueCode.custom,
62044
+ path: ["frontmatter"],
62045
+ message: "a frontmatter record carries its frontmatter"
62046
+ });
62047
+ }
62048
+ if (row.origin === "split" && row.frontmatter !== null) {
61444
62049
  ctx.addIssue({
61445
62050
  code: external_exports.ZodIssueCode.custom,
61446
62051
  path: ["frontmatter"],
61447
- message: "a frontmatter record carries its frontmatter, and a split statement carries none"
62052
+ message: "a split statement carries no frontmatter"
62053
+ });
62054
+ }
62055
+ if (row.origin === "skill" && row.kind !== "skill") {
62056
+ ctx.addIssue({
62057
+ code: external_exports.ZodIssueCode.custom,
62058
+ path: ["kind"],
62059
+ message: "a whole skill, command, or subagent file is a skill"
62060
+ });
62061
+ }
62062
+ if (row.origin !== "skill" && (row.files !== void 0 || row.name !== void 0)) {
62063
+ ctx.addIssue({
62064
+ code: external_exports.ZodIssueCode.custom,
62065
+ path: ["files"],
62066
+ message: "only a skill row carries a name and files"
62067
+ });
62068
+ }
62069
+ if (row.scope === "repository" !== (row.repos !== void 0)) {
62070
+ ctx.addIssue({
62071
+ code: external_exports.ZodIssueCode.custom,
62072
+ path: ["repos"],
62073
+ message: "a repository-scoped row names its repos, and no other row does"
62074
+ });
62075
+ }
62076
+ if (row.load === "match" && row.applies_to === void 0) {
62077
+ ctx.addIssue({
62078
+ code: external_exports.ZodIssueCode.custom,
62079
+ path: ["applies_to"],
62080
+ message: "a row that loads on match names the paths it matches"
61448
62081
  });
61449
62082
  }
61450
62083
  });
@@ -66184,10 +66817,10 @@ var require_resolve_block_map = __commonJS({
66184
66817
  let offset = bm.offset;
66185
66818
  let commentEnd = null;
66186
66819
  for (const collItem of bm.items) {
66187
- const { start, key, sep: sep12, value } = collItem;
66820
+ const { start, key, sep: sep13, value } = collItem;
66188
66821
  const keyProps = resolveProps.resolveProps(start, {
66189
66822
  indicator: "explicit-key-ind",
66190
- next: key ?? sep12?.[0],
66823
+ next: key ?? sep13?.[0],
66191
66824
  offset,
66192
66825
  onError,
66193
66826
  parentIndent: bm.indent,
@@ -66201,7 +66834,7 @@ var require_resolve_block_map = __commonJS({
66201
66834
  else if ("indent" in key && key.indent !== bm.indent)
66202
66835
  onError(offset, "BAD_INDENT", startColMsg);
66203
66836
  }
66204
- if (!keyProps.anchor && !keyProps.tag && !sep12) {
66837
+ if (!keyProps.anchor && !keyProps.tag && !sep13) {
66205
66838
  commentEnd = keyProps.end;
66206
66839
  if (keyProps.comment) {
66207
66840
  if (map.comment)
@@ -66225,7 +66858,7 @@ var require_resolve_block_map = __commonJS({
66225
66858
  ctx.atKey = false;
66226
66859
  if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
66227
66860
  onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
66228
- const valueProps = resolveProps.resolveProps(sep12 ?? [], {
66861
+ const valueProps = resolveProps.resolveProps(sep13 ?? [], {
66229
66862
  indicator: "map-value-ind",
66230
66863
  next: value,
66231
66864
  offset: keyNode.range[2],
@@ -66241,7 +66874,7 @@ var require_resolve_block_map = __commonJS({
66241
66874
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
66242
66875
  onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
66243
66876
  }
66244
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep12, null, valueProps, onError);
66877
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep13, null, valueProps, onError);
66245
66878
  if (ctx.schema.compat)
66246
66879
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
66247
66880
  offset = valueNode.range[2];
@@ -66332,7 +66965,7 @@ var require_resolve_end = __commonJS({
66332
66965
  let comment = "";
66333
66966
  if (end) {
66334
66967
  let hasSpace = false;
66335
- let sep12 = "";
66968
+ let sep13 = "";
66336
66969
  for (const token of end) {
66337
66970
  const { source, type } = token;
66338
66971
  switch (type) {
@@ -66346,13 +66979,13 @@ var require_resolve_end = __commonJS({
66346
66979
  if (!comment)
66347
66980
  comment = cb;
66348
66981
  else
66349
- comment += sep12 + cb;
66350
- sep12 = "";
66982
+ comment += sep13 + cb;
66983
+ sep13 = "";
66351
66984
  break;
66352
66985
  }
66353
66986
  case "newline":
66354
66987
  if (comment)
66355
- sep12 += source;
66988
+ sep13 += source;
66356
66989
  hasSpace = true;
66357
66990
  break;
66358
66991
  default:
@@ -66395,18 +67028,18 @@ var require_resolve_flow_collection = __commonJS({
66395
67028
  let offset = fc.offset + fc.start.source.length;
66396
67029
  for (let i2 = 0; i2 < fc.items.length; ++i2) {
66397
67030
  const collItem = fc.items[i2];
66398
- const { start, key, sep: sep12, value } = collItem;
67031
+ const { start, key, sep: sep13, value } = collItem;
66399
67032
  const props = resolveProps.resolveProps(start, {
66400
67033
  flow: fcName,
66401
67034
  indicator: "explicit-key-ind",
66402
- next: key ?? sep12?.[0],
67035
+ next: key ?? sep13?.[0],
66403
67036
  offset,
66404
67037
  onError,
66405
67038
  parentIndent: fc.indent,
66406
67039
  startOnNewline: false
66407
67040
  });
66408
67041
  if (!props.found) {
66409
- if (!props.anchor && !props.tag && !sep12 && !value) {
67042
+ if (!props.anchor && !props.tag && !sep13 && !value) {
66410
67043
  if (i2 === 0 && props.comma)
66411
67044
  onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
66412
67045
  else if (i2 < fc.items.length - 1)
@@ -66460,8 +67093,8 @@ var require_resolve_flow_collection = __commonJS({
66460
67093
  }
66461
67094
  }
66462
67095
  }
66463
- if (!isMap3 && !sep12 && !props.found) {
66464
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep12, null, props, onError);
67096
+ if (!isMap3 && !sep13 && !props.found) {
67097
+ const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep13, null, props, onError);
66465
67098
  coll.items.push(valueNode);
66466
67099
  offset = valueNode.range[2];
66467
67100
  if (isBlock(value))
@@ -66473,7 +67106,7 @@ var require_resolve_flow_collection = __commonJS({
66473
67106
  if (isBlock(key))
66474
67107
  onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
66475
67108
  ctx.atKey = false;
66476
- const valueProps = resolveProps.resolveProps(sep12 ?? [], {
67109
+ const valueProps = resolveProps.resolveProps(sep13 ?? [], {
66477
67110
  flow: fcName,
66478
67111
  indicator: "map-value-ind",
66479
67112
  next: value,
@@ -66484,8 +67117,8 @@ var require_resolve_flow_collection = __commonJS({
66484
67117
  });
66485
67118
  if (valueProps.found) {
66486
67119
  if (!isMap3 && !props.found && ctx.options.strict) {
66487
- if (sep12)
66488
- for (const st of sep12) {
67120
+ if (sep13)
67121
+ for (const st of sep13) {
66489
67122
  if (st === valueProps.found)
66490
67123
  break;
66491
67124
  if (st.type === "newline") {
@@ -66502,7 +67135,7 @@ var require_resolve_flow_collection = __commonJS({
66502
67135
  else
66503
67136
  onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
66504
67137
  }
66505
- const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep12, null, valueProps, onError) : null;
67138
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep13, null, valueProps, onError) : null;
66506
67139
  if (valueNode) {
66507
67140
  if (isBlock(value))
66508
67141
  onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -66682,7 +67315,7 @@ var require_resolve_block_scalar = __commonJS({
66682
67315
  chompStart = i2 + 1;
66683
67316
  }
66684
67317
  let value = "";
66685
- let sep12 = "";
67318
+ let sep13 = "";
66686
67319
  let prevMoreIndented = false;
66687
67320
  for (let i2 = 0; i2 < contentStart; ++i2)
66688
67321
  value += lines[i2][0].slice(trimIndent) + "\n";
@@ -66699,24 +67332,24 @@ var require_resolve_block_scalar = __commonJS({
66699
67332
  indent = "";
66700
67333
  }
66701
67334
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
66702
- value += sep12 + indent.slice(trimIndent) + content;
66703
- sep12 = "\n";
67335
+ value += sep13 + indent.slice(trimIndent) + content;
67336
+ sep13 = "\n";
66704
67337
  } else if (indent.length > trimIndent || content[0] === " ") {
66705
- if (sep12 === " ")
66706
- sep12 = "\n";
66707
- else if (!prevMoreIndented && sep12 === "\n")
66708
- sep12 = "\n\n";
66709
- value += sep12 + indent.slice(trimIndent) + content;
66710
- sep12 = "\n";
67338
+ if (sep13 === " ")
67339
+ sep13 = "\n";
67340
+ else if (!prevMoreIndented && sep13 === "\n")
67341
+ sep13 = "\n\n";
67342
+ value += sep13 + indent.slice(trimIndent) + content;
67343
+ sep13 = "\n";
66711
67344
  prevMoreIndented = true;
66712
67345
  } else if (content === "") {
66713
- if (sep12 === "\n")
67346
+ if (sep13 === "\n")
66714
67347
  value += "\n";
66715
67348
  else
66716
- sep12 = "\n";
67349
+ sep13 = "\n";
66717
67350
  } else {
66718
- value += sep12 + content;
66719
- sep12 = " ";
67351
+ value += sep13 + content;
67352
+ sep13 = " ";
66720
67353
  prevMoreIndented = false;
66721
67354
  }
66722
67355
  }
@@ -66899,25 +67532,25 @@ var require_resolve_flow_scalar = __commonJS({
66899
67532
  trimBoth = /^[ \t]+|[ \t]+$/g;
66900
67533
  }
66901
67534
  let res = match[1].replace(trimEnd, "");
66902
- let sep12 = " ";
67535
+ let sep13 = " ";
66903
67536
  let pos = line.lastIndex;
66904
67537
  while (match = line.exec(source)) {
66905
67538
  const lm = match[1].replace(trimBoth, "");
66906
67539
  if (lm === "") {
66907
- if (sep12 === "\n")
66908
- res += sep12;
67540
+ if (sep13 === "\n")
67541
+ res += sep13;
66909
67542
  else
66910
- sep12 = "\n";
67543
+ sep13 = "\n";
66911
67544
  } else {
66912
- res += sep12 + lm;
66913
- sep12 = " ";
67545
+ res += sep13 + lm;
67546
+ sep13 = " ";
66914
67547
  }
66915
67548
  pos = line.lastIndex;
66916
67549
  }
66917
67550
  const last = /[ \t]*(.*)/sy;
66918
67551
  last.lastIndex = pos;
66919
67552
  match = last.exec(source);
66920
- return res + sep12 + (match?.[1] ?? "");
67553
+ return res + sep13 + (match?.[1] ?? "");
66921
67554
  }
66922
67555
  function doubleQuotedValue(source, onError) {
66923
67556
  let res = "";
@@ -67727,14 +68360,14 @@ var require_cst_stringify = __commonJS({
67727
68360
  }
67728
68361
  }
67729
68362
  }
67730
- function stringifyItem({ start, key, sep: sep12, value }) {
68363
+ function stringifyItem({ start, key, sep: sep13, value }) {
67731
68364
  let res = "";
67732
68365
  for (const st of start)
67733
68366
  res += st.source;
67734
68367
  if (key)
67735
68368
  res += stringifyToken(key);
67736
- if (sep12)
67737
- for (const st of sep12)
68369
+ if (sep13)
68370
+ for (const st of sep13)
67738
68371
  res += st.source;
67739
68372
  if (value)
67740
68373
  res += stringifyToken(value);
@@ -68901,18 +69534,18 @@ var require_parser = __commonJS({
68901
69534
  if (this.type === "map-value-ind") {
68902
69535
  const prev = getPrevProps(this.peek(2));
68903
69536
  const start = getFirstKeyStartProps(prev);
68904
- let sep12;
69537
+ let sep13;
68905
69538
  if (scalar2.end) {
68906
- sep12 = scalar2.end;
68907
- sep12.push(this.sourceToken);
69539
+ sep13 = scalar2.end;
69540
+ sep13.push(this.sourceToken);
68908
69541
  delete scalar2.end;
68909
69542
  } else
68910
- sep12 = [this.sourceToken];
69543
+ sep13 = [this.sourceToken];
68911
69544
  const map = {
68912
69545
  type: "block-map",
68913
69546
  offset: scalar2.offset,
68914
69547
  indent: scalar2.indent,
68915
- items: [{ start, key: scalar2, sep: sep12 }]
69548
+ items: [{ start, key: scalar2, sep: sep13 }]
68916
69549
  };
68917
69550
  this.onKeyLine = true;
68918
69551
  this.stack[this.stack.length - 1] = map;
@@ -69065,15 +69698,15 @@ var require_parser = __commonJS({
69065
69698
  } else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
69066
69699
  const start2 = getFirstKeyStartProps(it.start);
69067
69700
  const key = it.key;
69068
- const sep12 = it.sep;
69069
- sep12.push(this.sourceToken);
69701
+ const sep13 = it.sep;
69702
+ sep13.push(this.sourceToken);
69070
69703
  delete it.key;
69071
69704
  delete it.sep;
69072
69705
  this.stack.push({
69073
69706
  type: "block-map",
69074
69707
  offset: this.offset,
69075
69708
  indent: this.indent,
69076
- items: [{ start: start2, key, sep: sep12 }]
69709
+ items: [{ start: start2, key, sep: sep13 }]
69077
69710
  });
69078
69711
  } else if (start.length > 0) {
69079
69712
  it.sep = it.sep.concat(start, this.sourceToken);
@@ -69267,13 +69900,13 @@ var require_parser = __commonJS({
69267
69900
  const prev = getPrevProps(parent);
69268
69901
  const start = getFirstKeyStartProps(prev);
69269
69902
  fixFlowSeqItems(fc);
69270
- const sep12 = fc.end.splice(1, fc.end.length);
69271
- sep12.push(this.sourceToken);
69903
+ const sep13 = fc.end.splice(1, fc.end.length);
69904
+ sep13.push(this.sourceToken);
69272
69905
  const map = {
69273
69906
  type: "block-map",
69274
69907
  offset: fc.offset,
69275
69908
  indent: fc.indent,
69276
- items: [{ start, key: fc, sep: sep12 }]
69909
+ items: [{ start, key: fc, sep: sep13 }]
69277
69910
  };
69278
69911
  this.onKeyLine = true;
69279
69912
  this.stack[this.stack.length - 1] = map;
@@ -71167,166 +71800,940 @@ var init_files = __esm({
71167
71800
  }
71168
71801
  });
71169
71802
 
71170
- // ../../packages/oxagen/src/steering-repo/tokens.ts
71171
- function utf8Length(text5) {
71172
- let bytes = 0;
71173
- for (const char of text5) {
71174
- const code = char.codePointAt(0);
71175
- if (code < 128) bytes += 1;
71176
- else if (code < 2048) bytes += 2;
71177
- else if (code < 65536) bytes += 3;
71178
- else bytes += 4;
71803
+ // ../../packages/tacho/src/columns.ts
71804
+ var ENVELOPE_COLUMNS, TACHO_EVENT_COLUMNS;
71805
+ var init_columns = __esm({
71806
+ "../../packages/tacho/src/columns.ts"() {
71807
+ "use strict";
71808
+ init_chain();
71809
+ init_envelope();
71810
+ ENVELOPE_COLUMNS = [
71811
+ // identity (2.1)
71812
+ "host_enrollment_id",
71813
+ "agent_key",
71814
+ "agent_principal_id",
71815
+ "initiating_principal_id",
71816
+ "runtime",
71817
+ "harness",
71818
+ "harness_version",
71819
+ "wrapper_version",
71820
+ "wrapper_attestation",
71821
+ "fidelity",
71822
+ "enforcement_tier",
71823
+ "fleet_id",
71824
+ // anthropic observations (2.2)
71825
+ "anthropic_user_id_hash",
71826
+ "anthropic_account_uuid",
71827
+ "anthropic_account_id",
71828
+ "anthropic_org_uuid",
71829
+ "api_key_source",
71830
+ // session, causality, ordering (2.3)
71831
+ "session_uuid",
71832
+ "harness_session_id",
71833
+ "root_session_uuid",
71834
+ "parent_session_uuid",
71835
+ "subagent_id",
71836
+ "subagent_type",
71837
+ "spawn_depth",
71838
+ "spawn_tool_use_id",
71839
+ "seq",
71840
+ "event_id",
71841
+ "event_id_idem",
71842
+ "ts",
71843
+ "turn_seq",
71844
+ "prompt_id",
71845
+ "turn_id",
71846
+ "trace_id",
71847
+ "span_id",
71848
+ "parent_span_id",
71849
+ "harness_event_sequence",
71850
+ // kind and source (2.4)
71851
+ "kind",
71852
+ "source",
71853
+ "hook_event_name",
71854
+ "hook_source_kind",
71855
+ "otel_event_name",
71856
+ // context (2.5)
71857
+ "cwd",
71858
+ "project_dir",
71859
+ "git_branch",
71860
+ "git_head_sha",
71861
+ "git_remote_digest",
71862
+ "git_dirty",
71863
+ "worktree_path",
71864
+ "worktree_branch",
71865
+ "permission_mode",
71866
+ "effort",
71867
+ "context_model",
71868
+ "entrypoint",
71869
+ "query_source",
71870
+ "session_kind",
71871
+ "terminal_type",
71872
+ "app_version",
71873
+ "output_style",
71874
+ // host (2.14)
71875
+ "hostname_digest",
71876
+ "os_type",
71877
+ "os_version",
71878
+ "host_arch",
71879
+ "os_user_digest",
71880
+ "claude_pid",
71881
+ "claude_ppid",
71882
+ "claude_parent_process",
71883
+ "claude_execpath",
71884
+ "is_child_session",
71885
+ "bridge_session_id",
71886
+ "has_tty",
71887
+ // chain and content (2.13, 2.15)
71888
+ "prev_hash",
71889
+ "hash",
71890
+ "content_digest",
71891
+ "bytes_ref",
71892
+ "redactions",
71893
+ "raw_source_digest",
71894
+ "body",
71895
+ "attrs"
71896
+ ];
71897
+ TACHO_EVENT_COLUMNS = [
71898
+ ...ENVELOPE_COLUMNS,
71899
+ ...BODY_MEMBER_NAMES
71900
+ ];
71179
71901
  }
71180
- return bytes;
71902
+ });
71903
+
71904
+ // ../../packages/tacho/src/evidence/merkle.ts
71905
+ import { createHash as createHash17 } from "node:crypto";
71906
+ function digestToBytes(digest7) {
71907
+ if (!SHA256_DIGEST_PATTERN.test(digest7)) {
71908
+ throw new TypeError(`not a sha256 digest: ${digest7}`);
71909
+ }
71910
+ return Buffer.from(digest7.slice("sha256:".length), "hex");
71181
71911
  }
71182
- function countTokens(text5) {
71183
- return Math.ceil(utf8Length(text5) / 4);
71912
+ function hash2(...parts) {
71913
+ const h = createHash17("sha256");
71914
+ for (const part2 of parts) h.update(part2);
71915
+ return h.digest();
71184
71916
  }
71185
- var DEFAULT_ALWAYS_ON_TOKENS, DEFAULT_WORKSPACE_DEFINITION_BUDGET, DEFAULT_SERVER_DEFINITION_BUDGET, ALWAYS_ON_BODY_WORDS_WARN, SKILL_LINES_WARN, FOLDER_FILES_WARN, RECORD_BYTES_MAX, SKILL_ASSET_BYTES_MAX, OPENAPI_BYTES_MAX, DESCRIPTION_MAX, SKILL_DESCRIPTION_MAX;
71186
- var init_tokens = __esm({
71187
- "../../packages/oxagen/src/steering-repo/tokens.ts"() {
71917
+ function largestPowerOfTwoBelow(n4) {
71918
+ let k = 1;
71919
+ while (k * 2 < n4) k *= 2;
71920
+ return k;
71921
+ }
71922
+ function treeHash(leaves) {
71923
+ if (leaves.length === 0) return hash2();
71924
+ if (leaves.length === 1) return hash2(LEAF_PREFIX, leaves[0]);
71925
+ const k = largestPowerOfTwoBelow(leaves.length);
71926
+ return hash2(
71927
+ NODE_PREFIX,
71928
+ treeHash(leaves.slice(0, k)),
71929
+ treeHash(leaves.slice(k))
71930
+ );
71931
+ }
71932
+ function merkleRoot(digests) {
71933
+ const leaves = digests.map(digestToBytes);
71934
+ return `sha256:${treeHash(leaves).toString("hex")}`;
71935
+ }
71936
+ var LEAF_PREFIX, NODE_PREFIX;
71937
+ var init_merkle = __esm({
71938
+ "../../packages/tacho/src/evidence/merkle.ts"() {
71188
71939
  "use strict";
71189
- DEFAULT_ALWAYS_ON_TOKENS = 4e3;
71190
- DEFAULT_WORKSPACE_DEFINITION_BUDGET = 2e4;
71191
- DEFAULT_SERVER_DEFINITION_BUDGET = 8e3;
71192
- ALWAYS_ON_BODY_WORDS_WARN = 120;
71193
- SKILL_LINES_WARN = 500;
71194
- FOLDER_FILES_WARN = 800;
71195
- RECORD_BYTES_MAX = 256 * 1024;
71196
- SKILL_ASSET_BYTES_MAX = 1024 * 1024;
71197
- OPENAPI_BYTES_MAX = 25 * 1024 * 1024;
71198
- DESCRIPTION_MAX = 200;
71199
- SKILL_DESCRIPTION_MAX = 1024;
71940
+ init_digest();
71941
+ LEAF_PREFIX = Buffer.from([0]);
71942
+ NODE_PREFIX = Buffer.from([1]);
71200
71943
  }
71201
71944
  });
71202
71945
 
71203
- // ../../packages/oxagen/src/steering-repo/record.ts
71204
- function effectiveLoad(record) {
71205
- if (record.load) return record.load;
71206
- return record.force === "must" || record.force === "should" ? "always" : "relevant";
71207
- }
71208
- function isAlwaysOn(record) {
71209
- return record.status === "active" && (record.force === "must" || record.force === "should") && effectiveLoad(record) === "always";
71210
- }
71211
- function splitRecordFile(text5) {
71212
- const lines = text5.split("\n");
71213
- if (lines[0] !== "---") {
71214
- return {
71215
- ok: false,
71216
- issue: {
71217
- line: 1,
71218
- field: null,
71219
- message: "a record starts with --- on its own line"
71220
- }
71221
- };
71946
+ // ../../packages/tacho/src/evidence/archive-segment.ts
71947
+ var encoder3, decoder;
71948
+ var init_archive_segment = __esm({
71949
+ "../../packages/tacho/src/evidence/archive-segment.ts"() {
71950
+ "use strict";
71951
+ init_digest();
71952
+ init_merkle();
71953
+ encoder3 = new TextEncoder();
71954
+ decoder = new TextDecoder("utf-8", { fatal: true });
71222
71955
  }
71223
- const close = lines.indexOf("---", 1);
71224
- if (close < 0) {
71225
- return {
71226
- ok: false,
71227
- issue: {
71228
- line: 1,
71229
- field: null,
71230
- message: "the frontmatter has no closing --- line"
71231
- }
71232
- };
71956
+ });
71957
+
71958
+ // ../../packages/tacho/src/evidence/transcript-kinds.ts
71959
+ function isTranscriptKind(value) {
71960
+ return typeof value === "string" && TRANSCRIPT_KINDS.includes(value);
71961
+ }
71962
+ var TRANSCRIPT_KINDS;
71963
+ var init_transcript_kinds = __esm({
71964
+ "../../packages/tacho/src/evidence/transcript-kinds.ts"() {
71965
+ "use strict";
71966
+ TRANSCRIPT_KINDS = [
71967
+ /**
71968
+ * The prompt an operator typed to open a turn: a `turn_start` on the run's
71969
+ * own chain. The request half of a model call is the context the model was
71970
+ * sent, and answers no chip.
71971
+ */
71972
+ "prompt",
71973
+ /**
71974
+ * What came back: a model call's response half or single receipt whose
71975
+ * body was kept, and a reply the harness reported with its words kept
71976
+ * (`turn_end`, or a message recorded as a response).
71977
+ */
71978
+ "responses",
71979
+ /**
71980
+ * A model call that spent reasoning tokens (`thinking_tokens`). The text of
71981
+ * the reasoning shows where the recorder kept the stream; the count shows
71982
+ * wherever the provider reported it.
71983
+ */
71984
+ "thinking",
71985
+ /** Either half of a tool call. */
71986
+ "tools",
71987
+ /** A decision a rule or a person made about a call: allow, deny, route. */
71988
+ "policy",
71989
+ /**
71990
+ * A frame that carried a cost record or token counts without one, or a
71991
+ * model call that recorded the reasoning effort it ran at.
71992
+ */
71993
+ "usage",
71994
+ /** What was pulled into the model's context. */
71995
+ "recall",
71996
+ /**
71997
+ * The run's own stop: the wrapped agent's `agent_stop` on the run's own
71998
+ * chain, or the ledger event that closes an attempt before its seal. The
71999
+ * chain's checkpoints and gaps are read on the Chain tab, not here.
72000
+ */
72001
+ "seal",
72002
+ /** A call that did not do what it was asked to. */
72003
+ "errors"
72004
+ ];
71233
72005
  }
71234
- return {
71235
- ok: true,
71236
- parts: {
71237
- frontmatter: lines.slice(1, close).join("\n"),
71238
- body: lines.slice(close + 1).join("\n"),
71239
- body_line: close + 2
71240
- }
71241
- };
72006
+ });
72007
+
72008
+ // ../../packages/tacho/src/evidence/attestation.ts
72009
+ import {
72010
+ createPrivateKey as createPrivateKey2,
72011
+ createPublicKey as createPublicKey4,
72012
+ sign as sign3,
72013
+ verify as verify5
72014
+ } from "node:crypto";
72015
+ function attestationBytes(payload) {
72016
+ return Buffer.from(jcs(payload), "utf8");
71242
72017
  }
71243
- function strictSubsetIssues(doc, lineOf) {
71244
- const issues = [];
71245
- const at = (range) => range ? lineOf(range[0]) : null;
71246
- (0, import_yaml.visit)(doc, {
71247
- Alias(_key, node2) {
71248
- issues.push({
71249
- line: at(node2.range),
71250
- field: null,
71251
- message: "the frontmatter uses a YAML alias. Write the value out."
71252
- });
72018
+ function verifyAttestation(attestation, publicKeyPem) {
72019
+ if (attestation.alg !== "ed25519") return false;
72020
+ if (attestation.key_id !== keyIdForPublicKey(publicKeyPem)) return false;
72021
+ try {
72022
+ return verify5(
72023
+ null,
72024
+ attestationBytes(attestation.payload),
72025
+ createPublicKey4(publicKeyPem),
72026
+ Buffer.from(attestation.sig, "base64")
72027
+ );
72028
+ } catch {
72029
+ return false;
72030
+ }
72031
+ }
72032
+ var init_attestation = __esm({
72033
+ "../../packages/tacho/src/evidence/attestation.ts"() {
72034
+ "use strict";
72035
+ init_digest();
72036
+ init_key_id();
72037
+ }
72038
+ });
72039
+
72040
+ // ../../packages/tacho/src/evidence/run-export.ts
72041
+ function normalizeInstant(value) {
72042
+ const m = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(?:\.(\d+))?(Z|[+-]\d{2}(?::?\d{2})?)$/.exec(
72043
+ value
72044
+ );
72045
+ if (!m) return value;
72046
+ const [, day, time, frac, zone] = m;
72047
+ const ms = (frac ?? "").slice(0, 3).padEnd(3, "0");
72048
+ let offset = zone;
72049
+ if (zone !== "Z") {
72050
+ const digits = zone.slice(1).replace(":", "");
72051
+ offset = `${zone[0]}${digits.slice(0, 2)}:${(digits.slice(2) || "00").padEnd(2, "0")}`;
72052
+ }
72053
+ const instant3 = /* @__PURE__ */ new Date(`${day}T${time}.${ms}${offset}`);
72054
+ return Number.isNaN(instant3.getTime()) ? value : instant3.toISOString();
72055
+ }
72056
+ function wrappedFrameOf(event, bytesRef) {
72057
+ const body2 = asRecord2(event["body"]) ?? {};
72058
+ const content = asRecord2(event["content"]);
72059
+ const turn = asRecord2(event["turn"]);
72060
+ const text5 = (value) => typeof value === "string" ? value : "";
72061
+ const count12 = (value) => typeof value === "number" ? value : null;
72062
+ return {
72063
+ event_id: event["event_id"] ?? null,
72064
+ seq: event["seq"] ?? null,
72065
+ ts: event["ts"] ?? null,
72066
+ kind: event["kind"] ?? null,
72067
+ prev_hash: event["prev_hash"] ?? null,
72068
+ hash: event["hash"] ?? null,
72069
+ content: {
72070
+ digest: content?.["digest"] ?? null,
72071
+ bytes_ref: bytesRef,
72072
+ redactions: content?.["redactions"] ?? []
71253
72073
  },
71254
- Node(_key, node2) {
71255
- if (node2.anchor) {
71256
- issues.push({
71257
- line: at(node2.range),
71258
- field: null,
71259
- message: "the frontmatter uses a YAML anchor. Write the value out."
71260
- });
72074
+ body: event["body"] ?? null,
72075
+ tool_name: text5(body2["tool_name"]),
72076
+ tool_status: text5(body2["tool_status"]),
72077
+ tool_use_id: text5(body2["tool_use_id"]),
72078
+ model: text5(body2["model"]),
72079
+ provider: text5(body2["provider"]),
72080
+ policy_decision: text5(body2["policy_decision"]),
72081
+ cost_usd_micros: count12(body2["cost_usd_micros"]),
72082
+ turn_seq: count12(turn?.["turn_seq"]),
72083
+ event
72084
+ };
72085
+ }
72086
+ function asRecord2(value) {
72087
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
72088
+ }
72089
+ function tally(counts) {
72090
+ return [...counts.entries()].map(([kind, { count: count12, frames }]) => ({ kind, count: count12, frames })).sort((a, b5) => a.kind.localeCompare(b5.kind));
72091
+ }
72092
+ function summarizeRunExportRedactions(envelopes) {
72093
+ const redacted = /* @__PURE__ */ new Map();
72094
+ const withheld = /* @__PURE__ */ new Map();
72095
+ const bump = (map, kind, count12) => {
72096
+ const entry2 = map.get(kind) ?? { count: 0, frames: 0 };
72097
+ entry2.count += count12;
72098
+ entry2.frames += 1;
72099
+ map.set(kind, entry2);
72100
+ };
72101
+ let total2 = 0;
72102
+ for (const envelope2 of envelopes) {
72103
+ const frame = asRecord2(envelope2);
72104
+ if (!frame) continue;
72105
+ const content = asRecord2(frame["content"]);
72106
+ const list = content?.["redactions"];
72107
+ if (Array.isArray(list)) {
72108
+ const perReason = /* @__PURE__ */ new Map();
72109
+ for (const item of list) {
72110
+ const reason3 = asRecord2(item)?.["reason"];
72111
+ const kind = typeof reason3 === "string" ? reason3 : "unknown";
72112
+ perReason.set(kind, (perReason.get(kind) ?? 0) + 1);
71261
72113
  }
71262
- if (node2.tag) {
71263
- issues.push({
71264
- line: at(node2.range),
71265
- field: null,
71266
- message: `the frontmatter uses the YAML tag ${node2.tag}. Remove it.`
71267
- });
72114
+ for (const [kind, count12] of perReason) {
72115
+ bump(redacted, kind, count12);
72116
+ total2 += count12;
71268
72117
  }
71269
72118
  }
72119
+ if (typeof content?.["bytes_ref"] === "string") {
72120
+ bump(withheld, WITHHELD_BODY, 1);
72121
+ }
72122
+ if (typeof frame["encrypted_payload_ref"] === "string") {
72123
+ bump(withheld, WITHHELD_ENCRYPTED_PAYLOAD, 1);
72124
+ }
72125
+ }
72126
+ return {
72127
+ format: RUN_EXPORT_REDACTIONS_FORMAT,
72128
+ redacted: tally(redacted),
72129
+ redacted_total: total2,
72130
+ withheld: tally(withheld)
72131
+ };
72132
+ }
72133
+ function digestOf2(frame) {
72134
+ const value = frame["event_digest"] ?? frame["hash"];
72135
+ return typeof value === "string" && DIGEST2.test(value) ? value : null;
72136
+ }
72137
+ function safeDigestJcs(value) {
72138
+ try {
72139
+ return digestJcs(value);
72140
+ } catch {
72141
+ return null;
72142
+ }
72143
+ }
72144
+ function checkWrappedFrame(frame, attemptId) {
72145
+ if (frame["event"] === void 0 || frame["event"] === null) {
72146
+ return { digest: "not_carried", reasons: [] };
72147
+ }
72148
+ const event = asRecord2(frame["event"]);
72149
+ if (!event) {
72150
+ return { digest: "broken", reasons: ["event is not a JSON object"] };
72151
+ }
72152
+ const reasons = [];
72153
+ if (event["session_uuid"] !== attemptId) {
72154
+ reasons.push(
72155
+ `the event belongs to session ${String(event["session_uuid"])}, not ${attemptId}`
72156
+ );
72157
+ }
72158
+ let holds2;
72159
+ try {
72160
+ holds2 = eventHashHolds(event, frame["hash"]);
72161
+ } catch {
72162
+ holds2 = false;
72163
+ }
72164
+ if (!holds2) {
72165
+ reasons.push("the event does not hash to hash");
72166
+ }
72167
+ const content = asRecord2(frame["content"]);
72168
+ const bytesRef = typeof content?.["bytes_ref"] === "string" ? content["bytes_ref"] : null;
72169
+ const expected = wrappedFrameOf(event, bytesRef);
72170
+ const differs2 = [
72171
+ .../* @__PURE__ */ new Set([...Object.keys(expected), ...Object.keys(frame)])
72172
+ ].filter((name) => name !== "event").filter((name) => {
72173
+ const shown2 = frame[name];
72174
+ const read2 = expected[name];
72175
+ if (shown2 === void 0 || read2 === void 0) return true;
72176
+ return jcs(shown2) !== jcs(read2);
72177
+ }).sort();
72178
+ if (differs2.length > 0) {
72179
+ const verb = differs2.length === 1 ? "differs" : "differ";
72180
+ reasons.push(`${differs2.join(", ")} ${verb} from the hashed event`);
72181
+ }
72182
+ return { digest: reasons.length > 0 ? "broken" : "held", reasons };
72183
+ }
72184
+ function checkLedgerFrame(frame) {
72185
+ const reasons = [];
72186
+ const payloadDigest = frame["payload_digest"];
72187
+ let digest7 = "held";
72188
+ if (frame["payload_inline"] !== null && frame["payload_inline"] !== void 0) {
72189
+ const recomputed2 = safeDigestJcs(frame["payload_inline"]);
72190
+ if (recomputed2 !== payloadDigest) {
72191
+ digest7 = "broken";
72192
+ reasons.push("payload does not hash to payload_digest");
72193
+ }
72194
+ } else if (typeof frame["encrypted_payload_ref"] !== "string") {
72195
+ digest7 = "broken";
72196
+ reasons.push("frame carries neither a payload nor an encrypted reference");
72197
+ }
72198
+ const recomputed = safeDigestJcs({
72199
+ attempt_seq: frame["attempt_seq"] ?? null,
72200
+ event_schema_version: frame["event_schema_version"] ?? null,
72201
+ event_type: frame["event_type"] ?? null,
72202
+ stage: frame["stage"] ?? null,
72203
+ payload_digest: payloadDigest ?? null,
72204
+ observed_at: typeof frame["observed_at"] === "string" ? normalizeInstant(frame["observed_at"]) : frame["observed_at"] ?? null
71270
72205
  });
71271
- return issues;
72206
+ if (recomputed !== frame["event_digest"]) {
72207
+ digest7 = "broken";
72208
+ reasons.push("identity fields do not hash to event_digest");
72209
+ }
72210
+ return { digest: digest7, reasons };
71272
72211
  }
71273
- function parseFrontmatter(yamlText, firstLine3 = 2) {
71274
- const counter = new import_yaml.LineCounter();
71275
- const lineOf = (offset) => counter.linePos(offset).line + firstLine3 - 1;
71276
- const docs = (0, import_yaml.parseAllDocuments)(yamlText, {
71277
- lineCounter: counter,
71278
- uniqueKeys: true
72212
+ function parseJson2(text5, name, checks) {
72213
+ try {
72214
+ return JSON.parse(text5);
72215
+ } catch {
72216
+ checks.push({ name, status: "broken", detail: `${name} is not JSON` });
72217
+ return null;
72218
+ }
72219
+ }
72220
+ function verifyRunExport(files3) {
72221
+ const checks = [];
72222
+ const hold = (name, ok2, held, broken) => checks.push({
72223
+ name,
72224
+ status: ok2 ? "held" : "broken",
72225
+ detail: ok2 ? held : broken
71279
72226
  });
71280
- const doc = docs[0];
71281
- if (docs.length !== 1 || doc === void 0) {
72227
+ const manifest = parseJson2(
72228
+ files3["manifest.json"],
72229
+ "manifest",
72230
+ checks
72231
+ );
72232
+ const attestationFile = parseJson2(
72233
+ files3["attestation.json"],
72234
+ "attestation",
72235
+ checks
72236
+ );
72237
+ const raw = files3["frames.ndjson"];
72238
+ const text5 = raw.endsWith("\n") ? raw.slice(0, -1) : raw;
72239
+ const lines = text5.length === 0 ? [] : text5.split("\n");
72240
+ const frames = [];
72241
+ const verdicts = [];
72242
+ lines.forEach((line, i2) => {
72243
+ let parsed2 = null;
72244
+ try {
72245
+ parsed2 = asRecord2(JSON.parse(line));
72246
+ } catch {
72247
+ parsed2 = null;
72248
+ }
72249
+ frames.push(parsed2 ?? {});
72250
+ if (!parsed2) {
72251
+ verdicts.push({
72252
+ line: i2 + 1,
72253
+ attempt_id: "",
72254
+ seq: null,
72255
+ status: "broken",
72256
+ digest: "broken",
72257
+ link: "broken",
72258
+ reasons: ["line is not a JSON object"]
72259
+ });
72260
+ }
72261
+ });
72262
+ if (!manifest || !attestationFile) {
71282
72263
  return {
71283
72264
  ok: false,
71284
- issues: [
71285
- {
71286
- line: firstLine3,
71287
- field: null,
71288
- message: docs.length === 0 ? "the frontmatter is empty" : "the frontmatter holds more than one YAML document"
71289
- }
71290
- ]
72265
+ run_id: manifest?.run_id ?? null,
72266
+ format: manifest?.format ?? null,
72267
+ frames: verdicts,
72268
+ checks,
72269
+ redactions: null
71291
72270
  };
71292
72271
  }
71293
- const issues = doc.errors.map((error) => ({
71294
- line: error.linePos ? error.linePos[0].line + firstLine3 - 1 : null,
71295
- field: null,
71296
- message: error.message.split("\n", 1)[0]
71297
- }));
71298
- issues.push(...strictSubsetIssues(doc, lineOf));
71299
- if (issues.length > 0) return { ok: false, issues };
71300
- if (!(0, import_yaml.isMap)(doc.contents)) {
71301
- return {
71302
- ok: false,
71303
- issues: [
71304
- {
71305
- line: firstLine3,
71306
- field: null,
71307
- message: "the frontmatter is not a mapping of fields"
72272
+ hold(
72273
+ "format",
72274
+ ACCEPTED_FORMATS.has(manifest.format),
72275
+ manifest.format,
72276
+ `unknown bundle format ${String(manifest.format)}`
72277
+ );
72278
+ hold(
72279
+ "source",
72280
+ typeof manifest.run_id === "string" && (manifest.source === "ledger" && manifest.run_id.startsWith("arun_") || manifest.source === "tacho" && manifest.run_id.startsWith("tse_")),
72281
+ "the source matches the run identifier",
72282
+ "the source is invalid or does not match the run identifier"
72283
+ );
72284
+ const byLine = new Map(verdicts.map((v) => [v.line, v]));
72285
+ let offset = 0;
72286
+ for (const attempt of manifest.attempts ?? []) {
72287
+ let prevHash = null;
72288
+ let prevSeq = null;
72289
+ let stream = EMPTY_EVENT_STREAM_DIGEST;
72290
+ const end = Math.min(offset + attempt.frame_count, frames.length);
72291
+ for (let i2 = offset; i2 < end; i2 += 1) {
72292
+ const line = i2 + 1;
72293
+ if (byLine.has(line)) continue;
72294
+ const frame = frames[i2];
72295
+ const reasons = [];
72296
+ let digest7;
72297
+ let link = "held";
72298
+ let seq = null;
72299
+ if (manifest.source === "ledger") {
72300
+ const own = checkLedgerFrame(frame);
72301
+ digest7 = own.digest;
72302
+ reasons.push(...own.reasons);
72303
+ const attemptSeq = frame["attempt_seq"];
72304
+ seq = typeof attemptSeq === "number" ? attemptSeq : null;
72305
+ const expected = prevSeq === null ? 1 : prevSeq + 1;
72306
+ if (seq !== expected) {
72307
+ link = "broken";
72308
+ reasons.push(`attempt_seq ${String(seq)} where ${expected} was due`);
71308
72309
  }
71309
- ]
71310
- };
72310
+ prevSeq = seq;
72311
+ stream = digestJcs({
72312
+ previous: stream,
72313
+ entry: [
72314
+ frame["attempt_seq"] ?? null,
72315
+ frame["event_schema_version"] ?? null,
72316
+ frame["event_type"] ?? null,
72317
+ frame["payload_digest"] ?? null
72318
+ ]
72319
+ });
72320
+ } else {
72321
+ const own = checkWrappedFrame(frame, attempt.attempt_id);
72322
+ digest7 = own.digest;
72323
+ reasons.push(...own.reasons);
72324
+ const rawSeq = frame["seq"];
72325
+ seq = typeof rawSeq === "number" ? rawSeq : null;
72326
+ const expectedPrev = prevHash ?? (seq === 0 ? GENESIS_PREV_HASH2 : null);
72327
+ if (expectedPrev !== null && frame["prev_hash"] !== expectedPrev) {
72328
+ link = "broken";
72329
+ reasons.push(
72330
+ prevHash === null ? 'genesis prev_hash is not sha256("")' : "prev_hash is not the previous frame's hash"
72331
+ );
72332
+ }
72333
+ if (prevSeq !== null && seq !== prevSeq + 1) {
72334
+ link = "broken";
72335
+ reasons.push(`seq ${String(seq)} where ${prevSeq + 1} was due`);
72336
+ }
72337
+ prevSeq = seq;
72338
+ prevHash = typeof frame["hash"] === "string" ? frame["hash"] : null;
72339
+ }
72340
+ if (digestOf2(frame) === null) {
72341
+ digest7 = "broken";
72342
+ reasons.push("frame carries no sha256 digest");
72343
+ }
72344
+ verdicts.push({
72345
+ line,
72346
+ attempt_id: attempt.attempt_id,
72347
+ seq,
72348
+ status: digest7 === "broken" || link === "broken" ? "broken" : "held",
72349
+ digest: digest7,
72350
+ link,
72351
+ reasons
72352
+ });
72353
+ }
72354
+ if (manifest.source === "ledger" && typeof attempt.event_stream_digest === "string") {
72355
+ hold(
72356
+ `stream ${attempt.attempt_id}`,
72357
+ stream === attempt.event_stream_digest,
72358
+ "the frames fold to the sealed event_stream_digest",
72359
+ `the frames fold to ${stream}, the seal recorded ${attempt.event_stream_digest}`
72360
+ );
72361
+ }
72362
+ offset += attempt.frame_count;
71311
72363
  }
71312
- const key_lines = /* @__PURE__ */ new Map();
71313
- for (const pair of doc.contents.items) {
71314
- if ((0, import_yaml.isScalar)(pair.key) && pair.key.range) {
71315
- key_lines.set(String(pair.key.value), lineOf(pair.key.range[0]));
72364
+ for (let i2 = offset; i2 < frames.length; i2 += 1) {
72365
+ if (byLine.has(i2 + 1)) continue;
72366
+ verdicts.push({
72367
+ line: i2 + 1,
72368
+ attempt_id: "",
72369
+ seq: null,
72370
+ status: "broken",
72371
+ digest: "broken",
72372
+ link: "broken",
72373
+ reasons: ["frame lies outside every attested attempt"]
72374
+ });
72375
+ }
72376
+ verdicts.sort((a, b5) => a.line - b5.line);
72377
+ hold(
72378
+ "frame count",
72379
+ frames.length === manifest.frame_count,
72380
+ `${frames.length} frames`,
72381
+ `${frames.length} frames where the manifest says ${manifest.frame_count}`
72382
+ );
72383
+ const digests = frames.map(digestOf2);
72384
+ const allDigests = digests.every((d) => d !== null);
72385
+ const root = allDigests ? merkleRoot(digests) : null;
72386
+ hold(
72387
+ "merkle root",
72388
+ root === manifest.merkle_root,
72389
+ `root ${manifest.merkle_root}`,
72390
+ `frames hash to ${root ?? "nothing"}, the manifest says ${manifest.merkle_root}`
72391
+ );
72392
+ const pem = attestationFile.public_key_pem;
72393
+ let keyId = null;
72394
+ try {
72395
+ keyId = keyIdForPublicKey(pem);
72396
+ } catch {
72397
+ keyId = null;
72398
+ }
72399
+ hold(
72400
+ "attester key",
72401
+ keyId !== null && keyId === attestationFile.key_id && keyId === manifest.attester_key_id,
72402
+ `key ${String(keyId)}`,
72403
+ "the bundled public key does not match the recorded key id"
72404
+ );
72405
+ let covered = 0;
72406
+ const attestations = attestationFile.attestations ?? [];
72407
+ attestations.forEach((a, i2) => {
72408
+ const attemptId = a.payload?.attempt_id ?? `#${i2 + 1}`;
72409
+ hold(
72410
+ `signature ${attemptId}`,
72411
+ keyId !== null && verifyAttestation(a, pem),
72412
+ "Ed25519 signature verifies",
72413
+ "the attestation signature does not verify"
72414
+ );
72415
+ const slice = digests.slice(
72416
+ covered,
72417
+ covered + (a.payload?.frame_count ?? 0)
72418
+ );
72419
+ if (manifest.source === "tacho") {
72420
+ const exportedDigest = digestBytes(
72421
+ lines.slice(covered, covered + (a.payload?.frame_count ?? 0)).join("\n")
72422
+ );
72423
+ hold(
72424
+ `exported content ${attemptId}`,
72425
+ exportedDigest === a.payload?.archive_segment_digest,
72426
+ "the exported frame bytes match the signed segment digest",
72427
+ "the exported frame bytes do not match the signed segment digest"
72428
+ );
72429
+ }
72430
+ hold(
72431
+ `run identity ${attemptId}`,
72432
+ a.payload?.run_id === manifest.run_id,
72433
+ "the attestation names this run",
72434
+ "the manifest run differs from the signed run"
72435
+ );
72436
+ covered += a.payload?.frame_count ?? 0;
72437
+ const attemptRoot = slice.every((d) => d !== null) ? merkleRoot(slice) : null;
72438
+ hold(
72439
+ `attested root ${attemptId}`,
72440
+ attemptRoot === a.payload?.merkle_root,
72441
+ "the attempt's frames hash to the signed root",
72442
+ `the attempt's frames hash to ${attemptRoot ?? "nothing"}, the attestation signed ${String(a.payload?.merkle_root)}`
72443
+ );
72444
+ });
72445
+ hold(
72446
+ "coverage",
72447
+ covered === frames.length && attestations.length > 0,
72448
+ "the attestations cover every frame",
72449
+ `the attestations cover ${covered} of ${frames.length} frames`
72450
+ );
72451
+ let redactions = null;
72452
+ const redactionsText = files3["redactions.json"];
72453
+ if (redactionsText !== void 0) {
72454
+ redactions = parseJson2(
72455
+ redactionsText,
72456
+ "redactions",
72457
+ checks
72458
+ );
72459
+ if (redactions) {
72460
+ const recomputed = summarizeRunExportRedactions(frames);
72461
+ hold(
72462
+ "redactions",
72463
+ digestJcs(recomputed) === digestJcs(redactions),
72464
+ `${recomputed.redacted_total} redaction(s) summarised`,
72465
+ "redactions.json does not match what the frames record"
72466
+ );
71316
72467
  }
72468
+ } else if (manifest.format !== FORMAT_1) {
72469
+ hold("redactions", false, "", "redactions.json is missing");
71317
72470
  }
72471
+ const ok = verdicts.length === frames.length && verdicts.every((v) => v.status === "held") && checks.every((c) => c.status === "held");
71318
72472
  return {
71319
- ok: true,
71320
- frontmatter: {
71321
- value: doc.toJS({ maxAliasCount: 0 }),
71322
- key_lines
71323
- }
72473
+ ok,
72474
+ run_id: manifest.run_id,
72475
+ format: manifest.format,
72476
+ frames: verdicts,
72477
+ checks,
72478
+ redactions
71324
72479
  };
71325
72480
  }
71326
- function readSteeringRecord(text5) {
71327
- const encoding = encodingIssues(text5);
71328
- if (encoding.length > 0) return { ok: false, issues: encoding };
71329
- const split = splitRecordFile(text5);
72481
+ var RUN_EXPORT_FORMAT, FORMAT_1, ACCEPTED_FORMATS, RUN_EXPORT_REDACTIONS_FORMAT, GENESIS_PREV_HASH2, EMPTY_EVENT_STREAM_DIGEST, DIGEST2, WITHHELD_BODY, WITHHELD_ENCRYPTED_PAYLOAD;
72482
+ var init_run_export = __esm({
72483
+ "../../packages/tacho/src/evidence/run-export.ts"() {
72484
+ "use strict";
72485
+ init_chain();
72486
+ init_digest();
72487
+ init_key_id();
72488
+ init_attestation();
72489
+ init_merkle();
72490
+ RUN_EXPORT_FORMAT = "oxagen.run-export/3";
72491
+ FORMAT_1 = "oxagen.run-export/1";
72492
+ ACCEPTED_FORMATS = /* @__PURE__ */ new Set([
72493
+ FORMAT_1,
72494
+ "oxagen.run-export/2",
72495
+ RUN_EXPORT_FORMAT
72496
+ ]);
72497
+ RUN_EXPORT_REDACTIONS_FORMAT = "oxagen.run-export.redactions/1";
72498
+ GENESIS_PREV_HASH2 = digestBytes("");
72499
+ EMPTY_EVENT_STREAM_DIGEST = digestJcs([]);
72500
+ DIGEST2 = /^sha256:[0-9a-f]{64}$/;
72501
+ WITHHELD_BODY = "frame_body";
72502
+ WITHHELD_ENCRYPTED_PAYLOAD = "encrypted_payload";
72503
+ }
72504
+ });
72505
+
72506
+ // ../../packages/tacho/src/evidence/index.ts
72507
+ var init_evidence = __esm({
72508
+ "../../packages/tacho/src/evidence/index.ts"() {
72509
+ "use strict";
72510
+ init_archive_segment();
72511
+ init_merkle();
72512
+ init_redaction();
72513
+ init_retention();
72514
+ init_replay_grade();
72515
+ init_transcript_kinds();
72516
+ init_attestation();
72517
+ init_frame_body();
72518
+ init_run_export();
72519
+ }
72520
+ });
72521
+
72522
+ // ../../packages/tacho/src/session-subject.ts
72523
+ var ENRICHMENT_BUDGET_NOTE, ENRICHMENT_LIMIT_NOTE, PARTIAL_NOTE_HEAD, PARTIAL_NOTE_TAIL, escapeRegExp2, NOTE_SOURCE, TRAILING_NOTES, GITHUB_REF_SOURCE;
72524
+ var init_session_subject = __esm({
72525
+ "../../packages/tacho/src/session-subject.ts"() {
72526
+ "use strict";
72527
+ ENRICHMENT_BUDGET_NOTE = " The account covers only the start of the run: its enrichment budget ran out before the rest was read.";
72528
+ ENRICHMENT_LIMIT_NOTE = " The account covers only the start of the run because its transcript reached a read limit.";
72529
+ PARTIAL_NOTE_HEAD = "Evidence is partial: ";
72530
+ PARTIAL_NOTE_TAIL = " recorded bodies were unavailable.";
72531
+ escapeRegExp2 = (text5) => text5.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
72532
+ NOTE_SOURCE = [
72533
+ `${escapeRegExp2(PARTIAL_NOTE_HEAD)}\\d+${escapeRegExp2(PARTIAL_NOTE_TAIL)}`,
72534
+ escapeRegExp2(ENRICHMENT_BUDGET_NOTE.trim()),
72535
+ escapeRegExp2(ENRICHMENT_LIMIT_NOTE.trim())
72536
+ ].join("|");
72537
+ TRAILING_NOTES = new RegExp(
72538
+ `(?:^|\\s)((?:${NOTE_SOURCE})(?:\\s(?:${NOTE_SOURCE}))*)$`,
72539
+ "u"
72540
+ );
72541
+ GITHUB_REF_SOURCE = String.raw`\bhttps?:\/\/(?:www\.)?github\.com\/[\w.-]+\/[\w.-]+\/(pull|issues)\/(\d+)\S*`;
72542
+ }
72543
+ });
72544
+
72545
+ // ../../packages/tacho/src/session-title.ts
72546
+ var init_session_title = __esm({
72547
+ "../../packages/tacho/src/session-title.ts"() {
72548
+ "use strict";
72549
+ init_session_subject();
72550
+ }
72551
+ });
72552
+
72553
+ // ../../packages/tacho/src/index.ts
72554
+ var init_src4 = __esm({
72555
+ "../../packages/tacho/src/index.ts"() {
72556
+ "use strict";
72557
+ init_chain();
72558
+ init_columns();
72559
+ init_digest();
72560
+ init_envelope();
72561
+ init_harness_limits();
72562
+ init_ids();
72563
+ init_interjection();
72564
+ init_record_basis();
72565
+ init_remote();
72566
+ init_timestamp();
72567
+ init_wire();
72568
+ init_evidence();
72569
+ init_llm_call_dedupe();
72570
+ init_session_subject();
72571
+ init_session_title();
72572
+ init_context_window();
72573
+ }
72574
+ });
72575
+
72576
+ // ../../packages/oxagen/src/steering-repo/tokens.ts
72577
+ function utf8Length(text5) {
72578
+ let bytes = 0;
72579
+ for (const char of text5) {
72580
+ const code = char.codePointAt(0);
72581
+ if (code < 128) bytes += 1;
72582
+ else if (code < 2048) bytes += 2;
72583
+ else if (code < 65536) bytes += 3;
72584
+ else bytes += 4;
72585
+ }
72586
+ return bytes;
72587
+ }
72588
+ function countTokens(text5) {
72589
+ return Math.ceil(utf8Length(text5) / 4);
72590
+ }
72591
+ var DEFAULT_ALWAYS_ON_TOKENS, DEFAULT_WORKSPACE_DEFINITION_BUDGET, DEFAULT_SERVER_DEFINITION_BUDGET, ALWAYS_ON_BODY_WORDS_WARN, SKILL_LINES_WARN, FOLDER_FILES_WARN, RECORD_BYTES_MAX, SKILL_ASSET_BYTES_MAX, OPENAPI_BYTES_MAX, DESCRIPTION_MAX, SKILL_DESCRIPTION_MAX;
72592
+ var init_tokens = __esm({
72593
+ "../../packages/oxagen/src/steering-repo/tokens.ts"() {
72594
+ "use strict";
72595
+ init_src4();
72596
+ DEFAULT_ALWAYS_ON_TOKENS = LARGEST_PREFIX_BUDGET_TOKENS;
72597
+ DEFAULT_WORKSPACE_DEFINITION_BUDGET = 2e4;
72598
+ DEFAULT_SERVER_DEFINITION_BUDGET = 8e3;
72599
+ ALWAYS_ON_BODY_WORDS_WARN = 120;
72600
+ SKILL_LINES_WARN = 500;
72601
+ FOLDER_FILES_WARN = 800;
72602
+ RECORD_BYTES_MAX = 256 * 1024;
72603
+ SKILL_ASSET_BYTES_MAX = 1024 * 1024;
72604
+ OPENAPI_BYTES_MAX = 25 * 1024 * 1024;
72605
+ DESCRIPTION_MAX = 200;
72606
+ SKILL_DESCRIPTION_MAX = 1024;
72607
+ }
72608
+ });
72609
+
72610
+ // ../../packages/oxagen/src/steering-repo/record.ts
72611
+ function effectiveLoad(record) {
72612
+ if (record.load) return record.load;
72613
+ return record.force === "must" || record.force === "should" ? "always" : "relevant";
72614
+ }
72615
+ function isAlwaysOn(record) {
72616
+ return record.status === "active" && (record.force === "must" || record.force === "should") && effectiveLoad(record) === "always";
72617
+ }
72618
+ function splitRecordFile(text5) {
72619
+ const lines = text5.split("\n");
72620
+ if (lines[0] !== "---") {
72621
+ return {
72622
+ ok: false,
72623
+ issue: {
72624
+ line: 1,
72625
+ field: null,
72626
+ message: "a record starts with --- on its own line"
72627
+ }
72628
+ };
72629
+ }
72630
+ const close = lines.indexOf("---", 1);
72631
+ if (close < 0) {
72632
+ return {
72633
+ ok: false,
72634
+ issue: {
72635
+ line: 1,
72636
+ field: null,
72637
+ message: "the frontmatter has no closing --- line"
72638
+ }
72639
+ };
72640
+ }
72641
+ return {
72642
+ ok: true,
72643
+ parts: {
72644
+ frontmatter: lines.slice(1, close).join("\n"),
72645
+ body: lines.slice(close + 1).join("\n"),
72646
+ body_line: close + 2
72647
+ }
72648
+ };
72649
+ }
72650
+ function strictSubsetIssues(doc, lineOf) {
72651
+ const issues = [];
72652
+ const at = (range) => range ? lineOf(range[0]) : null;
72653
+ (0, import_yaml.visit)(doc, {
72654
+ Alias(_key, node2) {
72655
+ issues.push({
72656
+ line: at(node2.range),
72657
+ field: null,
72658
+ message: "the frontmatter uses a YAML alias. Write the value out."
72659
+ });
72660
+ },
72661
+ Node(_key, node2) {
72662
+ if (node2.anchor) {
72663
+ issues.push({
72664
+ line: at(node2.range),
72665
+ field: null,
72666
+ message: "the frontmatter uses a YAML anchor. Write the value out."
72667
+ });
72668
+ }
72669
+ if (node2.tag) {
72670
+ issues.push({
72671
+ line: at(node2.range),
72672
+ field: null,
72673
+ message: `the frontmatter uses the YAML tag ${node2.tag}. Remove it.`
72674
+ });
72675
+ }
72676
+ }
72677
+ });
72678
+ return issues;
72679
+ }
72680
+ function parseFrontmatter(yamlText, firstLine3 = 2) {
72681
+ const counter = new import_yaml.LineCounter();
72682
+ const lineOf = (offset) => counter.linePos(offset).line + firstLine3 - 1;
72683
+ const docs = (0, import_yaml.parseAllDocuments)(yamlText, {
72684
+ lineCounter: counter,
72685
+ uniqueKeys: true
72686
+ });
72687
+ const doc = docs[0];
72688
+ if (docs.length !== 1 || doc === void 0) {
72689
+ return {
72690
+ ok: false,
72691
+ issues: [
72692
+ {
72693
+ line: firstLine3,
72694
+ field: null,
72695
+ message: docs.length === 0 ? "the frontmatter is empty" : "the frontmatter holds more than one YAML document"
72696
+ }
72697
+ ]
72698
+ };
72699
+ }
72700
+ const issues = doc.errors.map((error) => ({
72701
+ line: error.linePos ? error.linePos[0].line + firstLine3 - 1 : null,
72702
+ field: null,
72703
+ message: error.message.split("\n", 1)[0]
72704
+ }));
72705
+ issues.push(...strictSubsetIssues(doc, lineOf));
72706
+ if (issues.length > 0) return { ok: false, issues };
72707
+ if (!(0, import_yaml.isMap)(doc.contents)) {
72708
+ return {
72709
+ ok: false,
72710
+ issues: [
72711
+ {
72712
+ line: firstLine3,
72713
+ field: null,
72714
+ message: "the frontmatter is not a mapping of fields"
72715
+ }
72716
+ ]
72717
+ };
72718
+ }
72719
+ const key_lines = /* @__PURE__ */ new Map();
72720
+ for (const pair of doc.contents.items) {
72721
+ if ((0, import_yaml.isScalar)(pair.key) && pair.key.range) {
72722
+ key_lines.set(String(pair.key.value), lineOf(pair.key.range[0]));
72723
+ }
72724
+ }
72725
+ return {
72726
+ ok: true,
72727
+ frontmatter: {
72728
+ value: doc.toJS({ maxAliasCount: 0 }),
72729
+ key_lines
72730
+ }
72731
+ };
72732
+ }
72733
+ function readSteeringRecord(text5) {
72734
+ const encoding = encodingIssues(text5);
72735
+ if (encoding.length > 0) return { ok: false, issues: encoding };
72736
+ const split = splitRecordFile(text5);
71330
72737
  if (!split.ok) return { ok: false, issues: [split.issue] };
71331
72738
  const { frontmatter, body: body2, body_line } = split.parts;
71332
72739
  const parsed2 = parseFrontmatter(frontmatter);
@@ -71365,7 +72772,7 @@ function stampRecord(frontmatter, body2) {
71365
72772
  const id2 = `rec_${recordSlug(String(frontmatter.lineage))}_${seed.slice(7, 19)}`;
71366
72773
  return { id: id2, hash: digest6({ ...preimage, id: id2 }) };
71367
72774
  }
71368
- var import_yaml, recordScopeSchema, recordStatusSchema, recordOriginSchema, recordLoadSchema, provenanceMemorySchema, recordProvenanceSchema, recordDateSchema, decisionStatusSchema, decisionSourceSchema, decisionFieldsSchema, declassificationShared, textDeclassificationSchema, standingDeclassificationSchema, declassificationFieldsSchema, recordShape, STEERING_RECORD_FIELDS, steeringRecordSchema;
72775
+ var import_yaml, recordStatusSchema, recordOriginSchema, provenanceMemorySchema, recordProvenanceSchema, recordDateSchema, decisionStatusSchema, decisionSourceSchema, decisionFieldsSchema, declassificationShared, textDeclassificationSchema, standingDeclassificationSchema, declassificationFieldsSchema, recordShape, STEERING_RECORD_FIELDS, steeringRecordSchema;
71369
72776
  var init_record = __esm({
71370
72777
  "../../packages/oxagen/src/steering-repo/record.ts"() {
71371
72778
  "use strict";
@@ -71380,22 +72787,13 @@ var init_record = __esm({
71380
72787
  init_record_effect();
71381
72788
  init_record_force();
71382
72789
  init_record_kind();
72790
+ init_record_scope();
71383
72791
  init_record_effect();
71384
72792
  init_record_force();
71385
72793
  init_record_kind();
71386
- recordScopeSchema = external_exports.enum([
71387
- "workspace",
71388
- "repository",
71389
- "organization"
71390
- ]);
72794
+ init_record_scope();
71391
72795
  recordStatusSchema = external_exports.enum(["active", "archived"]);
71392
72796
  recordOriginSchema = external_exports.enum(["user", "inferred"]);
71393
- recordLoadSchema = external_exports.enum([
71394
- "always",
71395
- "match",
71396
- "relevant",
71397
- "mention"
71398
- ]);
71399
72797
  provenanceMemorySchema = external_exports.object({
71400
72798
  agent: external_exports.string().nullable(),
71401
72799
  run: external_exports.string().nullable(),
@@ -71706,7 +73104,7 @@ function classifyServer(parts) {
71706
73104
  return "unknown";
71707
73105
  }
71708
73106
  function classifySteeringRepoPath(path2) {
71709
- const root = ROOT_FILES[path2];
73107
+ const root = ROOT_FILES2[path2];
71710
73108
  if (root) return root;
71711
73109
  const parts = path2.split("/");
71712
73110
  if (parts.some((part2) => part2 === "" || part2 === "." || part2 === "..")) {
@@ -71739,7 +73137,7 @@ function recordLineageFromPath(path2) {
71739
73137
  return parts[parts.length - 1].slice(0, -3);
71740
73138
  return null;
71741
73139
  }
71742
- var AGENTS_MD_PATH, CLAUDE_MD_PATH, README_PATH, GITATTRIBUTES_PATH, WORKSPACE_TOML_PATH, AGENTS_DIR, STEERING_DIR, GOVERNANCE_TOML_PATH, SKILLS_DIR, TOOLS_DIR, TOOL_SERVERS_DIR, POLICY_DIR, CEDAR_SCHEMA_PATH, CODEGRAPH_SETTINGS_DIR, SKILL_FILE_NAME, SERVER_TOML_NAME, TOOLS_TOML_NAME, TOOLS_LOCK_NAME, LEDGER_FILE, ROOT_FILES, SERVER_FILES, WORKSPACE_LINK_PATH;
73140
+ var AGENTS_MD_PATH, CLAUDE_MD_PATH, README_PATH, GITATTRIBUTES_PATH, WORKSPACE_TOML_PATH, AGENTS_DIR, STEERING_DIR, GOVERNANCE_TOML_PATH, SKILLS_DIR, TOOLS_DIR, TOOL_SERVERS_DIR, POLICY_DIR, CEDAR_SCHEMA_PATH, CODEGRAPH_SETTINGS_DIR, SKILL_FILE_NAME, SERVER_TOML_NAME, TOOLS_TOML_NAME, TOOLS_LOCK_NAME, LEDGER_FILE, ROOT_FILES2, SERVER_FILES, WORKSPACE_LINK_PATH;
71743
73141
  var init_paths2 = __esm({
71744
73142
  "../../packages/oxagen/src/steering-repo/paths.ts"() {
71745
73143
  "use strict";
@@ -71762,7 +73160,7 @@ var init_paths2 = __esm({
71762
73160
  TOOLS_TOML_NAME = "tools.toml";
71763
73161
  TOOLS_LOCK_NAME = "tools.lock.json";
71764
73162
  LEDGER_FILE = /^(\d{4}(?:-\d{2}(?:-\d{2})?|-W\d{2})?)(?:\.(\d{3}))?\.jsonl$/;
71765
- ROOT_FILES = {
73163
+ ROOT_FILES2 = {
71766
73164
  [AGENTS_MD_PATH]: "agents-md",
71767
73165
  [CLAUDE_MD_PATH]: "claude-md",
71768
73166
  [README_PATH]: "readme",
@@ -72107,1174 +73505,402 @@ var init_codegraph_settings = __esm({
72107
73505
  "A commit that changes more files than this teaches no co-change."
72108
73506
  ),
72109
73507
  30
72110
- ),
72111
- bot_authors: setting(
72112
- uniqueArray(external_exports.string().min(1).max(200), "bot_authors").describe(
72113
- "Authors whose commits history ignores."
72114
- ),
72115
- CODEGRAPH_BOT_AUTHORS_DEFAULT
72116
- ),
72117
- co_change_half_life_days: setting(
72118
- external_exports.number().int().min(1).describe("A co-change counts half as much after this many days."),
72119
- 365
72120
- ),
72121
- cross_repo_window_hours: setting(
72122
- external_exports.number().int().min(1).describe("Commits in two repositories this close together can pair."),
72123
- 24
72124
- ),
72125
- owner_features: setting(
72126
- external_exports.boolean().describe("Compute owners from history."),
72127
- true
72128
- )
72129
- }).strict();
72130
- CODEGRAPH_HISTORY_DEFAULTS = {
72131
- change_size_cutoff_files: 30,
72132
- bot_authors: CODEGRAPH_BOT_AUTHORS_DEFAULT,
72133
- co_change_half_life_days: 365,
72134
- cross_repo_window_hours: 24,
72135
- owner_features: true
72136
- };
72137
- codegraphDecisionsSchema = external_exports.object({
72138
- importance_threshold: setting(
72139
- share().describe(
72140
- "A signal at or above this importance suggests a decision record. The M4 backtest sets it."
72141
- ),
72142
- 0.7
72143
- ),
72144
- grouping_window_days: setting(
72145
- external_exports.number().int().min(1).describe("Signals on one topic within this many days group into one."),
72146
- 7
72147
- ),
72148
- stale_proposal_days: setting(
72149
- external_exports.number().int().min(1).describe("A proposal untouched this many days is stale."),
72150
- 30
72151
- ),
72152
- package_categories: uniqueArray(
72153
- external_exports.string().min(1).max(100),
72154
- "package_categories"
72155
- ).optional().describe(
72156
- "The package categories signals weigh. Unset: the curated list."
72157
- )
72158
- }).strict();
72159
- CODEGRAPH_DECISIONS_DEFAULTS = {
72160
- importance_threshold: 0.7,
72161
- grouping_window_days: 7,
72162
- stale_proposal_days: 30
72163
- };
72164
- codegraphHostDefaultSchema = external_exports.enum([
72165
- "sandbox",
72166
- "ask",
72167
- "approval"
72168
- ]);
72169
- CODEGRAPH_HOST_DEFAULTS = {
72170
- "read-only": "sandbox",
72171
- test: "sandbox",
72172
- build: "sandbox",
72173
- "local-write": "ask",
72174
- "remote-write": "approval",
72175
- destructive: "approval",
72176
- unknown: "approval"
72177
- };
72178
- codegraphScriptsSchema = external_exports.object({
72179
- host_defaults: external_exports.object({
72180
- "read-only": setting(
72181
- codegraphHostDefaultSchema,
72182
- CODEGRAPH_HOST_DEFAULTS["read-only"]
72183
- ),
72184
- test: setting(codegraphHostDefaultSchema, CODEGRAPH_HOST_DEFAULTS.test),
72185
- build: setting(
72186
- codegraphHostDefaultSchema,
72187
- CODEGRAPH_HOST_DEFAULTS.build
72188
- ),
72189
- "local-write": setting(
72190
- codegraphHostDefaultSchema,
72191
- CODEGRAPH_HOST_DEFAULTS["local-write"]
72192
- ),
72193
- "remote-write": setting(
72194
- codegraphHostDefaultSchema,
72195
- CODEGRAPH_HOST_DEFAULTS["remote-write"]
72196
- ),
72197
- destructive: setting(
72198
- codegraphHostDefaultSchema,
72199
- CODEGRAPH_HOST_DEFAULTS.destructive
72200
- ),
72201
- unknown: setting(
72202
- codegraphHostDefaultSchema,
72203
- CODEGRAPH_HOST_DEFAULTS.unknown
72204
- )
72205
- }).strict().optional().describe(
72206
- "What a host does with a script of each effect class: run it in a sandbox, ask first, or wait for approval."
72207
- ),
72208
- trusted_policies: uniqueArray(
72209
- external_exports.string().min(1).max(200),
72210
- "trusted_policies"
72211
- ).optional().describe("Script policies the workspace trusts. Unset: none.")
72212
- }).strict();
72213
- CODEGRAPH_SCRIPTS_DEFAULTS = {
72214
- host_defaults: CODEGRAPH_HOST_DEFAULTS,
72215
- trusted_policies: []
72216
- };
72217
- codegraphDomainIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9_.-]{0,127}$/, "a domain id is lowercase");
72218
- codegraphBoundariesSchema = external_exports.object({
72219
- allowed_crossings: uniqueArray(
72220
- external_exports.object({
72221
- from: codegraphDomainIdSchema,
72222
- to: codegraphDomainIdSchema
72223
- }).strict(),
72224
- "allowed_crossings"
72225
- ).optional().describe(
72226
- "The domain crossings code may make. Unset: the table the current build found."
72227
- )
72228
- }).strict();
72229
- CODEGRAPH_BOUNDARIES_DEFAULTS = {};
72230
- codegraphBudgetsSchema = external_exports.object({
72231
- answer_budget_tokens: setting(
72232
- external_exports.number().int().min(1).describe(
72233
- "The default token budget of one answer. The spending cap is on the AI models and keys screen."
72234
- ),
72235
- 4e3
72236
- )
72237
- }).strict();
72238
- CODEGRAPH_BUDGETS_DEFAULTS = {
72239
- answer_budget_tokens: 4e3
72240
- };
72241
- codegraphFreshnessSchema = external_exports.object({
72242
- lag_window_minutes: setting(
72243
- external_exports.number().int().min(1).describe(
72244
- "The freshness check fails when the graph lags the code this long."
72245
- ),
72246
- 30
72247
- ),
72248
- revision_retention_days: setting(
72249
- external_exports.number().int().min(1).describe("Days a default-branch revision is kept."),
72250
- 90
72251
- ),
72252
- pr_copy_retention_days: setting(
72253
- external_exports.number().int().min(0).describe("Days a PR copy is kept after the PR closes."),
72254
- 7
72255
- )
72256
- }).strict();
72257
- CODEGRAPH_FRESHNESS_DEFAULTS = {
72258
- lag_window_minutes: 30,
72259
- revision_retention_days: 90,
72260
- pr_copy_retention_days: 7
72261
- };
72262
- CODEGRAPH_SETTINGS_GROUPS = [
72263
- {
72264
- group: "sources",
72265
- id: "codegraph-sources/v1",
72266
- title: "Code graph sources",
72267
- description: "codegraph/sources.toml: the source tags each linked code repository carries.",
72268
- schema: codegraphSourcesSchema,
72269
- defaults: CODEGRAPH_SOURCES_DEFAULTS,
72270
- timing: "next_build"
72271
- },
72272
- {
72273
- group: "indexing",
72274
- id: "codegraph-indexing/v1",
72275
- title: "Code graph indexing",
72276
- description: "codegraph/indexing.toml: the file size limit, skipped paths, live cloud inventory, and per-repository SCIP and version lookup.",
72277
- schema: codegraphIndexingSchema,
72278
- defaults: CODEGRAPH_INDEXING_DEFAULTS,
72279
- timing: "next_build"
72280
- },
72281
- {
72282
- group: "models",
72283
- id: "codegraph-models/v1",
72284
- title: "Code graph AI models and keys",
72285
- description: "codegraph/models.toml: the key source, the model for each task, call mode, providers, and escalation limits. The key itself is never stored here.",
72286
- schema: codegraphModelsSchema,
72287
- defaults: CODEGRAPH_MODELS_DEFAULTS,
72288
- timing: "next_build"
72289
- },
72290
- {
72291
- group: "embeddings",
72292
- id: "codegraph-embeddings/v1",
72293
- title: "Code graph embeddings",
72294
- description: "codegraph/embeddings.toml: whether builds embed cards, and with the Oxagen provider or the workspace's own endpoint.",
72295
- schema: codegraphEmbeddingsSchema,
72296
- defaults: CODEGRAPH_EMBEDDINGS_DEFAULTS,
72297
- timing: "next_build"
72298
- },
72299
- {
72300
- group: "local",
72301
- id: "codegraph-local/v1",
72302
- title: "Code graph local graphs",
72303
- description: "codegraph/local.toml: whether operators may build local graphs, the watch debounce, the memory limit, and local SCIP.",
72304
- schema: codegraphLocalSchema,
72305
- defaults: CODEGRAPH_LOCAL_DEFAULTS,
72306
- timing: "next_build"
72307
- },
72308
- {
72309
- group: "confidence",
72310
- id: "codegraph-confidence/v1",
72311
- title: "Code graph confidence",
72312
- description: "codegraph/confidence.toml: the confidence of each provenance, the default minConfidence, and the agent link limits.",
72313
- schema: codegraphConfidenceSchema,
72314
- defaults: CODEGRAPH_CONFIDENCE_DEFAULTS,
72315
- timing: "next_call"
72316
- },
72317
- {
72318
- group: "domains",
72319
- id: "codegraph-domains/v1",
72320
- title: "Code graph domains",
72321
- description: "codegraph/domains.toml: the tag score, the close-call margin and limit, and the regrouping threshold.",
72322
- schema: codegraphDomainsSchema,
72323
- defaults: CODEGRAPH_DOMAINS_DEFAULTS,
72324
- timing: "next_build"
72325
- },
72326
- {
72327
- group: "history",
72328
- id: "codegraph-history/v1",
72329
- title: "Code graph history",
72330
- description: "codegraph/history.toml: the change-size cutoff, bot authors, co-change half-life, cross-repository window, and owner features.",
72331
- schema: codegraphHistorySchema,
72332
- defaults: CODEGRAPH_HISTORY_DEFAULTS,
72333
- timing: "next_build"
72334
- },
72335
- {
72336
- group: "decisions",
72337
- id: "codegraph-decisions/v1",
72338
- title: "Code graph decision records",
72339
- description: "codegraph/decisions.toml: the importance threshold, grouping window, stale-proposal age, and package categories.",
72340
- schema: codegraphDecisionsSchema,
72341
- defaults: CODEGRAPH_DECISIONS_DEFAULTS,
72342
- timing: "next_build"
72343
- },
72344
- {
72345
- group: "scripts",
72346
- id: "codegraph-scripts/v1",
72347
- title: "Code graph scripts",
72348
- description: "codegraph/scripts.toml: the host default for each effect class and the trusted script policies.",
72349
- schema: codegraphScriptsSchema,
72350
- defaults: CODEGRAPH_SCRIPTS_DEFAULTS,
72351
- timing: "next_call"
72352
- },
72353
- {
72354
- group: "boundaries",
72355
- id: "codegraph-boundaries/v1",
72356
- title: "Code graph boundaries",
72357
- description: "codegraph/boundaries.toml: the crossings allowed between domains.",
72358
- schema: codegraphBoundariesSchema,
72359
- defaults: CODEGRAPH_BOUNDARIES_DEFAULTS,
72360
- timing: "next_call"
72361
- },
72362
- {
72363
- group: "budgets",
72364
- id: "codegraph-budgets/v1",
72365
- title: "Code graph budgets",
72366
- description: "codegraph/budgets.toml: the default answer budget.",
72367
- schema: codegraphBudgetsSchema,
72368
- defaults: CODEGRAPH_BUDGETS_DEFAULTS,
72369
- timing: "next_call"
72370
- },
72371
- {
72372
- group: "freshness",
72373
- id: "codegraph-freshness/v1",
72374
- title: "Code graph freshness and retention",
72375
- description: "codegraph/freshness.toml: the CI check's lag window and how long revisions and PR copies are kept.",
72376
- schema: codegraphFreshnessSchema,
72377
- defaults: CODEGRAPH_FRESHNESS_DEFAULTS,
72378
- timing: "next_build"
72379
- }
72380
- ];
72381
- }
72382
- });
72383
-
72384
- // ../../packages/oxagen/src/steering-repo/governance.ts
72385
- var ledgerRotationSchema, governanceSchema;
72386
- var init_governance = __esm({
72387
- "../../packages/oxagen/src/steering-repo/governance.ts"() {
72388
- "use strict";
72389
- init_zod();
72390
- init_context_steering_shared();
72391
- init_common();
72392
- init_json_schema();
72393
- init_tokens();
72394
- ledgerRotationSchema = external_exports.enum(["day", "week", "month", "year"]);
72395
- governanceSchema = withRules(
72396
- external_exports.object({
72397
- schema: external_exports.literal("governance/v1"),
72398
- mode: governanceModeSchema,
72399
- steering: external_exports.object({
72400
- always_on_tokens: external_exports.union([external_exports.number().int().positive(), external_exports.literal("off")]).optional().describe(
72401
- "The always-on budget per code repository, or off. Unset inherits Oxagen's default, which only warns."
72402
- )
72403
- }).strict().optional(),
72404
- ledger: external_exports.object({
72405
- rotate: ledgerRotationSchema.optional(),
72406
- max_lines: external_exports.number().int().positive().optional().describe("A new file starts here even mid-period.")
72407
- }).strict().optional(),
72408
- // `recall_unreviewed` left the memory table on 2026-09-30, because
72409
- // Oxagen no longer recalls a memory that waits for review (ADR-238).
72410
- memory: external_exports.object({
72411
- batch_size: external_exports.number().int().positive().optional().describe("Memories per memory PR."),
72412
- retire_after_days: external_exports.number().int().positive().optional(),
72413
- auto_merge: external_exports.boolean().optional().describe("Allowed in solo mode only.")
72414
- }).strict().optional(),
72415
- reviewers: external_exports.array(
72416
- external_exports.object({
72417
- paths: external_exports.array(external_exports.string().min(1)).min(1),
72418
- group: organizationSlugSchema
72419
- }).strict()
72420
- ).optional().describe(
72421
- "Route the folders a pull request changes to a reviewer group."
72422
- )
72423
- }).strict(),
72424
- [
72425
- {
72426
- kind: "equals",
72427
- when: { field: "mode", isNot: "solo" },
72428
- path: ["memory", "auto_merge"],
72429
- value: false
72430
- }
72431
- ]
72432
- );
72433
- }
72434
- });
72435
-
72436
- // ../../packages/oxagen/src/steering-repo/health.ts
72437
- var REPO_HEALTH_STATES, repoHealthSchema, settingsDifferenceSchema;
72438
- var init_health = __esm({
72439
- "../../packages/oxagen/src/steering-repo/health.ts"() {
72440
- "use strict";
72441
- init_zod();
72442
- init_common();
72443
- REPO_HEALTH_STATES = [
72444
- "healthy",
72445
- "drifted",
72446
- "disconnected",
72447
- "diverged"
72448
- ];
72449
- repoHealthSchema = external_exports.enum(REPO_HEALTH_STATES);
72450
- settingsDifferenceSchema = external_exports.object({
72451
- setting: external_exports.string().min(1).describe(
72452
- "The setting's path in the baseline, such as rulesets.oxagen_merges."
72453
- ),
72454
- expected: external_exports.unknown(),
72455
- actual: external_exports.unknown(),
72456
- changed_by: external_exports.string().nullable(),
72457
- changed_at: instantSchema2.nullable()
72458
- }).strict();
72459
- }
72460
- });
72461
-
72462
- // ../../packages/oxagen/src/steering-repo/promotion.ts
72463
- var promotionChangeSchema, branchSchema, promotionSchema;
72464
- var init_promotion = __esm({
72465
- "../../packages/oxagen/src/steering-repo/promotion.ts"() {
72466
- "use strict";
72467
- init_zod();
72468
- init_src3();
72469
- init_context_steering_shared();
72470
- init_common();
72471
- init_names();
72472
- promotionChangeSchema = external_exports.object({
72473
- path: repoPathSchema,
72474
- action: external_exports.enum(["added", "modified", "removed"]),
72475
- lineage: lineageSchema.optional(),
72476
- id: recordIdSchema.optional(),
72477
- hash: sha256Schema2.optional(),
72478
- replaces: recordIdSchema.optional().describe(
72479
- "The id this record had before a format change, such as the v0.1 conversion."
72480
- )
72481
- }).strict();
72482
- branchSchema = external_exports.string().regex(new RegExp(`^(?:${BRANCH_PREFIXES.join("|")})/.+$`)).describe("Starts with the top-level folder the change touches.");
72483
- promotionSchema = external_exports.object({
72484
- schema: external_exports.literal("promotion/v1"),
72485
- seq: external_exports.number().int().min(1).describe("The line's place in the whole chain, across files."),
72486
- at: instantSchema2,
72487
- pull_request: external_exports.object({
72488
- provider: repositoryProviderSchema,
72489
- number: external_exports.number().int().positive()
72490
- }).strict(),
72491
- branch: branchSchema,
72492
- mode: governanceModeSchema,
72493
- approved_by: external_exports.array(actorSchema),
72494
- merged_by: actorSchema,
72495
- without_review: external_exports.boolean().describe(
72496
- "True when the owner, or a role with merge_pr_without_review, merged without an approval."
72497
- ),
72498
- changes: external_exports.array(promotionChangeSchema).min(1),
72499
- prev: sha256Schema2.nullable().describe(
72500
- "The hash of the line before, or null on the first line of the chain."
72501
- ),
72502
- hash: sha256Schema2.describe(
72503
- "sha256 over the RFC 8785 canonical JSON of this line without hash."
72504
- )
72505
- }).strict();
72506
- }
72507
- });
72508
-
72509
- // ../../packages/tacho/src/columns.ts
72510
- var ENVELOPE_COLUMNS, TACHO_EVENT_COLUMNS;
72511
- var init_columns = __esm({
72512
- "../../packages/tacho/src/columns.ts"() {
72513
- "use strict";
72514
- init_chain();
72515
- init_envelope();
72516
- ENVELOPE_COLUMNS = [
72517
- // identity (2.1)
72518
- "host_enrollment_id",
72519
- "agent_key",
72520
- "agent_principal_id",
72521
- "initiating_principal_id",
72522
- "runtime",
72523
- "harness",
72524
- "harness_version",
72525
- "wrapper_version",
72526
- "wrapper_attestation",
72527
- "fidelity",
72528
- "enforcement_tier",
72529
- "fleet_id",
72530
- // anthropic observations (2.2)
72531
- "anthropic_user_id_hash",
72532
- "anthropic_account_uuid",
72533
- "anthropic_account_id",
72534
- "anthropic_org_uuid",
72535
- "api_key_source",
72536
- // session, causality, ordering (2.3)
72537
- "session_uuid",
72538
- "harness_session_id",
72539
- "root_session_uuid",
72540
- "parent_session_uuid",
72541
- "subagent_id",
72542
- "subagent_type",
72543
- "spawn_depth",
72544
- "spawn_tool_use_id",
72545
- "seq",
72546
- "event_id",
72547
- "event_id_idem",
72548
- "ts",
72549
- "turn_seq",
72550
- "prompt_id",
72551
- "turn_id",
72552
- "trace_id",
72553
- "span_id",
72554
- "parent_span_id",
72555
- "harness_event_sequence",
72556
- // kind and source (2.4)
72557
- "kind",
72558
- "source",
72559
- "hook_event_name",
72560
- "hook_source_kind",
72561
- "otel_event_name",
72562
- // context (2.5)
72563
- "cwd",
72564
- "project_dir",
72565
- "git_branch",
72566
- "git_head_sha",
72567
- "git_remote_digest",
72568
- "git_dirty",
72569
- "worktree_path",
72570
- "worktree_branch",
72571
- "permission_mode",
72572
- "effort",
72573
- "context_model",
72574
- "entrypoint",
72575
- "query_source",
72576
- "session_kind",
72577
- "terminal_type",
72578
- "app_version",
72579
- "output_style",
72580
- // host (2.14)
72581
- "hostname_digest",
72582
- "os_type",
72583
- "os_version",
72584
- "host_arch",
72585
- "os_user_digest",
72586
- "claude_pid",
72587
- "claude_ppid",
72588
- "claude_parent_process",
72589
- "claude_execpath",
72590
- "is_child_session",
72591
- "bridge_session_id",
72592
- "has_tty",
72593
- // chain and content (2.13, 2.15)
72594
- "prev_hash",
72595
- "hash",
72596
- "content_digest",
72597
- "bytes_ref",
72598
- "redactions",
72599
- "raw_source_digest",
72600
- "body",
72601
- "attrs"
72602
- ];
72603
- TACHO_EVENT_COLUMNS = [
72604
- ...ENVELOPE_COLUMNS,
72605
- ...BODY_MEMBER_NAMES
72606
- ];
72607
- }
72608
- });
72609
-
72610
- // ../../packages/tacho/src/evidence/merkle.ts
72611
- import { createHash as createHash17 } from "node:crypto";
72612
- function digestToBytes(digest7) {
72613
- if (!SHA256_DIGEST_PATTERN.test(digest7)) {
72614
- throw new TypeError(`not a sha256 digest: ${digest7}`);
72615
- }
72616
- return Buffer.from(digest7.slice("sha256:".length), "hex");
72617
- }
72618
- function hash2(...parts) {
72619
- const h = createHash17("sha256");
72620
- for (const part2 of parts) h.update(part2);
72621
- return h.digest();
72622
- }
72623
- function largestPowerOfTwoBelow(n4) {
72624
- let k = 1;
72625
- while (k * 2 < n4) k *= 2;
72626
- return k;
72627
- }
72628
- function treeHash(leaves) {
72629
- if (leaves.length === 0) return hash2();
72630
- if (leaves.length === 1) return hash2(LEAF_PREFIX, leaves[0]);
72631
- const k = largestPowerOfTwoBelow(leaves.length);
72632
- return hash2(
72633
- NODE_PREFIX,
72634
- treeHash(leaves.slice(0, k)),
72635
- treeHash(leaves.slice(k))
72636
- );
72637
- }
72638
- function merkleRoot(digests) {
72639
- const leaves = digests.map(digestToBytes);
72640
- return `sha256:${treeHash(leaves).toString("hex")}`;
72641
- }
72642
- var LEAF_PREFIX, NODE_PREFIX;
72643
- var init_merkle = __esm({
72644
- "../../packages/tacho/src/evidence/merkle.ts"() {
72645
- "use strict";
72646
- init_digest();
72647
- LEAF_PREFIX = Buffer.from([0]);
72648
- NODE_PREFIX = Buffer.from([1]);
72649
- }
72650
- });
72651
-
72652
- // ../../packages/tacho/src/evidence/archive-segment.ts
72653
- var encoder3, decoder;
72654
- var init_archive_segment = __esm({
72655
- "../../packages/tacho/src/evidence/archive-segment.ts"() {
72656
- "use strict";
72657
- init_digest();
72658
- init_merkle();
72659
- encoder3 = new TextEncoder();
72660
- decoder = new TextDecoder("utf-8", { fatal: true });
72661
- }
72662
- });
72663
-
72664
- // ../../packages/tacho/src/evidence/transcript-kinds.ts
72665
- function isTranscriptKind(value) {
72666
- return typeof value === "string" && TRANSCRIPT_KINDS.includes(value);
72667
- }
72668
- var TRANSCRIPT_KINDS;
72669
- var init_transcript_kinds = __esm({
72670
- "../../packages/tacho/src/evidence/transcript-kinds.ts"() {
72671
- "use strict";
72672
- TRANSCRIPT_KINDS = [
72673
- /**
72674
- * The prompt an operator typed to open a turn: a `turn_start` on the run's
72675
- * own chain. The request half of a model call is the context the model was
72676
- * sent, and answers no chip.
72677
- */
72678
- "prompt",
72679
- /**
72680
- * What came back: a model call's response half or single receipt whose
72681
- * body was kept, and a reply the harness reported with its words kept
72682
- * (`turn_end`, or a message recorded as a response).
72683
- */
72684
- "responses",
72685
- /**
72686
- * A model call that spent reasoning tokens (`thinking_tokens`). The text of
72687
- * the reasoning shows where the recorder kept the stream; the count shows
72688
- * wherever the provider reported it.
72689
- */
72690
- "thinking",
72691
- /** Either half of a tool call. */
72692
- "tools",
72693
- /** A decision a rule or a person made about a call: allow, deny, route. */
72694
- "policy",
72695
- /**
72696
- * A frame that carried a cost record or token counts without one, or a
72697
- * model call that recorded the reasoning effort it ran at.
72698
- */
72699
- "usage",
72700
- /** What was pulled into the model's context. */
72701
- "recall",
72702
- /**
72703
- * The run's own stop: the wrapped agent's `agent_stop` on the run's own
72704
- * chain, or the ledger event that closes an attempt before its seal. The
72705
- * chain's checkpoints and gaps are read on the Chain tab, not here.
72706
- */
72707
- "seal",
72708
- /** A call that did not do what it was asked to. */
72709
- "errors"
72710
- ];
72711
- }
72712
- });
72713
-
72714
- // ../../packages/tacho/src/evidence/attestation.ts
72715
- import {
72716
- createPrivateKey as createPrivateKey2,
72717
- createPublicKey as createPublicKey4,
72718
- sign as sign3,
72719
- verify as verify5
72720
- } from "node:crypto";
72721
- function attestationBytes(payload) {
72722
- return Buffer.from(jcs(payload), "utf8");
72723
- }
72724
- function verifyAttestation(attestation, publicKeyPem) {
72725
- if (attestation.alg !== "ed25519") return false;
72726
- if (attestation.key_id !== keyIdForPublicKey(publicKeyPem)) return false;
72727
- try {
72728
- return verify5(
72729
- null,
72730
- attestationBytes(attestation.payload),
72731
- createPublicKey4(publicKeyPem),
72732
- Buffer.from(attestation.sig, "base64")
72733
- );
72734
- } catch {
72735
- return false;
72736
- }
72737
- }
72738
- var init_attestation = __esm({
72739
- "../../packages/tacho/src/evidence/attestation.ts"() {
72740
- "use strict";
72741
- init_digest();
72742
- init_key_id();
72743
- }
72744
- });
72745
-
72746
- // ../../packages/tacho/src/evidence/run-export.ts
72747
- function normalizeInstant(value) {
72748
- const m = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(?:\.(\d+))?(Z|[+-]\d{2}(?::?\d{2})?)$/.exec(
72749
- value
72750
- );
72751
- if (!m) return value;
72752
- const [, day, time, frac, zone] = m;
72753
- const ms = (frac ?? "").slice(0, 3).padEnd(3, "0");
72754
- let offset = zone;
72755
- if (zone !== "Z") {
72756
- const digits = zone.slice(1).replace(":", "");
72757
- offset = `${zone[0]}${digits.slice(0, 2)}:${(digits.slice(2) || "00").padEnd(2, "0")}`;
72758
- }
72759
- const instant3 = /* @__PURE__ */ new Date(`${day}T${time}.${ms}${offset}`);
72760
- return Number.isNaN(instant3.getTime()) ? value : instant3.toISOString();
72761
- }
72762
- function wrappedFrameOf(event, bytesRef) {
72763
- const body2 = asRecord2(event["body"]) ?? {};
72764
- const content = asRecord2(event["content"]);
72765
- const turn = asRecord2(event["turn"]);
72766
- const text5 = (value) => typeof value === "string" ? value : "";
72767
- const count12 = (value) => typeof value === "number" ? value : null;
72768
- return {
72769
- event_id: event["event_id"] ?? null,
72770
- seq: event["seq"] ?? null,
72771
- ts: event["ts"] ?? null,
72772
- kind: event["kind"] ?? null,
72773
- prev_hash: event["prev_hash"] ?? null,
72774
- hash: event["hash"] ?? null,
72775
- content: {
72776
- digest: content?.["digest"] ?? null,
72777
- bytes_ref: bytesRef,
72778
- redactions: content?.["redactions"] ?? []
72779
- },
72780
- body: event["body"] ?? null,
72781
- tool_name: text5(body2["tool_name"]),
72782
- tool_status: text5(body2["tool_status"]),
72783
- tool_use_id: text5(body2["tool_use_id"]),
72784
- model: text5(body2["model"]),
72785
- provider: text5(body2["provider"]),
72786
- policy_decision: text5(body2["policy_decision"]),
72787
- cost_usd_micros: count12(body2["cost_usd_micros"]),
72788
- turn_seq: count12(turn?.["turn_seq"]),
72789
- event
72790
- };
72791
- }
72792
- function asRecord2(value) {
72793
- return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
72794
- }
72795
- function tally(counts) {
72796
- return [...counts.entries()].map(([kind, { count: count12, frames }]) => ({ kind, count: count12, frames })).sort((a, b5) => a.kind.localeCompare(b5.kind));
72797
- }
72798
- function summarizeRunExportRedactions(envelopes) {
72799
- const redacted = /* @__PURE__ */ new Map();
72800
- const withheld = /* @__PURE__ */ new Map();
72801
- const bump = (map, kind, count12) => {
72802
- const entry2 = map.get(kind) ?? { count: 0, frames: 0 };
72803
- entry2.count += count12;
72804
- entry2.frames += 1;
72805
- map.set(kind, entry2);
72806
- };
72807
- let total2 = 0;
72808
- for (const envelope2 of envelopes) {
72809
- const frame = asRecord2(envelope2);
72810
- if (!frame) continue;
72811
- const content = asRecord2(frame["content"]);
72812
- const list = content?.["redactions"];
72813
- if (Array.isArray(list)) {
72814
- const perReason = /* @__PURE__ */ new Map();
72815
- for (const item of list) {
72816
- const reason3 = asRecord2(item)?.["reason"];
72817
- const kind = typeof reason3 === "string" ? reason3 : "unknown";
72818
- perReason.set(kind, (perReason.get(kind) ?? 0) + 1);
72819
- }
72820
- for (const [kind, count12] of perReason) {
72821
- bump(redacted, kind, count12);
72822
- total2 += count12;
72823
- }
72824
- }
72825
- if (typeof content?.["bytes_ref"] === "string") {
72826
- bump(withheld, WITHHELD_BODY, 1);
72827
- }
72828
- if (typeof frame["encrypted_payload_ref"] === "string") {
72829
- bump(withheld, WITHHELD_ENCRYPTED_PAYLOAD, 1);
72830
- }
72831
- }
72832
- return {
72833
- format: RUN_EXPORT_REDACTIONS_FORMAT,
72834
- redacted: tally(redacted),
72835
- redacted_total: total2,
72836
- withheld: tally(withheld)
72837
- };
72838
- }
72839
- function digestOf2(frame) {
72840
- const value = frame["event_digest"] ?? frame["hash"];
72841
- return typeof value === "string" && DIGEST2.test(value) ? value : null;
72842
- }
72843
- function safeDigestJcs(value) {
72844
- try {
72845
- return digestJcs(value);
72846
- } catch {
72847
- return null;
72848
- }
72849
- }
72850
- function checkWrappedFrame(frame, attemptId) {
72851
- if (frame["event"] === void 0 || frame["event"] === null) {
72852
- return { digest: "not_carried", reasons: [] };
72853
- }
72854
- const event = asRecord2(frame["event"]);
72855
- if (!event) {
72856
- return { digest: "broken", reasons: ["event is not a JSON object"] };
72857
- }
72858
- const reasons = [];
72859
- if (event["session_uuid"] !== attemptId) {
72860
- reasons.push(
72861
- `the event belongs to session ${String(event["session_uuid"])}, not ${attemptId}`
72862
- );
72863
- }
72864
- let holds2;
72865
- try {
72866
- holds2 = eventHashHolds(event, frame["hash"]);
72867
- } catch {
72868
- holds2 = false;
72869
- }
72870
- if (!holds2) {
72871
- reasons.push("the event does not hash to hash");
72872
- }
72873
- const content = asRecord2(frame["content"]);
72874
- const bytesRef = typeof content?.["bytes_ref"] === "string" ? content["bytes_ref"] : null;
72875
- const expected = wrappedFrameOf(event, bytesRef);
72876
- const differs2 = [
72877
- .../* @__PURE__ */ new Set([...Object.keys(expected), ...Object.keys(frame)])
72878
- ].filter((name) => name !== "event").filter((name) => {
72879
- const shown2 = frame[name];
72880
- const read2 = expected[name];
72881
- if (shown2 === void 0 || read2 === void 0) return true;
72882
- return jcs(shown2) !== jcs(read2);
72883
- }).sort();
72884
- if (differs2.length > 0) {
72885
- const verb = differs2.length === 1 ? "differs" : "differ";
72886
- reasons.push(`${differs2.join(", ")} ${verb} from the hashed event`);
72887
- }
72888
- return { digest: reasons.length > 0 ? "broken" : "held", reasons };
72889
- }
72890
- function checkLedgerFrame(frame) {
72891
- const reasons = [];
72892
- const payloadDigest = frame["payload_digest"];
72893
- let digest7 = "held";
72894
- if (frame["payload_inline"] !== null && frame["payload_inline"] !== void 0) {
72895
- const recomputed2 = safeDigestJcs(frame["payload_inline"]);
72896
- if (recomputed2 !== payloadDigest) {
72897
- digest7 = "broken";
72898
- reasons.push("payload does not hash to payload_digest");
72899
- }
72900
- } else if (typeof frame["encrypted_payload_ref"] !== "string") {
72901
- digest7 = "broken";
72902
- reasons.push("frame carries neither a payload nor an encrypted reference");
72903
- }
72904
- const recomputed = safeDigestJcs({
72905
- attempt_seq: frame["attempt_seq"] ?? null,
72906
- event_schema_version: frame["event_schema_version"] ?? null,
72907
- event_type: frame["event_type"] ?? null,
72908
- stage: frame["stage"] ?? null,
72909
- payload_digest: payloadDigest ?? null,
72910
- observed_at: typeof frame["observed_at"] === "string" ? normalizeInstant(frame["observed_at"]) : frame["observed_at"] ?? null
72911
- });
72912
- if (recomputed !== frame["event_digest"]) {
72913
- digest7 = "broken";
72914
- reasons.push("identity fields do not hash to event_digest");
72915
- }
72916
- return { digest: digest7, reasons };
72917
- }
72918
- function parseJson2(text5, name, checks) {
72919
- try {
72920
- return JSON.parse(text5);
72921
- } catch {
72922
- checks.push({ name, status: "broken", detail: `${name} is not JSON` });
72923
- return null;
72924
- }
72925
- }
72926
- function verifyRunExport(files3) {
72927
- const checks = [];
72928
- const hold = (name, ok2, held, broken) => checks.push({
72929
- name,
72930
- status: ok2 ? "held" : "broken",
72931
- detail: ok2 ? held : broken
72932
- });
72933
- const manifest = parseJson2(
72934
- files3["manifest.json"],
72935
- "manifest",
72936
- checks
72937
- );
72938
- const attestationFile = parseJson2(
72939
- files3["attestation.json"],
72940
- "attestation",
72941
- checks
72942
- );
72943
- const raw = files3["frames.ndjson"];
72944
- const text5 = raw.endsWith("\n") ? raw.slice(0, -1) : raw;
72945
- const lines = text5.length === 0 ? [] : text5.split("\n");
72946
- const frames = [];
72947
- const verdicts = [];
72948
- lines.forEach((line, i2) => {
72949
- let parsed2 = null;
72950
- try {
72951
- parsed2 = asRecord2(JSON.parse(line));
72952
- } catch {
72953
- parsed2 = null;
72954
- }
72955
- frames.push(parsed2 ?? {});
72956
- if (!parsed2) {
72957
- verdicts.push({
72958
- line: i2 + 1,
72959
- attempt_id: "",
72960
- seq: null,
72961
- status: "broken",
72962
- digest: "broken",
72963
- link: "broken",
72964
- reasons: ["line is not a JSON object"]
72965
- });
72966
- }
72967
- });
72968
- if (!manifest || !attestationFile) {
72969
- return {
72970
- ok: false,
72971
- run_id: manifest?.run_id ?? null,
72972
- format: manifest?.format ?? null,
72973
- frames: verdicts,
72974
- checks,
72975
- redactions: null
72976
- };
72977
- }
72978
- hold(
72979
- "format",
72980
- ACCEPTED_FORMATS.has(manifest.format),
72981
- manifest.format,
72982
- `unknown bundle format ${String(manifest.format)}`
72983
- );
72984
- hold(
72985
- "source",
72986
- typeof manifest.run_id === "string" && (manifest.source === "ledger" && manifest.run_id.startsWith("arun_") || manifest.source === "tacho" && manifest.run_id.startsWith("tse_")),
72987
- "the source matches the run identifier",
72988
- "the source is invalid or does not match the run identifier"
72989
- );
72990
- const byLine = new Map(verdicts.map((v) => [v.line, v]));
72991
- let offset = 0;
72992
- for (const attempt of manifest.attempts ?? []) {
72993
- let prevHash = null;
72994
- let prevSeq = null;
72995
- let stream = EMPTY_EVENT_STREAM_DIGEST;
72996
- const end = Math.min(offset + attempt.frame_count, frames.length);
72997
- for (let i2 = offset; i2 < end; i2 += 1) {
72998
- const line = i2 + 1;
72999
- if (byLine.has(line)) continue;
73000
- const frame = frames[i2];
73001
- const reasons = [];
73002
- let digest7;
73003
- let link = "held";
73004
- let seq = null;
73005
- if (manifest.source === "ledger") {
73006
- const own = checkLedgerFrame(frame);
73007
- digest7 = own.digest;
73008
- reasons.push(...own.reasons);
73009
- const attemptSeq = frame["attempt_seq"];
73010
- seq = typeof attemptSeq === "number" ? attemptSeq : null;
73011
- const expected = prevSeq === null ? 1 : prevSeq + 1;
73012
- if (seq !== expected) {
73013
- link = "broken";
73014
- reasons.push(`attempt_seq ${String(seq)} where ${expected} was due`);
73015
- }
73016
- prevSeq = seq;
73017
- stream = digestJcs({
73018
- previous: stream,
73019
- entry: [
73020
- frame["attempt_seq"] ?? null,
73021
- frame["event_schema_version"] ?? null,
73022
- frame["event_type"] ?? null,
73023
- frame["payload_digest"] ?? null
73024
- ]
73025
- });
73026
- } else {
73027
- const own = checkWrappedFrame(frame, attempt.attempt_id);
73028
- digest7 = own.digest;
73029
- reasons.push(...own.reasons);
73030
- const rawSeq = frame["seq"];
73031
- seq = typeof rawSeq === "number" ? rawSeq : null;
73032
- const expectedPrev = prevHash ?? (seq === 0 ? GENESIS_PREV_HASH2 : null);
73033
- if (expectedPrev !== null && frame["prev_hash"] !== expectedPrev) {
73034
- link = "broken";
73035
- reasons.push(
73036
- prevHash === null ? 'genesis prev_hash is not sha256("")' : "prev_hash is not the previous frame's hash"
73037
- );
73038
- }
73039
- if (prevSeq !== null && seq !== prevSeq + 1) {
73040
- link = "broken";
73041
- reasons.push(`seq ${String(seq)} where ${prevSeq + 1} was due`);
73042
- }
73043
- prevSeq = seq;
73044
- prevHash = typeof frame["hash"] === "string" ? frame["hash"] : null;
73045
- }
73046
- if (digestOf2(frame) === null) {
73047
- digest7 = "broken";
73048
- reasons.push("frame carries no sha256 digest");
73049
- }
73050
- verdicts.push({
73051
- line,
73052
- attempt_id: attempt.attempt_id,
73053
- seq,
73054
- status: digest7 === "broken" || link === "broken" ? "broken" : "held",
73055
- digest: digest7,
73056
- link,
73057
- reasons
73058
- });
73059
- }
73060
- if (manifest.source === "ledger" && typeof attempt.event_stream_digest === "string") {
73061
- hold(
73062
- `stream ${attempt.attempt_id}`,
73063
- stream === attempt.event_stream_digest,
73064
- "the frames fold to the sealed event_stream_digest",
73065
- `the frames fold to ${stream}, the seal recorded ${attempt.event_stream_digest}`
73066
- );
73067
- }
73068
- offset += attempt.frame_count;
73069
- }
73070
- for (let i2 = offset; i2 < frames.length; i2 += 1) {
73071
- if (byLine.has(i2 + 1)) continue;
73072
- verdicts.push({
73073
- line: i2 + 1,
73074
- attempt_id: "",
73075
- seq: null,
73076
- status: "broken",
73077
- digest: "broken",
73078
- link: "broken",
73079
- reasons: ["frame lies outside every attested attempt"]
73080
- });
73081
- }
73082
- verdicts.sort((a, b5) => a.line - b5.line);
73083
- hold(
73084
- "frame count",
73085
- frames.length === manifest.frame_count,
73086
- `${frames.length} frames`,
73087
- `${frames.length} frames where the manifest says ${manifest.frame_count}`
73088
- );
73089
- const digests = frames.map(digestOf2);
73090
- const allDigests = digests.every((d) => d !== null);
73091
- const root = allDigests ? merkleRoot(digests) : null;
73092
- hold(
73093
- "merkle root",
73094
- root === manifest.merkle_root,
73095
- `root ${manifest.merkle_root}`,
73096
- `frames hash to ${root ?? "nothing"}, the manifest says ${manifest.merkle_root}`
73097
- );
73098
- const pem = attestationFile.public_key_pem;
73099
- let keyId = null;
73100
- try {
73101
- keyId = keyIdForPublicKey(pem);
73102
- } catch {
73103
- keyId = null;
73104
- }
73105
- hold(
73106
- "attester key",
73107
- keyId !== null && keyId === attestationFile.key_id && keyId === manifest.attester_key_id,
73108
- `key ${String(keyId)}`,
73109
- "the bundled public key does not match the recorded key id"
73110
- );
73111
- let covered = 0;
73112
- const attestations = attestationFile.attestations ?? [];
73113
- attestations.forEach((a, i2) => {
73114
- const attemptId = a.payload?.attempt_id ?? `#${i2 + 1}`;
73115
- hold(
73116
- `signature ${attemptId}`,
73117
- keyId !== null && verifyAttestation(a, pem),
73118
- "Ed25519 signature verifies",
73119
- "the attestation signature does not verify"
73120
- );
73121
- const slice = digests.slice(
73122
- covered,
73123
- covered + (a.payload?.frame_count ?? 0)
73124
- );
73125
- if (manifest.source === "tacho") {
73126
- const exportedDigest = digestBytes(
73127
- lines.slice(covered, covered + (a.payload?.frame_count ?? 0)).join("\n")
73128
- );
73129
- hold(
73130
- `exported content ${attemptId}`,
73131
- exportedDigest === a.payload?.archive_segment_digest,
73132
- "the exported frame bytes match the signed segment digest",
73133
- "the exported frame bytes do not match the signed segment digest"
73134
- );
73135
- }
73136
- hold(
73137
- `run identity ${attemptId}`,
73138
- a.payload?.run_id === manifest.run_id,
73139
- "the attestation names this run",
73140
- "the manifest run differs from the signed run"
73141
- );
73142
- covered += a.payload?.frame_count ?? 0;
73143
- const attemptRoot = slice.every((d) => d !== null) ? merkleRoot(slice) : null;
73144
- hold(
73145
- `attested root ${attemptId}`,
73146
- attemptRoot === a.payload?.merkle_root,
73147
- "the attempt's frames hash to the signed root",
73148
- `the attempt's frames hash to ${attemptRoot ?? "nothing"}, the attestation signed ${String(a.payload?.merkle_root)}`
73149
- );
73150
- });
73151
- hold(
73152
- "coverage",
73153
- covered === frames.length && attestations.length > 0,
73154
- "the attestations cover every frame",
73155
- `the attestations cover ${covered} of ${frames.length} frames`
73156
- );
73157
- let redactions = null;
73158
- const redactionsText = files3["redactions.json"];
73159
- if (redactionsText !== void 0) {
73160
- redactions = parseJson2(
73161
- redactionsText,
73162
- "redactions",
73163
- checks
73164
- );
73165
- if (redactions) {
73166
- const recomputed = summarizeRunExportRedactions(frames);
73167
- hold(
73168
- "redactions",
73169
- digestJcs(recomputed) === digestJcs(redactions),
73170
- `${recomputed.redacted_total} redaction(s) summarised`,
73171
- "redactions.json does not match what the frames record"
73172
- );
73173
- }
73174
- } else if (manifest.format !== FORMAT_1) {
73175
- hold("redactions", false, "", "redactions.json is missing");
73176
- }
73177
- const ok = verdicts.length === frames.length && verdicts.every((v) => v.status === "held") && checks.every((c) => c.status === "held");
73178
- return {
73179
- ok,
73180
- run_id: manifest.run_id,
73181
- format: manifest.format,
73182
- frames: verdicts,
73183
- checks,
73184
- redactions
73185
- };
73186
- }
73187
- var RUN_EXPORT_FORMAT, FORMAT_1, ACCEPTED_FORMATS, RUN_EXPORT_REDACTIONS_FORMAT, GENESIS_PREV_HASH2, EMPTY_EVENT_STREAM_DIGEST, DIGEST2, WITHHELD_BODY, WITHHELD_ENCRYPTED_PAYLOAD;
73188
- var init_run_export = __esm({
73189
- "../../packages/tacho/src/evidence/run-export.ts"() {
73190
- "use strict";
73191
- init_chain();
73192
- init_digest();
73193
- init_key_id();
73194
- init_attestation();
73195
- init_merkle();
73196
- RUN_EXPORT_FORMAT = "oxagen.run-export/3";
73197
- FORMAT_1 = "oxagen.run-export/1";
73198
- ACCEPTED_FORMATS = /* @__PURE__ */ new Set([
73199
- FORMAT_1,
73200
- "oxagen.run-export/2",
73201
- RUN_EXPORT_FORMAT
73508
+ ),
73509
+ bot_authors: setting(
73510
+ uniqueArray(external_exports.string().min(1).max(200), "bot_authors").describe(
73511
+ "Authors whose commits history ignores."
73512
+ ),
73513
+ CODEGRAPH_BOT_AUTHORS_DEFAULT
73514
+ ),
73515
+ co_change_half_life_days: setting(
73516
+ external_exports.number().int().min(1).describe("A co-change counts half as much after this many days."),
73517
+ 365
73518
+ ),
73519
+ cross_repo_window_hours: setting(
73520
+ external_exports.number().int().min(1).describe("Commits in two repositories this close together can pair."),
73521
+ 24
73522
+ ),
73523
+ owner_features: setting(
73524
+ external_exports.boolean().describe("Compute owners from history."),
73525
+ true
73526
+ )
73527
+ }).strict();
73528
+ CODEGRAPH_HISTORY_DEFAULTS = {
73529
+ change_size_cutoff_files: 30,
73530
+ bot_authors: CODEGRAPH_BOT_AUTHORS_DEFAULT,
73531
+ co_change_half_life_days: 365,
73532
+ cross_repo_window_hours: 24,
73533
+ owner_features: true
73534
+ };
73535
+ codegraphDecisionsSchema = external_exports.object({
73536
+ importance_threshold: setting(
73537
+ share().describe(
73538
+ "A signal at or above this importance suggests a decision record. The M4 backtest sets it."
73539
+ ),
73540
+ 0.7
73541
+ ),
73542
+ grouping_window_days: setting(
73543
+ external_exports.number().int().min(1).describe("Signals on one topic within this many days group into one."),
73544
+ 7
73545
+ ),
73546
+ stale_proposal_days: setting(
73547
+ external_exports.number().int().min(1).describe("A proposal untouched this many days is stale."),
73548
+ 30
73549
+ ),
73550
+ package_categories: uniqueArray(
73551
+ external_exports.string().min(1).max(100),
73552
+ "package_categories"
73553
+ ).optional().describe(
73554
+ "The package categories signals weigh. Unset: the curated list."
73555
+ )
73556
+ }).strict();
73557
+ CODEGRAPH_DECISIONS_DEFAULTS = {
73558
+ importance_threshold: 0.7,
73559
+ grouping_window_days: 7,
73560
+ stale_proposal_days: 30
73561
+ };
73562
+ codegraphHostDefaultSchema = external_exports.enum([
73563
+ "sandbox",
73564
+ "ask",
73565
+ "approval"
73202
73566
  ]);
73203
- RUN_EXPORT_REDACTIONS_FORMAT = "oxagen.run-export.redactions/1";
73204
- GENESIS_PREV_HASH2 = digestBytes("");
73205
- EMPTY_EVENT_STREAM_DIGEST = digestJcs([]);
73206
- DIGEST2 = /^sha256:[0-9a-f]{64}$/;
73207
- WITHHELD_BODY = "frame_body";
73208
- WITHHELD_ENCRYPTED_PAYLOAD = "encrypted_payload";
73209
- }
73210
- });
73211
-
73212
- // ../../packages/tacho/src/evidence/index.ts
73213
- var init_evidence = __esm({
73214
- "../../packages/tacho/src/evidence/index.ts"() {
73215
- "use strict";
73216
- init_archive_segment();
73217
- init_merkle();
73218
- init_redaction();
73219
- init_retention();
73220
- init_replay_grade();
73221
- init_transcript_kinds();
73222
- init_attestation();
73223
- init_frame_body();
73224
- init_run_export();
73567
+ CODEGRAPH_HOST_DEFAULTS = {
73568
+ "read-only": "sandbox",
73569
+ test: "sandbox",
73570
+ build: "sandbox",
73571
+ "local-write": "ask",
73572
+ "remote-write": "approval",
73573
+ destructive: "approval",
73574
+ unknown: "approval"
73575
+ };
73576
+ codegraphScriptsSchema = external_exports.object({
73577
+ host_defaults: external_exports.object({
73578
+ "read-only": setting(
73579
+ codegraphHostDefaultSchema,
73580
+ CODEGRAPH_HOST_DEFAULTS["read-only"]
73581
+ ),
73582
+ test: setting(codegraphHostDefaultSchema, CODEGRAPH_HOST_DEFAULTS.test),
73583
+ build: setting(
73584
+ codegraphHostDefaultSchema,
73585
+ CODEGRAPH_HOST_DEFAULTS.build
73586
+ ),
73587
+ "local-write": setting(
73588
+ codegraphHostDefaultSchema,
73589
+ CODEGRAPH_HOST_DEFAULTS["local-write"]
73590
+ ),
73591
+ "remote-write": setting(
73592
+ codegraphHostDefaultSchema,
73593
+ CODEGRAPH_HOST_DEFAULTS["remote-write"]
73594
+ ),
73595
+ destructive: setting(
73596
+ codegraphHostDefaultSchema,
73597
+ CODEGRAPH_HOST_DEFAULTS.destructive
73598
+ ),
73599
+ unknown: setting(
73600
+ codegraphHostDefaultSchema,
73601
+ CODEGRAPH_HOST_DEFAULTS.unknown
73602
+ )
73603
+ }).strict().optional().describe(
73604
+ "What a host does with a script of each effect class: run it in a sandbox, ask first, or wait for approval."
73605
+ ),
73606
+ trusted_policies: uniqueArray(
73607
+ external_exports.string().min(1).max(200),
73608
+ "trusted_policies"
73609
+ ).optional().describe("Script policies the workspace trusts. Unset: none.")
73610
+ }).strict();
73611
+ CODEGRAPH_SCRIPTS_DEFAULTS = {
73612
+ host_defaults: CODEGRAPH_HOST_DEFAULTS,
73613
+ trusted_policies: []
73614
+ };
73615
+ codegraphDomainIdSchema = external_exports.string().regex(/^[a-z0-9][a-z0-9_.-]{0,127}$/, "a domain id is lowercase");
73616
+ codegraphBoundariesSchema = external_exports.object({
73617
+ allowed_crossings: uniqueArray(
73618
+ external_exports.object({
73619
+ from: codegraphDomainIdSchema,
73620
+ to: codegraphDomainIdSchema
73621
+ }).strict(),
73622
+ "allowed_crossings"
73623
+ ).optional().describe(
73624
+ "The domain crossings code may make. Unset: the table the current build found."
73625
+ )
73626
+ }).strict();
73627
+ CODEGRAPH_BOUNDARIES_DEFAULTS = {};
73628
+ codegraphBudgetsSchema = external_exports.object({
73629
+ answer_budget_tokens: setting(
73630
+ external_exports.number().int().min(1).describe(
73631
+ "The default token budget of one answer. The spending cap is on the AI models and keys screen."
73632
+ ),
73633
+ 4e3
73634
+ )
73635
+ }).strict();
73636
+ CODEGRAPH_BUDGETS_DEFAULTS = {
73637
+ answer_budget_tokens: 4e3
73638
+ };
73639
+ codegraphFreshnessSchema = external_exports.object({
73640
+ lag_window_minutes: setting(
73641
+ external_exports.number().int().min(1).describe(
73642
+ "The freshness check fails when the graph lags the code this long."
73643
+ ),
73644
+ 30
73645
+ ),
73646
+ revision_retention_days: setting(
73647
+ external_exports.number().int().min(1).describe("Days a default-branch revision is kept."),
73648
+ 90
73649
+ ),
73650
+ pr_copy_retention_days: setting(
73651
+ external_exports.number().int().min(0).describe("Days a PR copy is kept after the PR closes."),
73652
+ 7
73653
+ )
73654
+ }).strict();
73655
+ CODEGRAPH_FRESHNESS_DEFAULTS = {
73656
+ lag_window_minutes: 30,
73657
+ revision_retention_days: 90,
73658
+ pr_copy_retention_days: 7
73659
+ };
73660
+ CODEGRAPH_SETTINGS_GROUPS = [
73661
+ {
73662
+ group: "sources",
73663
+ id: "codegraph-sources/v1",
73664
+ title: "Code graph sources",
73665
+ description: "codegraph/sources.toml: the source tags each linked code repository carries.",
73666
+ schema: codegraphSourcesSchema,
73667
+ defaults: CODEGRAPH_SOURCES_DEFAULTS,
73668
+ timing: "next_build"
73669
+ },
73670
+ {
73671
+ group: "indexing",
73672
+ id: "codegraph-indexing/v1",
73673
+ title: "Code graph indexing",
73674
+ description: "codegraph/indexing.toml: the file size limit, skipped paths, live cloud inventory, and per-repository SCIP and version lookup.",
73675
+ schema: codegraphIndexingSchema,
73676
+ defaults: CODEGRAPH_INDEXING_DEFAULTS,
73677
+ timing: "next_build"
73678
+ },
73679
+ {
73680
+ group: "models",
73681
+ id: "codegraph-models/v1",
73682
+ title: "Code graph AI models and keys",
73683
+ description: "codegraph/models.toml: the key source, the model for each task, call mode, providers, and escalation limits. The key itself is never stored here.",
73684
+ schema: codegraphModelsSchema,
73685
+ defaults: CODEGRAPH_MODELS_DEFAULTS,
73686
+ timing: "next_build"
73687
+ },
73688
+ {
73689
+ group: "embeddings",
73690
+ id: "codegraph-embeddings/v1",
73691
+ title: "Code graph embeddings",
73692
+ description: "codegraph/embeddings.toml: whether builds embed cards, and with the Oxagen provider or the workspace's own endpoint.",
73693
+ schema: codegraphEmbeddingsSchema,
73694
+ defaults: CODEGRAPH_EMBEDDINGS_DEFAULTS,
73695
+ timing: "next_build"
73696
+ },
73697
+ {
73698
+ group: "local",
73699
+ id: "codegraph-local/v1",
73700
+ title: "Code graph local graphs",
73701
+ description: "codegraph/local.toml: whether operators may build local graphs, the watch debounce, the memory limit, and local SCIP.",
73702
+ schema: codegraphLocalSchema,
73703
+ defaults: CODEGRAPH_LOCAL_DEFAULTS,
73704
+ timing: "next_build"
73705
+ },
73706
+ {
73707
+ group: "confidence",
73708
+ id: "codegraph-confidence/v1",
73709
+ title: "Code graph confidence",
73710
+ description: "codegraph/confidence.toml: the confidence of each provenance, the default minConfidence, and the agent link limits.",
73711
+ schema: codegraphConfidenceSchema,
73712
+ defaults: CODEGRAPH_CONFIDENCE_DEFAULTS,
73713
+ timing: "next_call"
73714
+ },
73715
+ {
73716
+ group: "domains",
73717
+ id: "codegraph-domains/v1",
73718
+ title: "Code graph domains",
73719
+ description: "codegraph/domains.toml: the tag score, the close-call margin and limit, and the regrouping threshold.",
73720
+ schema: codegraphDomainsSchema,
73721
+ defaults: CODEGRAPH_DOMAINS_DEFAULTS,
73722
+ timing: "next_build"
73723
+ },
73724
+ {
73725
+ group: "history",
73726
+ id: "codegraph-history/v1",
73727
+ title: "Code graph history",
73728
+ description: "codegraph/history.toml: the change-size cutoff, bot authors, co-change half-life, cross-repository window, and owner features.",
73729
+ schema: codegraphHistorySchema,
73730
+ defaults: CODEGRAPH_HISTORY_DEFAULTS,
73731
+ timing: "next_build"
73732
+ },
73733
+ {
73734
+ group: "decisions",
73735
+ id: "codegraph-decisions/v1",
73736
+ title: "Code graph decision records",
73737
+ description: "codegraph/decisions.toml: the importance threshold, grouping window, stale-proposal age, and package categories.",
73738
+ schema: codegraphDecisionsSchema,
73739
+ defaults: CODEGRAPH_DECISIONS_DEFAULTS,
73740
+ timing: "next_build"
73741
+ },
73742
+ {
73743
+ group: "scripts",
73744
+ id: "codegraph-scripts/v1",
73745
+ title: "Code graph scripts",
73746
+ description: "codegraph/scripts.toml: the host default for each effect class and the trusted script policies.",
73747
+ schema: codegraphScriptsSchema,
73748
+ defaults: CODEGRAPH_SCRIPTS_DEFAULTS,
73749
+ timing: "next_call"
73750
+ },
73751
+ {
73752
+ group: "boundaries",
73753
+ id: "codegraph-boundaries/v1",
73754
+ title: "Code graph boundaries",
73755
+ description: "codegraph/boundaries.toml: the crossings allowed between domains.",
73756
+ schema: codegraphBoundariesSchema,
73757
+ defaults: CODEGRAPH_BOUNDARIES_DEFAULTS,
73758
+ timing: "next_call"
73759
+ },
73760
+ {
73761
+ group: "budgets",
73762
+ id: "codegraph-budgets/v1",
73763
+ title: "Code graph budgets",
73764
+ description: "codegraph/budgets.toml: the default answer budget.",
73765
+ schema: codegraphBudgetsSchema,
73766
+ defaults: CODEGRAPH_BUDGETS_DEFAULTS,
73767
+ timing: "next_call"
73768
+ },
73769
+ {
73770
+ group: "freshness",
73771
+ id: "codegraph-freshness/v1",
73772
+ title: "Code graph freshness and retention",
73773
+ description: "codegraph/freshness.toml: the CI check's lag window and how long revisions and PR copies are kept.",
73774
+ schema: codegraphFreshnessSchema,
73775
+ defaults: CODEGRAPH_FRESHNESS_DEFAULTS,
73776
+ timing: "next_build"
73777
+ }
73778
+ ];
73225
73779
  }
73226
73780
  });
73227
73781
 
73228
- // ../../packages/tacho/src/session-subject.ts
73229
- var ENRICHMENT_BUDGET_NOTE, ENRICHMENT_LIMIT_NOTE, PARTIAL_NOTE_HEAD, PARTIAL_NOTE_TAIL, escapeRegExp2, NOTE_SOURCE, TRAILING_NOTES, GITHUB_REF_SOURCE;
73230
- var init_session_subject = __esm({
73231
- "../../packages/tacho/src/session-subject.ts"() {
73782
+ // ../../packages/oxagen/src/steering-repo/governance.ts
73783
+ var ledgerRotationSchema, governanceSchema;
73784
+ var init_governance = __esm({
73785
+ "../../packages/oxagen/src/steering-repo/governance.ts"() {
73232
73786
  "use strict";
73233
- ENRICHMENT_BUDGET_NOTE = " The account covers only the start of the run: its enrichment budget ran out before the rest was read.";
73234
- ENRICHMENT_LIMIT_NOTE = " The account covers only the start of the run because its transcript reached a read limit.";
73235
- PARTIAL_NOTE_HEAD = "Evidence is partial: ";
73236
- PARTIAL_NOTE_TAIL = " recorded bodies were unavailable.";
73237
- escapeRegExp2 = (text5) => text5.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
73238
- NOTE_SOURCE = [
73239
- `${escapeRegExp2(PARTIAL_NOTE_HEAD)}\\d+${escapeRegExp2(PARTIAL_NOTE_TAIL)}`,
73240
- escapeRegExp2(ENRICHMENT_BUDGET_NOTE.trim()),
73241
- escapeRegExp2(ENRICHMENT_LIMIT_NOTE.trim())
73242
- ].join("|");
73243
- TRAILING_NOTES = new RegExp(
73244
- `(?:^|\\s)((?:${NOTE_SOURCE})(?:\\s(?:${NOTE_SOURCE}))*)$`,
73245
- "u"
73787
+ init_zod();
73788
+ init_context_steering_shared();
73789
+ init_common();
73790
+ init_json_schema();
73791
+ init_tokens();
73792
+ ledgerRotationSchema = external_exports.enum(["day", "week", "month", "year"]);
73793
+ governanceSchema = withRules(
73794
+ external_exports.object({
73795
+ schema: external_exports.literal("governance/v1"),
73796
+ mode: governanceModeSchema,
73797
+ steering: external_exports.object({
73798
+ always_on_tokens: external_exports.union([external_exports.number().int().positive(), external_exports.literal("off")]).optional().describe(
73799
+ "The always-on budget per code repository, or off. Unset inherits Oxagen's default, the largest harness hook limit. A budget above that limit fails the budget check."
73800
+ )
73801
+ }).strict().optional(),
73802
+ ledger: external_exports.object({
73803
+ rotate: ledgerRotationSchema.optional(),
73804
+ max_lines: external_exports.number().int().positive().optional().describe("A new file starts here even mid-period.")
73805
+ }).strict().optional(),
73806
+ // `recall_unreviewed` left the memory table on 2026-09-30, because
73807
+ // Oxagen no longer recalls a memory that waits for review (ADR-238).
73808
+ memory: external_exports.object({
73809
+ batch_size: external_exports.number().int().positive().optional().describe("Memories per memory PR."),
73810
+ retire_after_days: external_exports.number().int().positive().optional(),
73811
+ auto_merge: external_exports.boolean().optional().describe("Allowed in solo mode only.")
73812
+ }).strict().optional(),
73813
+ reviewers: external_exports.array(
73814
+ external_exports.object({
73815
+ paths: external_exports.array(external_exports.string().min(1)).min(1),
73816
+ group: organizationSlugSchema
73817
+ }).strict()
73818
+ ).optional().describe(
73819
+ "Route the folders a pull request changes to a reviewer group."
73820
+ )
73821
+ }).strict(),
73822
+ [
73823
+ {
73824
+ kind: "equals",
73825
+ when: { field: "mode", isNot: "solo" },
73826
+ path: ["memory", "auto_merge"],
73827
+ value: false
73828
+ }
73829
+ ]
73246
73830
  );
73247
- GITHUB_REF_SOURCE = String.raw`\bhttps?:\/\/(?:www\.)?github\.com\/[\w.-]+\/[\w.-]+\/(pull|issues)\/(\d+)\S*`;
73248
73831
  }
73249
73832
  });
73250
73833
 
73251
- // ../../packages/tacho/src/session-title.ts
73252
- var init_session_title = __esm({
73253
- "../../packages/tacho/src/session-title.ts"() {
73834
+ // ../../packages/oxagen/src/steering-repo/health.ts
73835
+ var REPO_HEALTH_STATES, repoHealthSchema, settingsDifferenceSchema;
73836
+ var init_health = __esm({
73837
+ "../../packages/oxagen/src/steering-repo/health.ts"() {
73254
73838
  "use strict";
73255
- init_session_subject();
73839
+ init_zod();
73840
+ init_common();
73841
+ REPO_HEALTH_STATES = [
73842
+ "healthy",
73843
+ "drifted",
73844
+ "disconnected",
73845
+ "diverged"
73846
+ ];
73847
+ repoHealthSchema = external_exports.enum(REPO_HEALTH_STATES);
73848
+ settingsDifferenceSchema = external_exports.object({
73849
+ setting: external_exports.string().min(1).describe(
73850
+ "The setting's path in the baseline, such as rulesets.oxagen_merges."
73851
+ ),
73852
+ expected: external_exports.unknown(),
73853
+ actual: external_exports.unknown(),
73854
+ changed_by: external_exports.string().nullable(),
73855
+ changed_at: instantSchema2.nullable()
73856
+ }).strict();
73256
73857
  }
73257
73858
  });
73258
73859
 
73259
- // ../../packages/tacho/src/index.ts
73260
- var init_src4 = __esm({
73261
- "../../packages/tacho/src/index.ts"() {
73860
+ // ../../packages/oxagen/src/steering-repo/promotion.ts
73861
+ var promotionChangeSchema, branchSchema, promotionSchema;
73862
+ var init_promotion = __esm({
73863
+ "../../packages/oxagen/src/steering-repo/promotion.ts"() {
73262
73864
  "use strict";
73263
- init_chain();
73264
- init_columns();
73265
- init_digest();
73266
- init_envelope();
73267
- init_ids();
73268
- init_interjection();
73269
- init_record_basis();
73270
- init_remote();
73271
- init_timestamp();
73272
- init_wire();
73273
- init_evidence();
73274
- init_llm_call_dedupe();
73275
- init_session_subject();
73276
- init_session_title();
73277
- init_context_window();
73865
+ init_zod();
73866
+ init_src3();
73867
+ init_context_steering_shared();
73868
+ init_common();
73869
+ init_names();
73870
+ promotionChangeSchema = external_exports.object({
73871
+ path: repoPathSchema,
73872
+ action: external_exports.enum(["added", "modified", "removed"]),
73873
+ lineage: lineageSchema.optional(),
73874
+ id: recordIdSchema.optional(),
73875
+ hash: sha256Schema2.optional(),
73876
+ replaces: recordIdSchema.optional().describe(
73877
+ "The id this record had before a format change, such as the v0.1 conversion."
73878
+ )
73879
+ }).strict();
73880
+ branchSchema = external_exports.string().regex(new RegExp(`^(?:${BRANCH_PREFIXES.join("|")})/.+$`)).describe("Starts with the top-level folder the change touches.");
73881
+ promotionSchema = external_exports.object({
73882
+ schema: external_exports.literal("promotion/v1"),
73883
+ seq: external_exports.number().int().min(1).describe("The line's place in the whole chain, across files."),
73884
+ at: instantSchema2,
73885
+ pull_request: external_exports.object({
73886
+ provider: repositoryProviderSchema,
73887
+ number: external_exports.number().int().positive()
73888
+ }).strict(),
73889
+ branch: branchSchema,
73890
+ mode: governanceModeSchema,
73891
+ approved_by: external_exports.array(actorSchema),
73892
+ merged_by: actorSchema,
73893
+ without_review: external_exports.boolean().describe(
73894
+ "True when the owner, or a role with merge_pr_without_review, merged without an approval."
73895
+ ),
73896
+ changes: external_exports.array(promotionChangeSchema).min(1),
73897
+ prev: sha256Schema2.nullable().describe(
73898
+ "The hash of the line before, or null on the first line of the chain."
73899
+ ),
73900
+ hash: sha256Schema2.describe(
73901
+ "sha256 over the RFC 8785 canonical JSON of this line without hash."
73902
+ )
73903
+ }).strict();
73278
73904
  }
73279
73905
  });
73280
73906
 
@@ -74730,6 +75356,41 @@ function definitionBudget(tree) {
74730
75356
  function repositoryName(repository) {
74731
75357
  return repository ?? "a repository no record names";
74732
75358
  }
75359
+ function harnessNames(harnesses) {
75360
+ const names2 = harnesses.map((harness) => HARNESS_LABELS[harness] ?? harness);
75361
+ if (names2.length <= 1) return names2.join("");
75362
+ return `${names2.slice(0, -1).join(", ")} and ${names2[names2.length - 1]}`;
75363
+ }
75364
+ function budgetCeiling(budget, line) {
75365
+ if (budget === "off" || budget.tokens <= LARGEST_PREFIX_BUDGET_TOKENS)
75366
+ return null;
75367
+ const at = harnessesAtLargestBudget();
75368
+ const limit = formatCount(LARGEST_PREFIX_BUDGET_TOKENS);
75369
+ const chars = formatCount(
75370
+ Math.max(...at.map((harness) => HARNESS_HOOK_LIMITS[harness].chars))
75371
+ );
75372
+ return find2({
75373
+ rule: "always-on-ceiling",
75374
+ severity: "error",
75375
+ path: GOVERNANCE_TOML_PATH,
75376
+ line,
75377
+ field: "steering.always_on_tokens",
75378
+ message: `always_on_tokens is ${formatCount(budget.tokens)}, above the ${limit} tokens ${harnessNames(at)} take from one hook answer (${chars} characters). No harness would hand an agent the extra text.`,
75379
+ expected: `At most ${limit} tokens, the largest harness hook limit.`,
75380
+ fix: `Set always_on_tokens to ${limit} or less in this PR, or remove it to inherit Oxagen's default, which is that limit.`,
75381
+ detail: {
75382
+ budget: budget.tokens,
75383
+ budget_source: budget.source,
75384
+ ceiling: LARGEST_PREFIX_BUDGET_TOKENS,
75385
+ harnesses: at.map((harness) => ({
75386
+ harness,
75387
+ chars: HARNESS_HOOK_LIMITS[harness].chars,
75388
+ tokens: prefixBudgetTokens(harness),
75389
+ source: HARNESS_HOOK_LIMITS[harness].source
75390
+ }))
75391
+ }
75392
+ });
75393
+ }
74733
75394
  function sameBudget(a, b5) {
74734
75395
  if (a === "off" || b5 === "off") return a === b5;
74735
75396
  return a.tokens === b5.tokens;
@@ -74784,6 +75445,8 @@ function alwaysOnPart(env) {
74784
75445
  const line = governance === void 0 ? null : tomlLine(governance, "steering.always_on_tokens");
74785
75446
  const findings = [];
74786
75447
  const notes = [];
75448
+ const ceiling = budgetCeiling(budget, line);
75449
+ if (ceiling !== null) findings.push(ceiling);
74787
75450
  for (const block of alwaysOnBlocks(env.head)) {
74788
75451
  const prior = before.get(block.repository);
74789
75452
  if (!budgetMoved && prior?.text === block.text) continue;
@@ -74896,16 +75559,23 @@ function toolsPart(env) {
74896
75559
  ]
74897
75560
  };
74898
75561
  }
74899
- var find2, LARGEST, budgetCheck;
75562
+ var find2, LARGEST, HARNESS_LABELS, budgetCheck;
74900
75563
  var init_budget3 = __esm({
74901
75564
  "../../packages/steering-check/src/checks/budget.ts"() {
74902
75565
  "use strict";
75566
+ init_src4();
74903
75567
  init_steering_repo();
74904
75568
  init_always_on();
74905
75569
  init_finding();
74906
75570
  init_repo2();
74907
75571
  find2 = finder("budget");
74908
75572
  LARGEST = 3;
75573
+ HARNESS_LABELS = {
75574
+ "claude-code": "Claude Code",
75575
+ codex: "Codex",
75576
+ cursor: "Cursor",
75577
+ stella: "Stella"
75578
+ };
74909
75579
  budgetCheck = (env) => {
74910
75580
  const always = alwaysOnPart(env);
74911
75581
  const tools = toolsPart(env);
@@ -76922,7 +77592,9 @@ function importFilename(path2, folder) {
76922
77592
  async function readImportDocuments(sources, target2, writer) {
76923
77593
  const documents = [];
76924
77594
  const unreadable = [];
77595
+ const binary = [];
76925
77596
  const tooLong = [];
77597
+ const tooMany = [];
76926
77598
  for (const source of sources) {
76927
77599
  let content;
76928
77600
  try {
@@ -76940,9 +77612,36 @@ async function readImportDocuments(sources, target2, writer) {
76940
77612
  continue;
76941
77613
  }
76942
77614
  const filename = importFilename(source.path, source.folder);
76943
- documents.push(
76944
- target2 === void 0 ? { filename, content } : { filename, content, target: target2 }
76945
- );
77615
+ const document = { filename, content };
77616
+ if (target2 !== void 0) document.target = target2;
77617
+ if (source.source !== void 0) document.source = source.source;
77618
+ if (source.files !== void 0 && source.files.length > 0) {
77619
+ const files3 = [];
77620
+ for (const file of source.files) {
77621
+ let text5;
77622
+ try {
77623
+ text5 = await readFile9(file.file, "utf8");
77624
+ } catch {
77625
+ unreadable.push(file.file);
77626
+ continue;
77627
+ }
77628
+ if (text5.includes("\0")) {
77629
+ binary.push(file.file);
77630
+ continue;
77631
+ }
77632
+ if (text5.length > MARKDOWN_IMPORT_FILE_CHARS_MAX) {
77633
+ tooLong.push(file.file);
77634
+ continue;
77635
+ }
77636
+ if (files3.length >= MARKDOWN_IMPORT_SKILL_FILES_MAX) {
77637
+ tooMany.push(file.file);
77638
+ continue;
77639
+ }
77640
+ files3.push({ path: file.path, content: text5 });
77641
+ }
77642
+ if (files3.length > 0) document.files = files3;
77643
+ }
77644
+ documents.push(document);
76946
77645
  }
76947
77646
  if (unreadable.length > 0) {
76948
77647
  writer.writeErr(
@@ -76950,12 +77649,24 @@ async function readImportDocuments(sources, target2, writer) {
76950
77649
  ${unreadable.join("\n ")}`
76951
77650
  );
76952
77651
  }
77652
+ if (binary.length > 0) {
77653
+ writer.writeErr(
77654
+ `Skipped binary files, which the import does not carry:
77655
+ ${binary.join("\n ")}`
77656
+ );
77657
+ }
76953
77658
  if (tooLong.length > 0) {
76954
77659
  writer.writeErr(
76955
77660
  `Skipped files over ${MARKDOWN_IMPORT_FILE_CHARS_MAX.toLocaleString("en-US")} characters, the most one file may hold:
76956
77661
  ${tooLong.join("\n ")}`
76957
77662
  );
76958
77663
  }
77664
+ if (tooMany.length > 0) {
77665
+ writer.writeErr(
77666
+ `Skipped skill files past the ${MARKDOWN_IMPORT_SKILL_FILES_MAX} one skill may carry:
77667
+ ${tooMany.join("\n ")}`
77668
+ );
77669
+ }
76959
77670
  if (documents.length === 0) {
76960
77671
  failCommand("No readable, non-empty files to import.", writer);
76961
77672
  }
@@ -77144,24 +77855,25 @@ var init_markdown_import = __esm({
77144
77855
  // src/commands/steering-import.ts
77145
77856
  var steering_import_exports = {};
77146
77857
  __export(steering_import_exports, {
77147
- CURSOR_FOLDER: () => CURSOR_FOLDER,
77148
- CURSOR_RULES_FOLDER: () => CURSOR_RULES_FOLDER,
77149
- CURSOR_RULE_EXTENSIONS: () => CURSOR_RULE_EXTENSIONS,
77858
+ CATALOGUE_FOLDERS: () => CATALOGUE_FOLDERS,
77150
77859
  MARKDOWN_EXTENSIONS: () => MARKDOWN_EXTENSIONS,
77151
77860
  STEERING_IMPORT_CAPABILITIES: () => STEERING_IMPORT_CAPABILITIES,
77152
77861
  findMarkdownFiles: () => findMarkdownFiles,
77153
77862
  handleSteeringImport: () => handleSteeringImport
77154
77863
  });
77155
77864
  import { readdir as readdir4, realpath as realpath2, stat as stat4 } from "node:fs/promises";
77156
- import { basename as basename8, extname, join as join50 } from "node:path";
77865
+ import { basename as basename8, extname, join as join50, relative as relative7, sep as sep8 } from "node:path";
77157
77866
  function byName(a, b5) {
77158
77867
  return a.name < b5.name ? -1 : 1;
77159
77868
  }
77869
+ function under(root, path2) {
77870
+ return relative7(root, path2).split(sep8).join("/");
77871
+ }
77160
77872
  async function findMarkdownFiles(paths) {
77161
77873
  const sources = [];
77162
77874
  const unreadable = [];
77163
77875
  const seen = /* @__PURE__ */ new Set();
77164
- const take = async (path2, folder) => {
77876
+ const take = async (path2, extra = {}) => {
77165
77877
  let real = path2;
77166
77878
  try {
77167
77879
  real = await realpath2(path2);
@@ -77169,9 +77881,29 @@ async function findMarkdownFiles(paths) {
77169
77881
  }
77170
77882
  if (seen.has(real)) return;
77171
77883
  seen.add(real);
77172
- sources.push(folder === void 0 ? { path: path2 } : { path: path2, folder });
77884
+ sources.push({ path: path2, ...extra });
77885
+ };
77886
+ const filesUnder = async (dir, from) => {
77887
+ let entries2;
77888
+ try {
77889
+ entries2 = await readdir4(dir, { withFileTypes: true });
77890
+ } catch {
77891
+ unreadable.push(dir);
77892
+ return [];
77893
+ }
77894
+ const found = [];
77895
+ for (const entry2 of entries2.sort(byName)) {
77896
+ const path2 = join50(dir, entry2.name);
77897
+ if (entry2.isDirectory()) {
77898
+ if (!entry2.name.startsWith(".") && entry2.name !== "node_modules")
77899
+ found.push(...await filesUnder(path2, from));
77900
+ } else if (entry2.isFile() || entry2.isSymbolicLink()) {
77901
+ if (under(from, path2) !== "SKILL.md") found.push(path2);
77902
+ }
77903
+ }
77904
+ return found;
77173
77905
  };
77174
- const walk2 = async (dir, folder, place2) => {
77906
+ const walk2 = async (dir, root, folder, inCatalogue) => {
77175
77907
  let entries2;
77176
77908
  try {
77177
77909
  entries2 = await readdir4(dir, { withFileTypes: true });
@@ -77180,25 +77912,45 @@ async function findMarkdownFiles(paths) {
77180
77912
  return;
77181
77913
  }
77182
77914
  entries2.sort(byName);
77183
- const extensions2 = place2 === "rules" ? CURSOR_RULE_EXTENSIONS : MARKDOWN_EXTENSIONS;
77184
77915
  for (const entry2 of entries2) {
77185
77916
  const path2 = join50(dir, entry2.name);
77917
+ const rel = under(root, path2);
77186
77918
  if (entry2.isDirectory()) {
77187
- if (place2 === "cursor") {
77188
- if (entry2.name === CURSOR_RULES_FOLDER) {
77189
- await walk2(path2, folder, "rules");
77190
- }
77191
- continue;
77192
- }
77193
77919
  if (entry2.name === "node_modules") continue;
77194
- if (entry2.name === CURSOR_FOLDER && place2 === "plain") {
77195
- await walk2(path2, folder, "cursor");
77920
+ if (entry2.name.startsWith(".")) {
77921
+ if (!inCatalogue && CATALOGUE_FOLDERS.has(entry2.name))
77922
+ await walk2(path2, root, folder, true);
77196
77923
  continue;
77197
77924
  }
77198
- if (entry2.name.startsWith(".")) continue;
77199
- await walk2(path2, folder, place2);
77200
- } else if (place2 !== "cursor" && (entry2.isFile() || entry2.isSymbolicLink()) && extensions2.has(extname(entry2.name).toLowerCase())) {
77201
- await take(path2, folder);
77925
+ await walk2(path2, root, folder, inCatalogue);
77926
+ continue;
77927
+ }
77928
+ if (!entry2.isFile() && !entry2.isSymbolicLink()) continue;
77929
+ const source = markdownImportSourceOf(rel);
77930
+ if (inCatalogue) {
77931
+ if (source === null) continue;
77932
+ if (source.kind === "skill") {
77933
+ const skillDir = dir;
77934
+ await take(path2, {
77935
+ folder,
77936
+ source: { ...source, path: rel },
77937
+ files: (await filesUnder(skillDir, skillDir)).map((file) => ({
77938
+ path: under(skillDir, file),
77939
+ file
77940
+ }))
77941
+ });
77942
+ } else {
77943
+ await take(path2, { folder, source: { ...source, path: rel } });
77944
+ }
77945
+ continue;
77946
+ }
77947
+ if (MARKDOWN_EXTENSIONS.has(extname(entry2.name).toLowerCase())) {
77948
+ await take(
77949
+ path2,
77950
+ source === null ? { folder } : { folder, source: { ...source, path: rel } }
77951
+ );
77952
+ } else if (source !== null && source.kind === "instructions") {
77953
+ await take(path2, { folder, source: { ...source, path: rel } });
77202
77954
  }
77203
77955
  }
77204
77956
  };
@@ -77211,9 +77963,16 @@ async function findMarkdownFiles(paths) {
77211
77963
  continue;
77212
77964
  }
77213
77965
  if (isFolder) {
77214
- const place2 = basename8(path2) === CURSOR_FOLDER ? "cursor" : "plain";
77215
- await walk2(path2, path2, place2);
77216
- } else await take(path2);
77966
+ const named = CATALOGUE_FOLDERS.has(basename8(path2));
77967
+ await walk2(path2, named ? join50(path2, "..") : path2, path2, false);
77968
+ } else {
77969
+ const rel = under(process.cwd(), path2);
77970
+ const source = rel.startsWith("..") ? null : markdownImportSourceOf(rel);
77971
+ await take(
77972
+ path2,
77973
+ source === null ? {} : { source: { ...source, path: rel } }
77974
+ );
77975
+ }
77217
77976
  }
77218
77977
  return { sources, unreadable };
77219
77978
  }
@@ -77254,9 +78013,11 @@ async function handleSteeringImport(paths, opts, writer = stdoutWriter) {
77254
78013
  writer
77255
78014
  );
77256
78015
  }
77257
- var STEERING_IMPORT_CAPABILITIES, MARKDOWN_EXTENSIONS, CURSOR_FOLDER, CURSOR_RULES_FOLDER, CURSOR_RULE_EXTENSIONS, TARGETS;
78016
+ var STEERING_IMPORT_CAPABILITIES, MARKDOWN_EXTENSIONS, CATALOGUE_FOLDERS, TARGETS;
77258
78017
  var init_steering_import = __esm({
77259
78018
  "src/commands/steering-import.ts"() {
78019
+ init_steering_markdown_import_shared();
78020
+ init_harness_files();
77260
78021
  init_capture_writer();
77261
78022
  init_markdown_import();
77262
78023
  STEERING_IMPORT_CAPABILITIES = [
@@ -77269,12 +78030,11 @@ var init_steering_import = __esm({
77269
78030
  ".mdx",
77270
78031
  ".mdc"
77271
78032
  ]);
77272
- CURSOR_FOLDER = ".cursor";
77273
- CURSOR_RULES_FOLDER = "rules";
77274
- CURSOR_RULE_EXTENSIONS = /* @__PURE__ */ new Set([
77275
- ".mdc",
77276
- ".md"
77277
- ]);
78033
+ CATALOGUE_FOLDERS = new Set(
78034
+ WELL_KNOWN_FOLDERS.map((folder) => folder.split("/")[0] ?? "").filter(
78035
+ (name) => name.startsWith(".")
78036
+ )
78037
+ );
77278
78038
  TARGETS = [
77279
78039
  "records",
77280
78040
  "policies",
@@ -79401,7 +80161,7 @@ async function handleMemoryList(opts, writer = stdoutWriter) {
79401
80161
  const states2 = listOpt(opts.state);
79402
80162
  for (const state of states2)
79403
80163
  oneOf(state, WORKSPACE_MEMORY_STATES, "--state", writer);
79404
- const harness = oneOf(opts.harness, HARNESSES2, "--harness", writer);
80164
+ const harness = oneOf(opts.harness, HARNESSES3, "--harness", writer);
79405
80165
  try {
79406
80166
  const result2 = await listWorkspaceMemories({
79407
80167
  states: states2.length === 0 ? void 0 : states2,
@@ -79608,7 +80368,7 @@ async function handleMemoryImport(files3, opts, writer = stdoutWriter) {
79608
80368
  writer
79609
80369
  );
79610
80370
  }
79611
- var MEMORY_COMMAND_CAPABILITIES, HARNESSES2, KINDS2, FORCES2, EFFECTS2, DISMISS_REASONS, MEMORY_IMPORT_CAPABILITIES;
80371
+ var MEMORY_COMMAND_CAPABILITIES, HARNESSES3, KINDS2, FORCES2, EFFECTS2, DISMISS_REASONS, MEMORY_IMPORT_CAPABILITIES;
79612
80372
  var init_memory2 = __esm({
79613
80373
  "src/commands/memory.ts"() {
79614
80374
  init_api();
@@ -79623,7 +80383,7 @@ var init_memory2 = __esm({
79623
80383
  "dismiss_memories",
79624
80384
  "drop_memory_record"
79625
80385
  ];
79626
- HARNESSES2 = [
80386
+ HARNESSES3 = [
79627
80387
  "claude-code",
79628
80388
  "codex",
79629
80389
  "cursor",
@@ -79901,7 +80661,7 @@ import {
79901
80661
  writeFileSync as writeFileSync10
79902
80662
  } from "node:fs";
79903
80663
  import { homedir as homedir12, hostname as osHostname3 } from "node:os";
79904
- import { join as join52, relative as relative7, resolve as resolve20, sep as sep8 } from "node:path";
80664
+ import { join as join52, relative as relative8, resolve as resolve20, sep as sep9 } from "node:path";
79905
80665
  function git4(cwd, args) {
79906
80666
  return new Promise((done) => {
79907
80667
  try {
@@ -79972,7 +80732,7 @@ function symlinkState(root) {
79972
80732
  try {
79973
80733
  if (!lstatSync9(at).isSymbolicLink()) return "missing";
79974
80734
  const target2 = realpathSync8(at);
79975
- if (target2 !== oxagenReal && !target2.startsWith(oxagenReal + sep8)) {
80735
+ if (target2 !== oxagenReal && !target2.startsWith(oxagenReal + sep9)) {
79976
80736
  return "missing";
79977
80737
  }
79978
80738
  } catch {
@@ -80062,10 +80822,10 @@ async function ensureWorkspaceLinkIgnored(root) {
80062
80822
  const top = await git4(root, ["rev-parse", "--show-toplevel"]);
80063
80823
  if (!top) return null;
80064
80824
  const topDir = resolve20(top);
80065
- const entry2 = relative7(
80825
+ const entry2 = relative8(
80066
80826
  topDir,
80067
80827
  join52(realpathOr2(root), ".oxagen", "workspace.json")
80068
- ).split(sep8).join("/");
80828
+ ).split(sep9).join("/");
80069
80829
  if (entry2.startsWith("../")) return null;
80070
80830
  const rule = await git4(topDir, ["check-ignore", "--no-index", "-v", entry2]);
80071
80831
  if (rule !== null) return null;
@@ -80556,7 +81316,7 @@ import {
80556
81316
  join as join53,
80557
81317
  parse as parsePath2,
80558
81318
  posix as posix4,
80559
- sep as sep9
81319
+ sep as sep10
80560
81320
  } from "node:path";
80561
81321
  function checkSteeringPath(path2) {
80562
81322
  if (typeof path2 !== "string" || path2.length === 0) {
@@ -80703,7 +81463,7 @@ function assertInsideOxagen(root, path2) {
80703
81463
  real = null;
80704
81464
  }
80705
81465
  if (real !== null) {
80706
- if (real !== oxagenReal && !real.startsWith(oxagenReal + sep9)) {
81466
+ if (real !== oxagenReal && !real.startsWith(oxagenReal + sep10)) {
80707
81467
  throw new Error(`${path2} resolves outside .oxagen/`);
80708
81468
  }
80709
81469
  return;
@@ -80716,7 +81476,7 @@ function assertInsideOxagen(root, path2) {
80716
81476
  function pruneEmptyDirs(root, path2) {
80717
81477
  const stop = join53(root, OXAGEN_DIR);
80718
81478
  let dir = dirname29(join53(root, ...path2.split("/")));
80719
- while (dir.startsWith(stop + sep9)) {
81479
+ while (dir.startsWith(stop + sep10)) {
80720
81480
  try {
80721
81481
  if (readdirSync14(dir).length > 0) return;
80722
81482
  rmdirSync7(dir);
@@ -124033,7 +124793,7 @@ import {
124033
124793
  readlinkSync as readlinkSync4,
124034
124794
  statSync as statSync13
124035
124795
  } from "node:fs";
124036
- import { dirname as dirname30, isAbsolute as isAbsolute15, join as join54, relative as relative8, resolve as resolve22, sep as sep10 } from "node:path";
124796
+ import { dirname as dirname30, isAbsolute as isAbsolute15, join as join54, relative as relative9, resolve as resolve22, sep as sep11 } from "node:path";
124037
124797
  function git5(cwd, args, input) {
124038
124798
  try {
124039
124799
  return execFileSync2("git", args, {
@@ -124173,11 +124933,11 @@ function within3(path2, scope) {
124173
124933
  function scopesFor(root, cwd, paths, trees) {
124174
124934
  const scopes = [];
124175
124935
  for (const path2 of paths) {
124176
- const rel = relative8(root, resolve22(cwd, path2));
124177
- if (rel === ".." || rel.startsWith(`..${sep10}`) || isAbsolute15(rel)) {
124936
+ const rel = relative9(root, resolve22(cwd, path2));
124937
+ if (rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute15(rel)) {
124178
124938
  return { error: `${path2} is outside the steering repo at ${root}.` };
124179
124939
  }
124180
- const scope = rel.split(sep10).join("/");
124940
+ const scope = rel.split(sep11).join("/");
124181
124941
  const known = trees.some(
124182
124942
  (tree) => tree !== null && [...tree.keys()].some((file) => within3(file, scope))
124183
124943
  );
@@ -124485,7 +125245,7 @@ async function check(paths = [], opts = {}, writer = stdoutWriter, cwd = process
124485
125245
  }
124486
125246
  if (!report.passed) process.exitCode = 1;
124487
125247
  }
124488
- var ROOT_FILES2, TREE_DIRS, PATHSPECS, DEFAULT_BASES, NOT_A_STEERING_REPO, NO_BASE, GIT_TIMEOUT_MS2, GIT_MAX_BUFFER, CACHE_MAX_AGE_MS, CONTEXT_KEYS, workspaceSlugs, KEY_SCOPE_MISMATCH, ScopeMismatchError;
125248
+ var ROOT_FILES3, TREE_DIRS, PATHSPECS, DEFAULT_BASES, NOT_A_STEERING_REPO, NO_BASE, GIT_TIMEOUT_MS2, GIT_MAX_BUFFER, CACHE_MAX_AGE_MS, CONTEXT_KEYS, workspaceSlugs, KEY_SCOPE_MISMATCH, ScopeMismatchError;
124489
125249
  var init_check3 = __esm({
124490
125250
  "src/commands/check.ts"() {
124491
125251
  init_paths2();
@@ -124498,7 +125258,7 @@ var init_check3 = __esm({
124498
125258
  init_capture_writer();
124499
125259
  init_config();
124500
125260
  init_output();
124501
- ROOT_FILES2 = [
125261
+ ROOT_FILES3 = [
124502
125262
  AGENTS_MD_PATH,
124503
125263
  CLAUDE_MD_PATH,
124504
125264
  README_PATH,
@@ -124511,7 +125271,7 @@ var init_check3 = __esm({
124511
125271
  TOOLS_DIR,
124512
125272
  POLICY_DIR
124513
125273
  ];
124514
- PATHSPECS = [...ROOT_FILES2, ...TREE_DIRS];
125274
+ PATHSPECS = [...ROOT_FILES3, ...TREE_DIRS];
124515
125275
  DEFAULT_BASES = ["origin/HEAD", "origin/main"];
124516
125276
  NOT_A_STEERING_REPO = "This directory is not in a steering repo. Run oxagen check inside a clone that holds workspace.toml, or AGENTS.md and steering/ for an organization repo.";
124517
125277
  NO_BASE = `No production branch to compare with. ${DEFAULT_BASES.join(" and ")} do not resolve in this clone, so the checks read the working tree whole. Pass --base <ref> to compare with a branch.`;
@@ -128189,13 +128949,13 @@ var init_src9 = __esm({
128189
128949
 
128190
128950
  // src/commands/codegraph-upload/files.ts
128191
128951
  import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
128192
- import { join as join55, relative as relative9, sep as sep11 } from "node:path";
128952
+ import { join as join55, relative as relative10, sep as sep12 } from "node:path";
128193
128953
  function hasGlobChars(pattern) {
128194
128954
  return /[*?[\]{}]/.test(pattern);
128195
128955
  }
128196
128956
  function normalize2(path2) {
128197
128957
  const trimmed = path2.replace(/^\.\//, "");
128198
- return sep11 === "/" ? trimmed : trimmed.split(sep11).join("/");
128958
+ return sep12 === "/" ? trimmed : trimmed.split(sep12).join("/");
128199
128959
  }
128200
128960
  async function walk(root, dir, out) {
128201
128961
  const entries2 = await readdir5(dir, { withFileTypes: true });
@@ -128205,7 +128965,7 @@ async function walk(root, dir, out) {
128205
128965
  if (entry2.isDirectory()) {
128206
128966
  if (!SKIP_DIRS.has(entry2.name)) await walk(root, full, out);
128207
128967
  } else if (entry2.isFile()) {
128208
- out.push(normalize2(relative9(root, full)));
128968
+ out.push(normalize2(relative10(root, full)));
128209
128969
  }
128210
128970
  }
128211
128971
  }