agent-contracts 0.12.0 → 0.12.2

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>;
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()),
@@ -54961,9 +54968,10 @@ function score(dsl) {
54961
54968
  }
54962
54969
 
54963
54970
  // src/guardrail-generator/generator.ts
54964
- 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";
54965
54972
  import { resolve as resolve6, dirname as dirname6 } from "path";
54966
54973
  import Handlebars2 from "handlebars";
54974
+ import YAML from "yaml";
54967
54975
 
54968
54976
  // src/guardrail-generator/resolve-checks.ts
54969
54977
  function resolveChecks(dsl, binding, policy) {
@@ -55035,6 +55043,81 @@ Handlebars2.registerHelper(
55035
55043
  return new Handlebars2.SafeString(result);
55036
55044
  }
55037
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
+ }
55038
55121
  async function generateGuardrails(options) {
55039
55122
  const { dsl, config, loadedBindings, filterBindings, dryRun } = options;
55040
55123
  const outputFiles = [];
@@ -55104,6 +55187,31 @@ async function generateGuardrails(options) {
55104
55187
  continue;
55105
55188
  }
55106
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
+ }
55107
55215
  let templateContent;
55108
55216
  if (outputDef.inline_template) {
55109
55217
  templateContent = outputDef.inline_template;
@@ -55130,12 +55238,13 @@ async function generateGuardrails(options) {
55130
55238
  } else {
55131
55239
  diagnostics.push({
55132
55240
  path: `binding.${binding.software}.outputs.${outputId}`,
55133
- message: "Output has neither template nor inline_template",
55241
+ message: "Output has neither template, inline_template, nor source",
55134
55242
  severity: "error"
55135
55243
  });
55136
55244
  continue;
55137
55245
  }
55138
55246
  const shouldSkipEmpty = outputDef.skip_empty === true;
55247
+ const isPatch = outputDef.mode === "patch";
55139
55248
  if (outputDef.group_by) {
55140
55249
  const groupField = outputDef.group_by;
55141
55250
  const groups = /* @__PURE__ */ new Map();
@@ -55153,9 +55262,9 @@ async function generateGuardrails(options) {
55153
55262
  current_group: groupKey
55154
55263
  };
55155
55264
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
55156
- const output = compiled(groupCtx);
55265
+ const rendered = compiled(groupCtx);
55157
55266
  const groupTarget = resolve6(targetPath, groupKey);
55158
- if (shouldSkipEmpty && output.trim().length === 0) {
55267
+ if (shouldSkipEmpty && rendered.trim().length === 0) {
55159
55268
  if (!dryRun) {
55160
55269
  try {
55161
55270
  await unlink2(groupTarget);
@@ -55164,6 +55273,7 @@ async function generateGuardrails(options) {
55164
55273
  }
55165
55274
  continue;
55166
55275
  }
55276
+ const output = isPatch && !dryRun ? await applyPatch(groupTarget, rendered, outputDef) : rendered;
55167
55277
  if (!dryRun) {
55168
55278
  await mkdir2(dirname6(groupTarget), { recursive: true });
55169
55279
  await writeFile2(groupTarget, output, "utf8");
@@ -55175,8 +55285,8 @@ async function generateGuardrails(options) {
55175
55285
  }
55176
55286
  } else {
55177
55287
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
55178
- const output = compiled(ctx);
55179
- if (shouldSkipEmpty && output.trim().length === 0) {
55288
+ const rendered = compiled(ctx);
55289
+ if (shouldSkipEmpty && rendered.trim().length === 0) {
55180
55290
  if (!dryRun) {
55181
55291
  try {
55182
55292
  await unlink2(targetPath);
@@ -55184,6 +55294,7 @@ async function generateGuardrails(options) {
55184
55294
  }
55185
55295
  }
55186
55296
  } else {
55297
+ const output = isPatch && !dryRun ? await applyPatch(targetPath, rendered, outputDef) : rendered;
55187
55298
  if (!dryRun) {
55188
55299
  await mkdir2(dirname6(targetPath), { recursive: true });
55189
55300
  await writeFile2(targetPath, output, "utf8");