agent-contracts 0.11.0 → 0.11.1

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
@@ -1003,6 +1003,76 @@ outputs:
1003
1003
  template: ./templates/cursor-hook-wrapper.sh.hbs
1004
1004
  ````
1005
1005
 
1006
+ ### Binding inheritance
1007
+
1008
+ Binding files support `extends` for inheriting and extending a base binding, using the same mechanism as DSL-level `extends`.
1009
+
1010
+ A base binding defines shared guardrail implementations and outputs:
1011
+
1012
+ ````yaml
1013
+ # skeleton/bindings/cursor.yaml (base)
1014
+ software: cursor
1015
+ version: 1
1016
+
1017
+ guardrail_impl:
1018
+ no-force-push:
1019
+ checks:
1020
+ - hook_event: beforeShellExecution
1021
+ matcher:
1022
+ type: command_regex
1023
+ pattern: "git\\s+push\\s+.*--force"
1024
+ message: "Force push is forbidden"
1025
+
1026
+ outputs:
1027
+ policy-bundle:
1028
+ target: "{cursor_root}/guardrails/policy.json"
1029
+ mode: write
1030
+ inline_template: "{{json resolved_checks}}"
1031
+ ````
1032
+
1033
+ A project binding extends the base and adds project-specific guardrail implementations:
1034
+
1035
+ ````yaml
1036
+ # project/bindings/cursor.yaml
1037
+ extends: ../../skeleton/bindings/cursor.yaml
1038
+ software: cursor
1039
+ version: 1
1040
+
1041
+ guardrail_impl:
1042
+ lint-on-save:
1043
+ checks:
1044
+ - hook_event: afterFileEdit
1045
+ matcher:
1046
+ type: file_glob
1047
+ pattern: "**/*.{ts,tsx}"
1048
+ message: "TS file edited — lint results attached."
1049
+ ````
1050
+
1051
+ The result is a single merged binding with all guardrail implementations from both base and project.
1052
+
1053
+ Merge behavior:
1054
+
1055
+ | Field | Behavior |
1056
+ |-------|----------|
1057
+ | `software` | Project wins |
1058
+ | `guardrail_impl` | Map merge by guardrail ID (new IDs added; same ID deep-merged) |
1059
+ | `outputs` | Map merge by output ID (project overrides base) |
1060
+ | `reporting` | Deep merge (project fields override base) |
1061
+ | passthrough fields | Project wins |
1062
+
1063
+ All merge operators (`$append`, `$prepend`, `$insert_after`, `$replace`, `$remove`) work within binding `extends`, the same as DSL `extends`.
1064
+
1065
+ Chained inheritance (grandparent → parent → child) and both local path (`./`, `../`) and npm package references are supported. Circular extends are detected and rejected.
1066
+
1067
+ When using binding `extends`, the config only needs to list the child binding:
1068
+
1069
+ ````yaml
1070
+ # agent-contracts.config.yaml
1071
+ bindings:
1072
+ - ./bindings/cursor.yaml # extends base internally
1073
+ - ./bindings/git.yaml
1074
+ ````
1075
+
1006
1076
  ### Config
1007
1077
 
1008
1078
  ````yaml
package/dist/cli.js CHANGED
@@ -159,11 +159,11 @@ function __metadata(metadataKey, metadataValue) {
159
159
  }
160
160
  function __awaiter(thisArg, _arguments, P2, generator) {
161
161
  function adopt(value) {
162
- return value instanceof P2 ? value : new P2(function(resolve6) {
163
- resolve6(value);
162
+ return value instanceof P2 ? value : new P2(function(resolve7) {
163
+ resolve7(value);
164
164
  });
165
165
  }
166
- return new (P2 || (P2 = Promise))(function(resolve6, reject) {
166
+ return new (P2 || (P2 = Promise))(function(resolve7, reject) {
167
167
  function fulfilled(value) {
168
168
  try {
169
169
  step(generator.next(value));
@@ -179,7 +179,7 @@ function __awaiter(thisArg, _arguments, P2, generator) {
179
179
  }
180
180
  }
181
181
  function step(result) {
182
- result.done ? resolve6(result.value) : adopt(result.value).then(fulfilled, rejected);
182
+ result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
183
183
  }
184
184
  step((generator = generator.apply(thisArg, _arguments || [])).next());
185
185
  });
@@ -370,14 +370,14 @@ function __asyncValues(o3) {
370
370
  }, i3);
371
371
  function verb(n3) {
372
372
  i3[n3] = o3[n3] && function(v2) {
373
- return new Promise(function(resolve6, reject) {
374
- v2 = o3[n3](v2), settle(resolve6, reject, v2.done, v2.value);
373
+ return new Promise(function(resolve7, reject) {
374
+ v2 = o3[n3](v2), settle(resolve7, reject, v2.done, v2.value);
375
375
  });
376
376
  };
377
377
  }
378
- function settle(resolve6, reject, d2, v2) {
378
+ function settle(resolve7, reject, d2, v2) {
379
379
  Promise.resolve(v2).then(function(v3) {
380
- resolve6({ value: v3, done: d2 });
380
+ resolve7({ value: v3, done: d2 });
381
381
  }, reject);
382
382
  }
383
383
  }
@@ -13033,11 +13033,11 @@ function __metadata2(metadataKey, metadataValue) {
13033
13033
  }
13034
13034
  function __awaiter2(thisArg, _arguments, P2, generator) {
13035
13035
  function adopt(value) {
13036
- return value instanceof P2 ? value : new P2(function(resolve6) {
13037
- resolve6(value);
13036
+ return value instanceof P2 ? value : new P2(function(resolve7) {
13037
+ resolve7(value);
13038
13038
  });
13039
13039
  }
13040
- return new (P2 || (P2 = Promise))(function(resolve6, reject) {
13040
+ return new (P2 || (P2 = Promise))(function(resolve7, reject) {
13041
13041
  function fulfilled(value) {
13042
13042
  try {
13043
13043
  step(generator.next(value));
@@ -13053,7 +13053,7 @@ function __awaiter2(thisArg, _arguments, P2, generator) {
13053
13053
  }
13054
13054
  }
13055
13055
  function step(result) {
13056
- result.done ? resolve6(result.value) : adopt(result.value).then(fulfilled, rejected);
13056
+ result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
13057
13057
  }
13058
13058
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13059
13059
  });
@@ -13231,14 +13231,14 @@ function __asyncValues2(o3) {
13231
13231
  }, i3);
13232
13232
  function verb(n3) {
13233
13233
  i3[n3] = o3[n3] && function(v2) {
13234
- return new Promise(function(resolve6, reject) {
13235
- v2 = o3[n3](v2), settle(resolve6, reject, v2.done, v2.value);
13234
+ return new Promise(function(resolve7, reject) {
13235
+ v2 = o3[n3](v2), settle(resolve7, reject, v2.done, v2.value);
13236
13236
  });
13237
13237
  };
13238
13238
  }
13239
- function settle(resolve6, reject, d2, v2) {
13239
+ function settle(resolve7, reject, d2, v2) {
13240
13240
  Promise.resolve(v2).then(function(v3) {
13241
- resolve6({ value: v3, done: d2 });
13241
+ resolve7({ value: v3, done: d2 });
13242
13242
  }, reject);
13243
13243
  }
13244
13244
  }
@@ -15152,7 +15152,7 @@ function consumeBody() {
15152
15152
  let accum = [];
15153
15153
  let accumBytes = 0;
15154
15154
  let abort = false;
15155
- return new Body.Promise(function(resolve6, reject) {
15155
+ return new Body.Promise(function(resolve7, reject) {
15156
15156
  let resTimeout;
15157
15157
  if (_this4.timeout) {
15158
15158
  resTimeout = setTimeout(function() {
@@ -15186,7 +15186,7 @@ function consumeBody() {
15186
15186
  }
15187
15187
  clearTimeout(resTimeout);
15188
15188
  try {
15189
- resolve6(Buffer.concat(accum, accumBytes));
15189
+ resolve7(Buffer.concat(accum, accumBytes));
15190
15190
  } catch (err) {
15191
15191
  reject(new FetchError(`Could not create Buffer from response body for ${_this4.url}: ${err.message}`, "system", err));
15192
15192
  }
@@ -15449,7 +15449,7 @@ function fetch(url, opts) {
15449
15449
  throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
15450
15450
  }
15451
15451
  Body.Promise = fetch.Promise;
15452
- return new fetch.Promise(function(resolve6, reject) {
15452
+ return new fetch.Promise(function(resolve7, reject) {
15453
15453
  const request = new Request(url, opts);
15454
15454
  const options = getNodeRequestOptions(request);
15455
15455
  const send = (options.protocol === "https:" ? https : http).request;
@@ -15582,7 +15582,7 @@ function fetch(url, opts) {
15582
15582
  requestOpts.body = void 0;
15583
15583
  requestOpts.headers.delete("content-length");
15584
15584
  }
15585
- resolve6(fetch(new Request(locationURL, requestOpts)));
15585
+ resolve7(fetch(new Request(locationURL, requestOpts)));
15586
15586
  finalize();
15587
15587
  return;
15588
15588
  }
@@ -15603,7 +15603,7 @@ function fetch(url, opts) {
15603
15603
  const codings = headers.get("Content-Encoding");
15604
15604
  if (!request.compress || request.method === "HEAD" || codings === null || res.statusCode === 204 || res.statusCode === 304) {
15605
15605
  response = new Response(body, response_options);
15606
- resolve6(response);
15606
+ resolve7(response);
15607
15607
  return;
15608
15608
  }
15609
15609
  const zlibOptions = {
@@ -15613,7 +15613,7 @@ function fetch(url, opts) {
15613
15613
  if (codings == "gzip" || codings == "x-gzip") {
15614
15614
  body = body.pipe(zlib.createGunzip(zlibOptions));
15615
15615
  response = new Response(body, response_options);
15616
- resolve6(response);
15616
+ resolve7(response);
15617
15617
  return;
15618
15618
  }
15619
15619
  if (codings == "deflate" || codings == "x-deflate") {
@@ -15625,12 +15625,12 @@ function fetch(url, opts) {
15625
15625
  body = body.pipe(zlib.createInflateRaw());
15626
15626
  }
15627
15627
  response = new Response(body, response_options);
15628
- resolve6(response);
15628
+ resolve7(response);
15629
15629
  });
15630
15630
  raw.on("end", function() {
15631
15631
  if (!response) {
15632
15632
  response = new Response(body, response_options);
15633
- resolve6(response);
15633
+ resolve7(response);
15634
15634
  }
15635
15635
  });
15636
15636
  return;
@@ -15638,11 +15638,11 @@ function fetch(url, opts) {
15638
15638
  if (codings == "br" && typeof zlib.createBrotliDecompress === "function") {
15639
15639
  body = body.pipe(zlib.createBrotliDecompress());
15640
15640
  response = new Response(body, response_options);
15641
- resolve6(response);
15641
+ resolve7(response);
15642
15642
  return;
15643
15643
  }
15644
15644
  response = new Response(body, response_options);
15645
- resolve6(response);
15645
+ resolve7(response);
15646
15646
  });
15647
15647
  writeToStream(req, request);
15648
15648
  });
@@ -16355,13 +16355,13 @@ var require_file = __commonJS({
16355
16355
  Object.defineProperty(exports, "__esModule", { value: true });
16356
16356
  var fs_1 = __require("fs");
16357
16357
  function resolveFile(ref) {
16358
- return new Promise((resolve6, reject) => {
16358
+ return new Promise((resolve7, reject) => {
16359
16359
  const path = ref.href();
16360
16360
  fs_1.readFile(path, "utf8", (err, data) => {
16361
16361
  if (err) {
16362
16362
  reject(err);
16363
16363
  } else {
16364
- resolve6(data);
16364
+ resolve7(data);
16365
16365
  }
16366
16366
  });
16367
16367
  });
@@ -23964,12 +23964,12 @@ var require_reader = __commonJS({
23964
23964
  }
23965
23965
  } else {
23966
23966
  try {
23967
- return await new Promise((resolve6, reject) => {
23967
+ return await new Promise((resolve7, reject) => {
23968
23968
  fs.readFile(name, opts.encoding, (err, data) => {
23969
23969
  if (err !== null) {
23970
23970
  reject(err);
23971
23971
  } else {
23972
- resolve6(data);
23972
+ resolve7(data);
23973
23973
  }
23974
23974
  });
23975
23975
  });
@@ -40854,14 +40854,14 @@ var require_AsyncFromSyncIteratorContinuation = __commonJS({
40854
40854
  if (!$Promise) {
40855
40855
  throw new $SyntaxError("This environment does not support Promises.");
40856
40856
  }
40857
- return new $Promise(function(resolve6) {
40857
+ return new $Promise(function(resolve7) {
40858
40858
  var done = IteratorComplete(result);
40859
40859
  var value = IteratorValue(result);
40860
40860
  var valueWrapper = PromiseResolve($Promise, value);
40861
40861
  var onFulfilled = function(value2) {
40862
40862
  return CreateIteratorResultObject(value2, done);
40863
40863
  };
40864
- resolve6($then(valueWrapper, onFulfilled));
40864
+ resolve7($then(valueWrapper, onFulfilled));
40865
40865
  });
40866
40866
  };
40867
40867
  }
@@ -41409,7 +41409,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
41409
41409
  var O2 = this;
41410
41410
  SLOT.assert(O2, "[[SyncIteratorRecord]]");
41411
41411
  var argsLength = arguments.length;
41412
- return new $Promise(function(resolve6) {
41412
+ return new $Promise(function(resolve7) {
41413
41413
  var syncIteratorRecord = SLOT.get(O2, "[[SyncIteratorRecord]]");
41414
41414
  var result;
41415
41415
  if (argsLength > 0) {
@@ -41417,7 +41417,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
41417
41417
  } else {
41418
41418
  result = IteratorNext(syncIteratorRecord);
41419
41419
  }
41420
- resolve6(AsyncFromSyncIteratorContinuation(result));
41420
+ resolve7(AsyncFromSyncIteratorContinuation(result));
41421
41421
  });
41422
41422
  },
41423
41423
  "return": function() {
@@ -41428,12 +41428,12 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
41428
41428
  SLOT.assert(O2, "[[SyncIteratorRecord]]");
41429
41429
  var valueIsPresent = arguments.length > 0;
41430
41430
  var value = valueIsPresent ? arguments[0] : void 0;
41431
- return new $Promise(function(resolve6, reject) {
41431
+ return new $Promise(function(resolve7, reject) {
41432
41432
  var syncIterator = SLOT.get(O2, "[[SyncIteratorRecord]]")["[[Iterator]]"];
41433
41433
  var iteratorReturn = GetMethod(syncIterator, "return");
41434
41434
  if (typeof iteratorReturn === "undefined") {
41435
41435
  var iterResult = CreateIteratorResultObject(value, true);
41436
- Call(resolve6, void 0, [iterResult]);
41436
+ Call(resolve7, void 0, [iterResult]);
41437
41437
  return;
41438
41438
  }
41439
41439
  var result;
@@ -41446,7 +41446,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
41446
41446
  Call(reject, void 0, [new $TypeError("Iterator `return` method returned a non-object value.")]);
41447
41447
  return;
41448
41448
  }
41449
- resolve6(AsyncFromSyncIteratorContinuation(result));
41449
+ resolve7(AsyncFromSyncIteratorContinuation(result));
41450
41450
  });
41451
41451
  },
41452
41452
  "throw": function() {
@@ -41457,7 +41457,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
41457
41457
  SLOT.assert(O2, "[[SyncIteratorRecord]]");
41458
41458
  var valueIsPresent = arguments.length > 0;
41459
41459
  var value = valueIsPresent ? arguments[0] : void 0;
41460
- return new $Promise(function(resolve6, reject) {
41460
+ return new $Promise(function(resolve7, reject) {
41461
41461
  var syncIterator = SLOT.get(O2, "[[SyncIteratorRecord]]")["[[Iterator]]"];
41462
41462
  var throwMethod = GetMethod(syncIterator, "throw");
41463
41463
  if (typeof throwMethod === "undefined") {
@@ -41474,7 +41474,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
41474
41474
  Call(reject, void 0, [new $TypeError("Iterator `throw` method returned a non-object value.")]);
41475
41475
  return;
41476
41476
  }
41477
- resolve6(AsyncFromSyncIteratorContinuation(
41477
+ resolve7(AsyncFromSyncIteratorContinuation(
41478
41478
  result
41479
41479
  /* , promiseCapability */
41480
41480
  ));
@@ -50431,8 +50431,10 @@ import { Command as Command7 } from "commander";
50431
50431
  import { Command } from "commander";
50432
50432
 
50433
50433
  // src/config/binding-loader.ts
50434
- import { readFile as readFile2 } from "fs/promises";
50435
- import { parse as parseYaml2 } from "yaml";
50434
+ import { readFile as readFile3 } from "fs/promises";
50435
+ import { dirname as dirname4, resolve as resolve5 } from "path";
50436
+ import { stat as stat2 } from "fs/promises";
50437
+ import { parse as parseYaml3 } from "yaml";
50436
50438
 
50437
50439
  // src/schema/agent.ts
50438
50440
  import { z } from "zod";
@@ -50963,51 +50965,14 @@ function resolveDslPath(dirArg, dirArgDefault, config) {
50963
50965
  return resolve(dirArgDefault);
50964
50966
  }
50965
50967
 
50966
- // src/config/binding-loader.ts
50967
- async function loadBindings(bindingPaths) {
50968
- const results = [];
50969
- for (const filePath of bindingPaths) {
50970
- let content;
50971
- try {
50972
- content = await readFile2(filePath, "utf8");
50973
- } catch {
50974
- throw new ConfigLoadError(
50975
- `Failed to read binding file: ${filePath}`,
50976
- filePath
50977
- );
50978
- }
50979
- let raw;
50980
- try {
50981
- raw = parseYaml2(content);
50982
- } catch (err) {
50983
- const msg = err instanceof Error ? err.message : String(err);
50984
- throw new ConfigLoadError(
50985
- `Invalid YAML syntax in binding file ${filePath}: ${msg}`,
50986
- filePath
50987
- );
50988
- }
50989
- const result = SoftwareBindingSchema.safeParse(raw);
50990
- if (!result.success) {
50991
- const issues = result.error.issues.map((i3) => ` ${i3.path.join(".")}: ${i3.message}`).join("\n");
50992
- throw new ConfigLoadError(
50993
- `Invalid binding schema in ${filePath}:
50994
- ${issues}`,
50995
- filePath
50996
- );
50997
- }
50998
- results.push({ filePath, binding: result.data });
50999
- }
51000
- return results;
51001
- }
51002
-
51003
50968
  // src/resolver/base-resolver.ts
51004
50969
  import { resolve as resolve3, join as join2 } from "path";
51005
50970
  import { stat } from "fs/promises";
51006
50971
 
51007
50972
  // src/loader/loader.ts
51008
- import { readFile as readFile3, readdir, stat as fsStat } from "fs/promises";
50973
+ import { readFile as readFile2, readdir, stat as fsStat } from "fs/promises";
51009
50974
  import { dirname as dirname2, resolve as resolve2, join, extname } from "path";
51010
- import { parse as parseYaml3 } from "yaml";
50975
+ import { parse as parseYaml2 } from "yaml";
51011
50976
  var DslLoadError = class extends Error {
51012
50977
  constructor(message, filePath) {
51013
50978
  super(message);
@@ -51060,7 +51025,7 @@ function hasRefs(value) {
51060
51025
  async function readYaml(filePath) {
51061
51026
  let content;
51062
51027
  try {
51063
- content = await readFile3(filePath, "utf8");
51028
+ content = await readFile2(filePath, "utf8");
51064
51029
  } catch {
51065
51030
  throw new DslLoadError(
51066
51031
  `File not found: ${filePath}`,
@@ -51068,7 +51033,7 @@ async function readYaml(filePath) {
51068
51033
  );
51069
51034
  }
51070
51035
  try {
51071
- return parseYaml3(content);
51036
+ return parseYaml2(content);
51072
51037
  } catch (err) {
51073
51038
  const msg = err instanceof Error ? err.message : String(err);
51074
51039
  throw new DslLoadError(
@@ -51649,6 +51614,143 @@ function substituteVars(data, vars) {
51649
51614
  return walk(data, vars);
51650
51615
  }
51651
51616
 
51617
+ // src/config/binding-merger.ts
51618
+ function isRecord3(v2) {
51619
+ return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
51620
+ }
51621
+ var BINDING_MERGE_SECTIONS = ["guardrail_impl", "outputs"];
51622
+ function mergeBinding(base, project) {
51623
+ const hasExtends = typeof project["extends"] === "string";
51624
+ const result = { ...base, ...project };
51625
+ for (const section of BINDING_MERGE_SECTIONS) {
51626
+ const baseVal = base[section];
51627
+ const projVal = project[section];
51628
+ if (projVal === void 0) {
51629
+ continue;
51630
+ }
51631
+ const baseMap = isRecord3(baseVal) ? baseVal : {};
51632
+ result[section] = mergeEntityMaps(
51633
+ baseMap,
51634
+ projVal,
51635
+ section,
51636
+ hasExtends
51637
+ );
51638
+ }
51639
+ if (project["reporting"] !== void 0 && isRecord3(base["reporting"]) && isRecord3(project["reporting"])) {
51640
+ result["reporting"] = deepMergeEntities(
51641
+ base["reporting"],
51642
+ project["reporting"],
51643
+ "reporting",
51644
+ hasExtends
51645
+ );
51646
+ }
51647
+ delete result["extends"];
51648
+ return result;
51649
+ }
51650
+
51651
+ // src/config/binding-loader.ts
51652
+ async function loadRawBinding(filePath) {
51653
+ let content;
51654
+ try {
51655
+ content = await readFile3(filePath, "utf8");
51656
+ } catch {
51657
+ throw new ConfigLoadError(
51658
+ `Failed to read binding file: ${filePath}`,
51659
+ filePath
51660
+ );
51661
+ }
51662
+ try {
51663
+ return parseYaml3(content);
51664
+ } catch (err) {
51665
+ const msg = err instanceof Error ? err.message : String(err);
51666
+ throw new ConfigLoadError(
51667
+ `Invalid YAML syntax in binding file ${filePath}: ${msg}`,
51668
+ filePath
51669
+ );
51670
+ }
51671
+ }
51672
+ async function resolveBindingExtends(raw, filePath, seen) {
51673
+ const extendsValue = raw["extends"];
51674
+ if (typeof extendsValue !== "string") {
51675
+ return raw;
51676
+ }
51677
+ const bindingDir = dirname4(filePath);
51678
+ let basePath;
51679
+ if (extendsValue.startsWith("./") || extendsValue.startsWith("../")) {
51680
+ basePath = resolve5(bindingDir, extendsValue);
51681
+ } else {
51682
+ try {
51683
+ const resolved = import.meta.resolve(extendsValue);
51684
+ basePath = new URL(resolved).pathname;
51685
+ } catch {
51686
+ throw new ConfigLoadError(
51687
+ `Could not resolve binding extends package: ${extendsValue}`,
51688
+ filePath
51689
+ );
51690
+ }
51691
+ }
51692
+ try {
51693
+ const s2 = await stat2(basePath);
51694
+ if (s2.isDirectory()) {
51695
+ const candidates = ["binding.yaml", "binding.yml"];
51696
+ let found = false;
51697
+ for (const name of candidates) {
51698
+ const candidate = resolve5(basePath, name);
51699
+ try {
51700
+ const cs = await stat2(candidate);
51701
+ if (cs.isFile()) {
51702
+ basePath = candidate;
51703
+ found = true;
51704
+ break;
51705
+ }
51706
+ } catch {
51707
+ continue;
51708
+ }
51709
+ }
51710
+ if (!found) {
51711
+ throw new ConfigLoadError(
51712
+ `No binding.yaml found in directory: ${basePath}`,
51713
+ filePath
51714
+ );
51715
+ }
51716
+ }
51717
+ } catch (err) {
51718
+ if (err instanceof ConfigLoadError) throw err;
51719
+ throw new ConfigLoadError(
51720
+ `Base binding path not found: ${basePath}`,
51721
+ filePath
51722
+ );
51723
+ }
51724
+ if (seen.has(basePath)) {
51725
+ throw new ConfigLoadError(
51726
+ `Circular binding extends detected: ${basePath}`,
51727
+ filePath
51728
+ );
51729
+ }
51730
+ seen.add(basePath);
51731
+ const baseRaw = await loadRawBinding(basePath);
51732
+ const resolvedBase = await resolveBindingExtends(baseRaw, basePath, seen);
51733
+ return mergeBinding(resolvedBase, raw);
51734
+ }
51735
+ async function loadBindings(bindingPaths) {
51736
+ const results = [];
51737
+ for (const filePath of bindingPaths) {
51738
+ const raw = await loadRawBinding(filePath);
51739
+ const merged = await resolveBindingExtends(raw, filePath, /* @__PURE__ */ new Set([filePath]));
51740
+ const result = SoftwareBindingSchema.safeParse(merged);
51741
+ if (!result.success) {
51742
+ const issues = result.error.issues.map((i3) => ` ${i3.path.join(".")}: ${i3.message}`).join("\n");
51743
+ throw new ConfigLoadError(
51744
+ `Invalid binding schema in ${filePath}:
51745
+ ${issues}`,
51746
+ filePath
51747
+ );
51748
+ }
51749
+ results.push({ filePath, binding: result.data });
51750
+ }
51751
+ return results;
51752
+ }
51753
+
51652
51754
  // src/cli/commands/resolve.ts
51653
51755
  import { stringify } from "yaml";
51654
51756
  var DIR_DEFAULT = "agent-contracts.yaml";
@@ -53179,7 +53281,7 @@ import { Command as Command4 } from "commander";
53179
53281
 
53180
53282
  // src/renderer/renderer.ts
53181
53283
  import { readFile as readFile4, writeFile, mkdir } from "fs/promises";
53182
- import { dirname as dirname4 } from "path";
53284
+ import { dirname as dirname5 } from "path";
53183
53285
  import Handlebars from "handlebars";
53184
53286
 
53185
53287
  // src/renderer/context.ts
@@ -54302,7 +54404,7 @@ async function renderFromConfig(dsl, renderTargets) {
54302
54404
  if (target.context === "system") {
54303
54405
  const ctx = buildSystemContext(dsl);
54304
54406
  const output = compiled(ctx);
54305
- await mkdir(dirname4(target.output), { recursive: true });
54407
+ await mkdir(dirname5(target.output), { recursive: true });
54306
54408
  await writeFile(target.output, output, "utf8");
54307
54409
  outputFiles.push(target.output);
54308
54410
  } else {
@@ -54313,7 +54415,7 @@ async function renderFromConfig(dsl, renderTargets) {
54313
54415
  const ctx = buildEntityContext(dsl, target.context, entityId);
54314
54416
  const output = compiled(ctx);
54315
54417
  const outputPath = expandOutputPath(target.output, target.context, entityId);
54316
- await mkdir(dirname4(outputPath), { recursive: true });
54418
+ await mkdir(dirname5(outputPath), { recursive: true });
54317
54419
  await writeFile(outputPath, output, "utf8");
54318
54420
  outputFiles.push(outputPath);
54319
54421
  }
@@ -54507,7 +54609,7 @@ import { Command as Command6 } from "commander";
54507
54609
 
54508
54610
  // src/guardrail-generator/generator.ts
54509
54611
  import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod } from "fs/promises";
54510
- import { resolve as resolve5, dirname as dirname5 } from "path";
54612
+ import { resolve as resolve6, dirname as dirname6 } from "path";
54511
54613
  import Handlebars2 from "handlebars";
54512
54614
 
54513
54615
  // src/guardrail-generator/resolve-checks.ts
@@ -54648,7 +54750,7 @@ async function generateGuardrails(options) {
54648
54750
  if (pathResult.diagnostics.some((d2) => d2.severity === "error")) {
54649
54751
  continue;
54650
54752
  }
54651
- const targetPath = resolve5(config.configDir, pathResult.resolved);
54753
+ const targetPath = resolve6(config.configDir, pathResult.resolved);
54652
54754
  let templateContent;
54653
54755
  if (outputDef.inline_template) {
54654
54756
  templateContent = outputDef.inline_template;
@@ -54661,7 +54763,7 @@ async function generateGuardrails(options) {
54661
54763
  });
54662
54764
  continue;
54663
54765
  }
54664
- const templatePath = resolve5(config.configDir, outputDef.template);
54766
+ const templatePath = resolve6(config.configDir, outputDef.template);
54665
54767
  try {
54666
54768
  templateContent = await readFile5(templatePath, "utf8");
54667
54769
  } catch {
@@ -54698,9 +54800,9 @@ async function generateGuardrails(options) {
54698
54800
  };
54699
54801
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54700
54802
  const output = compiled(groupCtx);
54701
- const groupTarget = resolve5(targetPath, groupKey);
54803
+ const groupTarget = resolve6(targetPath, groupKey);
54702
54804
  if (!dryRun) {
54703
- await mkdir2(dirname5(groupTarget), { recursive: true });
54805
+ await mkdir2(dirname6(groupTarget), { recursive: true });
54704
54806
  await writeFile2(groupTarget, output, "utf8");
54705
54807
  if (outputDef.executable) {
54706
54808
  await chmod(groupTarget, 493);
@@ -54712,7 +54814,7 @@ async function generateGuardrails(options) {
54712
54814
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54713
54815
  const output = compiled(ctx);
54714
54816
  if (!dryRun) {
54715
- await mkdir2(dirname5(targetPath), { recursive: true });
54817
+ await mkdir2(dirname6(targetPath), { recursive: true });
54716
54818
  await writeFile2(targetPath, output, "utf8");
54717
54819
  if (outputDef.executable) {
54718
54820
  await chmod(targetPath, 493);