agent-contracts 0.22.3 → 0.22.4

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/cli.js CHANGED
@@ -49436,7 +49436,7 @@ function createProgram(handlers2, version) {
49436
49436
  }
49437
49437
  await handlers2.score(dir, opts, globalOpts);
49438
49438
  });
49439
- program2.command("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs.").argument("[type]", "Audit type to run: render (semantic diff of generated outputs vs DSL), dsl (design coherence review), prompt (generated prompt fidelity check), or all (run all three).").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--scope <entities>", "Limit audit scope to specified entities (e.g. agents:architect,implementer).").option("--dry-run", "Output the audit prompt without calling LLM.", false).option("--adapter <name>", "SDK adapter to use for LLM calls (overrides config audit.adapter).").option("--model <name>", "LLM model override (overrides config audit.model).").option("--fail-on <level>", "Minimum finding severity that causes exit 10 (info|warning|error|critical).", "critical").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Alias for --format. When both are specified, --report-format takes precedence.", "text").action(async (type, opts, cmd) => {
49439
+ program2.command("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs.").argument("[type]", "Audit type to run: render (semantic diff of generated outputs vs DSL), dsl (design coherence review), prompt (generated prompt fidelity check), extensions (unconsumed x-* property detection), or all (run all four).").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--scope <entities>", "Limit audit scope to specified entities (e.g. agents:architect,implementer).").option("--dry-run", "Output the audit prompt without calling LLM.", false).option("--adapter <name>", "SDK adapter to use for LLM calls (overrides config audit.adapter).").option("--model <name>", "LLM model override (overrides config audit.model).").option("--fail-on <level>", "Minimum finding severity that causes exit 10 (info|warning|error|critical).", "critical").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Alias for --format. When both are specified, --report-format takes precedence.", "text").action(async (type, opts, cmd) => {
49440
49440
  const globalOpts = cmd.optsWithGlobals();
49441
49441
  if (globalOpts.introspect) {
49442
49442
  const policy = deriveCommandPolicy("audit", opts);
@@ -49533,6 +49533,7 @@ var ArtifactSchema = z2.object({
49533
49533
  states: z2.array(z2.string()),
49534
49534
  required_validations: z2.array(z2.string()).default([]),
49535
49535
  visibility: z2.string().optional(),
49536
+ classification: z2.string().optional(),
49536
49537
  guardrails: z2.array(z2.string()).optional()
49537
49538
  }).passthrough();
49538
49539
 
@@ -49737,7 +49738,7 @@ var ExecutionStepSchema = z9.object({
49737
49738
  var TaskSchema = z9.object({
49738
49739
  description: z9.string(),
49739
49740
  target_agent: z9.string(),
49740
- allowed_from_agents: z9.array(z9.string()),
49741
+ allowed_from_agents: z9.array(z9.string()).default([]),
49741
49742
  workflow: z9.string(),
49742
49743
  input_artifacts: z9.array(z9.string()),
49743
49744
  invocation_handoff: z9.string(),
@@ -49810,7 +49811,8 @@ var ValidationSchema = z13.object({
49810
49811
  executor_type: z13.enum(["tool", "agent"]),
49811
49812
  executor: z13.string(),
49812
49813
  blocking: z13.boolean(),
49813
- produces_evidence: z13.string().optional()
49814
+ produces_evidence: z13.string().optional(),
49815
+ description: z13.string().optional()
49814
49816
  }).passthrough();
49815
49817
 
49816
49818
  // src/schema/workflow.ts
@@ -50194,7 +50196,8 @@ ${issues}`,
50194
50196
  bindings: [],
50195
50197
  activeGuardrailPolicy: void 0,
50196
50198
  paths: void 0,
50197
- teams: resolveTeamConfigs(config.teams, configDir)
50199
+ teams: resolveTeamConfigs(config.teams, configDir),
50200
+ audit: config.audit ?? void 0
50198
50201
  };
50199
50202
  }
50200
50203
  return {
@@ -50204,7 +50207,8 @@ ${issues}`,
50204
50207
  configDir,
50205
50208
  bindings: (config.bindings ?? []).map((b3) => resolve(configDir, b3)),
50206
50209
  activeGuardrailPolicy: config.active_guardrail_policy,
50207
- paths: config.paths
50210
+ paths: config.paths,
50211
+ audit: config.audit ?? void 0
50208
50212
  };
50209
50213
  }
50210
50214
  function resolveDslPath(dirArg, dirArgDefault, config) {
@@ -50248,7 +50252,7 @@ function deepClone(value) {
50248
50252
  }
50249
50253
  return result;
50250
50254
  }
50251
- function resolveJsonPointer(root, pointer) {
50255
+ function tryResolveJsonPointer(root, pointer) {
50252
50256
  const path = pointer.slice(2);
50253
50257
  const segments = path.split("/").map(
50254
50258
  (s2) => s2.replace(/~1/g, "/").replace(/~0/g, "~")
@@ -50262,12 +50266,19 @@ function resolveJsonPointer(root, pointer) {
50262
50266
  }
50263
50267
  current = current[segment];
50264
50268
  if (current === void 0) {
50265
- throw new DslLoadError(
50266
- `Cannot resolve JSON Pointer "${pointer}": path segment "${segment}" not found`
50267
- );
50269
+ return { found: false };
50268
50270
  }
50269
50271
  }
50270
- return current;
50272
+ return { found: true, value: current };
50273
+ }
50274
+ function resolveJsonPointer(root, pointer) {
50275
+ const result = tryResolveJsonPointer(root, pointer);
50276
+ if (!result.found) {
50277
+ throw new DslLoadError(
50278
+ `Cannot resolve JSON Pointer "${pointer}": target not found`
50279
+ );
50280
+ }
50281
+ return result.value;
50271
50282
  }
50272
50283
  function hasRefs(value) {
50273
50284
  if (!("$refs" in value)) return false;
@@ -50311,7 +50322,7 @@ function deepMergeRefs(a3, b3, sourcePath) {
50311
50322
  }
50312
50323
  return result;
50313
50324
  }
50314
- async function loadRefsSource(refPath, baseDir, resolving, rootDoc) {
50325
+ async function loadRefsSource(refPath, baseDir, resolving) {
50315
50326
  const target = resolve2(baseDir, refPath);
50316
50327
  const s2 = await fsStat(target).catch(() => null);
50317
50328
  if (s2?.isDirectory()) {
@@ -50319,7 +50330,7 @@ async function loadRefsSource(refPath, baseDir, resolving, rootDoc) {
50319
50330
  throw new DslLoadError(`Circular $refs detected: ${target}`, target);
50320
50331
  }
50321
50332
  resolving.add(target);
50322
- const result = await loadDirectoryAsMap(target, resolving, rootDoc);
50333
+ const result = await loadDirectoryAsMap(target, resolving);
50323
50334
  resolving.delete(target);
50324
50335
  return result;
50325
50336
  }
@@ -50337,16 +50348,16 @@ async function loadRefsSource(refPath, baseDir, resolving, rootDoc) {
50337
50348
  target
50338
50349
  );
50339
50350
  }
50340
- const resolved = await resolveRefsDeep(
50351
+ const resolved = await assembleRefs(
50341
50352
  content,
50342
50353
  dirname2(target),
50343
50354
  resolving,
50344
- rootDoc
50355
+ content
50345
50356
  );
50346
50357
  resolving.delete(target);
50347
50358
  return resolved;
50348
50359
  }
50349
- async function loadDirectoryAsMap(dirPath, resolving, rootDoc) {
50360
+ async function loadDirectoryAsMap(dirPath, resolving) {
50350
50361
  let entries;
50351
50362
  try {
50352
50363
  entries = await readdir(dirPath);
@@ -50373,17 +50384,17 @@ async function loadDirectoryAsMap(dirPath, resolving, rootDoc) {
50373
50384
  filePath
50374
50385
  );
50375
50386
  }
50376
- const resolved = await resolveRefsDeep(
50387
+ const resolved = await assembleRefs(
50377
50388
  content,
50378
50389
  dirPath,
50379
50390
  resolving,
50380
- rootDoc
50391
+ content
50381
50392
  );
50382
50393
  merged = deepMergeRefs(merged, resolved, filePath);
50383
50394
  }
50384
50395
  return merged;
50385
50396
  }
50386
- async function processRefs(obj, baseDir, resolving, rootDoc) {
50397
+ async function processRefs(obj, baseDir, resolving) {
50387
50398
  const refPaths = obj["$refs"];
50388
50399
  const inline = {};
50389
50400
  for (const [key, value] of Object.entries(obj)) {
@@ -50393,17 +50404,17 @@ async function processRefs(obj, baseDir, resolving, rootDoc) {
50393
50404
  }
50394
50405
  let merged = {};
50395
50406
  for (const refPath of refPaths) {
50396
- const loaded = await loadRefsSource(refPath, baseDir, resolving, rootDoc);
50407
+ const loaded = await loadRefsSource(refPath, baseDir, resolving);
50397
50408
  merged = deepMergeRefs(merged, loaded, refPath);
50398
50409
  }
50399
50410
  merged = deepMergeRefs(merged, inline, "(inline)");
50400
50411
  return merged;
50401
50412
  }
50402
- async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
50413
+ async function assembleRefs(data, baseDir, resolving, fileRoot) {
50403
50414
  if (typeof data !== "object" || data === null) return data;
50404
50415
  if (Array.isArray(data)) {
50405
50416
  return Promise.all(
50406
- data.map((item) => resolveRefsDeep(item, baseDir, resolving, rootDoc))
50417
+ data.map((item) => assembleRefs(item, baseDir, resolving, fileRoot))
50407
50418
  );
50408
50419
  }
50409
50420
  if (isRef(data)) {
@@ -50412,13 +50423,16 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
50412
50423
  if (resolving.has(refValue)) {
50413
50424
  throw new DslLoadError(`Circular $ref detected: ${refValue}`);
50414
50425
  }
50426
+ const result2 = tryResolveJsonPointer(fileRoot, refValue);
50427
+ if (!result2.found) {
50428
+ return data;
50429
+ }
50415
50430
  resolving.add(refValue);
50416
- const target = resolveJsonPointer(rootDoc, refValue);
50417
- const resolved = await resolveRefsDeep(
50418
- deepClone(target),
50431
+ const resolved = await assembleRefs(
50432
+ deepClone(result2.value),
50419
50433
  baseDir,
50420
50434
  resolving,
50421
- rootDoc
50435
+ fileRoot
50422
50436
  );
50423
50437
  resolving.delete(refValue);
50424
50438
  return resolved;
@@ -50442,7 +50456,7 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
50442
50456
  );
50443
50457
  }
50444
50458
  resolving.add(refTarget);
50445
- const result2 = await loadDirectoryAsMap(refTarget, resolving, rootDoc);
50459
+ const result2 = await loadDirectoryAsMap(refTarget, resolving);
50446
50460
  resolving.delete(refTarget);
50447
50461
  return result2;
50448
50462
  }
@@ -50457,12 +50471,12 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
50457
50471
  }
50458
50472
  resolving.add(refTarget);
50459
50473
  const content = await readYaml(refTarget);
50460
- const fileRoot = fragment ? content : rootDoc;
50461
- let fileData = await resolveRefsDeep(
50474
+ const newFileRoot = isRecord(content) ? content : fileRoot;
50475
+ let fileData = await assembleRefs(
50462
50476
  content,
50463
50477
  dirname2(refTarget),
50464
50478
  resolving,
50465
- fileRoot
50479
+ newFileRoot
50466
50480
  );
50467
50481
  resolving.delete(refTarget);
50468
50482
  if (fragment && fragment.startsWith("#/")) {
@@ -50478,11 +50492,31 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
50478
50492
  }
50479
50493
  let obj = data;
50480
50494
  if (hasRefs(obj)) {
50481
- obj = await processRefs(obj, baseDir, resolving, rootDoc);
50495
+ obj = await processRefs(obj, baseDir, resolving);
50496
+ }
50497
+ const result = {};
50498
+ for (const [key, value] of Object.entries(obj)) {
50499
+ result[key] = await assembleRefs(value, baseDir, resolving, fileRoot);
50500
+ }
50501
+ return result;
50502
+ }
50503
+ function linkDocPointers(data, rootDoc) {
50504
+ if (typeof data !== "object" || data === null) return data;
50505
+ if (Array.isArray(data)) {
50506
+ return data.map((item) => linkDocPointers(item, rootDoc));
50482
50507
  }
50508
+ if (isRef(data)) {
50509
+ const refValue = data.$ref;
50510
+ if (refValue.startsWith("#/")) {
50511
+ const target = resolveJsonPointer(rootDoc, refValue);
50512
+ return linkDocPointers(deepClone(target), rootDoc);
50513
+ }
50514
+ return data;
50515
+ }
50516
+ const obj = data;
50483
50517
  const result = {};
50484
50518
  for (const [key, value] of Object.entries(obj)) {
50485
- result[key] = await resolveRefsDeep(value, baseDir, resolving, rootDoc);
50519
+ result[key] = linkDocPointers(value, rootDoc);
50486
50520
  }
50487
50521
  return result;
50488
50522
  }
@@ -50513,13 +50547,16 @@ async function loadDsl(entryPath) {
50513
50547
  const data = raw;
50514
50548
  checkVersion(data, absPath);
50515
50549
  const baseDir = dirname2(absPath);
50516
- const resolving = /* @__PURE__ */ new Set([absPath]);
50517
- const resolved = await resolveRefsDeep(
50550
+ const assembled = await assembleRefs(
50518
50551
  data,
50519
50552
  baseDir,
50520
- resolving,
50553
+ /* @__PURE__ */ new Set([absPath]),
50521
50554
  data
50522
50555
  );
50556
+ const resolved = linkDocPointers(
50557
+ assembled,
50558
+ assembled
50559
+ );
50523
50560
  return { data: resolved, filePath: absPath };
50524
50561
  }
50525
50562
 
@@ -52316,6 +52353,7 @@ var taskAgentBindingRule = {
52316
52353
  }
52317
52354
  for (const [taskId, task] of Object.entries(dsl.tasks)) {
52318
52355
  for (const fromAgentId of task.allowed_from_agents) {
52356
+ if (fromAgentId === task.target_agent) continue;
52319
52357
  const fromAgent = dsl.agents[fromAgentId];
52320
52358
  if (fromAgent && !fromAgent.can_invoke_agents.includes(task.target_agent)) {
52321
52359
  diagnostics.push({
@@ -52890,6 +52928,176 @@ var validationExecutorNoContextRule = {
52890
52928
  }
52891
52929
  };
52892
52930
 
52931
+ // src/linter/rules/extension-consumption.ts
52932
+ function isRecord5(v2) {
52933
+ return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
52934
+ }
52935
+ function collectXUsages(dsl) {
52936
+ const usages = /* @__PURE__ */ new Map();
52937
+ function record(key, path, nodeType) {
52938
+ let list = usages.get(key);
52939
+ if (!list) {
52940
+ list = [];
52941
+ usages.set(key, list);
52942
+ }
52943
+ list.push({ path, nodeType });
52944
+ }
52945
+ function walkObj(obj, path, nodeType) {
52946
+ for (const key of Object.keys(obj)) {
52947
+ if (key.startsWith("x-") && key !== "x-extensions" && key !== "x-extensions-strict") {
52948
+ record(key, path ? `${path}.${key}` : key, nodeType);
52949
+ }
52950
+ }
52951
+ }
52952
+ walkObj(dsl, "", "root");
52953
+ if (isRecord5(dsl.system)) {
52954
+ walkObj(dsl.system, "system", "system");
52955
+ }
52956
+ for (const [id, agent] of Object.entries(dsl.agents)) {
52957
+ const agentObj = agent;
52958
+ walkObj(agentObj, `agents.${id}`, "agent");
52959
+ if (Array.isArray(agentObj["rules"])) {
52960
+ for (let i3 = 0; i3 < agentObj["rules"].length; i3++) {
52961
+ const r3 = agentObj["rules"][i3];
52962
+ if (isRecord5(r3)) walkObj(r3, `agents.${id}.rules[${i3}]`, "rule");
52963
+ }
52964
+ }
52965
+ if (Array.isArray(agentObj["escalation_criteria"])) {
52966
+ for (let i3 = 0; i3 < agentObj["escalation_criteria"].length; i3++) {
52967
+ const e3 = agentObj["escalation_criteria"][i3];
52968
+ if (isRecord5(e3)) walkObj(e3, `agents.${id}.escalation_criteria[${i3}]`, "escalation_criterion");
52969
+ }
52970
+ }
52971
+ if (Array.isArray(agentObj["prerequisites"])) {
52972
+ for (let i3 = 0; i3 < agentObj["prerequisites"].length; i3++) {
52973
+ const p2 = agentObj["prerequisites"][i3];
52974
+ if (isRecord5(p2)) walkObj(p2, `agents.${id}.prerequisites[${i3}]`, "prerequisite");
52975
+ }
52976
+ }
52977
+ }
52978
+ for (const [id, task] of Object.entries(dsl.tasks)) {
52979
+ const taskObj = task;
52980
+ walkObj(taskObj, `tasks.${id}`, "task");
52981
+ if (Array.isArray(taskObj["execution_steps"])) {
52982
+ for (let i3 = 0; i3 < taskObj["execution_steps"].length; i3++) {
52983
+ const s2 = taskObj["execution_steps"][i3];
52984
+ if (isRecord5(s2)) walkObj(s2, `tasks.${id}.execution_steps[${i3}]`, "execution_step");
52985
+ }
52986
+ }
52987
+ }
52988
+ for (const [id, art] of Object.entries(dsl.artifacts)) {
52989
+ walkObj(art, `artifacts.${id}`, "artifact");
52990
+ }
52991
+ for (const [id, tool] of Object.entries(dsl.tools)) {
52992
+ const toolObj = tool;
52993
+ walkObj(toolObj, `tools.${id}`, "tool");
52994
+ if (Array.isArray(toolObj["commands"])) {
52995
+ for (let i3 = 0; i3 < toolObj["commands"].length; i3++) {
52996
+ const c2 = toolObj["commands"][i3];
52997
+ if (isRecord5(c2)) walkObj(c2, `tools.${id}.commands[${i3}]`, "tool_command");
52998
+ }
52999
+ }
53000
+ }
53001
+ for (const [id, val] of Object.entries(dsl.validations)) {
53002
+ walkObj(val, `validations.${id}`, "validation");
53003
+ }
53004
+ for (const [id, ht] of Object.entries(dsl.handoff_types)) {
53005
+ walkObj(ht, `handoff_types.${id}`, "handoff_type");
53006
+ }
53007
+ for (const [id, wf] of Object.entries(dsl.workflow)) {
53008
+ const wfObj = wf;
53009
+ walkObj(wfObj, `workflow.${id}`, "workflow");
53010
+ if (Array.isArray(wfObj["steps"])) {
53011
+ for (let i3 = 0; i3 < wfObj["steps"].length; i3++) {
53012
+ const s2 = wfObj["steps"][i3];
53013
+ if (isRecord5(s2)) walkObj(s2, `workflow.${id}.steps[${i3}]`, "workflow_step");
53014
+ }
53015
+ }
53016
+ }
53017
+ for (const [id, pol] of Object.entries(dsl.policies)) {
53018
+ walkObj(pol, `policies.${id}`, "policy");
53019
+ }
53020
+ for (const [id, gr] of Object.entries(dsl.guardrails)) {
53021
+ walkObj(gr, `guardrails.${id}`, "guardrail");
53022
+ }
53023
+ for (const [id, gp] of Object.entries(dsl.guardrail_policies)) {
53024
+ walkObj(gp, `guardrail_policies.${id}`, "guardrail_policy");
53025
+ }
53026
+ return usages;
53027
+ }
53028
+ var extensionDeclaredButUnusedRule = {
53029
+ id: "extension-declared-unused",
53030
+ description: "Declared extension in `extensions` is never used on any entity",
53031
+ run(dsl) {
53032
+ const diagnostics = [];
53033
+ const declaredKeys = Object.keys(dsl.extensions);
53034
+ if (declaredKeys.length === 0) return diagnostics;
53035
+ const usages = collectXUsages(dsl);
53036
+ for (const key of declaredKeys) {
53037
+ if (!usages.has(key)) {
53038
+ diagnostics.push({
53039
+ ruleId: "extension-declared-unused",
53040
+ severity: "warning",
53041
+ path: `extensions.${key}`,
53042
+ message: `Extension "${key}" is declared but never used on any entity`
53043
+ });
53044
+ }
53045
+ }
53046
+ return diagnostics;
53047
+ }
53048
+ };
53049
+ var extensionScopeMismatchRule = {
53050
+ id: "extension-scope-mismatch",
53051
+ description: "Extension used on a node type outside its declared scope",
53052
+ run(dsl) {
53053
+ const diagnostics = [];
53054
+ const extensions = dsl.extensions;
53055
+ if (Object.keys(extensions).length === 0) return diagnostics;
53056
+ const usages = collectXUsages(dsl);
53057
+ for (const [key, decl] of Object.entries(extensions)) {
53058
+ const scope = decl.scope;
53059
+ if (!scope || scope.length === 0) continue;
53060
+ const scopeSet = new Set(scope);
53061
+ const keyUsages = usages.get(key);
53062
+ if (!keyUsages) continue;
53063
+ for (const usage of keyUsages) {
53064
+ if (!scopeSet.has(usage.nodeType)) {
53065
+ diagnostics.push({
53066
+ ruleId: "extension-scope-mismatch",
53067
+ severity: "warning",
53068
+ path: usage.path,
53069
+ message: `Extension "${key}" is used on ${usage.nodeType} but declared scope is [${scope.join(", ")}]`
53070
+ });
53071
+ }
53072
+ }
53073
+ }
53074
+ return diagnostics;
53075
+ }
53076
+ };
53077
+ var extensionUndeclaredUsageRule = {
53078
+ id: "extension-undeclared-usage",
53079
+ description: "Entity uses x-* property that is not declared in extensions (when extensions section exists)",
53080
+ run(dsl) {
53081
+ const diagnostics = [];
53082
+ const extensions = dsl.extensions;
53083
+ if (Object.keys(extensions).length === 0) return diagnostics;
53084
+ const declaredKeys = new Set(Object.keys(extensions));
53085
+ const usages = collectXUsages(dsl);
53086
+ for (const [key, keyUsages] of usages) {
53087
+ if (declaredKeys.has(key)) continue;
53088
+ for (const usage of keyUsages) {
53089
+ diagnostics.push({
53090
+ ruleId: "extension-undeclared-usage",
53091
+ severity: "info",
53092
+ path: usage.path,
53093
+ message: `Extension "${key}" is used but not declared in extensions \u2014 consider adding a declaration`
53094
+ });
53095
+ }
53096
+ }
53097
+ return diagnostics;
53098
+ }
53099
+ };
53100
+
52893
53101
  // src/linter/linter.ts
52894
53102
  var builtinRules = [
52895
53103
  validationCoverageRule,
@@ -52906,7 +53114,10 @@ var builtinRules = [
52906
53114
  entityGuardrailUndefinedRule,
52907
53115
  entityNoGuardrailsRule,
52908
53116
  guardrailOrphanedRule,
52909
- validationExecutorNoContextRule
53117
+ validationExecutorNoContextRule,
53118
+ extensionDeclaredButUnusedRule,
53119
+ extensionScopeMismatchRule,
53120
+ extensionUndeclaredUsageRule
52910
53121
  ];
52911
53122
  function lint(dsl, rules = builtinRules) {
52912
53123
  const diagnostics = [];
@@ -55839,6 +56050,121 @@ function formatDslOverview(dsl) {
55839
56050
  `- Validations: ${Object.keys(dsl.validations).join(", ")}`
55840
56051
  ].join("\n");
55841
56052
  }
56053
+ function isRecord6(v2) {
56054
+ return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
56055
+ }
56056
+ function collectAllXUsages(dsl) {
56057
+ const entries = [];
56058
+ function walk2(obj, path, nodeType) {
56059
+ for (const key of Object.keys(obj)) {
56060
+ if (key.startsWith("x-") && key !== "x-extensions" && key !== "x-extensions-strict") {
56061
+ entries.push({ path: path ? `${path}.${key}` : key, nodeType, key });
56062
+ }
56063
+ }
56064
+ }
56065
+ walk2(dsl, "", "root");
56066
+ if (isRecord6(dsl.system)) walk2(dsl.system, "system", "system");
56067
+ for (const [id, a3] of Object.entries(dsl.agents))
56068
+ walk2(a3, `agents.${id}`, "agent");
56069
+ for (const [id, t3] of Object.entries(dsl.tasks))
56070
+ walk2(t3, `tasks.${id}`, "task");
56071
+ for (const [id, a3] of Object.entries(dsl.artifacts))
56072
+ walk2(a3, `artifacts.${id}`, "artifact");
56073
+ for (const [id, t3] of Object.entries(dsl.tools))
56074
+ walk2(t3, `tools.${id}`, "tool");
56075
+ for (const [id, v2] of Object.entries(dsl.validations))
56076
+ walk2(v2, `validations.${id}`, "validation");
56077
+ for (const [id, h2] of Object.entries(dsl.handoff_types))
56078
+ walk2(h2, `handoff_types.${id}`, "handoff_type");
56079
+ for (const [id, w2] of Object.entries(dsl.workflow))
56080
+ walk2(w2, `workflow.${id}`, "workflow");
56081
+ for (const [id, p2] of Object.entries(dsl.policies))
56082
+ walk2(p2, `policies.${id}`, "policy");
56083
+ for (const [id, g2] of Object.entries(dsl.guardrails))
56084
+ walk2(g2, `guardrails.${id}`, "guardrail");
56085
+ for (const [id, gp] of Object.entries(dsl.guardrail_policies))
56086
+ walk2(gp, `guardrail_policies.${id}`, "guardrail_policy");
56087
+ return entries;
56088
+ }
56089
+ function extractTemplateXReferences(config) {
56090
+ const refs = [];
56091
+ try {
56092
+ const { readFileSync: readFileSync3 } = __require("fs");
56093
+ for (const target of config.renders) {
56094
+ try {
56095
+ const content = readFileSync3(target.template, "utf8");
56096
+ const matches = content.matchAll(/\{\{[^}]*?(x-[\w-]+)[^}]*?\}\}/g);
56097
+ for (const m2 of matches) refs.push(m2[1]);
56098
+ } catch {
56099
+ }
56100
+ }
56101
+ } catch {
56102
+ }
56103
+ return [...new Set(refs)];
56104
+ }
56105
+ function buildExtensionsContext(dsl, config) {
56106
+ const parts = [];
56107
+ parts.push("## Extension Declarations");
56108
+ const declaredKeys = Object.keys(dsl.extensions);
56109
+ if (declaredKeys.length === 0) {
56110
+ parts.push("(No extensions declared in `extensions` section)");
56111
+ } else {
56112
+ parts.push("```yaml\n" + yaml.stringify({ extensions: dsl.extensions }) + "```");
56113
+ }
56114
+ parts.push("## x-* Usage Map");
56115
+ const usages = collectAllXUsages(dsl);
56116
+ if (usages.length === 0) {
56117
+ parts.push("(No x-* properties found on any entity)");
56118
+ } else {
56119
+ const byKey = /* @__PURE__ */ new Map();
56120
+ for (const u2 of usages) {
56121
+ let list = byKey.get(u2.key);
56122
+ if (!list) {
56123
+ list = [];
56124
+ byKey.set(u2.key, list);
56125
+ }
56126
+ list.push(u2);
56127
+ }
56128
+ const lines = ["| Extension | Node Type | Path |", "|-----------|-----------|------|"];
56129
+ for (const [key, entries] of byKey) {
56130
+ for (const e3 of entries) {
56131
+ lines.push(`| ${key} | ${e3.nodeType} | ${e3.path} |`);
56132
+ }
56133
+ }
56134
+ parts.push(lines.join("\n"));
56135
+ }
56136
+ parts.push("## Template x-* References");
56137
+ const templateRefs = extractTemplateXReferences(config);
56138
+ if (templateRefs.length === 0) {
56139
+ parts.push("(No x-* references found in render templates, or no templates configured)");
56140
+ } else {
56141
+ parts.push(templateRefs.map((r3) => `- ${r3}`).join("\n"));
56142
+ }
56143
+ parts.push("## Runtime Codegen Fixed Fields");
56144
+ parts.push(
56145
+ "The agent-contracts-runtime codegen templates emit only these fixed fields (x-* properties are not included in generated TypeScript contracts):\n- **AgentContract**: id, role_name, purpose, mode, dispatch_only, can_read_artifacts, can_write_artifacts, can_execute_tools, can_invoke_agents, can_return_handoffs, responsibilities, constraints, rules, escalation_criteria\n- **TaskContract**: id, description, target_agent, allowed_from_agents, workflow, invocation_handoff, result_handoff, input_artifacts, responsibilities, completion_criteria, optional\n- **WorkflowContract**: id, description, trigger, entry_conditions, steps"
56146
+ );
56147
+ const declaredSet = new Set(declaredKeys);
56148
+ const usedKeys = new Set(usages.map((u2) => u2.key));
56149
+ const templateRefSet = new Set(templateRefs);
56150
+ parts.push("## Gap Summary");
56151
+ const gaps = [];
56152
+ for (const key of declaredKeys) {
56153
+ if (!usedKeys.has(key)) gaps.push(`- **${key}**: declared but never populated on any entity`);
56154
+ }
56155
+ for (const key of usedKeys) {
56156
+ if (declaredKeys.length > 0 && !declaredSet.has(key))
56157
+ gaps.push(`- **${key}**: used on entities but not declared in extensions`);
56158
+ if (!templateRefSet.has(key))
56159
+ gaps.push(`- **${key}**: populated on entities but not referenced in any render template`);
56160
+ }
56161
+ if (gaps.length === 0) {
56162
+ parts.push("(No obvious gaps detected by static analysis)");
56163
+ } else {
56164
+ parts.push(gaps.join("\n"));
56165
+ }
56166
+ return parts.join("\n\n");
56167
+ }
55842
56168
  async function buildAuditContext(auditType, dsl, config) {
55843
56169
  const sections = [];
55844
56170
  sections.push(formatDslOverview(dsl));
@@ -55859,6 +56185,9 @@ ${entry.content}`);
55859
56185
  sections.push("(No rendered agent prompt files found. Run `agent-contracts render` first.)");
55860
56186
  }
55861
56187
  }
56188
+ if (auditType === "extensions") {
56189
+ sections.push(buildExtensionsContext(dsl, config));
56190
+ }
55862
56191
  if (auditType === "dsl") {
55863
56192
  sections.push("## Agent Definitions");
55864
56193
  for (const [agentId, agentDef] of Object.entries(dsl.agents)) {
@@ -55925,7 +56254,8 @@ var dslAuditor = {
55925
56254
  "Prioritize improvement recommendations (P0/P1/P2) with concrete fix proposals",
55926
56255
  "Report score-based improvement areas as audit recommendations (read-only; consumes dsl-score-report produced by dsl-designer)",
55927
56256
  "Review DSL design for semantic coherence (role overlap, scope breadth, gate placement)",
55928
- "Verify generated prompts faithfully represent DSL intent (no hallucinated permissions)"
56257
+ "Verify generated prompts faithfully represent DSL intent (no hallucinated permissions)",
56258
+ "Audit x-* extension consumption across render templates and runtime codegen paths"
55929
56259
  ],
55930
56260
  constraints: [
55931
56261
  "Do not directly modify DSL definitions (read-only analysis)",
@@ -56186,12 +56516,14 @@ var auditSemanticDesign = {
56186
56516
  "Verify handoff schemas carry sufficient fields for task completion_criteria",
56187
56517
  "Check workflow gates are placed effectively",
56188
56518
  "Detect guardrails declared but absent from execution path",
56189
- "Check semantic validations are distributed across phases"
56519
+ "Check semantic validations are distributed across phases",
56520
+ "Detect custom x- properties that replicate standard DSL control-flow features (gate, decision, entry_conditions)"
56190
56521
  ],
56191
56522
  completion_criteria: [
56192
56523
  "All agents reviewed for scope and overlap",
56193
56524
  "Workflow gate placement analyzed",
56194
56525
  "Guardrail enforcement path verified",
56526
+ "Custom x- property misuse flagged",
56195
56527
  "Findings classified with severity and category"
56196
56528
  ],
56197
56529
  optional: false
@@ -56224,6 +56556,35 @@ var auditGeneratedPrompts = {
56224
56556
  ],
56225
56557
  optional: false
56226
56558
  };
56559
+ var auditExtensionConsumption = {
56560
+ id: "audit-extension-consumption",
56561
+ description: "Audit declared x-* extensions for consumption gaps across render and runtime paths",
56562
+ target_agent: "dsl-auditor",
56563
+ allowed_from_agents: [
56564
+ "dsl-auditor"
56565
+ ],
56566
+ workflow: "dsl-audit",
56567
+ invocation_handoff: "dsl-task-request",
56568
+ result_handoff: "dsl-audit-result",
56569
+ input_artifacts: [
56570
+ "dsl-source",
56571
+ "dsl-generated-output"
56572
+ ],
56573
+ responsibilities: [
56574
+ "Cross-check extensions declarations against entity x-* usage",
56575
+ "Identify x-* properties populated in DSL but not consumed by any render template",
56576
+ "Detect semantic overlap between x-* extensions and standard DSL features",
56577
+ "Report runtime codegen reachability for each extension",
56578
+ "Distinguish intentional metadata-only extensions from consumption gaps"
56579
+ ],
56580
+ completion_criteria: [
56581
+ "All declared extensions checked for template and runtime consumption",
56582
+ "Unused extensions flagged with suggested action (remove, migrate to standard, or add template support)",
56583
+ "Runtime-unreachable extensions documented with explanation",
56584
+ "Findings classified with severity and category"
56585
+ ],
56586
+ optional: false
56587
+ };
56227
56588
  var taskRegistry = {
56228
56589
  "update-dsl-definitions": updateDslDefinitions,
56229
56590
  "update-dsl-binding": updateDslBinding,
@@ -56231,7 +56592,8 @@ var taskRegistry = {
56231
56592
  "check-dsl-score": checkDslScore,
56232
56593
  "audit-dsl-completeness": auditDslCompleteness,
56233
56594
  "audit-semantic-design": auditSemanticDesign,
56234
- "audit-generated-prompts": auditGeneratedPrompts
56595
+ "audit-generated-prompts": auditGeneratedPrompts,
56596
+ "audit-extension-consumption": auditExtensionConsumption
56235
56597
  };
56236
56598
 
56237
56599
  // src/generated/dsl-base/handoffs.ts
@@ -56253,8 +56615,44 @@ var DslTaskResultSchema = z20.object({
56253
56615
  score_dimensions: z20.record(z20.string(), z20.unknown()).optional(),
56254
56616
  notes: z20.string().optional()
56255
56617
  });
56618
+ var AuditResultSchema = z20.object({
56619
+ summary: z20.string(),
56620
+ riskLevel: z20.enum(["low", "medium", "high", "critical"]),
56621
+ findings: z20.array(z20.object({
56622
+ id: z20.string().optional(),
56623
+ severity: z20.enum(["info", "warning", "error", "critical"]),
56624
+ category: z20.string(),
56625
+ target: z20.string().optional(),
56626
+ location: z20.string().optional(),
56627
+ message: z20.string(),
56628
+ recommendation: z20.string().optional(),
56629
+ confidence: z20.number().optional(),
56630
+ evidence: z20.array(z20.object({
56631
+ kind: z20.enum(["file", "command", "schema", "diff", "stdout", "stderr", "text"]),
56632
+ target: z20.string().optional(),
56633
+ location: z20.string().optional(),
56634
+ excerpt: z20.string().optional()
56635
+ })).optional(),
56636
+ details: z20.record(z20.string(), z20.unknown()).optional()
56637
+ })),
56638
+ recommendedActions: z20.array(z20.object({
56639
+ kind: z20.enum(["run_command", "edit_file", "review", "confirm", "block", "ignore"]),
56640
+ title: z20.string(),
56641
+ command: z20.string().optional(),
56642
+ target: z20.string().optional(),
56643
+ rationale: z20.string().optional()
56644
+ })).optional(),
56645
+ metadata: z20.object({
56646
+ tool: z20.string().optional(),
56647
+ command: z20.string().optional(),
56648
+ version: z20.string().optional(),
56649
+ generatedAt: z20.string().optional(),
56650
+ adapter: z20.string().optional(),
56651
+ model: z20.string().optional()
56652
+ }).optional()
56653
+ });
56256
56654
  var DslAuditResultSchema = z20.object({
56257
- audit_type: z20.enum(["completeness", "semantic", "prompt"]),
56655
+ audit_type: z20.enum(["completeness", "semantic", "prompt", "extensions"]),
56258
56656
  total_dimensions: z20.number(),
56259
56657
  pass_count: z20.number(),
56260
56658
  miss_count: z20.number(),
@@ -56278,6 +56676,7 @@ var DslAuditResultSchema = z20.object({
56278
56676
  var handoffSchemas = {
56279
56677
  "dsl-task-request": DslTaskRequestSchema,
56280
56678
  "dsl-task-result": DslTaskResultSchema,
56679
+ "audit-result": AuditResultSchema,
56281
56680
  "dsl-audit-result": DslAuditResultSchema
56282
56681
  };
56283
56682
 
@@ -56330,7 +56729,8 @@ async function createAdapter(runtimePkg, name, config) {
56330
56729
  var AUDIT_TYPE_TO_TASK = {
56331
56730
  render: "audit-dsl-completeness",
56332
56731
  dsl: "audit-semantic-design",
56333
- prompt: "audit-generated-prompts"
56732
+ prompt: "audit-generated-prompts",
56733
+ extensions: "audit-extension-consumption"
56334
56734
  };
56335
56735
  async function runAudit(dsl, config, auditConfig, options) {
56336
56736
  const taskId = AUDIT_TYPE_TO_TASK[options.auditType];
@@ -56384,7 +56784,7 @@ async function runAudit(dsl, config, auditConfig, options) {
56384
56784
  };
56385
56785
  }
56386
56786
  async function runAllAudits(dsl, config, auditConfig, options) {
56387
- const types = ["render", "dsl", "prompt"];
56787
+ const types = ["render", "dsl", "prompt", "extensions"];
56388
56788
  const results = [];
56389
56789
  for (const auditType of types) {
56390
56790
  results.push(await runAudit(dsl, config, auditConfig, { ...options, auditType }));
@@ -57092,7 +57492,7 @@ ${issues}
57092
57492
  process.exit(1);
57093
57493
  }
57094
57494
  };
57095
- var AUDIT_TYPES = ["render", "dsl", "prompt", "all"];
57495
+ var AUDIT_TYPES = ["render", "dsl", "prompt", "extensions", "all"];
57096
57496
  function parseAuditConfig(configObj) {
57097
57497
  if (!configObj) return {};
57098
57498
  const audit = configObj;