agent-contracts 0.6.0 → 0.7.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/README.md CHANGED
@@ -244,6 +244,7 @@ Design regressions become testable.
244
244
  * **Structured handoff definitions**
245
245
  * **Artifact ownership and lifecycle modeling**
246
246
  * **Config-driven prompt rendering**
247
+ * **Variable substitution** via `${vars.xxx}` in DSL values
247
248
  * **Inheritance with merge operators via `extends`**
248
249
  * **Flexible file splitting** via `$ref` (replacement) and `$refs` (import + deep-merge)
249
250
  * **JSON Schema for editor support and external tooling**
@@ -533,6 +534,67 @@ Supported merge operators:
533
534
 
534
535
  ---
535
536
 
537
+ ## Variable substitution
538
+
539
+ When using `extends` to share a base DSL across projects, base definitions often contain values that differ per project (project name, language, repository URL, etc.).
540
+
541
+ `vars` in `agent-contracts.config.yaml` lets you define project-specific values that are substituted into DSL string values using `${vars.xxx}` syntax.
542
+
543
+ ### Defining vars
544
+
545
+ Add a `vars` section to your config file. Values must be flat string key-value pairs.
546
+
547
+ ````yaml
548
+ # agent-contracts.config.yaml
549
+ vars:
550
+ project_name: "my-service"
551
+ language: "TypeScript"
552
+ repo_url: "https://github.com/org/my-service"
553
+ ````
554
+
555
+ ### Using placeholders in DSL
556
+
557
+ Use `${vars.<key>}` in any string value within the DSL YAML (base or project).
558
+
559
+ ````yaml
560
+ # base/agent-contracts.yaml
561
+ agents:
562
+ implementer:
563
+ purpose: "Implements features for ${vars.project_name}"
564
+ constraints:
565
+ - "Use ${vars.language} for all implementations"
566
+ - "Repository: ${vars.repo_url}"
567
+ ````
568
+
569
+ ### Processing order
570
+
571
+ Variable substitution happens **after** DSL resolution (`extends` merge) and **before** schema validation:
572
+
573
+ 1. Load config (including `vars`)
574
+ 2. Resolve DSL (load + merge `extends`)
575
+ 3. Substitute `${vars.xxx}` in all string values
576
+ 4. Validate schema
577
+ 5. Render / lint / check
578
+
579
+ This ensures that merged strings from both base and project are substituted, and the resulting values pass schema validation.
580
+
581
+ ### Error handling
582
+
583
+ If a placeholder references an undefined variable, the command exits with an error:
584
+
585
+ ````
586
+ VarsSubstitutionError: Undefined variable "repo_url" in value "Repository: ${vars.repo_url}"
587
+ Defined vars: project_name, language
588
+ ````
589
+
590
+ ### Notes
591
+
592
+ - Only string values are substituted; object keys are not affected.
593
+ - `vars` is optional. If omitted, no substitution occurs.
594
+ - Patterns that do not match `${vars.<key>}` (e.g. `${env.HOME}`, `$vars.xxx`, `{{vars.xxx}}`) are left unchanged.
595
+
596
+ ---
597
+
536
598
  ## CLI
537
599
 
538
600
  ### Installation
@@ -576,6 +638,11 @@ Rendering is configured via `agent-contracts.config.yaml`.
576
638
  ````yaml
577
639
  dsl: ./agent-contracts.yaml
578
640
 
641
+ vars:
642
+ project_name: "my-service"
643
+ language: "TypeScript"
644
+ repo_url: "https://github.com/org/my-service"
645
+
579
646
  renders:
580
647
  - template: ./templates/agent-prompt.md.hbs
581
648
  context: agent
@@ -597,6 +664,67 @@ This lets you generate static outputs for:
597
664
 
598
665
  all from the same resolved DSL.
599
666
 
667
+ ### Available context types
668
+
669
+ Each `context` type provides a different rendering scope:
670
+
671
+ | Context | Scope | Output | Key variables |
672
+ |---------|-------|--------|---------------|
673
+ | `system` | Single file | `output` as-is | `system`, `dsl` |
674
+ | `agent` | Per agent | `{agent.id}` in output path | `agent`, `receivableTasks`, `delegatableTasks`, `relatedArtifacts`, `relatedTools`, `relatedHandoffTypes`, `mergedBehavior`, `dsl` |
675
+ | `task` | Per task | `{task.id}` in output path | `task`, `targetAgent`, `dsl` |
676
+ | `artifact` | Per artifact | `{artifact.id}` in output path | `artifact`, `relatedTools`, `relatedValidations`, `producerAgents`, `consumerAgents`, `editorAgents`, `createdInWorkflows`, `dsl` |
677
+ | `tool` | Per tool | `{tool.id}` in output path | `tool`, `invokableAgents`, `inputArtifactDetails`, `outputArtifactDetails`, `dsl` |
678
+ | `validation` | Per validation | `{validation.id}` in output path | `validation`, `dsl` |
679
+ | `handoff_type` | Per handoff type | `{handoff_type.id}` in output path | `handoff_type`, `relatedTasks`, `dsl` |
680
+ | `workflow` | Per workflow phase | `{workflow.id}` in output path | `workflow`, `relatedAgents`, `relatedTasks`, `relatedTools`, `relatedArtifacts`, `relatedValidations`, `dsl` |
681
+ | `policy` | Per policy | `{policy.id}` in output path | `policy`, `dsl` |
682
+
683
+ #### Enriched context details
684
+
685
+ **`workflow` context** collects all entities involved in a phase:
686
+
687
+ * `relatedTasks` — tasks where `task.workflow` matches this phase
688
+ * `relatedAgents` — agents from task `target_agent`, `allowed_from_agents`, step `from_agent`, and validation executors
689
+ * `relatedTools` — tools from `can_execute_tools` of all related agents
690
+ * `relatedArtifacts` — artifacts from `can_read_artifacts`, `can_write_artifacts`, and `input_artifacts`
691
+ * `relatedValidations` — validations referenced in workflow steps
692
+
693
+ **`artifact` context** provides ownership and cross-reference data:
694
+
695
+ * `relatedTools` — tools with this artifact in `input_artifacts` or `output_artifacts`
696
+ * `relatedValidations` — validations targeting this artifact
697
+ * `producerAgents` / `consumerAgents` / `editorAgents` — resolved agent records
698
+ * `createdInWorkflows` — workflow phases where this artifact is written
699
+
700
+ **`tool` context** resolves agent and artifact references:
701
+
702
+ * `invokableAgents` — agents listed in `invokable_by`
703
+ * `inputArtifactDetails` / `outputArtifactDetails` — resolved artifact records
704
+
705
+ ### Handlebars helpers
706
+
707
+ Templates can use these built-in helpers:
708
+
709
+ | Helper | Usage | Description |
710
+ |--------|-------|-------------|
711
+ | `eq` | `{{#if (eq a b)}}` | Strict equality |
712
+ | `notEmpty` | `{{#if (notEmpty obj)}}` | True when object has at least one key |
713
+ | `inc` | `{{inc @index}}` | Increment number by 1 (for 1-based indexing) |
714
+ | `yamlBlock` | `{{{yamlBlock obj}}}` | Render value as YAML-formatted text |
715
+ | `lookupPayloadFields` | `{{#each (lookupPayloadFields payload)}}` | Extract payload field info (name, type, required, enum) |
716
+ | `join` | `{{join arr ", "}}` | Join array elements with separator |
717
+ | `contains` | `{{#if (contains arr "x")}}` | True when array includes value |
718
+ | `groupBy` | `{{#with (groupBy arr "key")}}` | Group array elements by field value |
719
+ | `filterByField` | `{{#each (filterByField arr "field" "val")}}` | Filter array by field match |
720
+ | `keys` | `{{#each (keys obj)}}` | Object keys as array |
721
+ | `values` | `{{#each (values obj)}}` | Object values as array |
722
+ | `size` | `{{size obj}}` | Array length or object key count |
723
+ | `not` | `{{#if (not x)}}` | Boolean negation |
724
+ | `or` | `{{#if (or a b)}}` | Boolean OR (variadic) |
725
+ | `and` | `{{#if (and a b)}}` | Boolean AND (variadic) |
726
+ | `gt` / `gte` / `lt` | `{{#if (gt a b)}}` | Numeric comparisons |
727
+
600
728
  ---
601
729
 
602
730
  ## Validation model
package/dist/cli.js CHANGED
@@ -11927,7 +11927,7 @@ var require_getJsonPathForPosition = __commonJS({
11927
11927
  return;
11928
11928
  return path;
11929
11929
  };
11930
- function* walk(node) {
11930
+ function* walk2(node) {
11931
11931
  switch (node.kind) {
11932
11932
  case types_1.Kind.MAP:
11933
11933
  if (node.mappings.length !== 0) {
@@ -11988,7 +11988,7 @@ var require_getJsonPathForPosition = __commonJS({
11988
11988
  return node;
11989
11989
  }
11990
11990
  function findClosestScalar(container, offset, line, lineMap) {
11991
- for (const node of walk(container)) {
11991
+ for (const node of walk2(container)) {
11992
11992
  if (node.startPosition <= offset && offset <= node.endPosition) {
11993
11993
  return node.kind === types_1.Kind.SCALAR ? node : findClosestScalar(node, offset, line, lineMap);
11994
11994
  }
@@ -58342,6 +58342,7 @@ var RenderTargetSchema = z.object({
58342
58342
  );
58343
58343
  var AgentContractsConfigSchema = z.object({
58344
58344
  dsl: z.string(),
58345
+ vars: z.record(z.string(), z.string()).optional(),
58345
58346
  renders: z.array(RenderTargetSchema).min(1)
58346
58347
  });
58347
58348
 
@@ -58410,6 +58411,7 @@ ${issues}`,
58410
58411
  const config = result.data;
58411
58412
  return {
58412
58413
  dsl: resolve(configDir, config.dsl),
58414
+ vars: config.vars,
58413
58415
  renders: config.renders.map((r3) => ({
58414
58416
  ...r3,
58415
58417
  template: resolve(configDir, r3.template),
@@ -58980,6 +58982,50 @@ async function resolve4(projectDirOrFile) {
58980
58982
  };
58981
58983
  }
58982
58984
 
58985
+ // src/resolver/substitute-vars.ts
58986
+ var VAR_PATTERN = /\$\{vars\.([a-zA-Z0-9_-]+)\}/g;
58987
+ var VarsSubstitutionError = class extends Error {
58988
+ constructor(varName, sourceValue, definedVars) {
58989
+ const defined = definedVars.length > 0 ? definedVars.join(", ") : "(none)";
58990
+ super(
58991
+ `Undefined variable "${varName}" in value "${sourceValue}"
58992
+ Defined vars: ${defined}`
58993
+ );
58994
+ this.varName = varName;
58995
+ this.sourceValue = sourceValue;
58996
+ this.definedVars = definedVars;
58997
+ this.name = "VarsSubstitutionError";
58998
+ }
58999
+ varName;
59000
+ sourceValue;
59001
+ definedVars;
59002
+ };
59003
+ function substituteString(value, vars) {
59004
+ return value.replace(VAR_PATTERN, (match, varName) => {
59005
+ if (!(varName in vars)) {
59006
+ throw new VarsSubstitutionError(varName, value, Object.keys(vars));
59007
+ }
59008
+ return vars[varName];
59009
+ });
59010
+ }
59011
+ function walk(data, vars) {
59012
+ if (typeof data === "string") return substituteString(data, vars);
59013
+ if (Array.isArray(data)) return data.map((item) => walk(item, vars));
59014
+ if (data !== null && typeof data === "object") {
59015
+ const result = {};
59016
+ for (const [key, value] of Object.entries(
59017
+ data
59018
+ )) {
59019
+ result[key] = walk(value, vars);
59020
+ }
59021
+ return result;
59022
+ }
59023
+ return data;
59024
+ }
59025
+ function substituteVars(data, vars) {
59026
+ return walk(data, vars);
59027
+ }
59028
+
58983
59029
  // src/cli/commands/resolve.ts
58984
59030
  import { stringify } from "yaml";
58985
59031
  var DIR_DEFAULT = "agent-contracts.yaml";
@@ -58988,10 +59034,11 @@ var resolveCommand = new Command("resolve").description("Resolve DSL (load + mer
58988
59034
  const config = await loadConfig(opts.config);
58989
59035
  const dslPath = resolveDslPath(dir, DIR_DEFAULT, config);
58990
59036
  const result = await resolve4(dslPath);
59037
+ const data = config?.vars ? substituteVars(result.data, config.vars) : result.data;
58991
59038
  if (opts.format === "json") {
58992
- process.stdout.write(JSON.stringify(result.data, null, 2) + "\n");
59039
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
58993
59040
  } else {
58994
- process.stdout.write(stringify(result.data));
59041
+ process.stdout.write(stringify(data));
58995
59042
  }
58996
59043
  } catch (err) {
58997
59044
  const msg = err instanceof Error ? err.message : String(err);
@@ -59512,7 +59559,8 @@ var validateCommand = new Command2("validate").description("Validate DSL against
59512
59559
  const config = await loadConfig(opts.config);
59513
59560
  const dslPath = resolveDslPath(dir, DIR_DEFAULT2, config);
59514
59561
  const resolved = await resolve4(dslPath);
59515
- const schemaResult = validateSchema(resolved.data);
59562
+ const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
59563
+ const schemaResult = validateSchema(data);
59516
59564
  if (!schemaResult.success) {
59517
59565
  const output = formatDiagnostics(schemaResult.diagnostics, opts);
59518
59566
  if (output) process.stderr.write(output + "\n");
@@ -60376,7 +60424,8 @@ var lintCommand = new Command3("lint").description("Run semantic lint rules on r
60376
60424
  const config = await loadConfig(opts.config);
60377
60425
  const dslPath = resolveDslPath(dir, DIR_DEFAULT3, config);
60378
60426
  const resolved = await resolve4(dslPath);
60379
- const schemaResult = validateSchema(resolved.data);
60427
+ const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
60428
+ const schemaResult = validateSchema(data);
60380
60429
  if (!schemaResult.success) {
60381
60430
  const output = formatDiagnostics(schemaResult.diagnostics, {
60382
60431
  format: opts.format,
@@ -60434,12 +60483,76 @@ function buildTaskContext(dsl, taskId) {
60434
60483
  function buildArtifactContext(dsl, artifactId) {
60435
60484
  const artifactDef = dsl.artifacts[artifactId];
60436
60485
  const artifact = { ...artifactDef, id: artifactId };
60437
- return { artifact, dsl };
60486
+ const relatedTools = {};
60487
+ for (const [id, tool] of Object.entries(dsl.tools)) {
60488
+ if (tool.input_artifacts.includes(artifactId) || tool.output_artifacts.includes(artifactId)) {
60489
+ relatedTools[id] = tool;
60490
+ }
60491
+ }
60492
+ const relatedValidations = {};
60493
+ for (const [id, val] of Object.entries(dsl.validations)) {
60494
+ if (val.target_artifact === artifactId) {
60495
+ relatedValidations[id] = val;
60496
+ }
60497
+ }
60498
+ const pickAgents = (ids) => {
60499
+ const result = {};
60500
+ for (const id of ids) {
60501
+ if (dsl.agents[id]) result[id] = dsl.agents[id];
60502
+ }
60503
+ return result;
60504
+ };
60505
+ const producerAgents = pickAgents(artifactDef.producers);
60506
+ const consumerAgents = pickAgents(artifactDef.consumers);
60507
+ const editorAgents = pickAgents(artifactDef.editors);
60508
+ const createdInWorkflows = [];
60509
+ for (const [_taskId, task] of Object.entries(dsl.tasks)) {
60510
+ if (createdInWorkflows.includes(task.workflow)) continue;
60511
+ const targetAgent = dsl.agents[task.target_agent];
60512
+ if (targetAgent?.can_write_artifacts.includes(artifactId)) {
60513
+ createdInWorkflows.push(task.workflow);
60514
+ continue;
60515
+ }
60516
+ const steps = task.execution_steps ?? [];
60517
+ for (const step of steps) {
60518
+ if (step["produces_artifact"] === artifactId) {
60519
+ createdInWorkflows.push(task.workflow);
60520
+ break;
60521
+ }
60522
+ }
60523
+ }
60524
+ return {
60525
+ artifact,
60526
+ relatedTools,
60527
+ relatedValidations,
60528
+ producerAgents,
60529
+ consumerAgents,
60530
+ editorAgents,
60531
+ createdInWorkflows,
60532
+ dsl
60533
+ };
60438
60534
  }
60439
60535
  function buildToolContext(dsl, toolId) {
60440
60536
  const toolDef = dsl.tools[toolId];
60441
60537
  const tool = { ...toolDef, id: toolId };
60442
- return { tool, dsl };
60538
+ const invokableAgents = {};
60539
+ for (const agentId of toolDef.invokable_by) {
60540
+ if (dsl.agents[agentId]) invokableAgents[agentId] = dsl.agents[agentId];
60541
+ }
60542
+ const pickArtifacts = (ids) => {
60543
+ const result = {};
60544
+ for (const id of ids) {
60545
+ if (dsl.artifacts[id]) result[id] = dsl.artifacts[id];
60546
+ }
60547
+ return result;
60548
+ };
60549
+ return {
60550
+ tool,
60551
+ invokableAgents,
60552
+ inputArtifactDetails: pickArtifacts(toolDef.input_artifacts),
60553
+ outputArtifactDetails: pickArtifacts(toolDef.output_artifacts),
60554
+ dsl
60555
+ };
60443
60556
  }
60444
60557
  function buildValidationContext(dsl, validationId) {
60445
60558
  const validationDef = dsl.validations[validationId];
@@ -60457,7 +60570,76 @@ function buildHandoffTypeContext(dsl, handoffTypeId) {
60457
60570
  function buildWorkflowContext(dsl, workflowId) {
60458
60571
  const wfDef = dsl.workflow[workflowId];
60459
60572
  const workflow = { ...wfDef, id: workflowId };
60460
- return { workflow, dsl };
60573
+ const relatedTasks = Object.entries(dsl.tasks).filter(([, t3]) => t3.workflow === workflowId).map(([id, t3]) => ({ ...t3, id }));
60574
+ const agentIds = /* @__PURE__ */ new Set();
60575
+ for (const task of relatedTasks) {
60576
+ agentIds.add(task.target_agent);
60577
+ for (const fromAgent of task.allowed_from_agents) {
60578
+ agentIds.add(fromAgent);
60579
+ }
60580
+ }
60581
+ for (const step of wfDef.steps) {
60582
+ if (step.type === "handoff" && step.from_agent) {
60583
+ agentIds.add(step.from_agent);
60584
+ }
60585
+ if (step.type === "validation") {
60586
+ const val = dsl.validations[step.validation];
60587
+ if (val?.executor_type === "agent" && val.executor) {
60588
+ agentIds.add(val.executor);
60589
+ }
60590
+ }
60591
+ }
60592
+ const relatedAgents = {};
60593
+ for (const id of agentIds) {
60594
+ if (dsl.agents[id]) relatedAgents[id] = dsl.agents[id];
60595
+ }
60596
+ const toolIds = /* @__PURE__ */ new Set();
60597
+ for (const id of agentIds) {
60598
+ const agent = dsl.agents[id];
60599
+ if (agent) {
60600
+ for (const toolId of agent.can_execute_tools) {
60601
+ toolIds.add(toolId);
60602
+ }
60603
+ }
60604
+ }
60605
+ const relatedTools = {};
60606
+ for (const id of toolIds) {
60607
+ if (dsl.tools[id]) relatedTools[id] = dsl.tools[id];
60608
+ }
60609
+ const artifactIds = /* @__PURE__ */ new Set();
60610
+ for (const task of relatedTasks) {
60611
+ for (const artId of task.input_artifacts) artifactIds.add(artId);
60612
+ }
60613
+ for (const id of agentIds) {
60614
+ const agent = dsl.agents[id];
60615
+ if (agent) {
60616
+ for (const artId of agent.can_read_artifacts) artifactIds.add(artId);
60617
+ for (const artId of agent.can_write_artifacts) artifactIds.add(artId);
60618
+ }
60619
+ }
60620
+ const relatedArtifacts = {};
60621
+ for (const id of artifactIds) {
60622
+ if (dsl.artifacts[id]) relatedArtifacts[id] = dsl.artifacts[id];
60623
+ }
60624
+ const validationIds = /* @__PURE__ */ new Set();
60625
+ for (const step of wfDef.steps) {
60626
+ if (step.type === "validation") {
60627
+ validationIds.add(step.validation);
60628
+ }
60629
+ }
60630
+ const relatedValidations = {};
60631
+ for (const id of validationIds) {
60632
+ if (dsl.validations[id]) relatedValidations[id] = dsl.validations[id];
60633
+ }
60634
+ return {
60635
+ workflow,
60636
+ relatedAgents,
60637
+ relatedTasks,
60638
+ relatedTools,
60639
+ relatedArtifacts,
60640
+ relatedValidations,
60641
+ dsl
60642
+ };
60461
60643
  }
60462
60644
  function buildPolicyContext(dsl, policyId) {
60463
60645
  const policyDef = dsl.policies[policyId];
@@ -60572,6 +60754,11 @@ function buildPerAgentContext(dsl, agent) {
60572
60754
 
60573
60755
  // src/renderer/renderer.ts
60574
60756
  Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
60757
+ Handlebars.registerHelper("notEmpty", (obj) => {
60758
+ if (!obj || typeof obj !== "object") return false;
60759
+ return Object.keys(obj).length > 0;
60760
+ });
60761
+ Handlebars.registerHelper("inc", (val) => val + 1);
60575
60762
  Handlebars.registerHelper(
60576
60763
  "lookupPayloadFields",
60577
60764
  (payload) => {
@@ -60660,6 +60847,72 @@ function toYamlLines(obj, indent) {
60660
60847
  Handlebars.registerHelper("yamlBlock", (obj) => {
60661
60848
  return toYamlLines(obj, 0).join("\n");
60662
60849
  });
60850
+ Handlebars.registerHelper(
60851
+ "join",
60852
+ (arr, separator) => {
60853
+ if (!Array.isArray(arr)) return "";
60854
+ const sep = typeof separator === "string" ? separator : ", ";
60855
+ return arr.join(sep);
60856
+ }
60857
+ );
60858
+ Handlebars.registerHelper("contains", (arr, value) => {
60859
+ if (!Array.isArray(arr)) return false;
60860
+ return arr.includes(value);
60861
+ });
60862
+ Handlebars.registerHelper(
60863
+ "groupBy",
60864
+ (arr, key) => {
60865
+ if (!Array.isArray(arr)) return {};
60866
+ const result = {};
60867
+ for (const item of arr) {
60868
+ const k2 = String(
60869
+ item?.[key] ?? "undefined"
60870
+ );
60871
+ (result[k2] ??= []).push(item);
60872
+ }
60873
+ return result;
60874
+ }
60875
+ );
60876
+ Handlebars.registerHelper(
60877
+ "keys",
60878
+ (obj) => {
60879
+ if (!obj || typeof obj !== "object") return [];
60880
+ return Object.keys(obj);
60881
+ }
60882
+ );
60883
+ Handlebars.registerHelper(
60884
+ "values",
60885
+ (obj) => {
60886
+ if (!obj || typeof obj !== "object") return [];
60887
+ return Object.values(obj);
60888
+ }
60889
+ );
60890
+ Handlebars.registerHelper(
60891
+ "filterByField",
60892
+ (arr, field, value) => {
60893
+ if (!Array.isArray(arr)) return [];
60894
+ return arr.filter(
60895
+ (item) => item?.[field] === value
60896
+ );
60897
+ }
60898
+ );
60899
+ Handlebars.registerHelper("not", (value) => !value);
60900
+ Handlebars.registerHelper("or", (...args) => {
60901
+ const _options = args.pop();
60902
+ return args.some((a3) => !!a3);
60903
+ });
60904
+ Handlebars.registerHelper("and", (...args) => {
60905
+ const _options = args.pop();
60906
+ return args.every((a3) => !!a3);
60907
+ });
60908
+ Handlebars.registerHelper("gt", (a3, b3) => a3 > b3);
60909
+ Handlebars.registerHelper("gte", (a3, b3) => a3 >= b3);
60910
+ Handlebars.registerHelper("lt", (a3, b3) => a3 < b3);
60911
+ Handlebars.registerHelper("size", (obj) => {
60912
+ if (Array.isArray(obj)) return obj.length;
60913
+ if (obj && typeof obj === "object") return Object.keys(obj).length;
60914
+ return 0;
60915
+ });
60663
60916
  function getDslSection(dsl, context) {
60664
60917
  const sectionMap = {
60665
60918
  agent: dsl.agents,
@@ -60782,7 +61035,8 @@ var renderCommand = new Command4("render").description("Render resolved DSL with
60782
61035
  process.exit(1);
60783
61036
  }
60784
61037
  const resolved = await resolve4(config.dsl);
60785
- const schemaResult = validateSchema(resolved.data);
61038
+ const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
61039
+ const schemaResult = validateSchema(data);
60786
61040
  if (!schemaResult.success) {
60787
61041
  process.stderr.write(
60788
61042
  "Schema validation failed. Run 'agent-contracts validate' for details.\n"
@@ -60847,7 +61101,8 @@ var checkCommand = new Command5("check").description("Run full pipeline: resolve
60847
61101
  process.exit(1);
60848
61102
  }
60849
61103
  const resolved = await resolve4(config.dsl);
60850
- const schemaResult = validateSchema(resolved.data);
61104
+ const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
61105
+ const schemaResult = validateSchema(data);
60851
61106
  if (!schemaResult.success) {
60852
61107
  const output = formatDiagnostics(schemaResult.diagnostics, {
60853
61108
  format: opts.format,