@oxagen/cli 2.1.4-679 → 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 +2227 -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-679";
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-679",
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",
@@ -72108,1173 +73506,401 @@ var init_codegraph_settings = __esm({
72108
73506
  ),
72109
73507
  30
72110
73508
  ),
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
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
 
@@ -73355,7 +73981,7 @@ var init_run_shared = __esm({
73355
73981
  });
73356
73982
 
73357
73983
  // ../../packages/oxagen/src/contracts/run.list.ts
73358
- var runPublicIdSchema, runSourceSchema, runStatusSchema, runOutcomeSchema, runCostSchema, replayGradeSchema, generatedRunSummarySchema, editedRunSummarySchema, runSummarySchema, operatorKindSchema, RUN_OPERATOR_ROLES, runOperatorRoleSchema, runModelSchema, runMachineSnapshotSchema, runMachineSchema, COMMAND_BLOCKS, STEER_BLOCKS, HOST_POLL_WINDOW_MS, RUN_PULL_REQUEST_MAX, runPullRequestSchema, runDiffSchema, RUN_PULL_REQUEST_FILTERS, RUN_PAUSE_STATES, runPauseSchema, RUN_REPLAY_FILTERS, RUN_SORT_KEYS, RUN_LIST_TOTAL_BOUND, RUN_LABEL_MAX, runItemSchema, runList;
73984
+ var runPublicIdSchema, runSourceSchema, runStatusSchema, runOutcomeSchema, runCostSchema, replayGradeSchema, generatedRunSummarySchema, editedRunSummarySchema, runSummarySchema, operatorKindSchema, RUN_OPERATOR_ROLES, runOperatorRoleSchema, runModelSchema, runMachineSnapshotSchema, runMachineSchema, COMMAND_BLOCKS, STEER_BLOCKS, HOST_POLL_WINDOW_MS, RUN_PULL_REQUEST_MAX, runPullRequestSchema, runDiffSchema, runAttributionSchema, RUN_PULL_REQUEST_FILTERS, RUN_PAUSE_STATES, runPauseSchema, RUN_REPLAY_FILTERS, RUN_SORT_KEYS, RUN_LIST_TOTAL_BOUND, RUN_LABEL_MAX, runItemSchema, runList;
73359
73985
  var init_run_list = __esm({
73360
73986
  "../../packages/oxagen/src/contracts/run.list.ts"() {
73361
73987
  "use strict";
@@ -73465,6 +74091,13 @@ var init_run_list = __esm({
73465
74091
  removed: external_exports.number().int().nonnegative(),
73466
74092
  basis: external_exports.enum(["harness_reported", "git_observed"])
73467
74093
  }).strict();
74094
+ runAttributionSchema = external_exports.object({
74095
+ commits: external_exports.number().int().nonnegative(),
74096
+ merges: external_exports.number().int().nonnegative(),
74097
+ written: external_exports.object({ added: external_exports.number().int().nonnegative(), removed: external_exports.number().int().nonnegative() }),
74098
+ shipped: external_exports.object({ added: external_exports.number().int().nonnegative(), removed: external_exports.number().int().nonnegative() }).nullable(),
74099
+ uncommitted: external_exports.object({ added: external_exports.number().int().nonnegative(), removed: external_exports.number().int().nonnegative() }).nullable()
74100
+ });
73468
74101
  RUN_PULL_REQUEST_FILTERS = ["any", "with", "without"];
73469
74102
  RUN_PAUSE_STATES = ["pausing", "paused", "resuming"];
73470
74103
  runPauseSchema = external_exports.object({
@@ -73810,6 +74443,7 @@ var init_run_list = __esm({
73810
74443
  pullRequestsOpened: external_exports.number().int().nonnegative().optional(),
73811
74444
  /** Lines added and removed; null when neither the harness nor git reported any. */
73812
74445
  diff: runDiffSchema.nullable().optional(),
74446
+ attribution: runAttributionSchema.nullable().optional(),
73813
74447
  /**
73814
74448
  * The run's token counts by class, from its `cost.run_totals` row. Null
73815
74449
  * when the run has no rollup row. The column is NOT NULL, so an unpriced
@@ -74722,6 +75356,41 @@ function definitionBudget(tree) {
74722
75356
  function repositoryName(repository) {
74723
75357
  return repository ?? "a repository no record names";
74724
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
+ }
74725
75394
  function sameBudget(a, b5) {
74726
75395
  if (a === "off" || b5 === "off") return a === b5;
74727
75396
  return a.tokens === b5.tokens;
@@ -74776,6 +75445,8 @@ function alwaysOnPart(env) {
74776
75445
  const line = governance === void 0 ? null : tomlLine(governance, "steering.always_on_tokens");
74777
75446
  const findings = [];
74778
75447
  const notes = [];
75448
+ const ceiling = budgetCeiling(budget, line);
75449
+ if (ceiling !== null) findings.push(ceiling);
74779
75450
  for (const block of alwaysOnBlocks(env.head)) {
74780
75451
  const prior = before.get(block.repository);
74781
75452
  if (!budgetMoved && prior?.text === block.text) continue;
@@ -74888,16 +75559,23 @@ function toolsPart(env) {
74888
75559
  ]
74889
75560
  };
74890
75561
  }
74891
- var find2, LARGEST, budgetCheck;
75562
+ var find2, LARGEST, HARNESS_LABELS, budgetCheck;
74892
75563
  var init_budget3 = __esm({
74893
75564
  "../../packages/steering-check/src/checks/budget.ts"() {
74894
75565
  "use strict";
75566
+ init_src4();
74895
75567
  init_steering_repo();
74896
75568
  init_always_on();
74897
75569
  init_finding();
74898
75570
  init_repo2();
74899
75571
  find2 = finder("budget");
74900
75572
  LARGEST = 3;
75573
+ HARNESS_LABELS = {
75574
+ "claude-code": "Claude Code",
75575
+ codex: "Codex",
75576
+ cursor: "Cursor",
75577
+ stella: "Stella"
75578
+ };
74901
75579
  budgetCheck = (env) => {
74902
75580
  const always = alwaysOnPart(env);
74903
75581
  const tools = toolsPart(env);
@@ -76914,7 +77592,9 @@ function importFilename(path2, folder) {
76914
77592
  async function readImportDocuments(sources, target2, writer) {
76915
77593
  const documents = [];
76916
77594
  const unreadable = [];
77595
+ const binary = [];
76917
77596
  const tooLong = [];
77597
+ const tooMany = [];
76918
77598
  for (const source of sources) {
76919
77599
  let content;
76920
77600
  try {
@@ -76932,9 +77612,36 @@ async function readImportDocuments(sources, target2, writer) {
76932
77612
  continue;
76933
77613
  }
76934
77614
  const filename = importFilename(source.path, source.folder);
76935
- documents.push(
76936
- target2 === void 0 ? { filename, content } : { filename, content, target: target2 }
76937
- );
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);
76938
77645
  }
76939
77646
  if (unreadable.length > 0) {
76940
77647
  writer.writeErr(
@@ -76942,12 +77649,24 @@ async function readImportDocuments(sources, target2, writer) {
76942
77649
  ${unreadable.join("\n ")}`
76943
77650
  );
76944
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
+ }
76945
77658
  if (tooLong.length > 0) {
76946
77659
  writer.writeErr(
76947
77660
  `Skipped files over ${MARKDOWN_IMPORT_FILE_CHARS_MAX.toLocaleString("en-US")} characters, the most one file may hold:
76948
77661
  ${tooLong.join("\n ")}`
76949
77662
  );
76950
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
+ }
76951
77670
  if (documents.length === 0) {
76952
77671
  failCommand("No readable, non-empty files to import.", writer);
76953
77672
  }
@@ -77136,24 +77855,25 @@ var init_markdown_import = __esm({
77136
77855
  // src/commands/steering-import.ts
77137
77856
  var steering_import_exports = {};
77138
77857
  __export(steering_import_exports, {
77139
- CURSOR_FOLDER: () => CURSOR_FOLDER,
77140
- CURSOR_RULES_FOLDER: () => CURSOR_RULES_FOLDER,
77141
- CURSOR_RULE_EXTENSIONS: () => CURSOR_RULE_EXTENSIONS,
77858
+ CATALOGUE_FOLDERS: () => CATALOGUE_FOLDERS,
77142
77859
  MARKDOWN_EXTENSIONS: () => MARKDOWN_EXTENSIONS,
77143
77860
  STEERING_IMPORT_CAPABILITIES: () => STEERING_IMPORT_CAPABILITIES,
77144
77861
  findMarkdownFiles: () => findMarkdownFiles,
77145
77862
  handleSteeringImport: () => handleSteeringImport
77146
77863
  });
77147
77864
  import { readdir as readdir4, realpath as realpath2, stat as stat4 } from "node:fs/promises";
77148
- 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";
77149
77866
  function byName(a, b5) {
77150
77867
  return a.name < b5.name ? -1 : 1;
77151
77868
  }
77869
+ function under(root, path2) {
77870
+ return relative7(root, path2).split(sep8).join("/");
77871
+ }
77152
77872
  async function findMarkdownFiles(paths) {
77153
77873
  const sources = [];
77154
77874
  const unreadable = [];
77155
77875
  const seen = /* @__PURE__ */ new Set();
77156
- const take = async (path2, folder) => {
77876
+ const take = async (path2, extra = {}) => {
77157
77877
  let real = path2;
77158
77878
  try {
77159
77879
  real = await realpath2(path2);
@@ -77161,9 +77881,29 @@ async function findMarkdownFiles(paths) {
77161
77881
  }
77162
77882
  if (seen.has(real)) return;
77163
77883
  seen.add(real);
77164
- 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;
77165
77905
  };
77166
- const walk2 = async (dir, folder, place2) => {
77906
+ const walk2 = async (dir, root, folder, inCatalogue) => {
77167
77907
  let entries2;
77168
77908
  try {
77169
77909
  entries2 = await readdir4(dir, { withFileTypes: true });
@@ -77172,25 +77912,45 @@ async function findMarkdownFiles(paths) {
77172
77912
  return;
77173
77913
  }
77174
77914
  entries2.sort(byName);
77175
- const extensions2 = place2 === "rules" ? CURSOR_RULE_EXTENSIONS : MARKDOWN_EXTENSIONS;
77176
77915
  for (const entry2 of entries2) {
77177
77916
  const path2 = join50(dir, entry2.name);
77917
+ const rel = under(root, path2);
77178
77918
  if (entry2.isDirectory()) {
77179
- if (place2 === "cursor") {
77180
- if (entry2.name === CURSOR_RULES_FOLDER) {
77181
- await walk2(path2, folder, "rules");
77182
- }
77183
- continue;
77184
- }
77185
77919
  if (entry2.name === "node_modules") continue;
77186
- if (entry2.name === CURSOR_FOLDER && place2 === "plain") {
77187
- 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);
77188
77923
  continue;
77189
77924
  }
77190
- if (entry2.name.startsWith(".")) continue;
77191
- await walk2(path2, folder, place2);
77192
- } else if (place2 !== "cursor" && (entry2.isFile() || entry2.isSymbolicLink()) && extensions2.has(extname(entry2.name).toLowerCase())) {
77193
- 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 } });
77194
77954
  }
77195
77955
  }
77196
77956
  };
@@ -77203,9 +77963,16 @@ async function findMarkdownFiles(paths) {
77203
77963
  continue;
77204
77964
  }
77205
77965
  if (isFolder) {
77206
- const place2 = basename8(path2) === CURSOR_FOLDER ? "cursor" : "plain";
77207
- await walk2(path2, path2, place2);
77208
- } 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
+ }
77209
77976
  }
77210
77977
  return { sources, unreadable };
77211
77978
  }
@@ -77246,9 +78013,11 @@ async function handleSteeringImport(paths, opts, writer = stdoutWriter) {
77246
78013
  writer
77247
78014
  );
77248
78015
  }
77249
- 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;
77250
78017
  var init_steering_import = __esm({
77251
78018
  "src/commands/steering-import.ts"() {
78019
+ init_steering_markdown_import_shared();
78020
+ init_harness_files();
77252
78021
  init_capture_writer();
77253
78022
  init_markdown_import();
77254
78023
  STEERING_IMPORT_CAPABILITIES = [
@@ -77261,12 +78030,11 @@ var init_steering_import = __esm({
77261
78030
  ".mdx",
77262
78031
  ".mdc"
77263
78032
  ]);
77264
- CURSOR_FOLDER = ".cursor";
77265
- CURSOR_RULES_FOLDER = "rules";
77266
- CURSOR_RULE_EXTENSIONS = /* @__PURE__ */ new Set([
77267
- ".mdc",
77268
- ".md"
77269
- ]);
78033
+ CATALOGUE_FOLDERS = new Set(
78034
+ WELL_KNOWN_FOLDERS.map((folder) => folder.split("/")[0] ?? "").filter(
78035
+ (name) => name.startsWith(".")
78036
+ )
78037
+ );
77270
78038
  TARGETS = [
77271
78039
  "records",
77272
78040
  "policies",
@@ -79393,7 +80161,7 @@ async function handleMemoryList(opts, writer = stdoutWriter) {
79393
80161
  const states2 = listOpt(opts.state);
79394
80162
  for (const state of states2)
79395
80163
  oneOf(state, WORKSPACE_MEMORY_STATES, "--state", writer);
79396
- const harness = oneOf(opts.harness, HARNESSES2, "--harness", writer);
80164
+ const harness = oneOf(opts.harness, HARNESSES3, "--harness", writer);
79397
80165
  try {
79398
80166
  const result2 = await listWorkspaceMemories({
79399
80167
  states: states2.length === 0 ? void 0 : states2,
@@ -79600,7 +80368,7 @@ async function handleMemoryImport(files3, opts, writer = stdoutWriter) {
79600
80368
  writer
79601
80369
  );
79602
80370
  }
79603
- 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;
79604
80372
  var init_memory2 = __esm({
79605
80373
  "src/commands/memory.ts"() {
79606
80374
  init_api();
@@ -79615,7 +80383,7 @@ var init_memory2 = __esm({
79615
80383
  "dismiss_memories",
79616
80384
  "drop_memory_record"
79617
80385
  ];
79618
- HARNESSES2 = [
80386
+ HARNESSES3 = [
79619
80387
  "claude-code",
79620
80388
  "codex",
79621
80389
  "cursor",
@@ -79893,7 +80661,7 @@ import {
79893
80661
  writeFileSync as writeFileSync10
79894
80662
  } from "node:fs";
79895
80663
  import { homedir as homedir12, hostname as osHostname3 } from "node:os";
79896
- 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";
79897
80665
  function git4(cwd, args) {
79898
80666
  return new Promise((done) => {
79899
80667
  try {
@@ -79964,7 +80732,7 @@ function symlinkState(root) {
79964
80732
  try {
79965
80733
  if (!lstatSync9(at).isSymbolicLink()) return "missing";
79966
80734
  const target2 = realpathSync8(at);
79967
- if (target2 !== oxagenReal && !target2.startsWith(oxagenReal + sep8)) {
80735
+ if (target2 !== oxagenReal && !target2.startsWith(oxagenReal + sep9)) {
79968
80736
  return "missing";
79969
80737
  }
79970
80738
  } catch {
@@ -80054,10 +80822,10 @@ async function ensureWorkspaceLinkIgnored(root) {
80054
80822
  const top = await git4(root, ["rev-parse", "--show-toplevel"]);
80055
80823
  if (!top) return null;
80056
80824
  const topDir = resolve20(top);
80057
- const entry2 = relative7(
80825
+ const entry2 = relative8(
80058
80826
  topDir,
80059
80827
  join52(realpathOr2(root), ".oxagen", "workspace.json")
80060
- ).split(sep8).join("/");
80828
+ ).split(sep9).join("/");
80061
80829
  if (entry2.startsWith("../")) return null;
80062
80830
  const rule = await git4(topDir, ["check-ignore", "--no-index", "-v", entry2]);
80063
80831
  if (rule !== null) return null;
@@ -80548,7 +81316,7 @@ import {
80548
81316
  join as join53,
80549
81317
  parse as parsePath2,
80550
81318
  posix as posix4,
80551
- sep as sep9
81319
+ sep as sep10
80552
81320
  } from "node:path";
80553
81321
  function checkSteeringPath(path2) {
80554
81322
  if (typeof path2 !== "string" || path2.length === 0) {
@@ -80695,7 +81463,7 @@ function assertInsideOxagen(root, path2) {
80695
81463
  real = null;
80696
81464
  }
80697
81465
  if (real !== null) {
80698
- if (real !== oxagenReal && !real.startsWith(oxagenReal + sep9)) {
81466
+ if (real !== oxagenReal && !real.startsWith(oxagenReal + sep10)) {
80699
81467
  throw new Error(`${path2} resolves outside .oxagen/`);
80700
81468
  }
80701
81469
  return;
@@ -80708,7 +81476,7 @@ function assertInsideOxagen(root, path2) {
80708
81476
  function pruneEmptyDirs(root, path2) {
80709
81477
  const stop = join53(root, OXAGEN_DIR);
80710
81478
  let dir = dirname29(join53(root, ...path2.split("/")));
80711
- while (dir.startsWith(stop + sep9)) {
81479
+ while (dir.startsWith(stop + sep10)) {
80712
81480
  try {
80713
81481
  if (readdirSync14(dir).length > 0) return;
80714
81482
  rmdirSync7(dir);
@@ -124025,7 +124793,7 @@ import {
124025
124793
  readlinkSync as readlinkSync4,
124026
124794
  statSync as statSync13
124027
124795
  } from "node:fs";
124028
- 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";
124029
124797
  function git5(cwd, args, input) {
124030
124798
  try {
124031
124799
  return execFileSync2("git", args, {
@@ -124165,11 +124933,11 @@ function within3(path2, scope) {
124165
124933
  function scopesFor(root, cwd, paths, trees) {
124166
124934
  const scopes = [];
124167
124935
  for (const path2 of paths) {
124168
- const rel = relative8(root, resolve22(cwd, path2));
124169
- if (rel === ".." || rel.startsWith(`..${sep10}`) || isAbsolute15(rel)) {
124936
+ const rel = relative9(root, resolve22(cwd, path2));
124937
+ if (rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute15(rel)) {
124170
124938
  return { error: `${path2} is outside the steering repo at ${root}.` };
124171
124939
  }
124172
- const scope = rel.split(sep10).join("/");
124940
+ const scope = rel.split(sep11).join("/");
124173
124941
  const known = trees.some(
124174
124942
  (tree) => tree !== null && [...tree.keys()].some((file) => within3(file, scope))
124175
124943
  );
@@ -124477,7 +125245,7 @@ async function check(paths = [], opts = {}, writer = stdoutWriter, cwd = process
124477
125245
  }
124478
125246
  if (!report.passed) process.exitCode = 1;
124479
125247
  }
124480
- 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;
124481
125249
  var init_check3 = __esm({
124482
125250
  "src/commands/check.ts"() {
124483
125251
  init_paths2();
@@ -124490,7 +125258,7 @@ var init_check3 = __esm({
124490
125258
  init_capture_writer();
124491
125259
  init_config();
124492
125260
  init_output();
124493
- ROOT_FILES2 = [
125261
+ ROOT_FILES3 = [
124494
125262
  AGENTS_MD_PATH,
124495
125263
  CLAUDE_MD_PATH,
124496
125264
  README_PATH,
@@ -124503,7 +125271,7 @@ var init_check3 = __esm({
124503
125271
  TOOLS_DIR,
124504
125272
  POLICY_DIR
124505
125273
  ];
124506
- PATHSPECS = [...ROOT_FILES2, ...TREE_DIRS];
125274
+ PATHSPECS = [...ROOT_FILES3, ...TREE_DIRS];
124507
125275
  DEFAULT_BASES = ["origin/HEAD", "origin/main"];
124508
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.";
124509
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.`;
@@ -128181,13 +128949,13 @@ var init_src9 = __esm({
128181
128949
 
128182
128950
  // src/commands/codegraph-upload/files.ts
128183
128951
  import { readdir as readdir5, stat as stat5 } from "node:fs/promises";
128184
- 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";
128185
128953
  function hasGlobChars(pattern) {
128186
128954
  return /[*?[\]{}]/.test(pattern);
128187
128955
  }
128188
128956
  function normalize2(path2) {
128189
128957
  const trimmed = path2.replace(/^\.\//, "");
128190
- return sep11 === "/" ? trimmed : trimmed.split(sep11).join("/");
128958
+ return sep12 === "/" ? trimmed : trimmed.split(sep12).join("/");
128191
128959
  }
128192
128960
  async function walk(root, dir, out) {
128193
128961
  const entries2 = await readdir5(dir, { withFileTypes: true });
@@ -128197,7 +128965,7 @@ async function walk(root, dir, out) {
128197
128965
  if (entry2.isDirectory()) {
128198
128966
  if (!SKIP_DIRS.has(entry2.name)) await walk(root, full, out);
128199
128967
  } else if (entry2.isFile()) {
128200
- out.push(normalize2(relative9(root, full)));
128968
+ out.push(normalize2(relative10(root, full)));
128201
128969
  }
128202
128970
  }
128203
128971
  }