agent-contracts 0.11.1 → 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
@@ -97,29 +97,31 @@ type Artifact = z.infer<typeof ArtifactSchema>;
97
97
  declare const MatcherSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
98
98
  type: z.ZodLiteral<"command_regex">;
99
99
  pattern: z.ZodString;
100
- }, z.core.$strip>, z.ZodObject<{
100
+ }, z.core.$loose>, z.ZodObject<{
101
101
  type: z.ZodLiteral<"content_regex">;
102
102
  pattern: z.ZodString;
103
103
  file_glob: z.ZodOptional<z.ZodString>;
104
104
  exclude_glob: z.ZodOptional<z.ZodString>;
105
- }, z.core.$strip>, z.ZodObject<{
105
+ }, z.core.$loose>, z.ZodObject<{
106
106
  type: z.ZodLiteral<"file_glob">;
107
107
  pattern: z.ZodString;
108
- }, z.core.$strip>], "type">;
108
+ exclude_glob: z.ZodOptional<z.ZodString>;
109
+ }, z.core.$loose>], "type">;
109
110
  type Matcher = z.infer<typeof MatcherSchema>;
110
111
  declare const CheckSchema: z.ZodObject<{
111
112
  matcher: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
112
113
  type: z.ZodLiteral<"command_regex">;
113
114
  pattern: z.ZodString;
114
- }, z.core.$strip>, z.ZodObject<{
115
+ }, z.core.$loose>, z.ZodObject<{
115
116
  type: z.ZodLiteral<"content_regex">;
116
117
  pattern: z.ZodString;
117
118
  file_glob: z.ZodOptional<z.ZodString>;
118
119
  exclude_glob: z.ZodOptional<z.ZodString>;
119
- }, z.core.$strip>, z.ZodObject<{
120
+ }, z.core.$loose>, z.ZodObject<{
120
121
  type: z.ZodLiteral<"file_glob">;
121
122
  pattern: z.ZodString;
122
- }, z.core.$strip>], "type">>;
123
+ exclude_glob: z.ZodOptional<z.ZodString>;
124
+ }, z.core.$loose>], "type">>;
123
125
  script: z.ZodOptional<z.ZodString>;
124
126
  message: z.ZodOptional<z.ZodString>;
125
127
  }, z.core.$loose>;
@@ -134,6 +136,7 @@ declare const BindingOutputSchema: z.ZodObject<{
134
136
  }>>;
135
137
  group_by: z.ZodOptional<z.ZodString>;
136
138
  executable: z.ZodOptional<z.ZodBoolean>;
139
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
137
140
  }, z.core.$loose>;
138
141
  type BindingOutput = z.infer<typeof BindingOutputSchema>;
139
142
  declare const ReportingSchema: z.ZodObject<{
@@ -151,15 +154,16 @@ declare const SoftwareBindingSchema: z.ZodObject<{
151
154
  matcher: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
152
155
  type: z.ZodLiteral<"command_regex">;
153
156
  pattern: z.ZodString;
154
- }, z.core.$strip>, z.ZodObject<{
157
+ }, z.core.$loose>, z.ZodObject<{
155
158
  type: z.ZodLiteral<"content_regex">;
156
159
  pattern: z.ZodString;
157
160
  file_glob: z.ZodOptional<z.ZodString>;
158
161
  exclude_glob: z.ZodOptional<z.ZodString>;
159
- }, z.core.$strip>, z.ZodObject<{
162
+ }, z.core.$loose>, z.ZodObject<{
160
163
  type: z.ZodLiteral<"file_glob">;
161
164
  pattern: z.ZodString;
162
- }, z.core.$strip>], "type">>;
165
+ exclude_glob: z.ZodOptional<z.ZodString>;
166
+ }, z.core.$loose>], "type">>;
163
167
  script: z.ZodOptional<z.ZodString>;
164
168
  message: z.ZodOptional<z.ZodString>;
165
169
  }, z.core.$loose>>;
@@ -174,6 +178,7 @@ declare const SoftwareBindingSchema: z.ZodObject<{
174
178
  }>>;
175
179
  group_by: z.ZodOptional<z.ZodString>;
176
180
  executable: z.ZodOptional<z.ZodBoolean>;
181
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
177
182
  }, z.core.$loose>>>;
178
183
  reporting: z.ZodOptional<z.ZodObject<{
179
184
  commands: z.ZodRecord<z.ZodString, z.ZodString>;
@@ -944,6 +949,7 @@ declare const RenderTargetSchema: z.ZodObject<{
944
949
  output: z.ZodString;
945
950
  include: z.ZodOptional<z.ZodArray<z.ZodString>>;
946
951
  exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
952
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
947
953
  }, z.core.$strip>;
948
954
  type RenderTarget = z.infer<typeof RenderTargetSchema>;
949
955
  declare const AgentContractsConfigSchema: z.ZodObject<{
@@ -967,6 +973,7 @@ declare const AgentContractsConfigSchema: z.ZodObject<{
967
973
  output: z.ZodString;
968
974
  include: z.ZodOptional<z.ZodArray<z.ZodString>>;
969
975
  exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
976
+ skip_empty: z.ZodOptional<z.ZodBoolean>;
970
977
  }, z.core.$strip>>;
971
978
  bindings: z.ZodDefault<z.ZodArray<z.ZodString>>;
972
979
  active_guardrail_policy: z.ZodOptional<z.ZodString>;
@@ -979,6 +986,7 @@ interface ResolvedRenderTarget {
979
986
  output: string;
980
987
  include?: string[];
981
988
  exclude?: string[];
989
+ skip_empty?: boolean;
982
990
  }
983
991
  interface ResolvedConfig {
984
992
  dsl: string;
package/dist/index.js CHANGED
@@ -50485,17 +50485,18 @@ import { z as z3 } from "zod";
50485
50485
  var CommandRegexMatcherSchema = z3.object({
50486
50486
  type: z3.literal("command_regex"),
50487
50487
  pattern: z3.string()
50488
- });
50488
+ }).passthrough();
50489
50489
  var ContentRegexMatcherSchema = z3.object({
50490
50490
  type: z3.literal("content_regex"),
50491
50491
  pattern: z3.string(),
50492
50492
  file_glob: z3.string().optional(),
50493
50493
  exclude_glob: z3.string().optional()
50494
- });
50494
+ }).passthrough();
50495
50495
  var FileGlobMatcherSchema = z3.object({
50496
50496
  type: z3.literal("file_glob"),
50497
- pattern: z3.string()
50498
- });
50497
+ pattern: z3.string(),
50498
+ exclude_glob: z3.string().optional()
50499
+ }).passthrough();
50499
50500
  var MatcherSchema = z3.discriminatedUnion("type", [
50500
50501
  CommandRegexMatcherSchema,
50501
50502
  ContentRegexMatcherSchema,
@@ -50512,7 +50513,8 @@ var BindingOutputSchema = z3.object({
50512
50513
  inline_template: z3.string().optional(),
50513
50514
  mode: z3.enum(["write", "patch"]).default("write"),
50514
50515
  group_by: z3.string().optional(),
50515
- executable: z3.boolean().optional()
50516
+ executable: z3.boolean().optional(),
50517
+ skip_empty: z3.boolean().optional()
50516
50518
  }).passthrough().refine(
50517
50519
  (data) => !(data.template && data.inline_template),
50518
50520
  { message: "template and inline_template are mutually exclusive" }
@@ -52827,7 +52829,7 @@ async function spectralLint(dslObject) {
52827
52829
  }
52828
52830
 
52829
52831
  // src/renderer/renderer.ts
52830
- import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
52832
+ import { readFile as readFile2, writeFile, mkdir, unlink } from "fs/promises";
52831
52833
  import { dirname as dirname3 } from "path";
52832
52834
  import Handlebars from "handlebars";
52833
52835
 
@@ -53958,6 +53960,15 @@ function buildEntityContext(dsl, context, entityId) {
53958
53960
  async function loadTemplate(templatePath) {
53959
53961
  return readFile2(templatePath, "utf8");
53960
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
+ }
53961
53972
  async function renderFromConfig(dsl, renderTargets) {
53962
53973
  const outputFiles = [];
53963
53974
  for (const target of renderTargets) {
@@ -53966,6 +53977,10 @@ async function renderFromConfig(dsl, renderTargets) {
53966
53977
  if (target.context === "system") {
53967
53978
  const ctx = buildSystemContext(dsl);
53968
53979
  const output = compiled(ctx);
53980
+ if (target.skip_empty && isEffectivelyEmpty(output)) {
53981
+ await removeIfExists(target.output);
53982
+ continue;
53983
+ }
53969
53984
  await mkdir(dirname3(target.output), { recursive: true });
53970
53985
  await writeFile(target.output, output, "utf8");
53971
53986
  outputFiles.push(target.output);
@@ -53977,6 +53992,10 @@ async function renderFromConfig(dsl, renderTargets) {
53977
53992
  const ctx = buildEntityContext(dsl, target.context, entityId);
53978
53993
  const output = compiled(ctx);
53979
53994
  const outputPath = expandOutputPath(target.output, target.context, entityId);
53995
+ if (target.skip_empty && isEffectivelyEmpty(output)) {
53996
+ await removeIfExists(outputPath);
53997
+ continue;
53998
+ }
53980
53999
  await mkdir(dirname3(outputPath), { recursive: true });
53981
54000
  await writeFile(outputPath, output, "utf8");
53982
54001
  outputFiles.push(outputPath);
@@ -53985,6 +54004,26 @@ async function renderFromConfig(dsl, renderTargets) {
53985
54004
  }
53986
54005
  return outputFiles;
53987
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
+ }
53988
54027
  async function checkDriftFromConfig(dsl, renderTargets) {
53989
54028
  const diffs = [];
53990
54029
  for (const target of renderTargets) {
@@ -53993,12 +54032,7 @@ async function checkDriftFromConfig(dsl, renderTargets) {
53993
54032
  if (target.context === "system") {
53994
54033
  const ctx = buildSystemContext(dsl);
53995
54034
  const expected = compiled(ctx);
53996
- try {
53997
- const existing = await readFile2(target.output, "utf8");
53998
- if (existing !== expected) diffs.push(target.output);
53999
- } catch {
54000
- diffs.push(target.output);
54001
- }
54035
+ await checkExpectedVsExisting(expected, target.output, target.skip_empty, diffs);
54002
54036
  } else {
54003
54037
  const section = getDslSection(dsl, target.context);
54004
54038
  const allIds = Object.keys(section);
@@ -54007,12 +54041,7 @@ async function checkDriftFromConfig(dsl, renderTargets) {
54007
54041
  const ctx = buildEntityContext(dsl, target.context, entityId);
54008
54042
  const expected = compiled(ctx);
54009
54043
  const outputPath = expandOutputPath(target.output, target.context, entityId);
54010
- try {
54011
- const existing = await readFile2(outputPath, "utf8");
54012
- if (existing !== expected) diffs.push(outputPath);
54013
- } catch {
54014
- diffs.push(outputPath);
54015
- }
54044
+ await checkExpectedVsExisting(expected, outputPath, target.skip_empty, diffs);
54016
54045
  }
54017
54046
  }
54018
54047
  }
@@ -54054,7 +54083,8 @@ var RenderTargetSchema = z16.object({
54054
54083
  context: ContextTypeSchema,
54055
54084
  output: z16.string(),
54056
54085
  include: z16.array(z16.string()).optional(),
54057
- exclude: z16.array(z16.string()).optional()
54086
+ exclude: z16.array(z16.string()).optional(),
54087
+ skip_empty: z16.boolean().optional()
54058
54088
  }).refine(
54059
54089
  (data) => !(data.include && data.exclude),
54060
54090
  { message: "include and exclude are mutually exclusive" }
@@ -54086,7 +54116,7 @@ var ConfigLoadError = class extends Error {
54086
54116
  }
54087
54117
  filePath;
54088
54118
  };
54089
- async function fileExists(filePath) {
54119
+ async function fileExists2(filePath) {
54090
54120
  try {
54091
54121
  await access(filePath);
54092
54122
  return true;
@@ -54097,7 +54127,7 @@ async function fileExists(filePath) {
54097
54127
  async function loadConfig(configPath) {
54098
54128
  const isExplicit = configPath !== void 0;
54099
54129
  const targetPath = resolve4(configPath ?? DEFAULT_CONFIG_NAME);
54100
- if (!await fileExists(targetPath)) {
54130
+ if (!await fileExists2(targetPath)) {
54101
54131
  if (isExplicit) {
54102
54132
  throw new ConfigLoadError(
54103
54133
  `Config file not found: ${targetPath}`,
@@ -54298,7 +54328,7 @@ ${issues}`,
54298
54328
  }
54299
54329
 
54300
54330
  // src/guardrail-generator/generator.ts
54301
- 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";
54302
54332
  import { resolve as resolve6, dirname as dirname6 } from "path";
54303
54333
  import Handlebars2 from "handlebars";
54304
54334
 
@@ -54472,6 +54502,7 @@ async function generateGuardrails(options) {
54472
54502
  });
54473
54503
  continue;
54474
54504
  }
54505
+ const shouldSkipEmpty = outputDef.skip_empty === true;
54475
54506
  if (outputDef.group_by) {
54476
54507
  const groupField = outputDef.group_by;
54477
54508
  const groups = /* @__PURE__ */ new Map();
@@ -54491,6 +54522,15 @@ async function generateGuardrails(options) {
54491
54522
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54492
54523
  const output = compiled(groupCtx);
54493
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
+ }
54494
54534
  if (!dryRun) {
54495
54535
  await mkdir2(dirname6(groupTarget), { recursive: true });
54496
54536
  await writeFile2(groupTarget, output, "utf8");
@@ -54503,14 +54543,23 @@ async function generateGuardrails(options) {
54503
54543
  } else {
54504
54544
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
54505
54545
  const output = compiled(ctx);
54506
- if (!dryRun) {
54507
- await mkdir2(dirname6(targetPath), { recursive: true });
54508
- await writeFile2(targetPath, output, "utf8");
54509
- if (outputDef.executable) {
54510
- 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
+ }
54511
54560
  }
54561
+ outputFiles.push(targetPath);
54512
54562
  }
54513
- outputFiles.push(targetPath);
54514
54563
  }
54515
54564
  }
54516
54565
  }