agent-contracts 0.11.2 → 0.11.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/README.md CHANGED
@@ -297,7 +297,7 @@ Design regressions become testable.
297
297
  * **Structured handoff definitions** with formal JSON Schema and `allOf` composition
298
298
  * **Reusable schema components** via `components.schemas` and JSON Pointer `$ref`
299
299
  * **Artifact ownership and lifecycle modeling**
300
- * **Config-driven prompt rendering**
300
+ * **Config-driven prompt rendering** with `skip_empty` support for conditional file generation
301
301
  * **Variable substitution** via `${vars.xxx}` in DSL values
302
302
  * **Inheritance with merge operators via `extends`**
303
303
  * **Guardrail definitions** for cross-cutting process constraints
@@ -865,6 +865,44 @@ This lets you generate static outputs for:
865
865
 
866
866
  all from the same resolved DSL.
867
867
 
868
+ ### Render target options
869
+
870
+ Each entry in `renders` supports these fields:
871
+
872
+ | Field | Type | Required | Description |
873
+ |-------|------|----------|-------------|
874
+ | `template` | string | yes | Path to Handlebars template |
875
+ | `context` | string | yes | Context type (see below) |
876
+ | `output` | string | yes | Output file path (supports `{<context>.id}` placeholder) |
877
+ | `include` | string[] | no | Only render these entity IDs (not with `system`) |
878
+ | `exclude` | string[] | no | Skip these entity IDs (not with `system`) |
879
+ | `skip_empty` | boolean | no | When `true`, if the rendered output is empty or whitespace-only, the file is **not written**. If the file already exists, it is **deleted**. |
880
+
881
+ #### `skip_empty` usage
882
+
883
+ `skip_empty` is useful when a single template applies to all entities of a context type, but only some entities produce meaningful output.
884
+
885
+ For example, when using `context: tool` to generate per-tool scripts, tools without an `x-script` property would produce empty files. With `skip_empty: true`, those files are simply not created:
886
+
887
+ ````yaml
888
+ renders:
889
+ - template: ./templates/tool-script.sh.hbs
890
+ context: tool
891
+ output: ./output/scripts/{tool.id}.sh
892
+ skip_empty: true
893
+ ````
894
+
895
+ ````handlebars
896
+ {{!-- tool-script.sh.hbs --}}
897
+ {{#if tool.x-script}}
898
+ {{{tool.x-script}}}
899
+ {{/if}}
900
+ ````
901
+
902
+ Tools with `x-script` get a generated script file; tools without it produce no file at all.
903
+
904
+ `skip_empty` also works with `render --check` (drift detection): when the expected output is empty, the check expects the file to **not exist** and reports drift if it does.
905
+
868
906
  ### Available context types
869
907
 
870
908
  Each `context` type provides a different rendering scope:
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(resolve7) {
163
- resolve7(value);
162
+ return value instanceof P2 ? value : new P2(function(resolve8) {
163
+ resolve8(value);
164
164
  });
165
165
  }
166
- return new (P2 || (P2 = Promise))(function(resolve7, reject) {
166
+ return new (P2 || (P2 = Promise))(function(resolve8, 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 ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
182
+ result.done ? resolve8(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(resolve7, reject) {
374
- v2 = o3[n3](v2), settle(resolve7, reject, v2.done, v2.value);
373
+ return new Promise(function(resolve8, reject) {
374
+ v2 = o3[n3](v2), settle(resolve8, reject, v2.done, v2.value);
375
375
  });
376
376
  };
377
377
  }
378
- function settle(resolve7, reject, d2, v2) {
378
+ function settle(resolve8, reject, d2, v2) {
379
379
  Promise.resolve(v2).then(function(v3) {
380
- resolve7({ value: v3, done: d2 });
380
+ resolve8({ 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(resolve7) {
13037
- resolve7(value);
13036
+ return value instanceof P2 ? value : new P2(function(resolve8) {
13037
+ resolve8(value);
13038
13038
  });
13039
13039
  }
13040
- return new (P2 || (P2 = Promise))(function(resolve7, reject) {
13040
+ return new (P2 || (P2 = Promise))(function(resolve8, 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 ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
13056
+ result.done ? resolve8(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(resolve7, reject) {
13235
- v2 = o3[n3](v2), settle(resolve7, reject, v2.done, v2.value);
13234
+ return new Promise(function(resolve8, reject) {
13235
+ v2 = o3[n3](v2), settle(resolve8, reject, v2.done, v2.value);
13236
13236
  });
13237
13237
  };
13238
13238
  }
13239
- function settle(resolve7, reject, d2, v2) {
13239
+ function settle(resolve8, reject, d2, v2) {
13240
13240
  Promise.resolve(v2).then(function(v3) {
13241
- resolve7({ value: v3, done: d2 });
13241
+ resolve8({ 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(resolve7, reject) {
15155
+ return new Body.Promise(function(resolve8, 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
- resolve7(Buffer.concat(accum, accumBytes));
15189
+ resolve8(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(resolve7, reject) {
15452
+ return new fetch.Promise(function(resolve8, 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
- resolve7(fetch(new Request(locationURL, requestOpts)));
15585
+ resolve8(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
- resolve7(response);
15606
+ resolve8(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
- resolve7(response);
15616
+ resolve8(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
- resolve7(response);
15628
+ resolve8(response);
15629
15629
  });
15630
15630
  raw.on("end", function() {
15631
15631
  if (!response) {
15632
15632
  response = new Response(body, response_options);
15633
- resolve7(response);
15633
+ resolve8(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
- resolve7(response);
15641
+ resolve8(response);
15642
15642
  return;
15643
15643
  }
15644
15644
  response = new Response(body, response_options);
15645
- resolve7(response);
15645
+ resolve8(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((resolve7, reject) => {
16358
+ return new Promise((resolve8, 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
- resolve7(data);
16364
+ resolve8(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((resolve7, reject) => {
23967
+ return await new Promise((resolve8, reject) => {
23968
23968
  fs.readFile(name, opts.encoding, (err, data) => {
23969
23969
  if (err !== null) {
23970
23970
  reject(err);
23971
23971
  } else {
23972
- resolve7(data);
23972
+ resolve8(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(resolve7) {
40857
+ return new $Promise(function(resolve8) {
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
- resolve7($then(valueWrapper, onFulfilled));
40864
+ resolve8($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(resolve7) {
41412
+ return new $Promise(function(resolve8) {
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
- resolve7(AsyncFromSyncIteratorContinuation(result));
41420
+ resolve8(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(resolve7, reject) {
41431
+ return new $Promise(function(resolve8, 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(resolve7, void 0, [iterResult]);
41436
+ Call(resolve8, 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
- resolve7(AsyncFromSyncIteratorContinuation(result));
41449
+ resolve8(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(resolve7, reject) {
41460
+ return new $Promise(function(resolve8, 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
- resolve7(AsyncFromSyncIteratorContinuation(
41477
+ resolve8(AsyncFromSyncIteratorContinuation(
41478
41478
  result
41479
41479
  /* , promiseCapability */
41480
41480
  ));
@@ -50425,6 +50425,9 @@ var require_dist13 = __commonJS({
50425
50425
  });
50426
50426
 
50427
50427
  // src/cli/cli.ts
50428
+ import { readFileSync } from "fs";
50429
+ import { fileURLToPath } from "url";
50430
+ import { resolve as resolve7, dirname as dirname7 } from "path";
50428
50431
  import { Command as Command7 } from "commander";
50429
50432
 
50430
50433
  // src/cli/commands/resolve.ts
@@ -50526,7 +50529,8 @@ var BindingOutputSchema = z3.object({
50526
50529
  inline_template: z3.string().optional(),
50527
50530
  mode: z3.enum(["write", "patch"]).default("write"),
50528
50531
  group_by: z3.string().optional(),
50529
- executable: z3.boolean().optional()
50532
+ executable: z3.boolean().optional(),
50533
+ skip_empty: z3.boolean().optional()
50530
50534
  }).passthrough().refine(
50531
50535
  (data) => !(data.template && data.inline_template),
50532
50536
  { message: "template and inline_template are mutually exclusive" }
@@ -50860,7 +50864,8 @@ var RenderTargetSchema = z14.object({
50860
50864
  context: ContextTypeSchema,
50861
50865
  output: z14.string(),
50862
50866
  include: z14.array(z14.string()).optional(),
50863
- exclude: z14.array(z14.string()).optional()
50867
+ exclude: z14.array(z14.string()).optional(),
50868
+ skip_empty: z14.boolean().optional()
50864
50869
  }).refine(
50865
50870
  (data) => !(data.include && data.exclude),
50866
50871
  { message: "include and exclude are mutually exclusive" }
@@ -53281,7 +53286,7 @@ var lintCommand = new Command3("lint").description("Run semantic lint rules on r
53281
53286
  import { Command as Command4 } from "commander";
53282
53287
 
53283
53288
  // src/renderer/renderer.ts
53284
- import { readFile as readFile4, writeFile, mkdir } from "fs/promises";
53289
+ import { readFile as readFile4, writeFile, mkdir, unlink } from "fs/promises";
53285
53290
  import { dirname as dirname5 } from "path";
53286
53291
  import Handlebars from "handlebars";
53287
53292
 
@@ -54397,6 +54402,15 @@ function buildEntityContext(dsl, context, entityId) {
54397
54402
  async function loadTemplate(templatePath) {
54398
54403
  return readFile4(templatePath, "utf8");
54399
54404
  }
54405
+ function isEffectivelyEmpty(output) {
54406
+ return output.trim().length === 0;
54407
+ }
54408
+ async function removeIfExists(filePath) {
54409
+ try {
54410
+ await unlink(filePath);
54411
+ } catch {
54412
+ }
54413
+ }
54400
54414
  async function renderFromConfig(dsl, renderTargets) {
54401
54415
  const outputFiles = [];
54402
54416
  for (const target of renderTargets) {
@@ -54405,6 +54419,10 @@ async function renderFromConfig(dsl, renderTargets) {
54405
54419
  if (target.context === "system") {
54406
54420
  const ctx = buildSystemContext(dsl);
54407
54421
  const output = compiled(ctx);
54422
+ if (target.skip_empty && isEffectivelyEmpty(output)) {
54423
+ await removeIfExists(target.output);
54424
+ continue;
54425
+ }
54408
54426
  await mkdir(dirname5(target.output), { recursive: true });
54409
54427
  await writeFile(target.output, output, "utf8");
54410
54428
  outputFiles.push(target.output);
@@ -54416,6 +54434,10 @@ async function renderFromConfig(dsl, renderTargets) {
54416
54434
  const ctx = buildEntityContext(dsl, target.context, entityId);
54417
54435
  const output = compiled(ctx);
54418
54436
  const outputPath = expandOutputPath(target.output, target.context, entityId);
54437
+ if (target.skip_empty && isEffectivelyEmpty(output)) {
54438
+ await removeIfExists(outputPath);
54439
+ continue;
54440
+ }
54419
54441
  await mkdir(dirname5(outputPath), { recursive: true });
54420
54442
  await writeFile(outputPath, output, "utf8");
54421
54443
  outputFiles.push(outputPath);
@@ -54424,6 +54446,26 @@ async function renderFromConfig(dsl, renderTargets) {
54424
54446
  }
54425
54447
  return outputFiles;
54426
54448
  }
54449
+ async function fileExists2(filePath) {
54450
+ try {
54451
+ await readFile4(filePath);
54452
+ return true;
54453
+ } catch {
54454
+ return false;
54455
+ }
54456
+ }
54457
+ function checkExpectedVsExisting(expected, outputPath, skipEmpty, diffs) {
54458
+ if (skipEmpty && isEffectivelyEmpty(expected)) {
54459
+ return fileExists2(outputPath).then((exists) => {
54460
+ if (exists) diffs.push(outputPath);
54461
+ });
54462
+ }
54463
+ return readFile4(outputPath, "utf8").then((existing) => {
54464
+ if (existing !== expected) diffs.push(outputPath);
54465
+ }).catch(() => {
54466
+ diffs.push(outputPath);
54467
+ });
54468
+ }
54427
54469
  async function checkDriftFromConfig(dsl, renderTargets) {
54428
54470
  const diffs = [];
54429
54471
  for (const target of renderTargets) {
@@ -54432,12 +54474,7 @@ async function checkDriftFromConfig(dsl, renderTargets) {
54432
54474
  if (target.context === "system") {
54433
54475
  const ctx = buildSystemContext(dsl);
54434
54476
  const expected = compiled(ctx);
54435
- try {
54436
- const existing = await readFile4(target.output, "utf8");
54437
- if (existing !== expected) diffs.push(target.output);
54438
- } catch {
54439
- diffs.push(target.output);
54440
- }
54477
+ await checkExpectedVsExisting(expected, target.output, target.skip_empty, diffs);
54441
54478
  } else {
54442
54479
  const section = getDslSection(dsl, target.context);
54443
54480
  const allIds = Object.keys(section);
@@ -54446,12 +54483,7 @@ async function checkDriftFromConfig(dsl, renderTargets) {
54446
54483
  const ctx = buildEntityContext(dsl, target.context, entityId);
54447
54484
  const expected = compiled(ctx);
54448
54485
  const outputPath = expandOutputPath(target.output, target.context, entityId);
54449
- try {
54450
- const existing = await readFile4(outputPath, "utf8");
54451
- if (existing !== expected) diffs.push(outputPath);
54452
- } catch {
54453
- diffs.push(outputPath);
54454
- }
54486
+ await checkExpectedVsExisting(expected, outputPath, target.skip_empty, diffs);
54455
54487
  }
54456
54488
  }
54457
54489
  }
@@ -54609,7 +54641,7 @@ var checkCommand = new Command5("check").description("Run full pipeline: resolve
54609
54641
  import { Command as Command6 } from "commander";
54610
54642
 
54611
54643
  // src/guardrail-generator/generator.ts
54612
- import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod } from "fs/promises";
54644
+ import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2 } from "fs/promises";
54613
54645
  import { resolve as resolve6, dirname as dirname6 } from "path";
54614
54646
  import Handlebars2 from "handlebars";
54615
54647
 
@@ -54783,6 +54815,7 @@ async function generateGuardrails(options) {
54783
54815
  });
54784
54816
  continue;
54785
54817
  }
54818
+ const shouldSkipEmpty = outputDef.skip_empty === true;
54786
54819
  if (outputDef.group_by) {
54787
54820
  const groupField = outputDef.group_by;
54788
54821
  const groups = /* @__PURE__ */ new Map();
@@ -54802,6 +54835,15 @@ async function generateGuardrails(options) {
54802
54835
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54803
54836
  const output = compiled(groupCtx);
54804
54837
  const groupTarget = resolve6(targetPath, groupKey);
54838
+ if (shouldSkipEmpty && output.trim().length === 0) {
54839
+ if (!dryRun) {
54840
+ try {
54841
+ await unlink2(groupTarget);
54842
+ } catch {
54843
+ }
54844
+ }
54845
+ continue;
54846
+ }
54805
54847
  if (!dryRun) {
54806
54848
  await mkdir2(dirname6(groupTarget), { recursive: true });
54807
54849
  await writeFile2(groupTarget, output, "utf8");
@@ -54814,14 +54856,23 @@ async function generateGuardrails(options) {
54814
54856
  } else {
54815
54857
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54816
54858
  const output = compiled(ctx);
54817
- if (!dryRun) {
54818
- await mkdir2(dirname6(targetPath), { recursive: true });
54819
- await writeFile2(targetPath, output, "utf8");
54820
- if (outputDef.executable) {
54821
- await chmod(targetPath, 493);
54859
+ if (shouldSkipEmpty && output.trim().length === 0) {
54860
+ if (!dryRun) {
54861
+ try {
54862
+ await unlink2(targetPath);
54863
+ } catch {
54864
+ }
54865
+ }
54866
+ } else {
54867
+ if (!dryRun) {
54868
+ await mkdir2(dirname6(targetPath), { recursive: true });
54869
+ await writeFile2(targetPath, output, "utf8");
54870
+ if (outputDef.executable) {
54871
+ await chmod(targetPath, 493);
54872
+ }
54822
54873
  }
54874
+ outputFiles.push(targetPath);
54823
54875
  }
54824
- outputFiles.push(targetPath);
54825
54876
  }
54826
54877
  }
54827
54878
  }
@@ -54913,8 +54964,10 @@ var generateGuardrailsCommand = new Command6("generate").description("Generate g
54913
54964
  );
54914
54965
 
54915
54966
  // src/cli/cli.ts
54967
+ var __dirname = dirname7(fileURLToPath(import.meta.url));
54968
+ var pkg = JSON.parse(readFileSync(resolve7(__dirname, "../package.json"), "utf8"));
54916
54969
  var program = new Command7();
54917
- program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version("0.0.2");
54970
+ program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version(pkg.version);
54918
54971
  program.addCommand(resolveCommand);
54919
54972
  program.addCommand(validateCommand);
54920
54973
  program.addCommand(lintCommand);