agent-contracts 0.11.8 → 0.12.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/dist/index.d.ts CHANGED
@@ -130,10 +130,21 @@ declare const BindingOutputSchema: z.ZodObject<{
130
130
  target: z.ZodString;
131
131
  template: z.ZodOptional<z.ZodString>;
132
132
  inline_template: z.ZodOptional<z.ZodString>;
133
+ source: z.ZodOptional<z.ZodString>;
133
134
  mode: z.ZodDefault<z.ZodEnum<{
134
135
  write: "write";
135
136
  patch: "patch";
136
137
  }>>;
138
+ format: z.ZodOptional<z.ZodEnum<{
139
+ json: "json";
140
+ yaml: "yaml";
141
+ text: "text";
142
+ }>>;
143
+ patch_strategy: z.ZodOptional<z.ZodEnum<{
144
+ deep_merge: "deep_merge";
145
+ append: "append";
146
+ }>>;
147
+ array_merge_key: z.ZodOptional<z.ZodString>;
137
148
  group_by: z.ZodOptional<z.ZodString>;
138
149
  executable: z.ZodOptional<z.ZodBoolean>;
139
150
  skip_empty: z.ZodOptional<z.ZodBoolean>;
@@ -172,10 +183,21 @@ declare const SoftwareBindingSchema: z.ZodObject<{
172
183
  target: z.ZodString;
173
184
  template: z.ZodOptional<z.ZodString>;
174
185
  inline_template: z.ZodOptional<z.ZodString>;
186
+ source: z.ZodOptional<z.ZodString>;
175
187
  mode: z.ZodDefault<z.ZodEnum<{
176
188
  write: "write";
177
189
  patch: "patch";
178
190
  }>>;
191
+ format: z.ZodOptional<z.ZodEnum<{
192
+ json: "json";
193
+ yaml: "yaml";
194
+ text: "text";
195
+ }>>;
196
+ patch_strategy: z.ZodOptional<z.ZodEnum<{
197
+ deep_merge: "deep_merge";
198
+ append: "append";
199
+ }>>;
200
+ array_merge_key: z.ZodOptional<z.ZodString>;
179
201
  group_by: z.ZodOptional<z.ZodString>;
180
202
  executable: z.ZodOptional<z.ZodBoolean>;
181
203
  skip_empty: z.ZodOptional<z.ZodBoolean>;
@@ -1034,8 +1056,18 @@ interface ResolvedConfig {
1034
1056
  paths?: Record<string, string>;
1035
1057
  }
1036
1058
 
1037
- declare function renderFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[]): Promise<string[]>;
1038
- declare function checkDriftFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[]): Promise<{
1059
+ interface LoadedBinding {
1060
+ filePath: string;
1061
+ binding: SoftwareBinding;
1062
+ }
1063
+ declare function loadBindings(bindingPaths: string[]): Promise<LoadedBinding[]>;
1064
+
1065
+ interface RenderOptions {
1066
+ loadedBindings?: LoadedBinding[];
1067
+ activeGuardrailPolicy?: string;
1068
+ }
1069
+ declare function renderFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[], options?: RenderOptions): Promise<string[]>;
1070
+ declare function checkDriftFromConfig(dsl: Dsl, renderTargets: ResolvedRenderTarget[], options?: RenderOptions): Promise<{
1039
1071
  hasDrift: boolean;
1040
1072
  diffs: string[];
1041
1073
  }>;
@@ -1054,9 +1086,29 @@ interface GlobalContext {
1054
1086
  guardrail_policies: Dsl["guardrail_policies"];
1055
1087
  [key: string]: unknown;
1056
1088
  }
1089
+ interface GuardrailEnforcementEntry {
1090
+ guardrail_id: string;
1091
+ description: string;
1092
+ severity: string;
1093
+ action: string;
1094
+ scoped_agents: string[];
1095
+ scoped_tasks: string[];
1096
+ scoped_workflows: string[];
1097
+ scoped_tools: string[];
1098
+ scoped_artifacts: string[];
1099
+ allow_override: boolean;
1100
+ override_requires: string[];
1101
+ trigger: string | null;
1102
+ escalation: {
1103
+ target: string;
1104
+ condition?: string;
1105
+ } | null;
1106
+ }
1057
1107
  interface SystemContext {
1058
1108
  system: System;
1059
1109
  dsl: Dsl;
1110
+ guardrailEnforcement?: GuardrailEnforcementEntry[];
1111
+ bindings?: SoftwareBinding[];
1060
1112
  [key: string]: unknown;
1061
1113
  }
1062
1114
  interface PerTaskContext {
@@ -1183,7 +1235,10 @@ interface PerAgentContext {
1183
1235
  [key: string]: unknown;
1184
1236
  }
1185
1237
  declare function buildGlobalContext(dsl: Dsl): GlobalContext;
1186
- declare function buildSystemContext(dsl: Dsl): SystemContext;
1238
+ declare function buildSystemContext(dsl: Dsl, options?: {
1239
+ loadedBindings?: LoadedBinding[];
1240
+ activeGuardrailPolicy?: string;
1241
+ }): SystemContext;
1187
1242
  declare function buildTaskContext(dsl: Dsl, taskId: string): PerTaskContext;
1188
1243
  declare function buildArtifactContext(dsl: Dsl, artifactId: string): PerArtifactContext;
1189
1244
  declare function buildToolContext(dsl: Dsl, toolId: string): PerToolContext;
@@ -1197,12 +1252,6 @@ declare function buildPerAgentContext(dsl: Dsl, agent: Agent & {
1197
1252
  id: string;
1198
1253
  }): PerAgentContext;
1199
1254
 
1200
- interface LoadedBinding {
1201
- filePath: string;
1202
- binding: SoftwareBinding;
1203
- }
1204
- declare function loadBindings(bindingPaths: string[]): Promise<LoadedBinding[]>;
1205
-
1206
1255
  declare class ConfigLoadError extends Error {
1207
1256
  readonly filePath?: string | undefined;
1208
1257
  constructor(message: string, filePath?: string | undefined);
package/dist/index.js CHANGED
@@ -2242,7 +2242,7 @@ var require_lodash = __commonJS({
2242
2242
  } else {
2243
2243
  newValue = [];
2244
2244
  }
2245
- } else if (isPlainObject(srcValue) || isArguments(srcValue)) {
2245
+ } else if (isPlainObject2(srcValue) || isArguments(srcValue)) {
2246
2246
  newValue = objValue;
2247
2247
  if (isArguments(objValue)) {
2248
2248
  newValue = toPlainObject(objValue);
@@ -3206,7 +3206,7 @@ var require_lodash = __commonJS({
3206
3206
  return objValue;
3207
3207
  }
3208
3208
  function customOmitClone(value) {
3209
- return isPlainObject(value) ? undefined2 : value;
3209
+ return isPlainObject2(value) ? undefined2 : value;
3210
3210
  }
3211
3211
  function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
3212
3212
  var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array.length, othLength = other.length;
@@ -4707,7 +4707,7 @@ var require_lodash = __commonJS({
4707
4707
  var isBuffer = nativeIsBuffer || stubFalse;
4708
4708
  var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
4709
4709
  function isElement(value) {
4710
- return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
4710
+ return isObjectLike(value) && value.nodeType === 1 && !isPlainObject2(value);
4711
4711
  }
4712
4712
  function isEmpty(value) {
4713
4713
  if (value == null) {
@@ -4743,7 +4743,7 @@ var require_lodash = __commonJS({
4743
4743
  return false;
4744
4744
  }
4745
4745
  var tag = baseGetTag(value);
4746
- return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject(value);
4746
+ return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject2(value);
4747
4747
  }
4748
4748
  function isFinite2(value) {
4749
4749
  return typeof value == "number" && nativeIsFinite(value);
@@ -4794,7 +4794,7 @@ var require_lodash = __commonJS({
4794
4794
  function isNumber(value) {
4795
4795
  return typeof value == "number" || isObjectLike(value) && baseGetTag(value) == numberTag;
4796
4796
  }
4797
- function isPlainObject(value) {
4797
+ function isPlainObject2(value) {
4798
4798
  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
4799
4799
  return false;
4800
4800
  }
@@ -5865,7 +5865,7 @@ var require_lodash = __commonJS({
5865
5865
  lodash.isNumber = isNumber;
5866
5866
  lodash.isObject = isObject2;
5867
5867
  lodash.isObjectLike = isObjectLike;
5868
- lodash.isPlainObject = isPlainObject;
5868
+ lodash.isPlainObject = isPlainObject2;
5869
5869
  lodash.isRegExp = isRegExp;
5870
5870
  lodash.isSafeInteger = isSafeInteger;
5871
5871
  lodash.isSet = isSet;
@@ -17505,10 +17505,10 @@ var require_immer_cjs_development = __commonJS({
17505
17505
  function isDraftable(value) {
17506
17506
  var _value$constructor;
17507
17507
  if (!value) return false;
17508
- return isPlainObject(value) || Array.isArray(value) || !!value[DRAFTABLE] || !!((_value$constructor = value.constructor) === null || _value$constructor === void 0 ? void 0 : _value$constructor[DRAFTABLE]) || isMap(value) || isSet(value);
17508
+ return isPlainObject2(value) || Array.isArray(value) || !!value[DRAFTABLE] || !!((_value$constructor = value.constructor) === null || _value$constructor === void 0 ? void 0 : _value$constructor[DRAFTABLE]) || isMap(value) || isSet(value);
17509
17509
  }
17510
17510
  var objectCtorString = /* @__PURE__ */ Object.prototype.constructor.toString();
17511
- function isPlainObject(value) {
17511
+ function isPlainObject2(value) {
17512
17512
  if (!value || typeof value !== "object") return false;
17513
17513
  var proto = Object.getPrototypeOf(value);
17514
17514
  if (proto === null) {
@@ -40191,10 +40191,10 @@ var require_object_inspect = __commonJS({
40191
40191
  }
40192
40192
  if (!isDate(obj) && !isRegExp(obj)) {
40193
40193
  var ys = arrObjKeys(obj, inspect);
40194
- var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
40194
+ var isPlainObject2 = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
40195
40195
  var protoTag = obj instanceof Object ? "" : "null prototype";
40196
- var stringTag = !isPlainObject && toStringTag2 && Object(obj) === obj && toStringTag2 in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? "Object" : "";
40197
- var constructorTag = isPlainObject || typeof obj.constructor !== "function" ? "" : obj.constructor.name ? obj.constructor.name + " " : "";
40196
+ var stringTag = !isPlainObject2 && toStringTag2 && Object(obj) === obj && toStringTag2 in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? "Object" : "";
40197
+ var constructorTag = isPlainObject2 || typeof obj.constructor !== "function" ? "" : obj.constructor.name ? obj.constructor.name + " " : "";
40198
40198
  var tag = constructorTag + (stringTag || protoTag ? "[" + $join.call($concat.call([], stringTag || [], protoTag || []), ": ") + "] " : "");
40199
40199
  if (ys.length === 0) {
40200
40200
  return tag + "{}";
@@ -44529,7 +44529,7 @@ var require_lodash3 = __commonJS({
44529
44529
  } else {
44530
44530
  newValue = [];
44531
44531
  }
44532
- } else if (isPlainObject(srcValue) || isArguments(srcValue)) {
44532
+ } else if (isPlainObject2(srcValue) || isArguments(srcValue)) {
44533
44533
  newValue = objValue;
44534
44534
  if (isArguments(objValue)) {
44535
44535
  newValue = toPlainObject(objValue);
@@ -45500,7 +45500,7 @@ var require_lodash3 = __commonJS({
45500
45500
  return objValue;
45501
45501
  }
45502
45502
  function customOmitClone(value) {
45503
- return isPlainObject(value) ? undefined2 : value;
45503
+ return isPlainObject2(value) ? undefined2 : value;
45504
45504
  }
45505
45505
  function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
45506
45506
  var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array.length, othLength = other.length;
@@ -47001,7 +47001,7 @@ var require_lodash3 = __commonJS({
47001
47001
  var isBuffer = nativeIsBuffer || stubFalse;
47002
47002
  var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
47003
47003
  function isElement(value) {
47004
- return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
47004
+ return isObjectLike(value) && value.nodeType === 1 && !isPlainObject2(value);
47005
47005
  }
47006
47006
  function isEmpty(value) {
47007
47007
  if (value == null) {
@@ -47037,7 +47037,7 @@ var require_lodash3 = __commonJS({
47037
47037
  return false;
47038
47038
  }
47039
47039
  var tag = baseGetTag(value);
47040
- return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject(value);
47040
+ return tag == errorTag || tag == domExcTag || typeof value.message == "string" && typeof value.name == "string" && !isPlainObject2(value);
47041
47041
  }
47042
47042
  function isFinite2(value) {
47043
47043
  return typeof value == "number" && nativeIsFinite(value);
@@ -47088,7 +47088,7 @@ var require_lodash3 = __commonJS({
47088
47088
  function isNumber(value) {
47089
47089
  return typeof value == "number" || isObjectLike(value) && baseGetTag(value) == numberTag;
47090
47090
  }
47091
- function isPlainObject(value) {
47091
+ function isPlainObject2(value) {
47092
47092
  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
47093
47093
  return false;
47094
47094
  }
@@ -48154,7 +48154,7 @@ var require_lodash3 = __commonJS({
48154
48154
  lodash.isNumber = isNumber;
48155
48155
  lodash.isObject = isObject2;
48156
48156
  lodash.isObjectLike = isObjectLike;
48157
- lodash.isPlainObject = isPlainObject;
48157
+ lodash.isPlainObject = isPlainObject2;
48158
48158
  lodash.isRegExp = isRegExp;
48159
48159
  lodash.isSafeInteger = isSafeInteger;
48160
48160
  lodash.isSet = isSet;
@@ -50511,13 +50511,20 @@ var BindingOutputSchema = z3.object({
50511
50511
  target: z3.string(),
50512
50512
  template: z3.string().optional(),
50513
50513
  inline_template: z3.string().optional(),
50514
+ source: z3.string().optional(),
50514
50515
  mode: z3.enum(["write", "patch"]).default("write"),
50516
+ format: z3.enum(["json", "yaml", "text"]).optional(),
50517
+ patch_strategy: z3.enum(["deep_merge", "append"]).optional(),
50518
+ array_merge_key: z3.string().optional(),
50515
50519
  group_by: z3.string().optional(),
50516
50520
  executable: z3.boolean().optional(),
50517
50521
  skip_empty: z3.boolean().optional()
50518
50522
  }).passthrough().refine(
50519
- (data) => !(data.template && data.inline_template),
50520
- { message: "template and inline_template are mutually exclusive" }
50523
+ (data) => {
50524
+ const count = [data.template, data.inline_template, data.source].filter(Boolean).length;
50525
+ return count === 1 || count === 0;
50526
+ },
50527
+ { message: "Only one of template, inline_template, or source may be specified" }
50521
50528
  );
50522
50529
  var ReportingSchema = z3.object({
50523
50530
  commands: z3.record(z3.string(), z3.string()),
@@ -53129,8 +53136,52 @@ function buildGlobalContext(dsl) {
53129
53136
  guardrail_policies: dsl.guardrail_policies
53130
53137
  };
53131
53138
  }
53132
- function buildSystemContext(dsl) {
53133
- return { system: dsl.system, dsl };
53139
+ function buildSystemContext(dsl, options) {
53140
+ const ctx = { system: dsl.system, dsl };
53141
+ if (options?.loadedBindings && options.loadedBindings.length > 0) {
53142
+ ctx.bindings = options.loadedBindings.map((lb) => lb.binding);
53143
+ const policyName = options.activeGuardrailPolicy;
53144
+ const policy = policyName ? dsl.guardrail_policies[policyName] : void 0;
53145
+ if (policy) {
53146
+ ctx.guardrailEnforcement = buildGuardrailEnforcement(dsl, policy, options.loadedBindings);
53147
+ }
53148
+ }
53149
+ return ctx;
53150
+ }
53151
+ function buildGuardrailEnforcement(dsl, policy, loadedBindings) {
53152
+ const entries = [];
53153
+ const bindingTriggers = /* @__PURE__ */ new Map();
53154
+ for (const lb of loadedBindings) {
53155
+ const impl = lb.binding.guardrail_impl ?? {};
53156
+ for (const [guardrailId, gi] of Object.entries(impl)) {
53157
+ for (const check of gi.checks) {
53158
+ if (check.matcher) {
53159
+ bindingTriggers.set(guardrailId, check.matcher.type);
53160
+ }
53161
+ }
53162
+ }
53163
+ }
53164
+ for (const rule of policy.rules) {
53165
+ const guardrail = dsl.guardrails[rule.guardrail];
53166
+ if (!guardrail) continue;
53167
+ const scope = guardrail.scope ?? {};
53168
+ entries.push({
53169
+ guardrail_id: rule.guardrail,
53170
+ description: guardrail.description,
53171
+ severity: rule.severity,
53172
+ action: rule.action,
53173
+ scoped_agents: scope.agents ?? [],
53174
+ scoped_tasks: scope.tasks ?? [],
53175
+ scoped_workflows: scope.workflows ?? [],
53176
+ scoped_tools: scope.tools ?? [],
53177
+ scoped_artifacts: scope.artifacts ?? [],
53178
+ allow_override: rule.allow_override,
53179
+ override_requires: rule.override_requires ?? [],
53180
+ trigger: bindingTriggers.get(rule.guardrail) ?? null,
53181
+ escalation: rule.escalation ? { target: rule.escalation.target, condition: rule.escalation.condition } : null
53182
+ });
53183
+ }
53184
+ return entries;
53134
53185
  }
53135
53186
  function buildTaskContext(dsl, taskId) {
53136
53187
  const taskDef = dsl.tasks[taskId];
@@ -54185,6 +54236,50 @@ Handlebars.registerHelper(
54185
54236
  return generateOverviewFlowchart(dsl);
54186
54237
  }
54187
54238
  );
54239
+ Handlebars.registerHelper(
54240
+ "guardrailCoverageMatrix",
54241
+ function() {
54242
+ const enforcement = this["guardrailEnforcement"];
54243
+ if (!enforcement || enforcement.length === 0) return "";
54244
+ const header = "| Guardrail | Severity | Action | Agents | Tasks | Workflows | Tools | Artifacts | Trigger | Override | Escalation |";
54245
+ const divider = "|-----------|----------|--------|--------|-------|-----------|-------|-----------|---------|----------|------------|";
54246
+ const rows = enforcement.map((e3) => {
54247
+ const agents = e3["scoped_agents"]?.join(", ") || "\u2014";
54248
+ const tasks = e3["scoped_tasks"]?.join(", ") || "\u2014";
54249
+ const workflows = e3["scoped_workflows"]?.join(", ") || "\u2014";
54250
+ const tools = e3["scoped_tools"]?.join(", ") || "\u2014";
54251
+ const artifacts = e3["scoped_artifacts"]?.join(", ") || "\u2014";
54252
+ const trigger = e3["trigger"] || "\u2014";
54253
+ const override = e3["allow_override"] ? "yes" : "no";
54254
+ const esc = e3["escalation"];
54255
+ const escalation = esc ? esc["target"] : "\u2014";
54256
+ return `| ${e3["guardrail_id"]} | ${e3["severity"]} | ${e3["action"]} | ${agents} | ${tasks} | ${workflows} | ${tools} | ${artifacts} | ${trigger} | ${override} | ${escalation} |`;
54257
+ });
54258
+ return [header, divider, ...rows].join("\n");
54259
+ }
54260
+ );
54261
+ Handlebars.registerHelper(
54262
+ "taskGuardrailMatrix",
54263
+ function() {
54264
+ const dsl = this["dsl"];
54265
+ const enforcement = this["guardrailEnforcement"];
54266
+ if (!dsl || !enforcement || enforcement.length === 0) return "";
54267
+ const taskIds = Object.keys(dsl.tasks);
54268
+ if (taskIds.length === 0) return "";
54269
+ const guardrailIds = enforcement.map((e3) => e3["guardrail_id"]);
54270
+ const header = `| Task | ${guardrailIds.join(" | ")} |`;
54271
+ const divider = `|------|${guardrailIds.map(() => "------").join("|")}|`;
54272
+ const rows = taskIds.map((taskId) => {
54273
+ const cells = enforcement.map((e3) => {
54274
+ const scopedTasks = e3["scoped_tasks"];
54275
+ if (scopedTasks.length > 0 && !scopedTasks.includes(taskId)) return "n/a";
54276
+ return e3["action"];
54277
+ });
54278
+ return `| ${taskId} | ${cells.join(" | ")} |`;
54279
+ });
54280
+ return [header, divider, ...rows].join("\n");
54281
+ }
54282
+ );
54188
54283
  function getDslSection(dsl, context) {
54189
54284
  const sectionMap = {
54190
54285
  agent: dsl.agents,
@@ -54249,13 +54344,13 @@ async function removeIfExists(filePath) {
54249
54344
  } catch {
54250
54345
  }
54251
54346
  }
54252
- async function renderFromConfig(dsl, renderTargets) {
54347
+ async function renderFromConfig(dsl, renderTargets, options) {
54253
54348
  const outputFiles = [];
54254
54349
  for (const target of renderTargets) {
54255
54350
  const templateContent = await loadTemplate(target.template);
54256
54351
  const compiled = Handlebars.compile(templateContent, { noEscape: false });
54257
54352
  if (target.context === "system") {
54258
- const ctx = buildSystemContext(dsl);
54353
+ const ctx = buildSystemContext(dsl, options);
54259
54354
  const output = compiled(ctx);
54260
54355
  if (target.skip_empty && isEffectivelyEmpty(output)) {
54261
54356
  await removeIfExists(target.output);
@@ -54304,13 +54399,13 @@ function checkExpectedVsExisting(expected, outputPath, skipEmpty, diffs) {
54304
54399
  diffs.push(outputPath);
54305
54400
  });
54306
54401
  }
54307
- async function checkDriftFromConfig(dsl, renderTargets) {
54402
+ async function checkDriftFromConfig(dsl, renderTargets, options) {
54308
54403
  const diffs = [];
54309
54404
  for (const target of renderTargets) {
54310
54405
  const templateContent = await loadTemplate(target.template);
54311
54406
  const compiled = Handlebars.compile(templateContent, { noEscape: false });
54312
54407
  if (target.context === "system") {
54313
- const ctx = buildSystemContext(dsl);
54408
+ const ctx = buildSystemContext(dsl, options);
54314
54409
  const expected = compiled(ctx);
54315
54410
  await checkExpectedVsExisting(expected, target.output, target.skip_empty, diffs);
54316
54411
  } else {
@@ -54873,9 +54968,10 @@ function score(dsl) {
54873
54968
  }
54874
54969
 
54875
54970
  // src/guardrail-generator/generator.ts
54876
- import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2 } from "fs/promises";
54971
+ import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2, copyFile } from "fs/promises";
54877
54972
  import { resolve as resolve6, dirname as dirname6 } from "path";
54878
54973
  import Handlebars2 from "handlebars";
54974
+ import YAML from "yaml";
54879
54975
 
54880
54976
  // src/guardrail-generator/resolve-checks.ts
54881
54977
  function resolveChecks(dsl, binding, policy) {
@@ -54947,6 +55043,81 @@ Handlebars2.registerHelper(
54947
55043
  return new Handlebars2.SafeString(result);
54948
55044
  }
54949
55045
  );
55046
+ function isPlainObject(val) {
55047
+ return typeof val === "object" && val !== null && !Array.isArray(val);
55048
+ }
55049
+ function deepMergeArrays(existing, incoming, mergeKey) {
55050
+ if (!mergeKey) return [...existing, ...incoming];
55051
+ const merged = [...existing];
55052
+ for (const item of incoming) {
55053
+ if (isPlainObject(item) && mergeKey in item) {
55054
+ const idx = merged.findIndex(
55055
+ (e3) => isPlainObject(e3) && e3[mergeKey] === item[mergeKey]
55056
+ );
55057
+ if (idx >= 0) {
55058
+ merged[idx] = item;
55059
+ } else {
55060
+ merged.push(item);
55061
+ }
55062
+ } else {
55063
+ merged.push(item);
55064
+ }
55065
+ }
55066
+ return merged;
55067
+ }
55068
+ function deepMerge(existing, incoming, arrayMergeKey) {
55069
+ if (Array.isArray(existing) && Array.isArray(incoming)) {
55070
+ return deepMergeArrays(existing, incoming, arrayMergeKey);
55071
+ }
55072
+ if (isPlainObject(existing) && isPlainObject(incoming)) {
55073
+ const result = { ...existing };
55074
+ for (const [key, val] of Object.entries(incoming)) {
55075
+ result[key] = key in result ? deepMerge(result[key], val, arrayMergeKey) : val;
55076
+ }
55077
+ return result;
55078
+ }
55079
+ return incoming;
55080
+ }
55081
+ function parseContent(raw, format2) {
55082
+ if (format2 === "json") return JSON.parse(raw);
55083
+ if (format2 === "yaml") return YAML.parse(raw);
55084
+ throw new Error(`Unsupported format for patch parsing: ${format2}`);
55085
+ }
55086
+ function serializeContent(data, format2) {
55087
+ if (format2 === "json") return JSON.stringify(data, null, 2) + "\n";
55088
+ if (format2 === "yaml") return YAML.stringify(data);
55089
+ throw new Error(`Unsupported format for patch serialization: ${format2}`);
55090
+ }
55091
+ async function applyPatch(targetPath, patchContent, outputDef) {
55092
+ const format2 = outputDef.format ?? "json";
55093
+ if (format2 === "text") {
55094
+ let existing = "";
55095
+ try {
55096
+ existing = await readFile5(targetPath, "utf8");
55097
+ } catch {
55098
+ }
55099
+ return existing + patchContent;
55100
+ }
55101
+ const patchData = parseContent(patchContent, format2);
55102
+ let existingData;
55103
+ try {
55104
+ const existingRaw = await readFile5(targetPath, "utf8");
55105
+ existingData = parseContent(existingRaw, format2);
55106
+ } catch {
55107
+ return serializeContent(patchData, format2);
55108
+ }
55109
+ const strategy = outputDef.patch_strategy ?? "deep_merge";
55110
+ if (strategy === "append" && Array.isArray(existingData)) {
55111
+ const merged2 = deepMergeArrays(
55112
+ existingData,
55113
+ Array.isArray(patchData) ? patchData : [patchData],
55114
+ outputDef.array_merge_key
55115
+ );
55116
+ return serializeContent(merged2, format2);
55117
+ }
55118
+ const merged = deepMerge(existingData, patchData, outputDef.array_merge_key);
55119
+ return serializeContent(merged, format2);
55120
+ }
54950
55121
  async function generateGuardrails(options) {
54951
55122
  const { dsl, config, loadedBindings, filterBindings, dryRun } = options;
54952
55123
  const outputFiles = [];
@@ -55016,6 +55187,31 @@ async function generateGuardrails(options) {
55016
55187
  continue;
55017
55188
  }
55018
55189
  const targetPath = resolve6(config.configDir, pathResult.resolved);
55190
+ if (outputDef.source) {
55191
+ const sourcePath = resolve6(config.configDir, outputDef.source);
55192
+ if (!dryRun) {
55193
+ try {
55194
+ await mkdir2(dirname6(targetPath), { recursive: true });
55195
+ await copyFile(sourcePath, targetPath);
55196
+ if (outputDef.executable) {
55197
+ await chmod(targetPath, 493);
55198
+ }
55199
+ } catch (err) {
55200
+ const code = err.code;
55201
+ if (code === "ENOENT") {
55202
+ diagnostics.push({
55203
+ path: `binding.${binding.software}.outputs.${outputId}`,
55204
+ message: `Source file not found: ${sourcePath}`,
55205
+ severity: "error"
55206
+ });
55207
+ continue;
55208
+ }
55209
+ throw err;
55210
+ }
55211
+ }
55212
+ outputFiles.push(targetPath);
55213
+ continue;
55214
+ }
55019
55215
  let templateContent;
55020
55216
  if (outputDef.inline_template) {
55021
55217
  templateContent = outputDef.inline_template;
@@ -55042,12 +55238,13 @@ async function generateGuardrails(options) {
55042
55238
  } else {
55043
55239
  diagnostics.push({
55044
55240
  path: `binding.${binding.software}.outputs.${outputId}`,
55045
- message: "Output has neither template nor inline_template",
55241
+ message: "Output has neither template, inline_template, nor source",
55046
55242
  severity: "error"
55047
55243
  });
55048
55244
  continue;
55049
55245
  }
55050
55246
  const shouldSkipEmpty = outputDef.skip_empty === true;
55247
+ const isPatch = outputDef.mode === "patch";
55051
55248
  if (outputDef.group_by) {
55052
55249
  const groupField = outputDef.group_by;
55053
55250
  const groups = /* @__PURE__ */ new Map();
@@ -55065,9 +55262,9 @@ async function generateGuardrails(options) {
55065
55262
  current_group: groupKey
55066
55263
  };
55067
55264
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
55068
- const output = compiled(groupCtx);
55265
+ const rendered = compiled(groupCtx);
55069
55266
  const groupTarget = resolve6(targetPath, groupKey);
55070
- if (shouldSkipEmpty && output.trim().length === 0) {
55267
+ if (shouldSkipEmpty && rendered.trim().length === 0) {
55071
55268
  if (!dryRun) {
55072
55269
  try {
55073
55270
  await unlink2(groupTarget);
@@ -55076,6 +55273,7 @@ async function generateGuardrails(options) {
55076
55273
  }
55077
55274
  continue;
55078
55275
  }
55276
+ const output = isPatch && !dryRun ? await applyPatch(groupTarget, rendered, outputDef) : rendered;
55079
55277
  if (!dryRun) {
55080
55278
  await mkdir2(dirname6(groupTarget), { recursive: true });
55081
55279
  await writeFile2(groupTarget, output, "utf8");
@@ -55087,8 +55285,8 @@ async function generateGuardrails(options) {
55087
55285
  }
55088
55286
  } else {
55089
55287
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
55090
- const output = compiled(ctx);
55091
- if (shouldSkipEmpty && output.trim().length === 0) {
55288
+ const rendered = compiled(ctx);
55289
+ if (shouldSkipEmpty && rendered.trim().length === 0) {
55092
55290
  if (!dryRun) {
55093
55291
  try {
55094
55292
  await unlink2(targetPath);
@@ -55096,6 +55294,7 @@ async function generateGuardrails(options) {
55096
55294
  }
55097
55295
  }
55098
55296
  } else {
55297
+ const output = isPatch && !dryRun ? await applyPatch(targetPath, rendered, outputDef) : rendered;
55099
55298
  if (!dryRun) {
55100
55299
  await mkdir2(dirname6(targetPath), { recursive: true });
55101
55300
  await writeFile2(targetPath, output, "utf8");