agent-valley 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6439,6 +6439,72 @@ var init_zod = __esm(() => {
6439
6439
  init_external();
6440
6440
  });
6441
6441
 
6442
+ // ../../packages/core/src/oma/skill-matrix-schema.ts
6443
+ var hash, name, bounded, path, skillCompatibilityConfigSchema, skillCompatibilityPolicySchema, omaConfigSchema, matrixSkillSchema, matrixReportSchema;
6444
+ var init_skill_matrix_schema = __esm(() => {
6445
+ init_zod();
6446
+ hash = string2().regex(/^[a-f0-9]{64}$/);
6447
+ name = string2().regex(/^[a-z0-9][a-z0-9-]{0,127}$/);
6448
+ bounded = string2().trim().min(1).max(2000);
6449
+ path = string2().min(1).max(4096).refine((value) => !value.includes("\x00"));
6450
+ skillCompatibilityConfigSchema = strictObject({
6451
+ report_path: path,
6452
+ max_age_hours: number2().finite().positive().max(8760).default(168),
6453
+ mode: _enum(["warn", "require"])
6454
+ });
6455
+ skillCompatibilityPolicySchema = strictObject({
6456
+ reportPath: path,
6457
+ maxAgeHours: number2().finite().positive().max(8760),
6458
+ mode: _enum(["warn", "require"])
6459
+ });
6460
+ omaConfigSchema = strictObject({
6461
+ mode: _enum(["off", "strict"]).default("off"),
6462
+ skill_compatibility: skillCompatibilityConfigSchema.optional()
6463
+ });
6464
+ matrixSkillSchema = object({
6465
+ name,
6466
+ hash,
6467
+ caseId: bounded,
6468
+ requiredFiles: array(path).min(1).max(500),
6469
+ missingFiles: array(path).max(500),
6470
+ excludedReferences: array(object({ path, reason: bounded })).max(500)
6471
+ });
6472
+ matrixReportSchema = object({
6473
+ schemaVersion: literal(1),
6474
+ kind: literal("skill-compatibility-matrix"),
6475
+ mode: _enum(["plan", "live"]),
6476
+ status: _enum(["planned", "completed", "cancelled", "interrupted"]),
6477
+ createdAt: exports_iso.datetime(),
6478
+ omaVersion: bounded,
6479
+ host: object({ platform: bounded, arch: bounded, node: bounded }),
6480
+ suiteHash: hash,
6481
+ sourceKind: _enum(["synthetic", "installed"]),
6482
+ delivery: _enum(["native", "injected"]),
6483
+ auditScope: _enum(["fixture-contract", "read-reference"]),
6484
+ protocolVersion: literal("oma-skill-matrix-v2"),
6485
+ bundle: object({ hash, skills: array(matrixSkillSchema).min(1).max(100) }).optional(),
6486
+ cases: array(object({ id: bounded, skill: name })).max(100),
6487
+ models: object({ claude: bounded.nullable(), codex: bounded.nullable() }),
6488
+ cells: array(object({
6489
+ caseId: bounded,
6490
+ skill: name,
6491
+ vendor: _enum(["claude", "codex"]),
6492
+ status: _enum(["pass", "fail", "unverifiable", "error"]),
6493
+ contentHash: hash,
6494
+ checks: array(object({
6495
+ id: bounded,
6496
+ status: _enum(["pass", "fail", "unverifiable"]),
6497
+ detail: bounded,
6498
+ proof: _enum(["read", "canary"]).optional()
6499
+ })).max(1000),
6500
+ nativeActivation: _enum(["observed", "unobserved"]),
6501
+ cliVersion: string2().regex(/^[\w .()+/-]{1,160}$/).nullable(),
6502
+ model: bounded.nullable(),
6503
+ durationMs: number2().finite().nonnegative()
6504
+ })).max(200)
6505
+ });
6506
+ });
6507
+
6442
6508
  // ../../packages/core/src/config/task-schema.ts
6443
6509
  var reportPath, taskSchema, resolvedTaskSchema;
6444
6510
  var init_task_schema = __esm(() => {
@@ -6896,6 +6962,7 @@ var init_execution = __esm(() => {
6896
6962
  var actorType, text, amount, routingCandidateSchema, chiefOperatingPolicySchema, operatingRunSchema, routeEvidenceSchema, reviewDecisionSchema, chiefOperationsSchema;
6897
6963
  var init_operations = __esm(() => {
6898
6964
  init_zod();
6965
+ init_skill_matrix_schema();
6899
6966
  actorType = string2().regex(/^[a-z0-9][a-z0-9-]{0,127}$/);
6900
6967
  text = string2().trim().min(1).max(2000);
6901
6968
  amount = number2().finite().nonnegative();
@@ -6914,6 +6981,7 @@ var init_operations = __esm(() => {
6914
6981
  reviewVendor: _enum(["prefer", "require", "off"]),
6915
6982
  readyActors: array(actorType).max(20).optional(),
6916
6983
  memory: boolean2(),
6984
+ skillCompatibility: skillCompatibilityPolicySchema.optional(),
6917
6985
  metricTargets: array(strictObject({
6918
6986
  name: text,
6919
6987
  unit: text.optional(),
@@ -7232,7 +7300,7 @@ function chiefExecutionPolicy(config) {
7232
7300
  autoResume: execution.auto_resume
7233
7301
  } : {});
7234
7302
  }
7235
- function chiefOperatingPolicy(config, readyActors, automatic = true) {
7303
+ function chiefOperatingPolicy(config, readyActors, automatic = true, skillCompatibility) {
7236
7304
  return chiefOperatingPolicySchema.parse({
7237
7305
  routing: config.routing ? {
7238
7306
  candidates: config.routing.candidates.map((item) => ({
@@ -7247,7 +7315,8 @@ function chiefOperatingPolicy(config, readyActors, automatic = true) {
7247
7315
  reviewVendor: config.review_vendor ?? "prefer",
7248
7316
  memory: config.memory ?? true,
7249
7317
  metricTargets: config.metric_targets,
7250
- readyActors
7318
+ readyActors,
7319
+ skillCompatibility
7251
7320
  });
7252
7321
  }
7253
7322
  function chiefCapturePolicy(config) {
@@ -14575,7 +14644,7 @@ function mergeConfigs(global2, project, env) {
14575
14644
  tunnel: buildTunnelConfig(project),
14576
14645
  verify: buildVerifyConfig(project),
14577
14646
  task: project?.task?.kind === "analysis" ? { kind: "analysis", reportPath: project.task.report_path } : { kind: "code" },
14578
- oma: { mode: project?.oma?.mode ?? "off" },
14647
+ oma: project?.oma ?? { mode: "off" },
14579
14648
  chief: global2?.chief || project?.chief ? mergeChiefConfig(global2?.chief, project?.chief) : undefined
14580
14649
  };
14581
14650
  }
@@ -14613,6 +14682,7 @@ Symphony cannot start until all config errors are resolved.`);
14613
14682
  var globalConfigSchema, projectConfigSchema, githubConfigSchema, mergedConfigSchema;
14614
14683
  var init_yaml_loader = __esm(() => {
14615
14684
  init_zod();
14685
+ init_skill_matrix_schema();
14616
14686
  init_actor_schema();
14617
14687
  init_budget_schema();
14618
14688
  init_chief_schema();
@@ -14706,7 +14776,7 @@ var init_yaml_loader = __esm(() => {
14706
14776
  tunnel: tunnelProjectSchema,
14707
14777
  verify: verifyProjectSchema,
14708
14778
  task: taskSchema.optional(),
14709
- oma: object({ mode: _enum(["off", "strict"]).default("off") }).optional(),
14779
+ oma: omaConfigSchema.optional(),
14710
14780
  chief: chiefConfigSchema.optional()
14711
14781
  }).strict().overwrite(normalizeActorDefaults);
14712
14782
  githubConfigSchema = object({
@@ -14775,7 +14845,7 @@ var init_yaml_loader = __esm(() => {
14775
14845
  tunnel: tunnelMergedSchema,
14776
14846
  verify: verifyMergedSchema,
14777
14847
  task: resolvedTaskSchema.optional(),
14778
- oma: object({ mode: _enum(["off", "strict"]) }).optional(),
14848
+ oma: omaConfigSchema.optional(),
14779
14849
  chief: chiefConfigSchema.optional()
14780
14850
  }).superRefine((cfg, ctx) => {
14781
14851
  if (cfg.trackerKind === "linear") {
@@ -19037,7 +19107,7 @@ var init_sandbox = __esm(() => {
19037
19107
  });
19038
19108
 
19039
19109
  // ../../packages/core/src/sessions/codex-session.ts
19040
- import { spawn as spawn7 } from "node:child_process";
19110
+ import { spawn as spawn8 } from "node:child_process";
19041
19111
  var CodexSession;
19042
19112
  var init_codex_session = __esm(() => {
19043
19113
  init_base_session();
@@ -19066,7 +19136,7 @@ var init_codex_session = __esm(() => {
19066
19136
  args,
19067
19137
  workspacePath: config.workspacePath
19068
19138
  });
19069
- this.process = spawn7(plan.command, plan.args, {
19139
+ this.process = spawn8(plan.command, plan.args, {
19070
19140
  detached: process.platform !== "win32",
19071
19141
  cwd: config.workspacePath,
19072
19142
  env: buildAgentEnv("codex", config.env),
@@ -19344,7 +19414,7 @@ var init_codex_session = __esm(() => {
19344
19414
  });
19345
19415
 
19346
19416
  // ../../packages/core/src/sessions/claude-session.ts
19347
- import { spawn as spawn8 } from "node:child_process";
19417
+ import { spawn as spawn9 } from "node:child_process";
19348
19418
  var ClaudeSession;
19349
19419
  var init_claude_session = __esm(() => {
19350
19420
  init_base_session();
@@ -19400,7 +19470,7 @@ var init_claude_session = __esm(() => {
19400
19470
  this.emitError("CRASH", `${err}`, false);
19401
19471
  return;
19402
19472
  }
19403
- this.process = spawn8(plan.command, plan.args, {
19473
+ this.process = spawn9(plan.command, plan.args, {
19404
19474
  detached: process.platform !== "win32",
19405
19475
  cwd: this.config.workspacePath,
19406
19476
  env: buildAgentEnv(this.vendor, this.config.env),
@@ -19614,7 +19684,7 @@ var init_qwen_session = __esm(() => {
19614
19684
  });
19615
19685
 
19616
19686
  // ../../packages/core/src/sessions/agy-session.ts
19617
- import { spawn as spawn9 } from "node:child_process";
19687
+ import { spawn as spawn10 } from "node:child_process";
19618
19688
  function formatAgyTimeout(seconds) {
19619
19689
  return `${Math.max(1, Math.round(seconds))}s`;
19620
19690
  }
@@ -19660,7 +19730,7 @@ var init_agy_session = __esm(() => {
19660
19730
  this.emitError("CRASH", `${err}`, false);
19661
19731
  return;
19662
19732
  }
19663
- this.process = spawn9(plan.command, plan.args, {
19733
+ this.process = spawn10(plan.command, plan.args, {
19664
19734
  detached: process.platform !== "win32",
19665
19735
  cwd: config.workspacePath,
19666
19736
  env: buildAgentEnv("antigravity", config.env),
@@ -19731,7 +19801,7 @@ var init_agy_session = __esm(() => {
19731
19801
  });
19732
19802
 
19733
19803
  // ../../packages/core/src/sessions/cursor-session.ts
19734
- import { spawn as spawn10 } from "node:child_process";
19804
+ import { spawn as spawn11 } from "node:child_process";
19735
19805
  var CURSOR_COMMAND = "cursor-agent", MAX_PROMPT_ARG_LENGTH = 1e5, CursorSession;
19736
19806
  var init_cursor_session = __esm(() => {
19737
19807
  init_base_session();
@@ -19779,7 +19849,7 @@ var init_cursor_session = __esm(() => {
19779
19849
  const apiKey = process.env.CURSOR_API_KEY;
19780
19850
  if (apiKey)
19781
19851
  extraEnv.CURSOR_API_KEY = apiKey;
19782
- this.process = spawn10(plan.command, plan.args, {
19852
+ this.process = spawn11(plan.command, plan.args, {
19783
19853
  detached: process.platform !== "win32",
19784
19854
  cwd: this.config.workspacePath,
19785
19855
  env: buildAgentEnv("cursor", extraEnv),
@@ -19915,7 +19985,7 @@ var init_cursor_session = __esm(() => {
19915
19985
  });
19916
19986
 
19917
19987
  // ../../packages/core/src/sessions/grok-session.ts
19918
- import { spawn as spawn11 } from "node:child_process";
19988
+ import { spawn as spawn12 } from "node:child_process";
19919
19989
  function isToolUseType(type) {
19920
19990
  return type === "tool_use" || type === "tool_call" || type === "function_call";
19921
19991
  }
@@ -19933,11 +20003,11 @@ function normalizeToolInput(raw) {
19933
20003
  }
19934
20004
  return;
19935
20005
  }
19936
- var GROK_COMMAND = "grok", MAX_OUTPUT_BYTES2, WRITE_TOOL_HINTS, EDIT_TOOL_HINTS, GrokSession;
20006
+ var GROK_COMMAND = "grok", MAX_OUTPUT_BYTES3, WRITE_TOOL_HINTS, EDIT_TOOL_HINTS, GrokSession;
19937
20007
  var init_grok_session = __esm(() => {
19938
20008
  init_base_session();
19939
20009
  init_sandbox();
19940
- MAX_OUTPUT_BYTES2 = 10 * 1024;
20010
+ MAX_OUTPUT_BYTES3 = 10 * 1024;
19941
20011
  WRITE_TOOL_HINTS = ["write"];
19942
20012
  EDIT_TOOL_HINTS = ["edit", "str_replace", "patch"];
19943
20013
  GrokSession = class GrokSession extends BaseSession {
@@ -19969,7 +20039,7 @@ var init_grok_session = __esm(() => {
19969
20039
  this.emitError("CRASH", `${err}`, false);
19970
20040
  return;
19971
20041
  }
19972
- this.process = spawn11(plan.command, plan.args, {
20042
+ this.process = spawn12(plan.command, plan.args, {
19973
20043
  detached: process.platform !== "win32",
19974
20044
  cwd: this.config.workspacePath,
19975
20045
  env: buildAgentEnv("grok", this.config.env),
@@ -20022,8 +20092,8 @@ var init_grok_session = __esm(() => {
20022
20092
  }
20023
20093
  appendOutputTail(chunk) {
20024
20094
  this.outputTail += chunk;
20025
- if (this.outputTail.length > MAX_OUTPUT_BYTES2) {
20026
- this.outputTail = this.outputTail.slice(-MAX_OUTPUT_BYTES2);
20095
+ if (this.outputTail.length > MAX_OUTPUT_BYTES3) {
20096
+ this.outputTail = this.outputTail.slice(-MAX_OUTPUT_BYTES3);
20027
20097
  }
20028
20098
  }
20029
20099
  handleToolUse(e) {
@@ -20084,7 +20154,7 @@ var init_grok_session = __esm(() => {
20084
20154
  });
20085
20155
 
20086
20156
  // ../../packages/core/src/sessions/kimi-session.ts
20087
- import { spawn as spawn12 } from "node:child_process";
20157
+ import { spawn as spawn13 } from "node:child_process";
20088
20158
  var KIMI_COMMAND = "kimi", MAX_RAW_TAIL_BYTES, KimiSession;
20089
20159
  var init_kimi_session = __esm(() => {
20090
20160
  init_base_session();
@@ -20122,7 +20192,7 @@ var init_kimi_session = __esm(() => {
20122
20192
  this.emitError("CRASH", `${err}`, false);
20123
20193
  return;
20124
20194
  }
20125
- this.process = spawn12(plan.command, plan.args, {
20195
+ this.process = spawn13(plan.command, plan.args, {
20126
20196
  detached: process.platform !== "win32",
20127
20197
  cwd: this.config.workspacePath,
20128
20198
  env: buildAgentEnv("kimi", this.config.env),
@@ -20261,7 +20331,7 @@ var init_kimi_session = __esm(() => {
20261
20331
  });
20262
20332
 
20263
20333
  // ../../packages/core/src/sessions/opencode-session.ts
20264
- import { spawn as spawn13 } from "node:child_process";
20334
+ import { spawn as spawn14 } from "node:child_process";
20265
20335
  function normalizeToolInput2(raw) {
20266
20336
  if (raw == null)
20267
20337
  return;
@@ -20276,11 +20346,11 @@ function normalizeToolInput2(raw) {
20276
20346
  }
20277
20347
  return;
20278
20348
  }
20279
- var OPENCODE_COMMAND = "opencode", MAX_PROMPT_ARG_LENGTH2 = 1e5, MAX_OUTPUT_BYTES3, MAX_RAW_TAIL_BYTES2, WRITE_TOOL_HINTS2, EDIT_TOOL_HINTS2, AUTH_FAILURE_PATTERN, OpencodeSession, TERMINAL_TYPE_HINTS;
20349
+ var OPENCODE_COMMAND = "opencode", MAX_PROMPT_ARG_LENGTH2 = 1e5, MAX_OUTPUT_BYTES4, MAX_RAW_TAIL_BYTES2, WRITE_TOOL_HINTS2, EDIT_TOOL_HINTS2, AUTH_FAILURE_PATTERN, OpencodeSession, TERMINAL_TYPE_HINTS;
20280
20350
  var init_opencode_session = __esm(() => {
20281
20351
  init_base_session();
20282
20352
  init_sandbox();
20283
- MAX_OUTPUT_BYTES3 = 10 * 1024;
20353
+ MAX_OUTPUT_BYTES4 = 10 * 1024;
20284
20354
  MAX_RAW_TAIL_BYTES2 = 4 * 1024;
20285
20355
  WRITE_TOOL_HINTS2 = ["write"];
20286
20356
  EDIT_TOOL_HINTS2 = ["edit", "str_replace", "patch"];
@@ -20328,7 +20398,7 @@ var init_opencode_session = __esm(() => {
20328
20398
  this.emitError("CRASH", `${err}`, false);
20329
20399
  return;
20330
20400
  }
20331
- this.process = spawn13(plan.command, plan.args, {
20401
+ this.process = spawn14(plan.command, plan.args, {
20332
20402
  detached: process.platform !== "win32",
20333
20403
  cwd: this.config.workspacePath,
20334
20404
  env: buildAgentEnv("opencode", this.config.env),
@@ -20381,8 +20451,8 @@ var init_opencode_session = __esm(() => {
20381
20451
  }
20382
20452
  appendOutputTail(chunk) {
20383
20453
  this.outputTail += chunk;
20384
- if (this.outputTail.length > MAX_OUTPUT_BYTES3) {
20385
- this.outputTail = this.outputTail.slice(-MAX_OUTPUT_BYTES3);
20454
+ if (this.outputTail.length > MAX_OUTPUT_BYTES4) {
20455
+ this.outputTail = this.outputTail.slice(-MAX_OUTPUT_BYTES4);
20386
20456
  }
20387
20457
  }
20388
20458
  handleEvent(event) {
@@ -20455,7 +20525,7 @@ var init_opencode_session = __esm(() => {
20455
20525
  return;
20456
20526
  const text = e.result ?? e.text ?? e.output;
20457
20527
  if (typeof text === "string" && text.length > 0) {
20458
- this.explicitResult = text.length > MAX_OUTPUT_BYTES3 ? text.slice(-MAX_OUTPUT_BYTES3) : text;
20528
+ this.explicitResult = text.length > MAX_OUTPUT_BYTES4 ? text.slice(-MAX_OUTPUT_BYTES4) : text;
20459
20529
  }
20460
20530
  const usage = e.usage ?? e.tokens ?? e.cost;
20461
20531
  if (!usage)
@@ -20724,7 +20794,7 @@ var init_readdirp = __esm(() => {
20724
20794
 
20725
20795
  // ../../node_modules/.bun/chokidar@5.0.0/node_modules/chokidar/handler.js
20726
20796
  import { watch as fs_watch, unwatchFile, watchFile } from "node:fs";
20727
- import { realpath as fsrealpath, lstat as lstat18, open as open11, stat as stat4 } from "node:fs/promises";
20797
+ import { realpath as fsrealpath, lstat as lstat18, open as open12, stat as stat4 } from "node:fs/promises";
20728
20798
  import { type as osType } from "node:os";
20729
20799
  import * as sp from "node:path";
20730
20800
  function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
@@ -21066,7 +21136,7 @@ var STR_DATA = "data", STR_END = "end", STR_CLOSE = "close", EMPTY_FN = () => {}
21066
21136
  cont.watcherUnusable = true;
21067
21137
  if (isWindows && error.code === "EPERM") {
21068
21138
  try {
21069
- const fd = await open11(path, "r");
21139
+ const fd = await open12(path, "r");
21070
21140
  await fd.close();
21071
21141
  broadcastErr(error);
21072
21142
  } catch (err) {}
@@ -22446,11 +22516,11 @@ function canonicalConfig(config) {
22446
22516
  }
22447
22517
 
22448
22518
  // src/agent-provisioning.ts
22449
- import { spawn as spawn16 } from "node:child_process";
22519
+ import { spawn as spawn17 } from "node:child_process";
22450
22520
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
22451
22521
  import { homedir as homedir7, tmpdir as tmpdir4 } from "node:os";
22452
22522
  import { delimiter as delimiter3, join as join46 } from "node:path";
22453
- function runTerminalCommand(request, spawnCommand = spawn16) {
22523
+ function runTerminalCommand(request, spawnCommand = spawn17) {
22454
22524
  return new Promise((resolve) => {
22455
22525
  let child;
22456
22526
  let timeout;
@@ -22699,7 +22769,7 @@ var init_agent_provisioning = __esm(() => {
22699
22769
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "node:fs";
22700
22770
  import { chmod as chmod4, lstat as lstat19, readdir as readdir12, readFile as readFile16, realpath as realpath25, unlink as unlink8, writeFile as writeFile14 } from "node:fs/promises";
22701
22771
  import { homedir as homedir8, tmpdir as tmpdir5 } from "node:os";
22702
- import { delimiter as delimiter4, isAbsolute as isAbsolute15, join as join47, relative as relative14, resolve as resolve27 } from "node:path";
22772
+ import { delimiter as delimiter4, isAbsolute as isAbsolute15, join as join47, relative as relative14, resolve as resolve28 } from "node:path";
22703
22773
  function defaults2() {
22704
22774
  const home = homedir8();
22705
22775
  return {
@@ -22727,7 +22797,7 @@ async function present(path) {
22727
22797
  return false;
22728
22798
  }
22729
22799
  }
22730
- async function installedVersion(skills) {
22800
+ async function installedVersion2(skills) {
22731
22801
  try {
22732
22802
  const marker = JSON.parse(await readFile16(join47(skills, "_version.json"), "utf8"));
22733
22803
  return marker.schemaVersion === 2 && marker.mode === "project" && typeof marker.version === "string" && /^\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?$/.test(marker.version) ? marker.version : null;
@@ -22773,7 +22843,7 @@ async function restoreConfig(agents, snapshots) {
22773
22843
  async function workspacePath(input) {
22774
22844
  if (!input.trim() || !isAbsolute15(input))
22775
22845
  return null;
22776
- const root = resolve27(input);
22846
+ const root = resolve28(input);
22777
22847
  if (!await directory2(root))
22778
22848
  return null;
22779
22849
  for (const path of [join47(root, ".agents"), join47(root, ".agents", "skills")]) {
@@ -22792,7 +22862,7 @@ async function inspectOma(workspaceRoot, _overrides = {}) {
22792
22862
  if (!root)
22793
22863
  return { success: false, message: "Choose an existing absolute workspace with project-local OMA files." };
22794
22864
  const skills = join47(root, ".agents", "skills");
22795
- const version = await installedVersion(skills);
22865
+ const version = await installedVersion2(skills);
22796
22866
  if (!version)
22797
22867
  throw new Error("Invalid installed metadata");
22798
22868
  const entries = (await readdir12(skills, { withFileTypes: true })).filter((entry) => /^oma-[a-z0-9-]+$/.test(entry.name));
@@ -22813,7 +22883,7 @@ async function inspectOma(workspaceRoot, _overrides = {}) {
22813
22883
  };
22814
22884
  }
22815
22885
  }
22816
- function failure2(action, result) {
22886
+ function failure3(action, result) {
22817
22887
  return {
22818
22888
  success: false,
22819
22889
  message: `${action} ${result?.failure === "timed_out" ? "timed out" : "did not complete"}. Retry OMA preparation or follow ${DOCUMENTATION_URL}.`
@@ -22835,7 +22905,7 @@ async function prepareOma(workspaceRoot, overrides = {}) {
22835
22905
  env: { ...deps.env, OMA_INSTALL_NO_RUN: "1" }
22836
22906
  });
22837
22907
  if (!bootstrap.success)
22838
- return bootstrap.stage === "prerequisites" ? { success: false, message: `Install curl and bash, then retry OMA preparation. ${DOCUMENTATION_URL}` } : failure2("OMA prerequisite preparation", bootstrap);
22908
+ return bootstrap.stage === "prerequisites" ? { success: false, message: `Install curl and bash, then retry OMA preparation. ${DOCUMENTATION_URL}` } : failure3("OMA prerequisite preparation", bootstrap);
22839
22909
  const bun = deps.resolveBinary("bun");
22840
22910
  if (!bun)
22841
22911
  return {
@@ -22854,9 +22924,9 @@ async function prepareOma(workspaceRoot, overrides = {}) {
22854
22924
  const request = { command: bun, env: environment, cwd: root, timeoutMs: 300000 };
22855
22925
  const latest = await deps.runCommand({ ...request, args: ["install", "--global", LATEST_PACKAGE] });
22856
22926
  if (!latest.success)
22857
- return failure2("OMA CLI update", latest);
22927
+ return failure3("OMA CLI update", latest);
22858
22928
  const agents = join47(root, ".agents");
22859
- const existing = await installedVersion(join47(agents, "skills")) !== null || await directory2(join47(agents, "skills")) && (await present(join47(agents, "oma-config.yaml")) || await present(join47(agents, "mcp.json")) || await directory2(join47(agents, "workflows")));
22929
+ const existing = await installedVersion2(join47(agents, "skills")) !== null || await directory2(join47(agents, "skills")) && (await present(join47(agents, "oma-config.yaml")) || await present(join47(agents, "mcp.json")) || await directory2(join47(agents, "workflows")));
22860
22930
  const custom = await snapshotConfig(agents);
22861
22931
  const args = existing ? ["update", "--yes", "--with-new-skills", "--all"] : ["install"];
22862
22932
  let installed;
@@ -22867,7 +22937,7 @@ async function prepareOma(workspaceRoot, overrides = {}) {
22867
22937
  await restoreConfig(agents, custom);
22868
22938
  }
22869
22939
  if (!installed.success)
22870
- return failure2(existing ? "OMA skill update" : "OMA skill installation", installed);
22940
+ return failure3(existing ? "OMA skill update" : "OMA skill installation", installed);
22871
22941
  const inspection = await inspectOma(root, deps);
22872
22942
  if (!inspection.success)
22873
22943
  return {
@@ -22880,7 +22950,7 @@ async function prepareOma(workspaceRoot, overrides = {}) {
22880
22950
  message: `Latest official OMA preparation completed. ${inspection.message.split(" Prepare ")[0]}`
22881
22951
  };
22882
22952
  } catch {
22883
- return failure2("OMA preparation");
22953
+ return failure3("OMA preparation");
22884
22954
  }
22885
22955
  }
22886
22956
  var INSTALLER_URL = "https://raw.githubusercontent.com/first-fluke/oh-my-agent/main/cli/install.sh", DOCUMENTATION_URL = "https://github.com/first-fluke/oh-my-agent", LATEST_PACKAGE = "oh-my-agent@latest", CUSTOM_CONFIG_NAMES;
@@ -22898,7 +22968,7 @@ var init_oma_provisioning = __esm(() => {
22898
22968
  });
22899
22969
 
22900
22970
  // src/setup/noninteractive-runtime.ts
22901
- import { spawn as spawn17 } from "node:child_process";
22971
+ import { spawn as spawn18 } from "node:child_process";
22902
22972
  function noninteractiveSetupDefaults() {
22903
22973
  const env = { ...process.env, CI: "true" };
22904
22974
  const runCommand = (request) => runTerminalCommand(request, quietSpawn);
@@ -22925,7 +22995,7 @@ function currentRuntimeIdentity(env) {
22925
22995
  throw new Error("Current runtime identity is ambiguous. Rerun av setup --yes --actor <current-vendor> --model <current-model-or-empty>; do not use OMA defaults to identify the caller.");
22926
22996
  return identities[0];
22927
22997
  }
22928
- var quietSpawn = (command, args, options) => spawn17(command, args, { ...options, stdio: "ignore" });
22998
+ var quietSpawn = (command, args, options) => spawn18(command, args, { ...options, stdio: "ignore" });
22929
22999
  var init_noninteractive_runtime = __esm(() => {
22930
23000
  init_yaml_loader();
22931
23001
  init_agent_discovery();
@@ -24399,7 +24469,7 @@ var init_workspace_step = __esm(() => {
24399
24469
 
24400
24470
  // src/setup/noninteractive-config.ts
24401
24471
  import { lstat as lstat20, realpath as realpath26 } from "node:fs/promises";
24402
- import { isAbsolute as isAbsolute17, join as join48, parse as parsePath, resolve as resolve28 } from "node:path";
24472
+ import { isAbsolute as isAbsolute17, join as join48, parse as parsePath, resolve as resolve29 } from "node:path";
24403
24473
  function validateNoninteractiveOptions(options) {
24404
24474
  if (!options.yes || options.edit || options.mode !== undefined && options.mode !== "order")
24405
24475
  throw new Error("Use av setup --yes only for local order setup; --edit and --mode tracker require interactive setup.");
@@ -24480,13 +24550,13 @@ async function prepareNoninteractiveConfig(options, deps) {
24480
24550
  validateNoninteractiveOptions(options);
24481
24551
  let projectRoot;
24482
24552
  try {
24483
- projectRoot = await realpath26(resolve28(deps.projectRoot));
24553
+ projectRoot = await realpath26(resolve29(deps.projectRoot));
24484
24554
  if (!(await lstat20(projectRoot)).isDirectory())
24485
24555
  throw new Error("not a directory");
24486
24556
  } catch {
24487
24557
  throw new Error(`AV configuration directory ${deps.projectRoot} does not exist. Run av setup from an existing directory.`);
24488
24558
  }
24489
- const globalPath = resolve28(deps.globalConfigPath);
24559
+ const globalPath = resolve29(deps.globalConfigPath);
24490
24560
  const projectPath = join48(projectRoot, "av.yaml");
24491
24561
  const project = await configFile(projectPath, projectConfigSchema);
24492
24562
  const global2 = await configFile(globalPath, globalConfigSchema);
@@ -24504,7 +24574,7 @@ async function prepareNoninteractiveConfig(options, deps) {
24504
24574
  }
24505
24575
  const savedWorkspace = project.raw.workspace?.root;
24506
24576
  const selectedWorkspace = options.workspace ?? savedWorkspace ?? projectRoot;
24507
- const workspacePath = isAbsolute17(selectedWorkspace) ? selectedWorkspace : resolve28(projectRoot, selectedWorkspace);
24577
+ const workspacePath = isAbsolute17(selectedWorkspace) ? selectedWorkspace : resolve29(projectRoot, selectedWorkspace);
24508
24578
  const workspaceError = await validateOrderWorkspace(workspacePath);
24509
24579
  if (workspaceError)
24510
24580
  throw new Error(workspaceError);
@@ -24539,7 +24609,7 @@ var init_noninteractive_config = __esm(() => {
24539
24609
  });
24540
24610
 
24541
24611
  // src/setup/noninteractive.ts
24542
- import { join as join49, parse as parsePath2, resolve as resolve29 } from "node:path";
24612
+ import { join as join49, parse as parsePath2, resolve as resolve30 } from "node:path";
24543
24613
  function rerunCommand(result, options) {
24544
24614
  const quote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
24545
24615
  return `cd ${quote(result.projectRoot)} && av setup --yes --actor ${result.chief.actorType} --model ${quote(result.chief.model ?? "")} --workspace ${quote(result.workspace ?? result.projectRoot)} --oma ${options.oma ?? "prepare"} --json`;
@@ -24550,11 +24620,11 @@ async function setupNoninteractive(options, overrides = {}) {
24550
24620
  version: 1,
24551
24621
  status: "failed",
24552
24622
  exitCode: 1,
24553
- projectRoot: resolve29(deps.projectRoot),
24623
+ projectRoot: resolve30(deps.projectRoot),
24554
24624
  workspace: null,
24555
24625
  config: {
24556
- project: join49(resolve29(deps.projectRoot), "av.yaml"),
24557
- global: resolve29(deps.globalConfigPath),
24626
+ project: join49(resolve30(deps.projectRoot), "av.yaml"),
24627
+ global: resolve30(deps.globalConfigPath),
24558
24628
  saved: false
24559
24629
  },
24560
24630
  chief: {
@@ -24668,7 +24738,7 @@ var init_noninteractive = __esm(() => {
24668
24738
  });
24669
24739
 
24670
24740
  // src/invite.ts
24671
- import { spawn as spawn18 } from "node:child_process";
24741
+ import { spawn as spawn19 } from "node:child_process";
24672
24742
  function encodeInvite(data) {
24673
24743
  const json = JSON.stringify(data);
24674
24744
  const b64 = Buffer.from(json).toString("base64url");
@@ -24694,7 +24764,7 @@ async function readClipboard() {
24694
24764
  try {
24695
24765
  const cmd = process.platform === "darwin" ? "pbpaste" : "xclip -selection clipboard -o";
24696
24766
  const parts = cmd.split(" ");
24697
- const proc = spawn18(parts[0], parts.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
24767
+ const proc = spawn19(parts[0], parts.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
24698
24768
  const { text, exitCode } = await new Promise((resolve, reject) => {
24699
24769
  const chunks = [];
24700
24770
  proc.stdout.on("data", (chunk) => chunks.push(chunk));
@@ -24711,7 +24781,7 @@ async function writeClipboard(text) {
24711
24781
  try {
24712
24782
  const cmd = process.platform === "darwin" ? "pbcopy" : "xclip -selection clipboard";
24713
24783
  const parts = cmd.split(" ");
24714
- const proc = spawn18(parts[0], parts.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
24784
+ const proc = spawn19(parts[0], parts.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
24715
24785
  proc.stdin.write(text);
24716
24786
  proc.stdin.end();
24717
24787
  const exitCode = await new Promise((resolve, reject) => {
@@ -25127,18 +25197,18 @@ async function stepMetrics(ctx) {
25127
25197
  draft.file = file;
25128
25198
  }
25129
25199
  for (const field of ["value_path", "timestamp_path", "unit_path"]) {
25130
- const value = await text12(`JSON ${field}`, old?.[field] ?? field.replace("_path", ""), path3);
25200
+ const value = await text12(`JSON ${field}`, old?.[field] ?? field.replace("_path", ""), path4);
25131
25201
  if (navigated2(value))
25132
25202
  return value;
25133
25203
  draft[field] = value;
25134
25204
  }
25135
- const start = await text12("JSON measurement window start path (optional; blank omits window)", old?.window_start_path ?? "", (value) => value ? path3(value) : undefined);
25205
+ const start = await text12("JSON measurement window start path (optional; blank omits window)", old?.window_start_path ?? "", (value) => value ? path4(value) : undefined);
25136
25206
  if (navigated2(start))
25137
25207
  return start;
25138
25208
  delete draft.window_start_path;
25139
25209
  delete draft.window_end_path;
25140
25210
  if (start) {
25141
- const end = await text12("JSON measurement window end path", old?.window_end_path ?? "window.end", path3);
25211
+ const end = await text12("JSON measurement window end path", old?.window_end_path ?? "window.end", path4);
25142
25212
  if (navigated2(end))
25143
25213
  return end;
25144
25214
  draft.window_start_path = start;
@@ -25184,7 +25254,7 @@ async function stepMetrics(ctx) {
25184
25254
  ctx.chiefChanged = true;
25185
25255
  log2.info("Metric settings are saved after confirmation. Measurements are collected at mission runtime; setup does not contact the source. Set --duration or chief.execution.max_duration_sec long enough for work and the full measurement/observation windows. The default mission limit is 86400 seconds including waits; Stripe's default measurement window is also 86400 seconds.");
25186
25256
  }
25187
- var envName3 = (value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value), navigated2 = (value) => typeof value !== "string", required2 = (limit) => (value) => value && value.length <= limit ? undefined : `Enter 1 to ${limit} characters.`, environment = (optional = false) => (value) => optional && !value || envName3(value) ? undefined : "Enter an environment variable name, never a token or URL.", number4 = (minimum, maximum) => (value) => value && Number.isInteger(Number(value)) && Number(value) >= minimum && Number(value) <= maximum ? undefined : `Enter a whole number from ${minimum} to ${maximum}.`, path3 = (value) => {
25257
+ var envName3 = (value) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(value), navigated2 = (value) => typeof value !== "string", required2 = (limit) => (value) => value && value.length <= limit ? undefined : `Enter 1 to ${limit} characters.`, environment = (optional = false) => (value) => optional && !value || envName3(value) ? undefined : "Enter an environment variable name, never a token or URL.", number4 = (minimum, maximum) => (value) => value && Number.isInteger(Number(value)) && Number(value) >= minimum && Number(value) <= maximum ? undefined : `Enter a whole number from ${minimum} to ${maximum}.`, path4 = (value) => {
25188
25258
  const result = metricSourceSchema.shape.value_path.safeParse(value);
25189
25259
  return result.success ? undefined : "Use dot-separated JSON keys or array indexes, without prototype keys.";
25190
25260
  };
@@ -27130,7 +27200,7 @@ var init_breakdown_publish = __esm(() => {
27130
27200
  });
27131
27201
 
27132
27202
  // src/breakdown.ts
27133
- import { spawn as spawn21 } from "node:child_process";
27203
+ import { spawn as spawn22 } from "node:child_process";
27134
27204
  function parseBreakdownOutput(output) {
27135
27205
  const parentTitleMatch = output.match(/^PARENT_TITLE:\s*(.+)$/m);
27136
27206
  const parentDescStart = output.match(/^PARENT_DESCRIPTION:\s*\n/m);
@@ -27184,7 +27254,7 @@ function renderDagPreview(result) {
27184
27254
  }
27185
27255
  async function expandBreakdownWithClaude(rawInput) {
27186
27256
  const output = await new Promise((resolve, reject) => {
27187
- const proc = spawn21("claude", ["--print", "--no-session-persistence", "-p", `${BREAKDOWN_PROMPT}
27257
+ const proc = spawn22("claude", ["--print", "--no-session-persistence", "-p", `${BREAKDOWN_PROMPT}
27188
27258
 
27189
27259
  Input: ${rawInput}`], { stdio: ["ignore", "pipe", "pipe"] });
27190
27260
  const chunks = [];
@@ -27322,7 +27392,7 @@ async function createGithubIssue(config, input, fetchImpl = fetch) {
27322
27392
  }
27323
27393
 
27324
27394
  // src/issue.ts
27325
- import { spawn as spawn22 } from "node:child_process";
27395
+ import { spawn as spawn23 } from "node:child_process";
27326
27396
  function parseIssueInput(raw) {
27327
27397
  const newlineIdx = raw.indexOf(`
27328
27398
  `);
@@ -27362,7 +27432,7 @@ async function expandWithClaude(rawInput) {
27362
27432
  const args = ["--print", "--no-session-persistence", "-p", `${EXPAND_PROMPT}
27363
27433
 
27364
27434
  Input: ${rawInput}`];
27365
- const proc = spawn22("claude", args, { stdio: ["pipe", "pipe", "pipe"] });
27435
+ const proc = spawn23("claude", args, { stdio: ["pipe", "pipe", "pipe"] });
27366
27436
  const { output, exitCode } = await new Promise((resolve, reject) => {
27367
27437
  const chunks = [];
27368
27438
  proc.stdout.on("data", (chunk) => chunks.push(chunk));
@@ -27760,9 +27830,9 @@ var init_login = __esm(() => {
27760
27830
  // src/index.ts
27761
27831
  init_project_config_path();
27762
27832
  init_yaml_loader();
27763
- import { spawn as spawn23, spawnSync as spawnSync5 } from "node:child_process";
27833
+ import { spawn as spawn24, spawnSync as spawnSync5 } from "node:child_process";
27764
27834
  import { existsSync as existsSync10, unlinkSync as unlinkSync2 } from "node:fs";
27765
- import { resolve as resolve30 } from "node:path";
27835
+ import { resolve as resolve31 } from "node:path";
27766
27836
 
27767
27837
  // ../../packages/core/src/version.ts
27768
27838
  import { readFileSync as readFileSync2 } from "node:fs";
@@ -27872,7 +27942,7 @@ function humanReadableArgName(arg) {
27872
27942
  // ../../node_modules/.bun/commander@15.0.0/node_modules/commander/lib/command.js
27873
27943
  import { EventEmitter } from "node:events";
27874
27944
  import childProcess from "node:child_process";
27875
- import path from "node:path";
27945
+ import path2 from "node:path";
27876
27946
  import fs from "node:fs";
27877
27947
  import process2 from "node:process";
27878
27948
  import { stripVTControlCharacters as stripVTControlCharacters2 } from "node:util";
@@ -29016,10 +29086,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
29016
29086
  args = args.slice();
29017
29087
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
29018
29088
  function findFile(baseDir, baseName) {
29019
- const localBin = path.resolve(baseDir, baseName);
29089
+ const localBin = path2.resolve(baseDir, baseName);
29020
29090
  if (fs.existsSync(localBin))
29021
29091
  return localBin;
29022
- if (sourceExt.includes(path.extname(baseName)))
29092
+ if (sourceExt.includes(path2.extname(baseName)))
29023
29093
  return;
29024
29094
  const foundExt = sourceExt.find((ext) => fs.existsSync(`${localBin}${ext}`));
29025
29095
  if (foundExt)
@@ -29037,19 +29107,19 @@ Expecting one of '${allowedValues.join("', '")}'`);
29037
29107
  } catch {
29038
29108
  resolvedScriptPath = this._scriptPath;
29039
29109
  }
29040
- executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
29110
+ executableDir = path2.resolve(path2.dirname(resolvedScriptPath), executableDir);
29041
29111
  }
29042
29112
  if (executableDir) {
29043
29113
  let localFile = findFile(executableDir, executableFile);
29044
29114
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
29045
- const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
29115
+ const legacyName = path2.basename(this._scriptPath, path2.extname(this._scriptPath));
29046
29116
  if (legacyName !== this._name) {
29047
29117
  localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
29048
29118
  }
29049
29119
  }
29050
29120
  executableFile = localFile || executableFile;
29051
29121
  }
29052
- const launchWithNode = sourceExt.includes(path.extname(executableFile));
29122
+ const launchWithNode = sourceExt.includes(path2.extname(executableFile));
29053
29123
  let proc;
29054
29124
  if (process2.platform !== "win32") {
29055
29125
  if (launchWithNode) {
@@ -29640,13 +29710,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
29640
29710
  cmd.helpGroup(this._defaultCommandGroup);
29641
29711
  }
29642
29712
  nameFromFilename(filename) {
29643
- this._name = path.basename(filename, path.extname(filename));
29713
+ this._name = path2.basename(filename, path2.extname(filename));
29644
29714
  return this;
29645
29715
  }
29646
- executableDir(path2) {
29647
- if (path2 === undefined)
29716
+ executableDir(path) {
29717
+ if (path === undefined)
29648
29718
  return this._executableDir;
29649
- this._executableDir = path2;
29719
+ this._executableDir = path;
29650
29720
  return this;
29651
29721
  }
29652
29722
  helpInformation(contextOptions) {
@@ -48938,7 +49008,7 @@ var sha256 = string2().regex(/^[a-f0-9]{64}$/);
48938
49008
  function safeVerificationPath(path) {
48939
49009
  return path.length > 0 && path.length <= 1024 && !isAbsolute2(path) && !/^[a-z]:/i.test(path) && !/[\\\0\r\n]/.test(path) && path.split("/").every((part) => part !== "" && part !== "." && part !== "..") && !/^(?:\.git(?:\/|$)|\.agent-valley(?:\/|$)|\.agents\/(?:state|results)(?:\/|$))/.test(path);
48940
49010
  }
48941
- var path2 = string2().refine(safeVerificationPath, "Use a literal relative product path inside the worktree.");
49011
+ var path3 = string2().refine(safeVerificationPath, "Use a literal relative product path inside the worktree.");
48942
49012
  var testPath = (name, nodeOnly = false) => safeVerificationPath(name) && !name.startsWith("-") && !/[*?{}]/.test(name) && !name.startsWith("node_modules/") && (nodeOnly ? /(?:\.test|\.spec)\.(?:js|mjs|cjs)$/ : /(?:\.test|\.spec)\.(?:[cm]?[jt]sx?)$/).test(name);
48943
49013
  function verificationCommandTestPaths(program, args) {
48944
49014
  if (program === "bun" && args[0] === "test")
@@ -48975,14 +49045,14 @@ function safeVerificationCommand(program, args) {
48975
49045
  var goalVerificationCheckSchema = discriminatedUnion("kind", [
48976
49046
  strictObject({
48977
49047
  kind: literal("file"),
48978
- path: path2,
49048
+ path: path3,
48979
49049
  minBytes: number2().int().min(1).max(4194304).default(1),
48980
49050
  contains: array(text4).min(1).max(10).optional(),
48981
49051
  sha256: sha256.optional()
48982
49052
  }),
48983
49053
  strictObject({
48984
49054
  kind: literal("json"),
48985
- path: path2,
49055
+ path: path3,
48986
49056
  pointer: string2().max(1024).refine((value) => value === "" || /^(?:\/(?:[^~]|~[01])*)+$/.test(value), {
48987
49057
  message: "Use an RFC 6901 JSON pointer such as /engines/node."
48988
49058
  }),
@@ -49444,16 +49514,29 @@ function routeEvidence(mission) {
49444
49514
  function price2(candidate) {
49445
49515
  return candidate.inputPerMillionUsd !== undefined && candidate.outputPerMillionUsd !== undefined ? candidate.inputPerMillionUsd + candidate.outputPerMillionUsd : Number.POSITIVE_INFINITY;
49446
49516
  }
49447
- function selectWorkActor(mission, actor, taskId) {
49517
+ function workActorCandidates(mission, actor, preserveExplicit = false) {
49518
+ const routing = mission.operatingPolicy?.routing;
49519
+ if (!routing || actor.id === mission.chiefId || !mission.availableAgents && (actor.model || preserveExplicit))
49520
+ return [{ actorType: actor.agentType, model: actor.model }];
49521
+ const ready = mission.operatingPolicy?.readyActors ?? mission.availableAgents ?? [];
49522
+ return routing.candidates.filter((candidate) => ready.includes(candidate.actorType));
49523
+ }
49524
+ function selectWorkActor(mission, actor, taskId, compatibleRoutes) {
49448
49525
  const routing = mission.operatingPolicy?.routing;
49449
- if (!routing || actor.id === mission.chiefId || !mission.availableAgents && actor.model)
49526
+ if (!routing || actor.id === mission.chiefId || !mission.availableAgents && (actor.model || compatibleRoutes)) {
49527
+ if (compatibleRoutes && !compatibleRoutes.has(routeKey({ actorType: actor.agentType, model: actor.model })))
49528
+ throw new Error("Skill compatibility required: the configured Actor/model has no current passing evidence. Refresh oma.skill_compatibility.report_path in av.yaml; explicit Actors are not rerouted.");
49450
49529
  return { actor, reason: "Preserved the configured Actor and explicit model." };
49530
+ }
49451
49531
  const ready = mission.operatingPolicy?.readyActors ?? mission.availableAgents ?? [];
49452
49532
  const candidates = routing.candidates.filter((candidate) => ready.includes(candidate.actorType));
49453
49533
  if (!candidates.length)
49454
49534
  throw new Error("No configured work routing candidate is ready. Install/login a candidate CLI or update chief.routing.candidates in av.yaml.");
49535
+ const compatible = compatibleRoutes ? candidates.filter((candidate) => compatibleRoutes.has(routeKey(candidate))) : candidates;
49536
+ if (!compatible.length)
49537
+ throw new Error("Skill compatibility required: no ready work candidate has current passing installed evidence. Refresh oma.skill_compatibility.report_path in av.yaml with explicit models before retrying.");
49455
49538
  const evidence = routeEvidence(mission);
49456
- const eligible = candidates.filter((candidate) => {
49539
+ const eligible = compatible.filter((candidate) => {
49457
49540
  const observed = evidence.find((item) => routeKey(item) === routeKey(candidate));
49458
49541
  return !observed || observed.samples < routing.minSamples || observed.successes / observed.samples >= routing.minSuccessRate;
49459
49542
  });
@@ -49515,6 +49598,10 @@ function operationsEvidence(mission) {
49515
49598
  pricingBasis: "Estimates from configured input/output prices and actual adapter-reported tokens; excludes unreported cache/reasoning/subagent usage and subscription billing.",
49516
49599
  routeQuality: routeEvidence(mission).slice(0, 20),
49517
49600
  reviewPolicy: mission.operatingPolicy?.reviewVendor ?? "legacy independent Actor",
49601
+ skillCompatibility: mission.operatingPolicy?.skillCompatibility ? {
49602
+ mode: mission.operatingPolicy.skillCompatibility.mode,
49603
+ recentChecks: mission.history.filter((entry) => entry.stage === "skill-compatibility").slice(-10)
49604
+ } : undefined,
49518
49605
  recentRuns: runs.slice(-20),
49519
49606
  crossVendorReviews: mission.operations?.reviewDecisions.slice(-20) ?? [],
49520
49607
  organizationContext: mission.organizationContext,
@@ -49530,6 +49617,10 @@ function operationsReportLines(mission) {
49530
49617
  `기록된 token·설정 단가 기반 부분 비용 추정 USD ${evidence.knownEstimatedCostUsd.toFixed(6)} / 비용 미확인 ${evidence.unknownCostRuns}회 / 전체 추정 ${evidence.totalEstimatedCostUsd === null ? "미확인" : `USD ${evidence.totalEstimatedCostUsd.toFixed(6)}`}`,
49531
49618
  `최근 독립 리뷰 배정: 다른 vendor ${evidence.crossVendorReviews.filter((review) => review.crossVendor).length}회 / 동일 vendor fallback ${evidence.crossVendorReviews.filter((review) => !review.crossVendor).length}회 / 실제 리뷰 통과 ${evidence.crossVendorReviews.filter((review) => review.outcome === "passed").length}회`,
49532
49619
  `vendor 리뷰 정책: ${evidence.reviewPolicy}`,
49620
+ ...evidence.skillCompatibility ? [
49621
+ `OMA 스킬 읽기·참조 정책: ${evidence.skillCompatibility.mode}; AV 실행 환경 또는 작업 품질 인증이 아닙니다.`,
49622
+ ...evidence.skillCompatibility.recentChecks.map((entry) => `${entry.at}: ${entry.message}`)
49623
+ ] : [],
49533
49624
  ...mission.organizationContext ? [
49534
49625
  `계획·리뷰에 제공한 조직 근거: 승인 memory ${mission.organizationContext.memories.length}개 / 과거 outcome ${mission.organizationContext.outcomes.length}개 / 기록된 metric sample ${mission.organizationContext.metrics.length}개`
49535
49626
  ] : [],
@@ -49557,15 +49648,15 @@ var chiefReportSchema = strictObject({
49557
49648
  checks: entries,
49558
49649
  remaining: entries
49559
49650
  });
49560
- function bounded(value, limit = 500) {
49651
+ function bounded2(value, limit = 500) {
49561
49652
  const content = value.trim();
49562
49653
  return content.length <= limit ? content : `${content.slice(0, limit - 8)}… [생략]`;
49563
49654
  }
49564
49655
  function compact(values, limit = 20) {
49565
49656
  if (values.length <= limit)
49566
- return values.map((value) => bounded(value)).filter(Boolean);
49657
+ return values.map((value) => bounded2(value)).filter(Boolean);
49567
49658
  return [
49568
- ...values.slice(0, limit - 1).map((value) => bounded(value)).filter(Boolean),
49659
+ ...values.slice(0, limit - 1).map((value) => bounded2(value)).filter(Boolean),
49569
49660
  `${values.length - limit + 1}개 항목 생략`
49570
49661
  ];
49571
49662
  }
@@ -49580,7 +49671,7 @@ function criteria(mission) {
49580
49671
  function incompleteReasons(mission) {
49581
49672
  const reasons = [];
49582
49673
  if (mission.error)
49583
- reasons.push(`${["waiting", "paused"].includes(mission.status) ? "대기·중단 이유" : "실패 원인"}: ${bounded(mission.error, 450)}`);
49674
+ reasons.push(`${["waiting", "paused"].includes(mission.status) ? "대기·중단 이유" : "실패 원인"}: ${bounded2(mission.error, 450)}`);
49584
49675
  if (mission.status !== "completed")
49585
49676
  reasons.push(`미션 상태: ${mission.status}. 완료 판정이 없습니다.`);
49586
49677
  if (!mission.verification)
@@ -49633,33 +49724,33 @@ function incompleteReasons(mission) {
49633
49724
  }
49634
49725
  function decisionEvidence(mission) {
49635
49726
  const actions = { repair: "수정", reassign: "담당 교체", replan: "재계획", wait: "대기", stop: "중단" };
49636
- return (mission.supervision?.decisions ?? []).slice(-20).map((decision) => bounded(`${decision.round}차 ${actions[decision.action]}${decision.taskId ? ` / 작업 ${decision.taskId}` : ""}${decision.personaId ? ` / 담당 ${decision.personaId}` : ""}: ${decision.reason}`));
49727
+ return (mission.supervision?.decisions ?? []).slice(-20).map((decision) => bounded2(`${decision.round}차 ${actions[decision.action]}${decision.taskId ? ` / 작업 ${decision.taskId}` : ""}${decision.personaId ? ` / 담당 ${decision.personaId}` : ""}: ${decision.reason}`));
49637
49728
  }
49638
49729
  function reviewEvidence(review) {
49639
49730
  return review ? {
49640
49731
  passed: review.passed,
49641
- summary: bounded(review.summary),
49732
+ summary: bounded2(review.summary),
49642
49733
  findings: compact(review.findings),
49643
49734
  criteria: review.criteria?.slice(0, 20).map((item) => ({
49644
- criterion: bounded(item.criterion),
49735
+ criterion: bounded2(item.criterion),
49645
49736
  passed: item.passed,
49646
- evidence: bounded(item.evidence)
49737
+ evidence: bounded2(item.evidence)
49647
49738
  }))
49648
49739
  } : undefined;
49649
49740
  }
49650
49741
  function verificationEvidence(verification) {
49651
49742
  return verification ? {
49652
49743
  ok: verification.ok,
49653
- output: verification.output ? bounded(verification.output, 3000) : undefined,
49654
- fingerprint: bounded(verification.fingerprint, 128)
49744
+ output: verification.output ? bounded2(verification.output, 3000) : undefined,
49745
+ fingerprint: bounded2(verification.fingerprint, 128)
49655
49746
  } : undefined;
49656
49747
  }
49657
49748
  function advisoryEvidence(kind, advisory) {
49658
49749
  return advisory ? {
49659
49750
  kind: `upfront ${kind} advice; historical snapshot; not current approval`,
49660
- planKey: bounded(advisory.planKey, 128),
49751
+ planKey: bounded2(advisory.planKey, 128),
49661
49752
  reviewerId: advisory.reviewerId,
49662
- fingerprint: bounded(advisory.fingerprint, 128),
49753
+ fingerprint: bounded2(advisory.fingerprint, 128),
49663
49754
  review: reviewEvidence(advisory.review)
49664
49755
  } : undefined;
49665
49756
  }
@@ -49669,24 +49760,24 @@ function historicalEvidence(mission) {
49669
49760
  const verification = decision.evidence?.verification;
49670
49761
  const review = decision.evidence?.finalReview;
49671
49762
  if (verification)
49672
- lines.push(bounded(`${decision.round}차 판단 당시 검증: ${verification.ok ? "통과" : "실패"} / 파일 상태 ${bounded(verification.fingerprint, 128)}${verification.output ? ` / ${bounded(verification.output, 250)}` : ""}`));
49763
+ lines.push(bounded2(`${decision.round}차 판단 당시 검증: ${verification.ok ? "통과" : "실패"} / 파일 상태 ${bounded2(verification.fingerprint, 128)}${verification.output ? ` / ${bounded2(verification.output, 250)}` : ""}`));
49673
49764
  if (review) {
49674
- lines.push(bounded(`${decision.round}차 판단 당시 최종 리뷰: ${review.passed ? "통과" : "실패"} / ${bounded(review.summary, 350)}`));
49675
- lines.push(...compact(review.findings, 3).map((finding) => bounded(`${decision.round}차 판단 당시 지적: ${finding}`)));
49765
+ lines.push(bounded2(`${decision.round}차 판단 당시 최종 리뷰: ${review.passed ? "통과" : "실패"} / ${bounded2(review.summary, 350)}`));
49766
+ lines.push(...compact(review.findings, 3).map((finding) => bounded2(`${decision.round}차 판단 당시 지적: ${finding}`)));
49676
49767
  }
49677
49768
  return lines;
49678
49769
  });
49679
49770
  }
49680
49771
  function checkEvidence(mission) {
49681
49772
  return compact([
49682
- `운영자 검증: ${mission.verification ? mission.verification.ok ? "통과" : "실패" : "미실행"} / 명령: ${bounded(mission.supervision?.operatorVerifyCommand ?? mission.verifyCommand, 350)}`,
49773
+ `운영자 검증: ${mission.verification ? mission.verification.ok ? "통과" : "실패" : "미실행"} / 명령: ${bounded2(mission.supervision?.operatorVerifyCommand ?? mission.verifyCommand, 350)}`,
49683
49774
  ...mission.verification?.output ? [`검증 출력: ${mission.verification.output}`] : [],
49684
49775
  `Chief Director 최종 리뷰: ${mission.finalReview ? mission.finalReview.passed && mission.finalReview.findings.length === 0 ? "통과" : "실패" : "미실행"}${mission.finalReview ? ` / ${mission.finalReview.summary}` : ""}`,
49685
49776
  ...mission.tasks.map((task) => `${task.id}: 상태 ${task.status}, 시도 ${task.attempts}회, 독립 리뷰 ${task.review ? task.review.passed && task.review.findings.length === 0 ? "통과" : "실패" : "미실행"} / 리뷰어 ${task.reviewerId}`)
49686
49777
  ]);
49687
49778
  }
49688
49779
  function criterionEvidence(mission) {
49689
- return (mission.finalReview?.criteria ?? []).map((item) => bounded(`${bounded(item.criterion, 200)}: ${item.passed ? "통과" : "실패"} / 근거: ${bounded(item.evidence, 250)}`));
49780
+ return (mission.finalReview?.criteria ?? []).map((item) => bounded2(`${bounded2(item.criterion, 200)}: ${item.passed ? "통과" : "실패"} / 근거: ${bounded2(item.evidence, 250)}`));
49690
49781
  }
49691
49782
  function reportPrompt(mission) {
49692
49783
  const goal = mission.supervision?.operatorGoal ?? mission.goal;
@@ -49714,8 +49805,8 @@ function reportPrompt(mission) {
49714
49805
  '{"summary":"result","eli5":"plain-language result and user impact","goalAssessment":"criteria and actual verdict","assumptions":[],"decisions":[],"deliverables":[],"checks":[],"remaining":[]}',
49715
49806
  `Report evidence (JSON data):
49716
49807
  ${JSON.stringify({
49717
- operatorGoal: bounded(goal, 4000),
49718
- interpretation: mission.goalBrief ? bounded(mission.goalBrief.interpretation, 2000) : undefined,
49808
+ operatorGoal: bounded2(goal, 4000),
49809
+ interpretation: mission.goalBrief ? bounded2(mission.goalBrief.interpretation, 2000) : undefined,
49719
49810
  assumptions: compact(mission.goalBrief?.assumptions ?? []),
49720
49811
  successCriteria: compact(criteria(mission)),
49721
49812
  status: mission.status,
@@ -49724,9 +49815,9 @@ ${JSON.stringify({
49724
49815
  containerObservation: mission.containerObservation,
49725
49816
  verdict: incompleteReasons(mission).length === 0 ? "completed" : "incomplete",
49726
49817
  incompleteReasons: incompleteReasons(mission),
49727
- error: mission.error ? bounded(mission.error, 2000) : undefined,
49728
- workspace: bounded(mission.workspace.path, 2000),
49729
- branch: bounded(mission.workspace.branch),
49818
+ error: mission.error ? bounded2(mission.error, 2000) : undefined,
49819
+ workspace: bounded2(mission.workspace.path, 2000),
49820
+ branch: bounded2(mission.workspace.branch),
49730
49821
  chiefId: mission.chiefId,
49731
49822
  technicalLeadId: mission.technicalLeadId,
49732
49823
  technicalAdvice: advisoryEvidence("technical", mission.technicalReview),
@@ -49736,10 +49827,10 @@ ${JSON.stringify({
49736
49827
  marketingAdvice: advisoryEvidence("marketing", mission.marketingReview),
49737
49828
  actors: mission.personas.slice(0, 20).map((persona) => ({
49738
49829
  id: persona.id,
49739
- name: bounded(persona.name),
49740
- role: bounded(persona.role),
49741
- cli: bounded(persona.agentType),
49742
- model: persona.model ? bounded(persona.model) : "native default (actual model not recorded)",
49830
+ name: bounded2(persona.name),
49831
+ role: bounded2(persona.role),
49832
+ cli: bounded2(persona.agentType),
49833
+ model: persona.model ? bounded2(persona.model) : "native default (actual model not recorded)",
49743
49834
  selectedSkills: persona.skills.slice(0, 30)
49744
49835
  })),
49745
49836
  decisions: decisions.map((decision) => ({
@@ -49747,8 +49838,8 @@ ${JSON.stringify({
49747
49838
  action: decision.action,
49748
49839
  taskId: decision.taskId,
49749
49840
  actorId: decision.personaId,
49750
- reason: bounded(decision.reason),
49751
- instructions: decision.instructions ? bounded(decision.instructions) : undefined,
49841
+ reason: bounded2(decision.reason),
49842
+ instructions: decision.instructions ? bounded2(decision.instructions) : undefined,
49752
49843
  historicalEvidence: decision.evidence && snapshotDecisions.has(decision) ? {
49753
49844
  kind: "evidence at the recovery decision; not current approval",
49754
49845
  finalReview: reviewEvidence(decision.evidence.finalReview),
@@ -49757,25 +49848,25 @@ ${JSON.stringify({
49757
49848
  })),
49758
49849
  tasks: mission.tasks.slice(0, 12).map((state) => ({
49759
49850
  id: state.id,
49760
- title: bounded(mission.plan?.tasks.find((task) => task.id === state.id)?.title ?? state.id),
49851
+ title: bounded2(mission.plan?.tasks.find((task) => task.id === state.id)?.title ?? state.id),
49761
49852
  actorId: mission.plan?.tasks.find((task) => task.id === state.id)?.personaId,
49762
49853
  reviewerId: state.reviewerId,
49763
49854
  status: state.status,
49764
49855
  attempts: state.attempts,
49765
- actorClaim: state.output ? bounded(state.output, 3000) : undefined,
49856
+ actorClaim: state.output ? bounded2(state.output, 3000) : undefined,
49766
49857
  review: reviewEvidence(state.review)
49767
49858
  })),
49768
- verifyCommand: bounded(mission.supervision?.operatorVerifyCommand ?? mission.verifyCommand, 1200),
49859
+ verifyCommand: bounded2(mission.supervision?.operatorVerifyCommand ?? mission.verifyCommand, 1200),
49769
49860
  verification: verificationEvidence(mission.verification),
49770
49861
  goalVerification: mission.goalVerification,
49771
49862
  execution: mission.execution,
49772
49863
  executionPolicy: mission.executionPolicy,
49773
49864
  finalReview: reviewEvidence(mission.finalReview),
49774
49865
  history: mission.history.slice(-30).map((event) => ({
49775
- at: bounded(event.at),
49776
- stage: bounded(event.stage),
49866
+ at: bounded2(event.at),
49867
+ stage: bounded2(event.stage),
49777
49868
  taskId: event.taskId,
49778
- message: bounded(event.message)
49869
+ message: bounded2(event.message)
49779
49870
  }))
49780
49871
  })}`
49781
49872
  ].join(`
@@ -49797,10 +49888,10 @@ function parseReport(source) {
49797
49888
  function fallbackReport(mission) {
49798
49889
  const reasons = incompleteReasons(mission);
49799
49890
  const complete = reasons.length === 0;
49800
- const goal = bounded(mission.supervision?.operatorGoal ?? mission.goal, 350);
49891
+ const goal = bounded2(mission.supervision?.operatorGoal ?? mission.goal, 350);
49801
49892
  return {
49802
49893
  summary: complete ? "작업, 독립 리뷰, 운영자 검증과 Chief Director 최종 리뷰를 통과했습니다." : "목표는 미완료입니다. 확인된 미해결 조건과 보관된 실행 기록을 보고합니다.",
49803
- eli5: complete ? `“${goal}”을 위한 결과물을 만들고, 다른 담당자의 점검과 지정한 확인 절차를 마쳤습니다. 결과물은 아래 작업 경로에 보관되어 있어 직접 확인할 수 있습니다.` : `“${goal}”을 위해 작업했지만, 아직 모든 확인 절차를 통과한 결과는 아닙니다. ${bounded(reasons[0] ?? "완료 증거가 없습니다.", 350)} 이미 만든 작업은 보관되어 있습니다. Chief Director가 기록한 판단과 다음 관측·재개 시각, 아직 충족되지 않은 조건을 아래에서 보고합니다.`,
49894
+ eli5: complete ? `“${goal}”을 위한 결과물을 만들고, 다른 담당자의 점검과 지정한 확인 절차를 마쳤습니다. 결과물은 아래 작업 경로에 보관되어 있어 직접 확인할 수 있습니다.` : `“${goal}”을 위해 작업했지만, 아직 모든 확인 절차를 통과한 결과는 아닙니다. ${bounded2(reasons[0] ?? "완료 증거가 없습니다.", 350)} 이미 만든 작업은 보관되어 있습니다. Chief Director가 기록한 판단과 다음 관측·재개 시각, 아직 충족되지 않은 조건을 아래에서 보고합니다.`,
49804
49895
  goalAssessment: complete ? "기록된 성공 기준에 대해 작업별 독립 리뷰와 운영자 검증이 통과했고, Chief Director가 최종 승인했습니다." : "성공 기준 전체의 충족을 확인하지 못했습니다. 일부 작업이나 검증이 통과했더라도 목표 달성으로 표시하지 않습니다.",
49805
49896
  assumptions: compact(mission.goalBrief?.assumptions ?? []),
49806
49897
  decisions: decisionEvidence(mission),
@@ -49818,7 +49909,7 @@ function fallbackReport(mission) {
49818
49909
  };
49819
49910
  }
49820
49911
  function markdown(value, limit = 1200) {
49821
- return bounded(value, limit).replace(/[\p{Cc}\p{Cf}]/gu, " ").replace(/\s+/g, " ").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/[\\`*_{}[\]()#+.!|~-]/g, "\\$&");
49912
+ return bounded2(value, limit).replace(/[\p{Cc}\p{Cf}]/gu, " ").replace(/\s+/g, " ").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/[\\`*_{}[\]()#+.!|~-]/g, "\\$&");
49822
49913
  }
49823
49914
  function list(values) {
49824
49915
  return values.length ? compact(values).map((value) => `- ${markdown(value)}`).join(`
@@ -50333,12 +50424,12 @@ async function assertMissionWorkspace(mission) {
50333
50424
  }
50334
50425
 
50335
50426
  // ../../packages/core/src/chief/parallel-workspace.ts
50336
- var hash = (value) => createHash10("sha256").update(value).digest("hex");
50427
+ var hash2 = (value) => createHash10("sha256").update(value).digest("hex");
50337
50428
  var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
50338
50429
  function identity3(missionId, taskId, attempt) {
50339
50430
  if (!taskId || taskId.length > 200 || !Number.isSafeInteger(attempt) || attempt < 1)
50340
50431
  throw new Error("Use a valid task ID and positive attempt number for each parallel Actor.");
50341
- return `${hash(missionId).slice(0, 16)}-${hash(taskId).slice(0, 16)}-${attempt}`;
50432
+ return `${hash2(missionId).slice(0, 16)}-${hash2(taskId).slice(0, 16)}-${attempt}`;
50342
50433
  }
50343
50434
  async function paths(source, missionId, taskId, attempt) {
50344
50435
  const root = await parallelRoot(source);
@@ -50482,7 +50573,7 @@ async function collectTaskDelivery(mission, workspace) {
50482
50573
  version: 1,
50483
50574
  workspace,
50484
50575
  patchPath: location.patch,
50485
- patchSha256: hash(patch),
50576
+ patchSha256: hash2(patch),
50486
50577
  deliveryTree: final.tree,
50487
50578
  changes,
50488
50579
  status: "prepared"
@@ -50498,7 +50589,7 @@ async function integrateTaskDelivery(mission, input) {
50498
50589
  if (delivery.workspace.missionId !== mission.id || !same(delivery.workspace, input.workspace) || delivery.patchSha256 !== input.patchSha256 || delivery.patchPath !== location.patch)
50499
50590
  throw new Error("Parallel delivery does not match its persisted task identity and patch. Inspect the saved artifacts before recovery.");
50500
50591
  const patch = await readFile4(location.patch);
50501
- if (hash(patch) !== delivery.patchSha256)
50592
+ if (hash2(patch) !== delivery.patchSha256)
50502
50593
  throw new Error("Parallel delivery patch changed. Restore its saved SHA256 before integration.");
50503
50594
  const current = await captureParallelBaseline(mission.workspace.path);
50504
50595
  const images = await parallelTreeImages(mission.workspace.path, current.tree);
@@ -66141,7 +66232,11 @@ ${details}` : ""}`);
66141
66232
  timeoutSec,
66142
66233
  maxRepairs,
66143
66234
  maxRounds,
66144
- operatingPolicy: chiefOperatingPolicy(chiefConfig, readyActors, !profile),
66235
+ operatingPolicy: chiefOperatingPolicy(chiefConfig, readyActors, !profile, project?.oma?.skill_compatibility ? {
66236
+ reportPath: resolve11(root, project.oma.skill_compatibility.report_path),
66237
+ maxAgeHours: project.oma.skill_compatibility.max_age_hours,
66238
+ mode: project.oma.skill_compatibility.mode
66239
+ } : undefined),
66145
66240
  capturePolicy: chiefCapturePolicy(chiefConfig),
66146
66241
  executionPolicy,
66147
66242
  metricSourcePolicy: chiefConfig.metric_sources,
@@ -66676,7 +66771,7 @@ class ContinuousOperationStore {
66676
66771
  }
66677
66772
 
66678
66773
  // src/chief-continuous.ts
66679
- import { execFile as execFile4 } from "node:child_process";
66774
+ import { execFile as execFile5 } from "node:child_process";
66680
66775
  import { randomUUID as randomUUID15 } from "node:crypto";
66681
66776
  import { mkdir as mkdir17, realpath as realpath19, rename as rename7, unlink as unlink7, writeFile as writeFile13 } from "node:fs/promises";
66682
66777
  import { join as join35, resolve as resolve19 } from "node:path";
@@ -67963,11 +68058,141 @@ function getCachedTriggerTable(rootDir = process.cwd()) {
67963
68058
  return table;
67964
68059
  }
67965
68060
 
68061
+ // ../../packages/core/src/oma/latest-cli.ts
68062
+ import { spawn as spawn7 } from "node:child_process";
68063
+ var VERSION_TIMEOUT_MS = 1e4;
68064
+ var REGISTRY_TIMEOUT_MS = 60000;
68065
+ var INSTALL_TIMEOUT_MS = 300000;
68066
+ var MAX_OUTPUT_BYTES2 = 1048576;
68067
+ var INSTALL_HINT = "Run npm install --global --ignore-scripts oh-my-agent@latest, confirm oma --version, then retry.";
68068
+ var VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/;
68069
+ function parseOmaCliVersion(value) {
68070
+ const trimmed = value.trim();
68071
+ if (trimmed.length > 128)
68072
+ return null;
68073
+ const version = trimmed.startsWith("v") ? trimmed.slice(1) : trimmed;
68074
+ return VERSION.test(version) ? version : null;
68075
+ }
68076
+
68077
+ class CommandFailure extends Error {
68078
+ kind;
68079
+ constructor(kind) {
68080
+ super(kind);
68081
+ this.kind = kind;
68082
+ }
68083
+ }
68084
+ var defaultIO = {
68085
+ run: (command, args, { timeoutMs, maxOutputBytes }) => new Promise((resolve, reject) => {
68086
+ let settled = false;
68087
+ let stdout = "";
68088
+ let stderr = "";
68089
+ let outputBytes = 0;
68090
+ let timer;
68091
+ const finish = (error, exitCode = null) => {
68092
+ if (settled)
68093
+ return;
68094
+ settled = true;
68095
+ clearTimeout(timer);
68096
+ if (error)
68097
+ reject(error);
68098
+ else
68099
+ resolve({ exitCode, stdout, stderr });
68100
+ };
68101
+ try {
68102
+ const child = spawn7(command, args, { stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
68103
+ const append = (chunk, destination) => {
68104
+ if (settled)
68105
+ return;
68106
+ outputBytes += Buffer.byteLength(chunk);
68107
+ if (outputBytes > maxOutputBytes) {
68108
+ child.kill("SIGKILL");
68109
+ finish(new CommandFailure("output"));
68110
+ } else if (destination === "stdout")
68111
+ stdout += chunk.toString();
68112
+ else
68113
+ stderr += chunk.toString();
68114
+ };
68115
+ child.stdout?.on("data", (chunk) => append(chunk, "stdout"));
68116
+ child.stderr?.on("data", (chunk) => append(chunk, "stderr"));
68117
+ child.once("error", () => finish(new CommandFailure("spawn")));
68118
+ child.once("close", (code) => finish(undefined, code));
68119
+ timer = setTimeout(() => {
68120
+ child.kill("SIGKILL");
68121
+ finish(new CommandFailure("timeout"));
68122
+ }, timeoutMs);
68123
+ } catch {
68124
+ finish(new CommandFailure("spawn"));
68125
+ }
68126
+ })
68127
+ };
68128
+ function failure2(stage, error) {
68129
+ const detail = error instanceof CommandFailure ? error.kind === "timeout" ? "request timed out" : error.kind === "output" ? "command output exceeded the limit" : "command could not start" : "command failed";
68130
+ return new Error(`Latest OMA CLI ${stage}: ${detail}. ${INSTALL_HINT}`);
68131
+ }
68132
+ async function installedVersion(io) {
68133
+ try {
68134
+ const result = await io.run("oma", ["--version"], {
68135
+ timeoutMs: VERSION_TIMEOUT_MS,
68136
+ maxOutputBytes: MAX_OUTPUT_BYTES2
68137
+ });
68138
+ return result.exitCode === 0 ? parseOmaCliVersion(result.stdout) : null;
68139
+ } catch {
68140
+ return null;
68141
+ }
68142
+ }
68143
+ async function prepare(io) {
68144
+ const installed = await installedVersion(io);
68145
+ let latest;
68146
+ try {
68147
+ const result = await io.run("npm", ["view", "oh-my-agent@latest", "version", "--json", "--prefer-online"], {
68148
+ timeoutMs: REGISTRY_TIMEOUT_MS,
68149
+ maxOutputBytes: MAX_OUTPUT_BYTES2
68150
+ });
68151
+ if (result.exitCode !== 0)
68152
+ throw failure2("registry lookup");
68153
+ const value = JSON.parse(result.stdout);
68154
+ latest = typeof value === "string" ? parseOmaCliVersion(value) : null;
68155
+ } catch (error) {
68156
+ throw failure2("registry lookup", error);
68157
+ }
68158
+ if (!latest)
68159
+ throw new Error(`Latest OMA CLI registry returned invalid version metadata. ${INSTALL_HINT}`);
68160
+ if (installed === latest)
68161
+ return { version: latest, installed: false };
68162
+ try {
68163
+ const result = await io.run("npm", ["install", "--global", "--ignore-scripts", "oh-my-agent@latest"], {
68164
+ timeoutMs: INSTALL_TIMEOUT_MS,
68165
+ maxOutputBytes: MAX_OUTPUT_BYTES2
68166
+ });
68167
+ if (result.exitCode !== 0)
68168
+ throw failure2("installation");
68169
+ } catch (error) {
68170
+ throw failure2("installation", error);
68171
+ }
68172
+ const confirmed = await installedVersion(io);
68173
+ if (confirmed !== latest)
68174
+ throw new Error(`Latest OMA CLI verification expected ${latest}, but oma --version reported ${confirmed ?? "unavailable"}. Check PATH for another OMA executable. ${INSTALL_HINT}`);
68175
+ return { version: latest, installed: true };
68176
+ }
68177
+ var preparing = new WeakMap;
68178
+ function ensureLatestOmaCli(options = {}) {
68179
+ const io = options.io ?? defaultIO;
68180
+ const current = preparing.get(io);
68181
+ if (current)
68182
+ return current;
68183
+ const pending = prepare(io).finally(() => {
68184
+ if (preparing.get(io) === pending)
68185
+ preparing.delete(io);
68186
+ });
68187
+ preparing.set(io, pending);
68188
+ return pending;
68189
+ }
68190
+
67966
68191
  // ../../packages/core/src/oma/receipt-adapter.ts
67967
- var SUPPORTED_OMA_VERSION = "15.0.15";
68192
+ var OMA_RECEIPT_SCHEMA_VERSION = 1;
67968
68193
  var RUN_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
67969
68194
  var HASH = /^[a-f0-9]{64}$/;
67970
- var defaultIO = {
68195
+ var defaultIO2 = {
67971
68196
  listRunFiles: (workspacePath) => {
67972
68197
  const dir = join25(workspacePath, ".agents", "state", "agent-runs");
67973
68198
  return readdirSync(dir).filter((name) => RUN_ID.test(name.slice(0, -5)) && name.endsWith(".json"));
@@ -67996,7 +68221,7 @@ function stringArray(value) {
67996
68221
  function shellQuote(value) {
67997
68222
  return `'${value.replaceAll("'", "'\\''")}'`;
67998
68223
  }
67999
- async function prepareOmaAttempt(request) {
68224
+ async function prepareOmaAttempt(request, dependencies = {}) {
68000
68225
  if (!request.verifyCommand.trim()) {
68001
68226
  throw new Error("oma.mode: strict requires verify.command in av.yaml or a routing verify_command");
68002
68227
  }
@@ -68011,6 +68236,7 @@ ${request.issue.description ?? ""}`, table);
68011
68236
  if (!existsSync4(file))
68012
68237
  throw new Error(`OMA workflow file missing in target worktree: ${file}`);
68013
68238
  }
68239
+ await ensureLatestOmaCli({ io: dependencies.latestCliIO });
68014
68240
  const path = join25(request.workspace.path, ".agents", "results", `plan-${request.attempt.id}.json`);
68015
68241
  const plan = {
68016
68242
  session_id: request.attempt.id,
@@ -68064,14 +68290,16 @@ function buildOmaGuidance(request) {
68064
68290
  ].join(`
68065
68291
  `);
68066
68292
  }
68067
- function validateOmaEvidence(request, io = defaultIO) {
68293
+ function validateOmaEvidence(request, io = defaultIO2) {
68068
68294
  const root = resolve14(request.workspace.path);
68069
68295
  if (!request.verifyCommand.trim())
68070
68296
  return fail("Strict OMA mode has no configured verify command");
68297
+ let cliVersion;
68071
68298
  try {
68072
68299
  const version = io.runCli(["--version"], root);
68073
- if (version.exitCode !== 0 || version.stdout.trim() !== SUPPORTED_OMA_VERSION) {
68074
- return fail(`OMA CLI ${SUPPORTED_OMA_VERSION} is required. Run npm install -g oh-my-agent@${SUPPORTED_OMA_VERSION}, then confirm oma --version.`);
68300
+ cliVersion = parseOmaCliVersion(version.stdout);
68301
+ if (version.exitCode !== 0 || !cliVersion) {
68302
+ return fail("OMA CLI is unavailable or returned a malformed version. Run npm install -g oh-my-agent@latest, then confirm oma --version and rerun the receipt verification.");
68075
68303
  }
68076
68304
  } catch (err) {
68077
68305
  return fail(`OMA CLI unavailable: ${String(err)}`);
@@ -68093,8 +68321,11 @@ function validateOmaEvidence(request, io = defaultIO) {
68093
68321
  const run = forAttempt.at(-1);
68094
68322
  if (!run)
68095
68323
  return fail("No OMA receipt is bound to this Valley attempt");
68096
- if (run.schemaVersion !== 1 || run.taskId !== request.attempt.id || !RUN_ID.test(String(run.runId))) {
68097
- return fail("OMA receipt schema or task identity is incompatible");
68324
+ if (run.schemaVersion !== OMA_RECEIPT_SCHEMA_VERSION) {
68325
+ return fail(`OMA CLI ${cliVersion} returned an unsupported receipt schema. AV requires agent-run schema v${OMA_RECEIPT_SCHEMA_VERSION}; update AV and OMA (npm install -g oh-my-agent@latest), then generate and verify a compatible receipt.`);
68326
+ }
68327
+ if (run.taskId !== request.attempt.id || !RUN_ID.test(String(run.runId))) {
68328
+ return fail("OMA receipt task identity is incompatible");
68098
68329
  }
68099
68330
  if (run.workspace !== root || run.artifactRoot !== root || run.status !== "completed" || run.exitCode !== 0) {
68100
68331
  return fail("OMA receipt has the wrong workspace or did not complete");
@@ -68161,6 +68392,8 @@ function validateOmaEvidence(request, io = defaultIO) {
68161
68392
  try {
68162
68393
  const status = io.runCli(["agent", "status", request.attempt.id, request.agentId, "--project-root", root], root);
68163
68394
  if (status.exitCode !== 0 || status.stdout.trim() !== `${request.agentId}:completed`) {
68395
+ if (status.stdout.trim() !== `${request.agentId}:stale`)
68396
+ return fail(`OMA CLI ${cliVersion} did not provide the required native <agent>:completed status proof. Update AV and OMA (npm install -g oh-my-agent@latest), then rerun verification; unknown status output cannot establish completion.`);
68164
68397
  return fail("OMA CLI did not confirm current completed evidence");
68165
68398
  }
68166
68399
  } catch (err) {
@@ -68169,6 +68402,214 @@ function validateOmaEvidence(request, io = defaultIO) {
68169
68402
  return { ok: true, runId: String(run.runId) };
68170
68403
  }
68171
68404
 
68405
+ // ../../packages/core/src/oma/skill-matrix-adapter.ts
68406
+ import { posix } from "node:path";
68407
+
68408
+ // ../../packages/core/src/oma/skill-matrix-io.ts
68409
+ init_skill_matrix_schema();
68410
+ import { execFile as execFile4 } from "node:child_process";
68411
+ import { constants as constants5 } from "node:fs";
68412
+ import { open as open7 } from "node:fs/promises";
68413
+ var MAX_BYTES = 4 * 1024 * 1024;
68414
+ async function command(binary, args, signal) {
68415
+ return new Promise((resolve, reject) => {
68416
+ execFile4(binary, args, {
68417
+ encoding: "utf8",
68418
+ timeout: 1e4,
68419
+ maxBuffer: MAX_BYTES,
68420
+ signal,
68421
+ ...binary === "oma" ? { env: { ...process.env, OMA_SKIP_VERSION_CHECK: "1" } } : {}
68422
+ }, (error, stdout) => {
68423
+ if (error)
68424
+ reject(new Error(`${binary} local diagnostic command failed. Check its installation/version and retry.`));
68425
+ else
68426
+ resolve(stdout);
68427
+ });
68428
+ });
68429
+ }
68430
+ async function readReport(path) {
68431
+ const file = await open7(path, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
68432
+ try {
68433
+ const info = await file.stat();
68434
+ if (!info.isFile() || info.size > MAX_BYTES)
68435
+ throw new Error("Matrix report must be a regular file at most 4 MiB.");
68436
+ const bytes = Buffer.alloc(info.size + 1);
68437
+ let length = 0;
68438
+ while (length < bytes.length) {
68439
+ const result = await file.read(bytes, length, bytes.length - length, length);
68440
+ if (!result.bytesRead)
68441
+ break;
68442
+ length += result.bytesRead;
68443
+ }
68444
+ if (length !== info.size)
68445
+ throw new Error("Matrix report changed during the read. Retry after its writer finishes.");
68446
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
68447
+ } finally {
68448
+ await file.close();
68449
+ }
68450
+ }
68451
+ var defaultSkillMatrixDeps = {
68452
+ now: Date.now,
68453
+ platform: process.platform,
68454
+ arch: process.arch,
68455
+ readReport,
68456
+ plan: async (workspace, skills, signal) => JSON.parse(await command("oma", [
68457
+ "skills",
68458
+ "matrix",
68459
+ "--project-root",
68460
+ workspace,
68461
+ "--skills",
68462
+ skills.join(","),
68463
+ "--delivery",
68464
+ "injected",
68465
+ "--vendors",
68466
+ "claude,codex",
68467
+ "--json"
68468
+ ], signal)),
68469
+ cliVersion: async (vendor, signal) => {
68470
+ const version = (await command(vendor, ["--version"], signal)).trim();
68471
+ return /^[\w .()+/-]{1,160}$/.test(version) ? version : null;
68472
+ }
68473
+ };
68474
+ function parseSkillMatrix(value) {
68475
+ const parsed = matrixReportSchema.safeParse(value);
68476
+ if (!parsed.success)
68477
+ throw new Error("Matrix report uses an unsupported or malformed evidence contract. Regenerate it with the current OMA CLI.");
68478
+ const report = parsed.data;
68479
+ const unique = (values) => new Set(values).size === values.length;
68480
+ if (!unique(report.cases.map((entry) => entry.id)) || !unique(report.cells.map((entry) => `${entry.vendor}\x00${entry.caseId}`)) || report.bundle && (!unique(report.bundle.skills.map((entry) => entry.name)) || !unique(report.bundle.skills.map((entry) => entry.caseId))) || report.cells.some((cell) => !unique(cell.checks.map((check) => check.id))))
68481
+ throw new Error("Matrix report repeats a skill, case or vendor cell. Regenerate an unambiguous report.");
68482
+ return report;
68483
+ }
68484
+
68485
+ // ../../packages/core/src/oma/skill-matrix-adapter.ts
68486
+ var scope = "installed injected read-reference audit; not AV runtime or task-quality certification";
68487
+ var safeNames = /^[a-z0-9][a-z0-9-]{0,127}$/;
68488
+ var remediation = "Regenerate the installed injected matrix with explicit models, then set oma.skill_compatibility.report_path in av.yaml.";
68489
+ var matrixRouteKey = (route) => `${route.actorType}\x00${route.model ?? ""}`;
68490
+ function sourceProblem(report) {
68491
+ if (report.sourceKind !== "installed" || report.delivery !== "injected" || report.auditScope !== "read-reference" || !report.bundle)
68492
+ return "Evidence is not an installed, injected, read-reference audit. Synthetic probes cannot authorize installed skills.";
68493
+ return;
68494
+ }
68495
+ function sameCoverage(a, b) {
68496
+ const sorted = (items) => JSON.stringify([...items].sort());
68497
+ return a.hash === b.hash && a.caseId === b.caseId && sorted(a.requiredFiles) === sorted(b.requiredFiles) && sorted(a.missingFiles) === sorted(b.missingFiles) && JSON.stringify(a.excludedReferences) === JSON.stringify(b.excludedReferences);
68498
+ }
68499
+ function assessRoute(report, plan, skills, route, version) {
68500
+ const result = (status, reason) => ({
68501
+ ...route,
68502
+ status,
68503
+ reason
68504
+ });
68505
+ if (route.actorType !== "claude" && route.actorType !== "codex")
68506
+ return result("unknown", "This matrix protocol measures only Claude and Codex.");
68507
+ if (!route.model)
68508
+ return result("unknown", "The candidate uses an unpinned native model default; it cannot match a measured model.");
68509
+ if (!version)
68510
+ return result("unknown", "The current native CLI version could not be verified.");
68511
+ for (const name of skills) {
68512
+ const current = plan.bundle?.skills.find((entry) => entry.name === name);
68513
+ const saved = report.bundle?.skills.find((entry) => entry.name === name);
68514
+ if (!current || !saved)
68515
+ return result("unknown", `Skill ${name} has no complete installed audit coverage.`);
68516
+ if (!sameCoverage(current, saved))
68517
+ return result("unknown", `Skill ${name} content or reference coverage changed after the audit.`);
68518
+ if (current.missingFiles.length || current.excludedReferences.length || saved.missingFiles.length || saved.excludedReferences.length)
68519
+ return result("unknown", `Skill ${name} has missing or excluded references; complete its audit coverage first.`);
68520
+ if (!report.cases.some((entry) => entry.id === saved.caseId && entry.skill === name))
68521
+ return result("unknown", `Skill ${name} required case is absent from the measured selection.`);
68522
+ const cell = report.cells.find((entry) => entry.caseId === saved.caseId && entry.vendor === route.actorType);
68523
+ if (!cell || cell.skill !== name || cell.contentHash !== current.hash)
68524
+ return result("unknown", `Skill ${name} lacks a matching measured vendor cell.`);
68525
+ if (cell.cliVersion !== version)
68526
+ return result("unknown", `Skill ${name} was measured with a different or unknown native CLI version.`);
68527
+ if (cell.model !== route.model)
68528
+ return result("unknown", `Skill ${name} was measured with a different or unknown reported model.`);
68529
+ if (cell.status !== "pass" || !cell.checks.length || cell.checks.some((check) => check.status !== "pass"))
68530
+ return result(cell.status === "fail" ? "fail" : "unknown", `Skill ${name} audit is ${cell.status}; passing read-reference evidence is required.`);
68531
+ const entry = `${name}/SKILL.md`;
68532
+ if (!current.requiredFiles.includes(entry))
68533
+ return result("unknown", `Skill ${name} audit omits its installed SKILL.md.`);
68534
+ const required = [
68535
+ "process",
68536
+ "output",
68537
+ "content",
68538
+ "integrity",
68539
+ "reference-coverage",
68540
+ ...current.requiredFiles.filter((file) => file !== entry).map((file) => `reference:${posix.relative(name, file)}`)
68541
+ ];
68542
+ if (required.some((id) => !cell.checks.some((check) => check.id === id && check.status === "pass" && (id === "content" || id.startsWith("reference:") ? check.proof === "read" : true))))
68543
+ return result("unknown", `Skill ${name} audit lacks a mandatory successful read-reference check.`);
68544
+ }
68545
+ return result("pass", "All selected skills have current passing installed injected read-reference evidence.");
68546
+ }
68547
+ async function inspectSkillCompatibility(policy, workspace, selectedSkills, routes, deps = defaultSkillMatrixDeps, signal) {
68548
+ const unknown = (reason) => ({
68549
+ scope,
68550
+ routes: routes.map((route) => ({ ...route, status: "unknown", reason }))
68551
+ });
68552
+ if (selectedSkills?.length === 0)
68553
+ return {
68554
+ scope,
68555
+ routes: routes.map((route) => ({
68556
+ ...route,
68557
+ status: "pass",
68558
+ reason: "No skills selected; no compatibility claim is required."
68559
+ }))
68560
+ };
68561
+ try {
68562
+ if (signal?.aborted)
68563
+ throw new Error("Interrupted");
68564
+ const report = parseSkillMatrix(await deps.readReport(policy.reportPath));
68565
+ const source = sourceProblem(report);
68566
+ if (source)
68567
+ return unknown(source);
68568
+ if (report.mode !== "live" || report.status !== "completed")
68569
+ return unknown("The report is not a completed live measurement; a plan is unmeasured.");
68570
+ const age = deps.now() - Date.parse(report.createdAt);
68571
+ if (age < -60000 || age > policy.maxAgeHours * 3600000)
68572
+ return unknown("The cached matrix is stale or has a future timestamp.");
68573
+ if (report.host.platform !== deps.platform || report.host.arch !== deps.arch)
68574
+ return unknown("The matrix host platform or architecture differs from this runtime.");
68575
+ const skills = [...new Set(selectedSkills ?? report.bundle?.skills.map((entry) => entry.name) ?? [])];
68576
+ if (!skills.length || skills.length > 100 || skills.some((name) => !safeNames.test(name)))
68577
+ return unknown("Select a bounded list of valid installed skill names.");
68578
+ const plan = parseSkillMatrix(await deps.plan(workspace, skills, signal));
68579
+ if (sourceProblem(plan) || plan.mode !== "plan" || plan.status !== "planned")
68580
+ return unknown("OMA did not return a supported installed injected plan.");
68581
+ if (plan.omaVersion !== report.omaVersion)
68582
+ return unknown("The OMA version changed after measurement; refresh the cached matrix.");
68583
+ if (plan.host.platform !== deps.platform || plan.host.arch !== deps.arch)
68584
+ return unknown("The current OMA plan host does not match this runtime.");
68585
+ const versions = new Map;
68586
+ for (const route of routes) {
68587
+ if (versions.has(route.actorType) || route.actorType !== "claude" && route.actorType !== "codex")
68588
+ continue;
68589
+ try {
68590
+ versions.set(route.actorType, await deps.cliVersion(route.actorType, signal));
68591
+ } catch {
68592
+ versions.set(route.actorType, null);
68593
+ }
68594
+ }
68595
+ if (signal?.aborted)
68596
+ throw new Error("Interrupted");
68597
+ return {
68598
+ scope,
68599
+ routes: routes.map((route) => assessRoute(report, plan, skills, route, versions.get(route.actorType) ?? null))
68600
+ };
68601
+ } catch {
68602
+ if (signal?.aborted)
68603
+ throw new Error("Skill compatibility inspection interrupted before Actor launch.");
68604
+ return unknown(`The cached report or local OMA plan could not be validated. ${remediation}`);
68605
+ }
68606
+ }
68607
+ function assertCompatibleRoute(route, inspection) {
68608
+ const result = inspection.routes.find((entry) => matrixRouteKey(entry) === matrixRouteKey(route));
68609
+ if (result?.status !== "pass")
68610
+ throw new Error(`Skill compatibility required for ${route.actorType}/${route.model ?? "native default"}: ${result?.reason ?? "no matching evidence"} ${remediation}`);
68611
+ }
68612
+
68172
68613
  // ../../packages/core/src/orchestrator/agent-runner.ts
68173
68614
  init_logger();
68174
68615
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -68510,7 +68951,7 @@ class AgentRunnerService {
68510
68951
  // ../../packages/core/src/orchestrator/verification-gate.ts
68511
68952
  init_logger();
68512
68953
  init_process_tree();
68513
- import { spawn as spawn14 } from "node:child_process";
68954
+ import { spawn as spawn15 } from "node:child_process";
68514
68955
  var MAX_OUTPUT_LENGTH = 10240;
68515
68956
  var DEFAULT_TIMEOUT_SEC = 600;
68516
68957
  var defaultVerifyExec = (command, cwd, timeoutMs, signal, onSpawned) => new Promise((resolve) => {
@@ -68518,7 +68959,7 @@ var defaultVerifyExec = (command, cwd, timeoutMs, signal, onSpawned) => new Prom
68518
68959
  resolve({ exitCode: -1, output: "Verification cancelled.", timedOut: false, aborted: true });
68519
68960
  return;
68520
68961
  }
68521
- const proc = spawn14(command, {
68962
+ const proc = spawn15(command, {
68522
68963
  cwd,
68523
68964
  shell: true,
68524
68965
  detached: process.platform !== "win32",
@@ -68660,8 +69101,8 @@ async function withMissionDeadline(mission, parent, run) {
68660
69101
 
68661
69102
  // ../../packages/core/src/chief/skills.ts
68662
69103
  init_dist();
68663
- import { constants as constants5 } from "node:fs";
68664
- import { lstat as lstat11, mkdir as mkdir13, open as open7, readdir as readdir6, realpath as realpath14, stat, writeFile as writeFile10 } from "node:fs/promises";
69104
+ import { constants as constants6 } from "node:fs";
69105
+ import { lstat as lstat11, mkdir as mkdir13, open as open8, readdir as readdir6, realpath as realpath14, stat, writeFile as writeFile10 } from "node:fs/promises";
68665
69106
  import { isAbsolute as isAbsolute8, join as join26, relative as relative8, sep as sep10 } from "node:path";
68666
69107
  var MAX_SKILL_BYTES = 256000;
68667
69108
  var MAX_METADATA_BYTES = 16384;
@@ -68742,7 +69183,7 @@ async function prepareMissionSkills(sourceRepositoryPath, workspacePath) {
68742
69183
  const parent = await realpath14(targetDirectory);
68743
69184
  if (parent !== destinationRoot && !inside(destinationRoot, parent))
68744
69185
  throw new Error("A target skill resource escapes the mission worktree. Fix its symlink before creating this order.");
68745
- const file = await open7(from, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
69186
+ const file = await open8(from, constants6.O_RDONLY | constants6.O_NOFOLLOW | constants6.O_NONBLOCK);
68746
69187
  try {
68747
69188
  const current = await file.stat();
68748
69189
  if (!current.isFile())
@@ -68803,7 +69244,7 @@ async function skillPath(root, name) {
68803
69244
  return path;
68804
69245
  }
68805
69246
  async function readSkill(path, metadataOnly) {
68806
- const file = await open7(path, constants5.O_RDONLY | constants5.O_NOFOLLOW | constants5.O_NONBLOCK);
69247
+ const file = await open8(path, constants6.O_RDONLY | constants6.O_NOFOLLOW | constants6.O_NONBLOCK);
68807
69248
  try {
68808
69249
  const info = await file.stat();
68809
69250
  if (!info.isFile())
@@ -69031,11 +69472,13 @@ class ChiefRuntime {
69031
69472
  store;
69032
69473
  signal;
69033
69474
  onStage;
69475
+ skillMatrixDeps;
69034
69476
  runners = new Set;
69035
- constructor(store, signal, onStage = () => {}) {
69477
+ constructor(store, signal, onStage = () => {}, skillMatrixDeps) {
69036
69478
  this.store = store;
69037
69479
  this.signal = signal;
69038
69480
  this.onStage = onStage;
69481
+ this.skillMatrixDeps = skillMatrixDeps;
69039
69482
  }
69040
69483
  ports() {
69041
69484
  return {
@@ -69111,8 +69554,22 @@ class ChiefRuntime {
69111
69554
  };
69112
69555
  if (signal?.aborted)
69113
69556
  throw new Error("Order interrupted. Resume it with av order --resume followed by its mission ID.");
69114
- const route = stage === "work" ? selectWorkActor(mission, persona, context?.taskId) : undefined;
69557
+ const compatibilityPolicy = mission.operatingPolicy?.skillCompatibility;
69558
+ const compatibility = stage === "work" && compatibilityPolicy ? await inspectSkillCompatibility(compatibilityPolicy, workspace.path, persona.skills, workActorCandidates(mission, persona, compatibilityPolicy.mode === "require"), this.skillMatrixDeps, signal) : undefined;
69559
+ const compatibleRoutes = compatibilityPolicy?.mode === "require" && compatibility ? new Set(compatibility.routes.filter((entry) => entry.status === "pass").map(matrixRouteKey)) : undefined;
69560
+ if (compatibility && compatibilityPolicy)
69561
+ mission.history.push({
69562
+ at: new Date().toISOString(),
69563
+ stage: "skill-compatibility",
69564
+ message: `${compatibilityPolicy.mode}: ${compatibility.routes.map((entry) => `${entry.actorType}/${entry.model ?? "native default"} ${entry.status}: ${entry.reason}`).join("; ")} Scope: ${compatibility.scope}.`,
69565
+ ...context?.taskId ? { taskId: context.taskId } : {}
69566
+ });
69567
+ const route = stage === "work" ? selectWorkActor(mission, persona, context?.taskId, compatibleRoutes) : undefined;
69115
69568
  persona = route?.actor ?? persona;
69569
+ if (compatibility && compatibilityPolicy) {
69570
+ if (compatibilityPolicy.mode === "require")
69571
+ assertCompatibleRoute({ actorType: persona.agentType, model: persona.model }, compatibility);
69572
+ }
69116
69573
  this.onStage(stage, persona);
69117
69574
  const attempt = {
69118
69575
  id: randomUUID11(),
@@ -69321,7 +69778,7 @@ function continuousDirectorAdvice(mission) {
69321
69778
  init_execution();
69322
69779
 
69323
69780
  // src/chief-supervisor.ts
69324
- import { spawn as spawn15 } from "node:child_process";
69781
+ import { spawn as spawn16 } from "node:child_process";
69325
69782
  import { randomUUID as randomUUID13 } from "node:crypto";
69326
69783
  import { join as join31 } from "node:path";
69327
69784
  init_execution();
@@ -69714,19 +70171,19 @@ init_report_delivery_contract();
69714
70171
  init_zod();
69715
70172
  init_report_delivery_contract();
69716
70173
  import { createHash as createHash16, randomUUID as randomUUID12 } from "node:crypto";
69717
- import { constants as constants6 } from "node:fs";
69718
- import { mkdir as mkdir14, open as open8, readdir as readdir7, readFile as readFile11, realpath as realpath15, rename as rename6, unlink as unlink5, writeFile as writeFile11 } from "node:fs/promises";
70174
+ import { constants as constants7 } from "node:fs";
70175
+ import { mkdir as mkdir14, open as open9, readdir as readdir7, readFile as readFile11, realpath as realpath15, rename as rename6, unlink as unlink5, writeFile as writeFile11 } from "node:fs/promises";
69719
70176
  import { isAbsolute as isAbsolute9, join as join28, relative as relative9, resolve as resolve16 } from "node:path";
69720
- var hash2 = string2().regex(/^[a-f0-9]{64}$/);
70177
+ var hash3 = string2().regex(/^[a-f0-9]{64}$/);
69721
70178
  var outboxRecordSchema = strictObject({
69722
70179
  version: literal(1),
69723
- id: hash2,
70180
+ id: hash3,
69724
70181
  missionId: string2().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/),
69725
70182
  missionStatus: _enum(["completed", "failed"]),
69726
70183
  destinationId: string2().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/),
69727
70184
  channel: string2().regex(/^[a-z][a-z0-9-]{0,63}$/),
69728
- reportHash: hash2,
69729
- destinationHash: hash2.optional(),
70185
+ reportHash: hash3,
70186
+ destinationHash: hash3.optional(),
69730
70187
  goal: string2().max(32000),
69731
70188
  markdown: string2().max(256000),
69732
70189
  reportPath: string2().max(4096),
@@ -69761,7 +70218,7 @@ class ReportOutbox {
69761
70218
  this.directory = join28(stateDir, "report-outbox");
69762
70219
  }
69763
70220
  path(id) {
69764
- if (!hash2.safeParse(id).success)
70221
+ if (!hash3.safeParse(id).success)
69765
70222
  throw new Error("Invalid report receipt ID. Use av reports to find a receipt.");
69766
70223
  return join28(this.directory, `${id}.json`);
69767
70224
  }
@@ -69824,7 +70281,7 @@ async function verifiedAttachment(attachment, artifactRoot, readBytes) {
69824
70281
  throw failure;
69825
70282
  if (resolve16(attachment.path) !== attachment.path)
69826
70283
  throw failure;
69827
- const file = await open8(attachment.path, constants6.O_RDONLY | constants6.O_NOFOLLOW);
70284
+ const file = await open9(attachment.path, constants7.O_RDONLY | constants7.O_NOFOLLOW);
69828
70285
  try {
69829
70286
  const stat = await file.stat();
69830
70287
  if (!stat.isFile() || stat.size !== attachment.sizeBytes)
@@ -70162,7 +70619,7 @@ function runWorker(args, root, signal) {
70162
70619
  reject(new Error("CLI entry point is unavailable. Run av order from the installed CLI."));
70163
70620
  return;
70164
70621
  }
70165
- const child = spawn15(process.execPath, [entry, ...args], { cwd: root, stdio: "inherit" });
70622
+ const child = spawn16(process.execPath, [entry, ...args], { cwd: root, stdio: "inherit" });
70166
70623
  const interrupt = () => child.kill("SIGTERM");
70167
70624
  signal.addEventListener("abort", interrupt, { once: true });
70168
70625
  if (signal.aborted)
@@ -70359,8 +70816,8 @@ Return one valid JSON object under the original charter and pinned evidence.` :
70359
70816
 
70360
70817
  // ../../packages/core/src/chief/metric-source-adapters.ts
70361
70818
  init_metric_source_policy();
70362
- import { constants as constants7 } from "node:fs";
70363
- import { lstat as lstat12, open as open9, realpath as realpath16 } from "node:fs/promises";
70819
+ import { constants as constants8 } from "node:fs";
70820
+ import { lstat as lstat12, open as open10, realpath as realpath16 } from "node:fs/promises";
70364
70821
  import { isAbsolute as isAbsolute10, relative as relative10, resolve as resolve17, sep as sep11 } from "node:path";
70365
70822
  var MAX_METRIC_RESPONSE_BYTES = 2000000;
70366
70823
  function metricSourceEnvironment(request, name) {
@@ -70458,7 +70915,7 @@ var jsonFileMetricAdapter = {
70458
70915
  if ((await lstat12(current)).isSymbolicLink())
70459
70916
  throw new MetricSourceError("Metric file and parent directories must not be symlinks. Choose a regular JSON file inside the source repository.");
70460
70917
  }
70461
- const file = await open9(path, constants7.O_RDONLY | constants7.O_NOFOLLOW);
70918
+ const file = await open10(path, constants8.O_RDONLY | constants8.O_NOFOLLOW);
70462
70919
  try {
70463
70920
  const stat = await file.stat();
70464
70921
  if (!stat.isFile() || stat.size > MAX_METRIC_RESPONSE_BYTES || await realpath16(path) !== path)
@@ -70859,8 +71316,8 @@ function createMissionMetricPorts(repository, mission, dependencies = {}) {
70859
71316
 
70860
71317
  // src/chief-tool-config.ts
70861
71318
  import { randomUUID as randomUUID14 } from "node:crypto";
70862
- import { constants as constants8 } from "node:fs";
70863
- import { link as link2, lstat as lstat13, mkdir as mkdir16, open as open10, realpath as realpath17, unlink as unlink6 } from "node:fs/promises";
71319
+ import { constants as constants9 } from "node:fs";
71320
+ import { link as link2, lstat as lstat13, mkdir as mkdir16, open as open11, realpath as realpath17, unlink as unlink6 } from "node:fs/promises";
70864
71321
  import { join as join32 } from "node:path";
70865
71322
  init_dist2();
70866
71323
  init_client_toml();
@@ -70894,7 +71351,7 @@ async function assertLocalPath(root, local) {
70894
71351
  return true;
70895
71352
  }
70896
71353
  async function readPrivateFile(path) {
70897
- const file = await open10(path, constants8.O_RDONLY | constants8.O_NOFOLLOW);
71354
+ const file = await open11(path, constants9.O_RDONLY | constants9.O_NOFOLLOW);
70898
71355
  try {
70899
71356
  const stats = await file.stat();
70900
71357
  if (!stats.isFile() || stats.size > maximumBytes)
@@ -70957,7 +71414,7 @@ async function privateExclude(original, target, paths) {
70957
71414
  const patterns = paths.flatMap((local) => [`/${local}`, `/${local}.av-mcp-*.tmp`]).filter((pattern) => !lines.has(pattern));
70958
71415
  if (!patterns.length)
70959
71416
  return;
70960
- const file = await open10(path, constants8.O_WRONLY | constants8.O_APPEND | constants8.O_CREAT | constants8.O_NOFOLLOW, 384);
71417
+ const file = await open11(path, constants9.O_WRONLY | constants9.O_APPEND | constants9.O_CREAT | constants9.O_NOFOLLOW, 384);
70961
71418
  try {
70962
71419
  await file.writeFile(`${content && !content.endsWith(`
70963
71420
  `) ? `
@@ -71002,7 +71459,7 @@ async function prepareToolConfig(originalRepository, targetWorkspace) {
71002
71459
  continue;
71003
71460
  const path = join32(target, config.path);
71004
71461
  const temporary = `${path}.av-mcp-${randomUUID14()}.tmp`;
71005
- const file = await open10(temporary, "wx", 384);
71462
+ const file = await open11(temporary, "wx", 384);
71006
71463
  try {
71007
71464
  await file.writeFile(config.content);
71008
71465
  } finally {
@@ -71031,7 +71488,7 @@ async function prepareChiefToolConfig(originalRepository, targetWorkspace) {
71031
71488
 
71032
71489
  // src/tool-discovery.ts
71033
71490
  init_client_toml();
71034
- import { constants as constants9 } from "node:fs";
71491
+ import { constants as constants10 } from "node:fs";
71035
71492
  import { access, lstat as lstat14, readFile as readFile12, realpath as realpath18 } from "node:fs/promises";
71036
71493
  import { homedir as homedir6 } from "node:os";
71037
71494
  import { delimiter as delimiter2, isAbsolute as isAbsolute11, join as join33, resolve as resolve18 } from "node:path";
@@ -71053,7 +71510,7 @@ async function executable(name, env) {
71053
71510
  for (const directory of (env.PATH ?? "").split(delimiter2).filter(isAbsolute11)) {
71054
71511
  try {
71055
71512
  const path = join33(directory, name);
71056
- await access(path, constants9.X_OK);
71513
+ await access(path, constants10.X_OK);
71057
71514
  if ((await lstat14(await realpath18(path))).isFile())
71058
71515
  return true;
71059
71516
  } catch {}
@@ -71308,7 +71765,7 @@ async function decideContinuousGoal(operation, decisionId, root, dependencies =
71308
71765
  }
71309
71766
 
71310
71767
  // src/chief-continuous.ts
71311
- var execute = promisify2(execFile4);
71768
+ var execute = promisify2(execFile5);
71312
71769
  var orderKeys = [
71313
71770
  "workspace",
71314
71771
  "verify",
@@ -72997,7 +73454,7 @@ function selectTaskReviewer(mission, task, state) {
72997
73454
  }
72998
73455
 
72999
73456
  // ../../packages/core/src/chief/coordinator.ts
73000
- var bounded2 = (value) => value.slice(-32000);
73457
+ var bounded3 = (value) => value.slice(-32000);
73001
73458
  async function coordinate(mission, ports) {
73002
73459
  Object.assign(mission, validateMission(mission));
73003
73460
  const operatorGoal = mission.goal;
@@ -73061,7 +73518,7 @@ async function coordinate(mission, ports) {
73061
73518
  if (task.effectScope === "external" && state.effectState === "unknown")
73062
73519
  throw new MissionPause(`External effect ${task.id} has no established destination outcome and will not be repeated.`, "unknown-effect");
73063
73520
  if (task.effectScope !== "external" || state.effectState !== "completed") {
73064
- state.output = bounded2(await run(persona(task.personaId), workPrompt(mission, task, state, persona(task.personaId)), "work", task.id));
73521
+ state.output = bounded3(await run(persona(task.personaId), workPrompt(mission, task, state, persona(task.personaId)), "work", task.id));
73065
73522
  if (task.effectScope === "external")
73066
73523
  state.effectState = "completed";
73067
73524
  }
@@ -73235,7 +73692,7 @@ async function coordinate(mission, ports) {
73235
73692
  mission.fingerprint = await ports.fingerprint(mission);
73236
73693
  mission.verification = {
73237
73694
  ok: result.ok,
73238
- output: result.output ? bounded2(result.output) : undefined,
73695
+ output: result.output ? bounded3(result.output) : undefined,
73239
73696
  fingerprint: mission.fingerprint
73240
73697
  };
73241
73698
  if (mission.verificationMode === "chief" && !mission.goalVerification?.ok) {
@@ -73334,7 +73791,7 @@ async function coordinate(mission, ports) {
73334
73791
  return mission;
73335
73792
  }
73336
73793
  mission.status = "failed";
73337
- mission.error = bounded2(error instanceof Error ? error.message : String(error));
73794
+ mission.error = bounded3(error instanceof Error ? error.message : String(error));
73338
73795
  if (error instanceof ReadOnlyViolation || error instanceof ContractViolation || error instanceof CheckpointError)
73339
73796
  executionState(mission).failureKind = "integrity";
73340
73797
  if (error instanceof ReadOnlyViolation)
@@ -73351,7 +73808,7 @@ async function coordinate(mission, ports) {
73351
73808
  if (reportError instanceof ReadOnlyViolation) {
73352
73809
  executionState(mission).failureKind = "integrity";
73353
73810
  invalidate();
73354
- mission.error = bounded2(`${mission.error}
73811
+ mission.error = bounded3(`${mission.error}
73355
73812
  ${reportError.message}`);
73356
73813
  mission.report = fallbackReport(mission);
73357
73814
  }
@@ -74418,21 +74875,21 @@ function checkOma(project, deps) {
74418
74875
  let version = null;
74419
74876
  if (omaPath) {
74420
74877
  try {
74421
- version = deps.getOmaVersion?.() ?? null;
74878
+ version = parseOmaCliVersion(deps.getOmaVersion?.() ?? "") ?? null;
74422
74879
  } catch {}
74423
74880
  }
74424
- results.push(version === SUPPORTED_OMA_VERSION ? {
74881
+ results.push(version !== null ? {
74425
74882
  id: "oma.cli",
74426
- name: "OMA CLI compatibility",
74883
+ name: "OMA CLI availability",
74427
74884
  status: "pass",
74428
- message: `${omaPath} (${version})`,
74885
+ message: `${omaPath} (${version}); receipt schema v${OMA_RECEIPT_SCHEMA_VERSION} and current evidence are checked for each task`,
74429
74886
  critical: false
74430
74887
  } : {
74431
74888
  id: "oma.cli",
74432
- name: "OMA CLI compatibility",
74889
+ name: "OMA CLI availability",
74433
74890
  status: "fail",
74434
- message: omaPath ? `OMA CLI version ${version ?? "unknown"}; expected ${SUPPORTED_OMA_VERSION}` : "oma not found on PATH",
74435
- fix: `Run npm install -g oh-my-agent@${SUPPORTED_OMA_VERSION}, verify with oma --version, then rerun av doctor.`,
74891
+ message: omaPath ? "OMA CLI did not return a valid version" : "oma not found on PATH",
74892
+ fix: "Run npm install -g oh-my-agent@latest, verify with oma --version, then rerun av doctor.",
74436
74893
  critical: true
74437
74894
  });
74438
74895
  const command = project?.verify?.command?.trim();
@@ -74485,6 +74942,37 @@ function checkOma(project, deps) {
74485
74942
  return results;
74486
74943
  }
74487
74944
 
74945
+ // src/doctor-skill-matrix-checks.ts
74946
+ import { resolve as resolve26 } from "node:path";
74947
+ async function checkSkillMatrix(project, global2, deps) {
74948
+ const config = project?.oma?.skill_compatibility;
74949
+ if (!config)
74950
+ return [];
74951
+ const projectActor = project?.actor ?? project?.agent;
74952
+ const globalActor = global2?.actor ?? global2?.agent;
74953
+ const actorType = projectActor?.type ?? globalActor?.type ?? "claude";
74954
+ const model = projectActor?.model ?? (globalActor?.type === actorType ? globalActor.model : undefined);
74955
+ const inspection = await inspectSkillCompatibility({
74956
+ reportPath: resolve26(deps.cwd, config.report_path),
74957
+ maxAgeHours: config.max_age_hours,
74958
+ mode: config.mode
74959
+ }, resolve26(deps.cwd, project?.workspace?.root ?? "."), undefined, [{ actorType, model }], deps.skillMatrix);
74960
+ const route = inspection.routes[0];
74961
+ const status = route?.status ?? "unknown";
74962
+ return [
74963
+ {
74964
+ id: "oma.skill-compatibility",
74965
+ name: "OMA skill read-reference compatibility",
74966
+ status,
74967
+ message: `${config.mode}: ${actorType}/${model ?? "native default"}: ${route?.reason ?? "Evidence unavailable."} Scope: ${inspection.scope}. Work dispatch rechecks its own selected skills and candidates.`,
74968
+ ...status !== "pass" ? {
74969
+ fix: "Generate a completed installed injected matrix with explicit models and set oma.skill_compatibility.report_path in av.yaml. av doctor never runs a live matrix."
74970
+ } : {},
74971
+ critical: config.mode === "require"
74972
+ }
74973
+ ];
74974
+ }
74975
+
74488
74976
  // src/doctor-config-checks.ts
74489
74977
  function checkTunnel(project, deps) {
74490
74978
  const provider = project?.tunnel?.provider ?? "ngrok";
@@ -74739,10 +75227,11 @@ async function runDoctorChecks(deps, options = {}) {
74739
75227
  results.push(checkTunnel(project, deps));
74740
75228
  results.push(checkWebhookSecret(project));
74741
75229
  results.push(...checkOma(project, deps));
75230
+ results.push(...await checkSkillMatrix(project, global2, deps));
74742
75231
  return results;
74743
75232
  }
74744
75233
  function computeExitCode(results) {
74745
- return results.some((r) => r.critical && r.status === "fail") ? 1 : 0;
75234
+ return results.some((r) => r.critical && (r.status === "fail" || r.status === "unknown")) ? 1 : 0;
74746
75235
  }
74747
75236
  function summarize(results) {
74748
75237
  return { passed: results.filter((r) => r.status === "pass").length, total: results.length };
@@ -74817,7 +75306,7 @@ async function registerLinearWebhook(root, tunnelUrl) {
74817
75306
  init_yaml_loader();
74818
75307
  import { existsSync as existsSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync2 } from "node:fs";
74819
75308
  import { createServer as createServer3 } from "node:net";
74820
- import { resolve as resolve26 } from "node:path";
75309
+ import { resolve as resolve27 } from "node:path";
74821
75310
  import { setTimeout as delay } from "node:timers/promises";
74822
75311
 
74823
75312
  // src/webhook-proxy.ts
@@ -74932,12 +75421,12 @@ function resolveServerPort(root, runningPort) {
74932
75421
  return String(port);
74933
75422
  }
74934
75423
  function resolveRuntimePaths(root, cliDir) {
74935
- const dashboardCwd = resolve26(root, "apps/dashboard");
74936
- if (!existsSync5(resolve26(dashboardCwd, "package.json"))) {
75424
+ const dashboardCwd = resolve27(root, "apps/dashboard");
75425
+ if (!existsSync5(resolve27(dashboardCwd, "package.json"))) {
74937
75426
  throw new Error(`Dashboard source is missing at ${dashboardCwd}. Clone https://github.com/first-fluke/agent-valley, run bun install, then run bun av setup and bun av dev from that checkout. The standalone CLI does not include the dashboard.`);
74938
75427
  }
74939
- const bundled = resolve26(cliDir, "supervisor.js");
74940
- const supervisorScript = existsSync5(bundled) ? bundled : resolve26(cliDir, "supervisor.ts");
75428
+ const bundled = resolve27(cliDir, "supervisor.js");
75429
+ const supervisorScript = existsSync5(bundled) ? bundled : resolve27(cliDir, "supervisor.ts");
74941
75430
  if (!existsSync5(supervisorScript)) {
74942
75431
  throw new Error(`Supervisor is missing at ${supervisorScript}. Run bun av up from an intact Agent Valley checkout.`);
74943
75432
  }
@@ -75012,7 +75501,7 @@ async function readStatus(port) {
75012
75501
  }
75013
75502
 
75014
75503
  // src/tunnel/cloudflare.ts
75015
- import { spawn as spawn19, spawnSync as spawnSync3 } from "node:child_process";
75504
+ import { spawn as spawn20, spawnSync as spawnSync3 } from "node:child_process";
75016
75505
 
75017
75506
  // src/tunnel/types.ts
75018
75507
  function nullTunnelHandle() {
@@ -75038,7 +75527,7 @@ function spawnCloudflare(cfg, input) {
75038
75527
  return spawnQuick(port, logger);
75039
75528
  }
75040
75529
  function spawnQuick(port, logger) {
75041
- const proc = spawn19("cloudflared", ["tunnel", "--url", `http://localhost:${port}`, "--logformat", "json", "--no-autoupdate"], {
75530
+ const proc = spawn20("cloudflared", ["tunnel", "--url", `http://localhost:${port}`, "--logformat", "json", "--no-autoupdate"], {
75042
75531
  stdio: ["ignore", "pipe", "pipe"],
75043
75532
  detached: true
75044
75533
  });
@@ -75055,7 +75544,7 @@ function spawnNamed(cfg, logger) {
75055
75544
  logger.dim(" Fix: add tunnel.cloudflare.name: <tunnel-name> or switch mode to 'quick'.");
75056
75545
  return nullTunnelHandle();
75057
75546
  }
75058
- const proc = spawn19("cloudflared", ["tunnel", "run", cfg.name, "--no-autoupdate"], {
75547
+ const proc = spawn20("cloudflared", ["tunnel", "run", cfg.name, "--no-autoupdate"], {
75059
75548
  stdio: ["ignore", "pipe", "pipe"],
75060
75549
  detached: true
75061
75550
  });
@@ -75124,7 +75613,7 @@ function emitMissingBinaryWarning(logger) {
75124
75613
  }
75125
75614
 
75126
75615
  // src/tunnel/ngrok.ts
75127
- import { spawn as spawn20, spawnSync as spawnSync4 } from "node:child_process";
75616
+ import { spawn as spawn21, spawnSync as spawnSync4 } from "node:child_process";
75128
75617
  function spawnNgrok(input) {
75129
75618
  const { port, logger } = input;
75130
75619
  const which = spawnSync4("which", ["ngrok"]);
@@ -75132,7 +75621,7 @@ function spawnNgrok(input) {
75132
75621
  emitMissingBinaryWarning2(logger);
75133
75622
  return nullTunnelHandle();
75134
75623
  }
75135
- const proc = spawn20("ngrok", ["http", port, "--log", "stdout", "--log-format", "json"], {
75624
+ const proc = spawn21("ngrok", ["http", port, "--log", "stdout", "--log-format", "json"], {
75136
75625
  stdio: ["ignore", "pipe", "pipe"],
75137
75626
  detached: true
75138
75627
  });
@@ -75216,8 +75705,8 @@ function spawnTunnel(config, input) {
75216
75705
 
75217
75706
  // src/index.ts
75218
75707
  var ROOT = process.cwd();
75219
- var PID_FILE = resolve30(ROOT, ".av.pid");
75220
- var LOG_FILE = resolve30(ROOT, ".av.log");
75708
+ var PID_FILE = resolve31(ROOT, ".av.pid");
75709
+ var LOG_FILE = resolve31(ROOT, ".av.log");
75221
75710
  function ensureConfig() {
75222
75711
  if (!existsSync10(resolveProjectConfigPath(ROOT))) {
75223
75712
  console.log(import_picocolors15.default.red("No av.yaml found. Run `av setup` first."));
@@ -75263,7 +75752,7 @@ program.command("up").description("Start dashboard + orchestrator + configured t
75263
75752
  else
75264
75753
  mode = "start";
75265
75754
  }
75266
- const dashProc = spawn23("bun", [supervisorScript, dashboardCwd, port, mode], {
75755
+ const dashProc = spawn24("bun", [supervisorScript, dashboardCwd, port, mode], {
75267
75756
  cwd: ROOT,
75268
75757
  stdio: "ignore",
75269
75758
  detached: true
@@ -75344,7 +75833,7 @@ program.command("dev").description("Start in foreground (with file watching + au
75344
75833
  const startDashboard = () => {
75345
75834
  if (shuttingDown)
75346
75835
  return;
75347
- const child = spawn23("bun", ["next", "dev", "--turbopack", "-p", port, "-H", listenHost], {
75836
+ const child = spawn24("bun", ["next", "dev", "--turbopack", "-p", port, "-H", listenHost], {
75348
75837
  cwd: dashboardCwd,
75349
75838
  stdio: "inherit",
75350
75839
  env: { ...process.env, HOSTNAME: listenHost }
@@ -75433,7 +75922,7 @@ program.command("logs").description("Tail dashboard + orchestrator logs").option
75433
75922
  console.log(import_picocolors15.default.yellow("No logs found. Start with: av up"));
75434
75923
  return;
75435
75924
  }
75436
- const tail = spawn23("tail", ["-n", opts.lines, "-f", LOG_FILE], { stdio: "inherit" });
75925
+ const tail = spawn24("tail", ["-n", opts.lines, "-f", LOG_FILE], { stdio: "inherit" });
75437
75926
  process.on("SIGINT", () => {
75438
75927
  tail.kill();
75439
75928
  process.exit(0);