agent-contracts 0.11.2 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -136,6 +136,7 @@ declare const BindingOutputSchema: z.ZodObject<{
136
136
  }>>;
137
137
  group_by: z.ZodOptional<z.ZodString>;
138
138
  executable: z.ZodOptional<z.ZodBoolean>;
139
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
139
140
  }, z.core.$loose>;
140
141
  type BindingOutput = z.infer<typeof BindingOutputSchema>;
141
142
  declare const ReportingSchema: z.ZodObject<{
@@ -177,6 +178,7 @@ declare const SoftwareBindingSchema: z.ZodObject<{
177
178
  }>>;
178
179
  group_by: z.ZodOptional<z.ZodString>;
179
180
  executable: z.ZodOptional<z.ZodBoolean>;
181
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
180
182
  }, z.core.$loose>>>;
181
183
  reporting: z.ZodOptional<z.ZodObject<{
182
184
  commands: z.ZodRecord<z.ZodString, z.ZodString>;
@@ -947,6 +949,7 @@ declare const RenderTargetSchema: z.ZodObject<{
947
949
  output: z.ZodString;
948
950
  include: z.ZodOptional<z.ZodArray<z.ZodString>>;
949
951
  exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
952
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
950
953
  }, z.core.$strip>;
951
954
  type RenderTarget = z.infer<typeof RenderTargetSchema>;
952
955
  declare const AgentContractsConfigSchema: z.ZodObject<{
@@ -970,6 +973,7 @@ declare const AgentContractsConfigSchema: z.ZodObject<{
970
973
  output: z.ZodString;
971
974
  include: z.ZodOptional<z.ZodArray<z.ZodString>>;
972
975
  exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
976
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
973
977
  }, z.core.$strip>>;
974
978
  bindings: z.ZodDefault<z.ZodArray<z.ZodString>>;
975
979
  active_guardrail_policy: z.ZodOptional<z.ZodString>;
@@ -982,6 +986,7 @@ interface ResolvedRenderTarget {
982
986
  output: string;
983
987
  include?: string[];
984
988
  exclude?: string[];
989
+ skip_empty?: boolean;
985
990
  }
986
991
  interface ResolvedConfig {
987
992
  dsl: string;
package/dist/index.js CHANGED
@@ -50513,7 +50513,8 @@ var BindingOutputSchema = z3.object({
50513
50513
  inline_template: z3.string().optional(),
50514
50514
  mode: z3.enum(["write", "patch"]).default("write"),
50515
50515
  group_by: z3.string().optional(),
50516
- executable: z3.boolean().optional()
50516
+ executable: z3.boolean().optional(),
50517
+ skip_empty: z3.boolean().optional()
50517
50518
  }).passthrough().refine(
50518
50519
  (data) => !(data.template && data.inline_template),
50519
50520
  { message: "template and inline_template are mutually exclusive" }
@@ -52828,7 +52829,7 @@ async function spectralLint(dslObject) {
52828
52829
  }
52829
52830
 
52830
52831
  // src/renderer/renderer.ts
52831
- import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
52832
+ import { readFile as readFile2, writeFile, mkdir, unlink } from "fs/promises";
52832
52833
  import { dirname as dirname3 } from "path";
52833
52834
  import Handlebars from "handlebars";
52834
52835
 
@@ -53959,6 +53960,15 @@ function buildEntityContext(dsl, context, entityId) {
53959
53960
  async function loadTemplate(templatePath) {
53960
53961
  return readFile2(templatePath, "utf8");
53961
53962
  }
53963
+ function isEffectivelyEmpty(output) {
53964
+ return output.trim().length === 0;
53965
+ }
53966
+ async function removeIfExists(filePath) {
53967
+ try {
53968
+ await unlink(filePath);
53969
+ } catch {
53970
+ }
53971
+ }
53962
53972
  async function renderFromConfig(dsl, renderTargets) {
53963
53973
  const outputFiles = [];
53964
53974
  for (const target of renderTargets) {
@@ -53967,6 +53977,10 @@ async function renderFromConfig(dsl, renderTargets) {
53967
53977
  if (target.context === "system") {
53968
53978
  const ctx = buildSystemContext(dsl);
53969
53979
  const output = compiled(ctx);
53980
+ if (target.skip_empty && isEffectivelyEmpty(output)) {
53981
+ await removeIfExists(target.output);
53982
+ continue;
53983
+ }
53970
53984
  await mkdir(dirname3(target.output), { recursive: true });
53971
53985
  await writeFile(target.output, output, "utf8");
53972
53986
  outputFiles.push(target.output);
@@ -53978,6 +53992,10 @@ async function renderFromConfig(dsl, renderTargets) {
53978
53992
  const ctx = buildEntityContext(dsl, target.context, entityId);
53979
53993
  const output = compiled(ctx);
53980
53994
  const outputPath = expandOutputPath(target.output, target.context, entityId);
53995
+ if (target.skip_empty && isEffectivelyEmpty(output)) {
53996
+ await removeIfExists(outputPath);
53997
+ continue;
53998
+ }
53981
53999
  await mkdir(dirname3(outputPath), { recursive: true });
53982
54000
  await writeFile(outputPath, output, "utf8");
53983
54001
  outputFiles.push(outputPath);
@@ -53986,6 +54004,26 @@ async function renderFromConfig(dsl, renderTargets) {
53986
54004
  }
53987
54005
  return outputFiles;
53988
54006
  }
54007
+ async function fileExists(filePath) {
54008
+ try {
54009
+ await readFile2(filePath);
54010
+ return true;
54011
+ } catch {
54012
+ return false;
54013
+ }
54014
+ }
54015
+ function checkExpectedVsExisting(expected, outputPath, skipEmpty, diffs) {
54016
+ if (skipEmpty && isEffectivelyEmpty(expected)) {
54017
+ return fileExists(outputPath).then((exists) => {
54018
+ if (exists) diffs.push(outputPath);
54019
+ });
54020
+ }
54021
+ return readFile2(outputPath, "utf8").then((existing) => {
54022
+ if (existing !== expected) diffs.push(outputPath);
54023
+ }).catch(() => {
54024
+ diffs.push(outputPath);
54025
+ });
54026
+ }
53989
54027
  async function checkDriftFromConfig(dsl, renderTargets) {
53990
54028
  const diffs = [];
53991
54029
  for (const target of renderTargets) {
@@ -53994,12 +54032,7 @@ async function checkDriftFromConfig(dsl, renderTargets) {
53994
54032
  if (target.context === "system") {
53995
54033
  const ctx = buildSystemContext(dsl);
53996
54034
  const expected = compiled(ctx);
53997
- try {
53998
- const existing = await readFile2(target.output, "utf8");
53999
- if (existing !== expected) diffs.push(target.output);
54000
- } catch {
54001
- diffs.push(target.output);
54002
- }
54035
+ await checkExpectedVsExisting(expected, target.output, target.skip_empty, diffs);
54003
54036
  } else {
54004
54037
  const section = getDslSection(dsl, target.context);
54005
54038
  const allIds = Object.keys(section);
@@ -54008,12 +54041,7 @@ async function checkDriftFromConfig(dsl, renderTargets) {
54008
54041
  const ctx = buildEntityContext(dsl, target.context, entityId);
54009
54042
  const expected = compiled(ctx);
54010
54043
  const outputPath = expandOutputPath(target.output, target.context, entityId);
54011
- try {
54012
- const existing = await readFile2(outputPath, "utf8");
54013
- if (existing !== expected) diffs.push(outputPath);
54014
- } catch {
54015
- diffs.push(outputPath);
54016
- }
54044
+ await checkExpectedVsExisting(expected, outputPath, target.skip_empty, diffs);
54017
54045
  }
54018
54046
  }
54019
54047
  }
@@ -54055,7 +54083,8 @@ var RenderTargetSchema = z16.object({
54055
54083
  context: ContextTypeSchema,
54056
54084
  output: z16.string(),
54057
54085
  include: z16.array(z16.string()).optional(),
54058
- exclude: z16.array(z16.string()).optional()
54086
+ exclude: z16.array(z16.string()).optional(),
54087
+ skip_empty: z16.boolean().optional()
54059
54088
  }).refine(
54060
54089
  (data) => !(data.include && data.exclude),
54061
54090
  { message: "include and exclude are mutually exclusive" }
@@ -54087,7 +54116,7 @@ var ConfigLoadError = class extends Error {
54087
54116
  }
54088
54117
  filePath;
54089
54118
  };
54090
- async function fileExists(filePath) {
54119
+ async function fileExists2(filePath) {
54091
54120
  try {
54092
54121
  await access(filePath);
54093
54122
  return true;
@@ -54098,7 +54127,7 @@ async function fileExists(filePath) {
54098
54127
  async function loadConfig(configPath) {
54099
54128
  const isExplicit = configPath !== void 0;
54100
54129
  const targetPath = resolve4(configPath ?? DEFAULT_CONFIG_NAME);
54101
- if (!await fileExists(targetPath)) {
54130
+ if (!await fileExists2(targetPath)) {
54102
54131
  if (isExplicit) {
54103
54132
  throw new ConfigLoadError(
54104
54133
  `Config file not found: ${targetPath}`,
@@ -54299,7 +54328,7 @@ ${issues}`,
54299
54328
  }
54300
54329
 
54301
54330
  // src/guardrail-generator/generator.ts
54302
- import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod } from "fs/promises";
54331
+ import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2 } from "fs/promises";
54303
54332
  import { resolve as resolve6, dirname as dirname6 } from "path";
54304
54333
  import Handlebars2 from "handlebars";
54305
54334
 
@@ -54473,6 +54502,7 @@ async function generateGuardrails(options) {
54473
54502
  });
54474
54503
  continue;
54475
54504
  }
54505
+ const shouldSkipEmpty = outputDef.skip_empty === true;
54476
54506
  if (outputDef.group_by) {
54477
54507
  const groupField = outputDef.group_by;
54478
54508
  const groups = /* @__PURE__ */ new Map();
@@ -54492,6 +54522,15 @@ async function generateGuardrails(options) {
54492
54522
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54493
54523
  const output = compiled(groupCtx);
54494
54524
  const groupTarget = resolve6(targetPath, groupKey);
54525
+ if (shouldSkipEmpty && output.trim().length === 0) {
54526
+ if (!dryRun) {
54527
+ try {
54528
+ await unlink2(groupTarget);
54529
+ } catch {
54530
+ }
54531
+ }
54532
+ continue;
54533
+ }
54495
54534
  if (!dryRun) {
54496
54535
  await mkdir2(dirname6(groupTarget), { recursive: true });
54497
54536
  await writeFile2(groupTarget, output, "utf8");
@@ -54504,14 +54543,23 @@ async function generateGuardrails(options) {
54504
54543
  } else {
54505
54544
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54506
54545
  const output = compiled(ctx);
54507
- if (!dryRun) {
54508
- await mkdir2(dirname6(targetPath), { recursive: true });
54509
- await writeFile2(targetPath, output, "utf8");
54510
- if (outputDef.executable) {
54511
- await chmod(targetPath, 493);
54546
+ if (shouldSkipEmpty && output.trim().length === 0) {
54547
+ if (!dryRun) {
54548
+ try {
54549
+ await unlink2(targetPath);
54550
+ } catch {
54551
+ }
54552
+ }
54553
+ } else {
54554
+ if (!dryRun) {
54555
+ await mkdir2(dirname6(targetPath), { recursive: true });
54556
+ await writeFile2(targetPath, output, "utf8");
54557
+ if (outputDef.executable) {
54558
+ await chmod(targetPath, 493);
54559
+ }
54512
54560
  }
54561
+ outputFiles.push(targetPath);
54513
54562
  }
54514
- outputFiles.push(targetPath);
54515
54563
  }
54516
54564
  }
54517
54565
  }