agent-contracts 0.25.0 → 0.30.0

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.js CHANGED
@@ -158,11 +158,11 @@ function __metadata(metadataKey, metadataValue) {
158
158
  }
159
159
  function __awaiter(thisArg, _arguments, P2, generator) {
160
160
  function adopt(value) {
161
- return value instanceof P2 ? value : new P2(function(resolve7) {
162
- resolve7(value);
161
+ return value instanceof P2 ? value : new P2(function(resolve8) {
162
+ resolve8(value);
163
163
  });
164
164
  }
165
- return new (P2 || (P2 = Promise))(function(resolve7, reject) {
165
+ return new (P2 || (P2 = Promise))(function(resolve8, reject) {
166
166
  function fulfilled(value) {
167
167
  try {
168
168
  step(generator.next(value));
@@ -178,7 +178,7 @@ function __awaiter(thisArg, _arguments, P2, generator) {
178
178
  }
179
179
  }
180
180
  function step(result) {
181
- result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
181
+ result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
182
182
  }
183
183
  step((generator = generator.apply(thisArg, _arguments || [])).next());
184
184
  });
@@ -369,14 +369,14 @@ function __asyncValues(o3) {
369
369
  }, i3);
370
370
  function verb(n3) {
371
371
  i3[n3] = o3[n3] && function(v2) {
372
- return new Promise(function(resolve7, reject) {
373
- v2 = o3[n3](v2), settle(resolve7, reject, v2.done, v2.value);
372
+ return new Promise(function(resolve8, reject) {
373
+ v2 = o3[n3](v2), settle(resolve8, reject, v2.done, v2.value);
374
374
  });
375
375
  };
376
376
  }
377
- function settle(resolve7, reject, d2, v2) {
377
+ function settle(resolve8, reject, d2, v2) {
378
378
  Promise.resolve(v2).then(function(v3) {
379
- resolve7({ value: v3, done: d2 });
379
+ resolve8({ value: v3, done: d2 });
380
380
  }, reject);
381
381
  }
382
382
  }
@@ -12936,13 +12936,13 @@ var require_yaml2 = __commonJS({
12936
12936
  function getLocationForJsonPath(result, path) {
12937
12937
  return (0, yaml_1.getLocationForJsonPath)(result, path);
12938
12938
  }
12939
- var parseYaml4 = (input) => (0, yaml_1.parseWithPointers)(input, {
12939
+ var parseYaml5 = (input) => (0, yaml_1.parseWithPointers)(input, {
12940
12940
  ignoreDuplicateKeys: false,
12941
12941
  mergeKeys: true,
12942
12942
  preserveKeyOrder: true,
12943
12943
  attachComments: false
12944
12944
  });
12945
- exports.parseYaml = parseYaml4;
12945
+ exports.parseYaml = parseYaml5;
12946
12946
  exports.Yaml = {
12947
12947
  parse: exports.parseYaml,
12948
12948
  getLocationForJsonPath,
@@ -13032,11 +13032,11 @@ function __metadata2(metadataKey, metadataValue) {
13032
13032
  }
13033
13033
  function __awaiter2(thisArg, _arguments, P2, generator) {
13034
13034
  function adopt(value) {
13035
- return value instanceof P2 ? value : new P2(function(resolve7) {
13036
- resolve7(value);
13035
+ return value instanceof P2 ? value : new P2(function(resolve8) {
13036
+ resolve8(value);
13037
13037
  });
13038
13038
  }
13039
- return new (P2 || (P2 = Promise))(function(resolve7, reject) {
13039
+ return new (P2 || (P2 = Promise))(function(resolve8, reject) {
13040
13040
  function fulfilled(value) {
13041
13041
  try {
13042
13042
  step(generator.next(value));
@@ -13052,7 +13052,7 @@ function __awaiter2(thisArg, _arguments, P2, generator) {
13052
13052
  }
13053
13053
  }
13054
13054
  function step(result) {
13055
- result.done ? resolve7(result.value) : adopt(result.value).then(fulfilled, rejected);
13055
+ result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
13056
13056
  }
13057
13057
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13058
13058
  });
@@ -13230,14 +13230,14 @@ function __asyncValues2(o3) {
13230
13230
  }, i3);
13231
13231
  function verb(n3) {
13232
13232
  i3[n3] = o3[n3] && function(v2) {
13233
- return new Promise(function(resolve7, reject) {
13234
- v2 = o3[n3](v2), settle(resolve7, reject, v2.done, v2.value);
13233
+ return new Promise(function(resolve8, reject) {
13234
+ v2 = o3[n3](v2), settle(resolve8, reject, v2.done, v2.value);
13235
13235
  });
13236
13236
  };
13237
13237
  }
13238
- function settle(resolve7, reject, d2, v2) {
13238
+ function settle(resolve8, reject, d2, v2) {
13239
13239
  Promise.resolve(v2).then(function(v3) {
13240
- resolve7({ value: v3, done: d2 });
13240
+ resolve8({ value: v3, done: d2 });
13241
13241
  }, reject);
13242
13242
  }
13243
13243
  }
@@ -18835,7 +18835,7 @@ function consumeBody() {
18835
18835
  let accum = [];
18836
18836
  let accumBytes = 0;
18837
18837
  let abort = false;
18838
- return new Body.Promise(function(resolve7, reject) {
18838
+ return new Body.Promise(function(resolve8, reject) {
18839
18839
  let resTimeout;
18840
18840
  if (_this4.timeout) {
18841
18841
  resTimeout = setTimeout(function() {
@@ -18869,7 +18869,7 @@ function consumeBody() {
18869
18869
  }
18870
18870
  clearTimeout(resTimeout);
18871
18871
  try {
18872
- resolve7(Buffer.concat(accum, accumBytes));
18872
+ resolve8(Buffer.concat(accum, accumBytes));
18873
18873
  } catch (err) {
18874
18874
  reject(new FetchError(`Could not create Buffer from response body for ${_this4.url}: ${err.message}`, "system", err));
18875
18875
  }
@@ -19132,7 +19132,7 @@ function fetch(url, opts) {
19132
19132
  throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
19133
19133
  }
19134
19134
  Body.Promise = fetch.Promise;
19135
- return new fetch.Promise(function(resolve7, reject) {
19135
+ return new fetch.Promise(function(resolve8, reject) {
19136
19136
  const request = new Request(url, opts);
19137
19137
  const options = getNodeRequestOptions(request);
19138
19138
  const send = (options.protocol === "https:" ? https : http).request;
@@ -19265,7 +19265,7 @@ function fetch(url, opts) {
19265
19265
  requestOpts.body = void 0;
19266
19266
  requestOpts.headers.delete("content-length");
19267
19267
  }
19268
- resolve7(fetch(new Request(locationURL, requestOpts)));
19268
+ resolve8(fetch(new Request(locationURL, requestOpts)));
19269
19269
  finalize();
19270
19270
  return;
19271
19271
  }
@@ -19286,7 +19286,7 @@ function fetch(url, opts) {
19286
19286
  const codings = headers.get("Content-Encoding");
19287
19287
  if (!request.compress || request.method === "HEAD" || codings === null || res.statusCode === 204 || res.statusCode === 304) {
19288
19288
  response = new Response(body, response_options);
19289
- resolve7(response);
19289
+ resolve8(response);
19290
19290
  return;
19291
19291
  }
19292
19292
  const zlibOptions = {
@@ -19296,7 +19296,7 @@ function fetch(url, opts) {
19296
19296
  if (codings == "gzip" || codings == "x-gzip") {
19297
19297
  body = body.pipe(zlib.createGunzip(zlibOptions));
19298
19298
  response = new Response(body, response_options);
19299
- resolve7(response);
19299
+ resolve8(response);
19300
19300
  return;
19301
19301
  }
19302
19302
  if (codings == "deflate" || codings == "x-deflate") {
@@ -19308,12 +19308,12 @@ function fetch(url, opts) {
19308
19308
  body = body.pipe(zlib.createInflateRaw());
19309
19309
  }
19310
19310
  response = new Response(body, response_options);
19311
- resolve7(response);
19311
+ resolve8(response);
19312
19312
  });
19313
19313
  raw.on("end", function() {
19314
19314
  if (!response) {
19315
19315
  response = new Response(body, response_options);
19316
- resolve7(response);
19316
+ resolve8(response);
19317
19317
  }
19318
19318
  });
19319
19319
  return;
@@ -19321,11 +19321,11 @@ function fetch(url, opts) {
19321
19321
  if (codings == "br" && typeof zlib.createBrotliDecompress === "function") {
19322
19322
  body = body.pipe(zlib.createBrotliDecompress());
19323
19323
  response = new Response(body, response_options);
19324
- resolve7(response);
19324
+ resolve8(response);
19325
19325
  return;
19326
19326
  }
19327
19327
  response = new Response(body, response_options);
19328
- resolve7(response);
19328
+ resolve8(response);
19329
19329
  });
19330
19330
  writeToStream(req, request);
19331
19331
  });
@@ -20038,13 +20038,13 @@ var require_file = __commonJS({
20038
20038
  Object.defineProperty(exports, "__esModule", { value: true });
20039
20039
  var fs_1 = __require("fs");
20040
20040
  function resolveFile(ref) {
20041
- return new Promise((resolve7, reject) => {
20041
+ return new Promise((resolve8, reject) => {
20042
20042
  const path = ref.href();
20043
20043
  fs_1.readFile(path, "utf8", (err, data) => {
20044
20044
  if (err) {
20045
20045
  reject(err);
20046
20046
  } else {
20047
- resolve7(data);
20047
+ resolve8(data);
20048
20048
  }
20049
20049
  });
20050
20050
  });
@@ -27647,12 +27647,12 @@ var require_reader = __commonJS({
27647
27647
  }
27648
27648
  } else {
27649
27649
  try {
27650
- return await new Promise((resolve7, reject) => {
27650
+ return await new Promise((resolve8, reject) => {
27651
27651
  fs.readFile(name, opts.encoding, (err, data) => {
27652
27652
  if (err !== null) {
27653
27653
  reject(err);
27654
27654
  } else {
27655
- resolve7(data);
27655
+ resolve8(data);
27656
27656
  }
27657
27657
  });
27658
27658
  });
@@ -44537,14 +44537,14 @@ var require_AsyncFromSyncIteratorContinuation = __commonJS({
44537
44537
  if (!$Promise) {
44538
44538
  throw new $SyntaxError("This environment does not support Promises.");
44539
44539
  }
44540
- return new $Promise(function(resolve7) {
44540
+ return new $Promise(function(resolve8) {
44541
44541
  var done = IteratorComplete(result);
44542
44542
  var value = IteratorValue(result);
44543
44543
  var valueWrapper = PromiseResolve($Promise, value);
44544
44544
  var onFulfilled = function(value2) {
44545
44545
  return CreateIteratorResultObject(value2, done);
44546
44546
  };
44547
- resolve7($then(valueWrapper, onFulfilled));
44547
+ resolve8($then(valueWrapper, onFulfilled));
44548
44548
  });
44549
44549
  };
44550
44550
  }
@@ -45092,7 +45092,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
45092
45092
  var O2 = this;
45093
45093
  SLOT.assert(O2, "[[SyncIteratorRecord]]");
45094
45094
  var argsLength = arguments.length;
45095
- return new $Promise(function(resolve7) {
45095
+ return new $Promise(function(resolve8) {
45096
45096
  var syncIteratorRecord = SLOT.get(O2, "[[SyncIteratorRecord]]");
45097
45097
  var result;
45098
45098
  if (argsLength > 0) {
@@ -45100,7 +45100,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
45100
45100
  } else {
45101
45101
  result = IteratorNext(syncIteratorRecord);
45102
45102
  }
45103
- resolve7(AsyncFromSyncIteratorContinuation(result));
45103
+ resolve8(AsyncFromSyncIteratorContinuation(result));
45104
45104
  });
45105
45105
  },
45106
45106
  "return": function() {
@@ -45111,12 +45111,12 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
45111
45111
  SLOT.assert(O2, "[[SyncIteratorRecord]]");
45112
45112
  var valueIsPresent = arguments.length > 0;
45113
45113
  var value = valueIsPresent ? arguments[0] : void 0;
45114
- return new $Promise(function(resolve7, reject) {
45114
+ return new $Promise(function(resolve8, reject) {
45115
45115
  var syncIterator = SLOT.get(O2, "[[SyncIteratorRecord]]")["[[Iterator]]"];
45116
45116
  var iteratorReturn = GetMethod(syncIterator, "return");
45117
45117
  if (typeof iteratorReturn === "undefined") {
45118
45118
  var iterResult = CreateIteratorResultObject(value, true);
45119
- Call(resolve7, void 0, [iterResult]);
45119
+ Call(resolve8, void 0, [iterResult]);
45120
45120
  return;
45121
45121
  }
45122
45122
  var result;
@@ -45129,7 +45129,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
45129
45129
  Call(reject, void 0, [new $TypeError("Iterator `return` method returned a non-object value.")]);
45130
45130
  return;
45131
45131
  }
45132
- resolve7(AsyncFromSyncIteratorContinuation(result));
45132
+ resolve8(AsyncFromSyncIteratorContinuation(result));
45133
45133
  });
45134
45134
  },
45135
45135
  "throw": function() {
@@ -45140,7 +45140,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
45140
45140
  SLOT.assert(O2, "[[SyncIteratorRecord]]");
45141
45141
  var valueIsPresent = arguments.length > 0;
45142
45142
  var value = valueIsPresent ? arguments[0] : void 0;
45143
- return new $Promise(function(resolve7, reject) {
45143
+ return new $Promise(function(resolve8, reject) {
45144
45144
  var syncIterator = SLOT.get(O2, "[[SyncIteratorRecord]]")["[[Iterator]]"];
45145
45145
  var throwMethod = GetMethod(syncIterator, "throw");
45146
45146
  if (typeof throwMethod === "undefined") {
@@ -45157,7 +45157,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
45157
45157
  Call(reject, void 0, [new $TypeError("Iterator `throw` method returned a non-object value.")]);
45158
45158
  return;
45159
45159
  }
45160
- resolve7(AsyncFromSyncIteratorContinuation(
45160
+ resolve8(AsyncFromSyncIteratorContinuation(
45161
45161
  result
45162
45162
  /* , promiseCapability */
45163
45163
  ));
@@ -48975,11 +48975,12 @@ var CONTEXT_TYPES = [
48975
48975
  "policy",
48976
48976
  "guardrail",
48977
48977
  "guardrail_policy",
48978
- "system"
48978
+ "system",
48979
+ "navigation_index"
48979
48980
  ];
48980
48981
  var ContextTypeSchema = z3.enum(CONTEXT_TYPES);
48981
48982
  var ITERABLE_CONTEXT_TYPES = CONTEXT_TYPES.filter(
48982
- (t3) => t3 !== "system"
48983
+ (t3) => t3 !== "system" && t3 !== "navigation_index"
48983
48984
  );
48984
48985
 
48985
48986
  // src/schema/binding.ts
@@ -49217,7 +49218,9 @@ var CommandSchema = z12.object({
49217
49218
  purpose: z12.string().optional()
49218
49219
  });
49219
49220
  var ToolSchema = z12.object({
49220
- kind: z12.string(),
49221
+ kind: z12.string().optional(),
49222
+ extends: z12.string().optional(),
49223
+ command: z12.string().optional(),
49221
49224
  description: z12.string().optional(),
49222
49225
  input_artifacts: z12.array(z12.string()).default([]),
49223
49226
  output_artifacts: z12.array(z12.string()).default([]),
@@ -50166,6 +50169,123 @@ function mergeDsl(base, project) {
50166
50169
 
50167
50170
  // src/resolver/resolve.ts
50168
50171
  import { dirname as dirname2, resolve as resolvePath } from "path";
50172
+
50173
+ // src/resolver/tool-extends.ts
50174
+ var ToolExtendsError = class extends Error {
50175
+ constructor(message) {
50176
+ super(message);
50177
+ this.name = "ToolExtendsError";
50178
+ }
50179
+ };
50180
+ function asStringArray(value) {
50181
+ return Array.isArray(value) ? value : [];
50182
+ }
50183
+ function asRecord(value) {
50184
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
50185
+ return value;
50186
+ }
50187
+ return {};
50188
+ }
50189
+ function asCommands(value) {
50190
+ return Array.isArray(value) ? value : [];
50191
+ }
50192
+ function isUnset(value) {
50193
+ return value === void 0 || value === null;
50194
+ }
50195
+ function mergeToolFields(base, child) {
50196
+ const merged = { ...child };
50197
+ merged.artifact_bindings = {
50198
+ ...asRecord(base.artifact_bindings),
50199
+ ...asRecord(child.artifact_bindings)
50200
+ };
50201
+ if (isUnset(child.kind) && !isUnset(base.kind)) {
50202
+ merged.kind = base.kind;
50203
+ }
50204
+ if (isUnset(child.cli_contract) && !isUnset(base.cli_contract)) {
50205
+ merged.cli_contract = base.cli_contract;
50206
+ }
50207
+ if (isUnset(child.description) && !isUnset(base.description)) {
50208
+ merged.description = base.description;
50209
+ }
50210
+ const childInvokableBy = asStringArray(child.invokable_by);
50211
+ const baseInvokableBy = asStringArray(base.invokable_by);
50212
+ if (childInvokableBy.length === 0 && baseInvokableBy.length > 0) {
50213
+ merged.invokable_by = [...baseInvokableBy];
50214
+ }
50215
+ const childInputArtifacts = asStringArray(child.input_artifacts);
50216
+ const baseInputArtifacts = asStringArray(base.input_artifacts);
50217
+ if (childInputArtifacts.length === 0 && baseInputArtifacts.length > 0) {
50218
+ merged.input_artifacts = [...baseInputArtifacts];
50219
+ }
50220
+ const childOutputArtifacts = asStringArray(child.output_artifacts);
50221
+ const baseOutputArtifacts = asStringArray(base.output_artifacts);
50222
+ if (childOutputArtifacts.length === 0 && baseOutputArtifacts.length > 0) {
50223
+ merged.output_artifacts = [...baseOutputArtifacts];
50224
+ }
50225
+ const childSideEffects = asStringArray(child.side_effects);
50226
+ const baseSideEffects = asStringArray(base.side_effects);
50227
+ if (childSideEffects.length === 0 && baseSideEffects.length > 0) {
50228
+ merged.side_effects = [...baseSideEffects];
50229
+ }
50230
+ const childCommands = asCommands(child.commands);
50231
+ const baseCommands = asCommands(base.commands);
50232
+ if (childCommands.length === 0 && baseCommands.length > 0) {
50233
+ merged.commands = [...baseCommands];
50234
+ }
50235
+ if (isUnset(child.guardrails) && !isUnset(base.guardrails)) {
50236
+ merged.guardrails = base.guardrails;
50237
+ }
50238
+ return merged;
50239
+ }
50240
+ function resolveToolChain(id, tools, resolving, resolved) {
50241
+ const cached = resolved.get(id);
50242
+ if (cached !== void 0) {
50243
+ return cached;
50244
+ }
50245
+ const tool = tools[id];
50246
+ if (tool === void 0) {
50247
+ throw new ToolExtendsError(`Tool "${id}" not found`);
50248
+ }
50249
+ const extendsId = tool.extends;
50250
+ if (extendsId === void 0) {
50251
+ resolved.set(id, tool);
50252
+ return tool;
50253
+ }
50254
+ if (resolving.has(id)) {
50255
+ throw new ToolExtendsError(
50256
+ `Circular tool extends detected involving "${id}"`
50257
+ );
50258
+ }
50259
+ const baseTool = tools[extendsId];
50260
+ if (baseTool === void 0) {
50261
+ resolved.set(id, tool);
50262
+ return tool;
50263
+ }
50264
+ resolving.add(id);
50265
+ try {
50266
+ const resolvedBase = resolveToolChain(
50267
+ extendsId,
50268
+ tools,
50269
+ resolving,
50270
+ resolved
50271
+ );
50272
+ const merged = mergeToolFields(resolvedBase, tool);
50273
+ resolved.set(id, merged);
50274
+ return merged;
50275
+ } finally {
50276
+ resolving.delete(id);
50277
+ }
50278
+ }
50279
+ function resolveToolExtends(tools) {
50280
+ const resolved = /* @__PURE__ */ new Map();
50281
+ const result = {};
50282
+ for (const id of Object.keys(tools)) {
50283
+ result[id] = resolveToolChain(id, tools, /* @__PURE__ */ new Set(), resolved);
50284
+ }
50285
+ return result;
50286
+ }
50287
+
50288
+ // src/resolver/resolve.ts
50169
50289
  async function resolveExtendsChain(data, filePath, seen) {
50170
50290
  const extendsValue = data["extends"];
50171
50291
  if (typeof extendsValue !== "string") {
@@ -50195,6 +50315,10 @@ async function resolve3(projectDirOrFile) {
50195
50315
  projectResult.filePath,
50196
50316
  /* @__PURE__ */ new Set()
50197
50317
  );
50318
+ const tools = data["tools"];
50319
+ if (tools !== void 0 && tools !== null && typeof tools === "object" && !Array.isArray(tools)) {
50320
+ data["tools"] = resolveToolExtends(tools);
50321
+ }
50198
50322
  return {
50199
50323
  data,
50200
50324
  projectPath: projectResult.filePath,
@@ -51012,7 +51136,7 @@ function checkReferences(dsl) {
51012
51136
  for (const [id, art] of Object.entries(dsl.artifacts)) {
51013
51137
  if (art.owner) {
51014
51138
  const ownerAgent = dsl.agents[art.owner];
51015
- if (ownerAgent && !ownerAgent.can_read_artifacts.includes(id)) {
51139
+ if (ownerAgent && ownerAgent.can_read_artifacts.length > 0 && !ownerAgent.can_read_artifacts.includes(id)) {
51016
51140
  diagnostics.push({
51017
51141
  path: `artifacts.${id}.owner`,
51018
51142
  message: `Agent "${art.owner}" owns artifact "${id}" but cannot read it (missing from can_read_artifacts)`,
@@ -51035,6 +51159,15 @@ function checkReferences(dsl) {
51035
51159
  }
51036
51160
  }
51037
51161
  for (const [id, tool] of Object.entries(dsl.tools)) {
51162
+ if (tool.extends) {
51163
+ checkExists(
51164
+ tool.extends,
51165
+ toolIds,
51166
+ "tools",
51167
+ `tools.${id}.extends`,
51168
+ "tool-extends-not-found"
51169
+ );
51170
+ }
51038
51171
  if (tool.invokable_by.length > 0) {
51039
51172
  for (const ref of tool.invokable_by) {
51040
51173
  checkExists(ref, agentIds, "agents", `tools.${id}.invokable_by`);
@@ -51117,14 +51250,16 @@ function checkReferences(dsl) {
51117
51250
  code: "result-handoff-not-returnable"
51118
51251
  });
51119
51252
  }
51120
- for (let j2 = 0; j2 < task.input_artifacts.length; j2++) {
51121
- const inputId = task.input_artifacts[j2];
51122
- if (!targetAgent.can_read_artifacts.includes(inputId)) {
51123
- diagnostics.push({
51124
- path: `tasks.${id}.input_artifacts[${j2}]`,
51125
- message: `Input artifact "${inputId}" is not in target agent "${task.target_agent}" can_read_artifacts`,
51126
- code: "input-artifact-not-readable"
51127
- });
51253
+ if (targetAgent.can_read_artifacts.length > 0) {
51254
+ for (let j2 = 0; j2 < task.input_artifacts.length; j2++) {
51255
+ const inputId = task.input_artifacts[j2];
51256
+ if (!targetAgent.can_read_artifacts.includes(inputId)) {
51257
+ diagnostics.push({
51258
+ path: `tasks.${id}.input_artifacts[${j2}]`,
51259
+ message: `Input artifact "${inputId}" is not in target agent "${task.target_agent}" can_read_artifacts`,
51260
+ code: "input-artifact-not-readable"
51261
+ });
51262
+ }
51128
51263
  }
51129
51264
  }
51130
51265
  }
@@ -51140,7 +51275,7 @@ function checkReferences(dsl) {
51140
51275
  if (agent.prerequisites) {
51141
51276
  for (let j2 = 0; j2 < agent.prerequisites.length; j2++) {
51142
51277
  const pre = agent.prerequisites[j2];
51143
- if (!agent.can_read_artifacts.includes(pre.target)) {
51278
+ if (agent.can_read_artifacts.length > 0 && !agent.can_read_artifacts.includes(pre.target)) {
51144
51279
  diagnostics.push({
51145
51280
  path: `agents.${id}.prerequisites[${j2}].target`,
51146
51281
  message: `Prerequisite target "${pre.target}" is not in agent "${id}" can_read_artifacts`,
@@ -51531,14 +51666,16 @@ var taskAgentBindingRule = {
51531
51666
  for (const [taskId, task] of Object.entries(dsl.tasks)) {
51532
51667
  const targetAgent = dsl.agents[task.target_agent];
51533
51668
  if (!targetAgent) continue;
51534
- for (const ref of task.input_artifacts) {
51535
- if (!targetAgent.can_read_artifacts.includes(ref)) {
51536
- diagnostics.push({
51537
- ruleId: "task-agent-binding",
51538
- severity: "error",
51539
- path: `tasks.${taskId}.input_artifacts`,
51540
- message: `Task "${taskId}" input_artifact "${ref}" not in target agent "${task.target_agent}" can_read_artifacts`
51541
- });
51669
+ if (targetAgent.can_read_artifacts.length > 0) {
51670
+ for (const ref of task.input_artifacts) {
51671
+ if (!targetAgent.can_read_artifacts.includes(ref)) {
51672
+ diagnostics.push({
51673
+ ruleId: "task-agent-binding",
51674
+ severity: "error",
51675
+ path: `tasks.${taskId}.input_artifacts`,
51676
+ message: `Task "${taskId}" input_artifact "${ref}" not in target agent "${task.target_agent}" can_read_artifacts`
51677
+ });
51678
+ }
51542
51679
  }
51543
51680
  }
51544
51681
  if (!targetAgent.can_return_handoffs.includes(task.result_handoff)) {
@@ -51574,7 +51711,7 @@ var taskAgentBindingRule = {
51574
51711
  });
51575
51712
  }
51576
51713
  }
51577
- if (step.produces_artifact) {
51714
+ if (step.produces_artifact && targetAgent.can_write_artifacts.length > 0) {
51578
51715
  if (!targetAgent.can_write_artifacts.includes(step.produces_artifact)) {
51579
51716
  diagnostics.push({
51580
51717
  ruleId: "task-agent-binding",
@@ -51584,7 +51721,7 @@ var taskAgentBindingRule = {
51584
51721
  });
51585
51722
  }
51586
51723
  }
51587
- if (step.reads_artifact) {
51724
+ if (step.reads_artifact && targetAgent.can_read_artifacts.length > 0) {
51588
51725
  if (!targetAgent.can_read_artifacts.includes(step.reads_artifact)) {
51589
51726
  diagnostics.push({
51590
51727
  ruleId: "task-agent-binding",
@@ -51649,7 +51786,8 @@ var artifactOwnershipRule = {
51649
51786
  }
51650
51787
  if (step.reads_artifact) {
51651
51788
  const artifact = dsl.artifacts[step.reads_artifact];
51652
- if (artifact && (artifact.consumers.length > 0 || artifact.producers.length > 0 || artifact.editors.length > 0)) {
51789
+ const hasDeprecatedOwnership = !!artifact?.owner || (artifact?.producers.length ?? 0) > 0 || (artifact?.editors.length ?? 0) > 0 || (artifact?.consumers.length ?? 0) > 0;
51790
+ if (artifact && hasDeprecatedOwnership) {
51653
51791
  const canRead = artifact.consumers.includes(agentId) || artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
51654
51792
  if (!canRead) {
51655
51793
  diagnostics.push({
@@ -52087,6 +52225,7 @@ var artifactOwnershipConsistencyRule = {
52087
52225
  run(dsl) {
52088
52226
  const diagnostics = [];
52089
52227
  for (const [agentId, agent] of Object.entries(dsl.agents)) {
52228
+ if (agent.own_artifacts.length === 0) continue;
52090
52229
  for (const artId of agent.own_artifacts) {
52091
52230
  if (!agent.can_read_artifacts.includes(artId)) {
52092
52231
  diagnostics.push({
@@ -52114,6 +52253,68 @@ var artifactOwnershipConsistencyRule = {
52114
52253
  }
52115
52254
  };
52116
52255
 
52256
+ // src/linter/rules/deprecated-ownership-fields.ts
52257
+ var ARTIFACT_FIELDS = ["owner", "producers", "editors", "consumers"];
52258
+ var AGENT_FIELDS = [
52259
+ "own_artifacts",
52260
+ "can_read_artifacts",
52261
+ "can_write_artifacts"
52262
+ ];
52263
+ function isArtifactFieldUsed(artifact, field) {
52264
+ switch (field) {
52265
+ case "owner":
52266
+ return !!artifact.owner;
52267
+ case "producers":
52268
+ return artifact.producers.length > 0;
52269
+ case "editors":
52270
+ return artifact.editors.length > 0;
52271
+ case "consumers":
52272
+ return artifact.consumers.length > 0;
52273
+ }
52274
+ }
52275
+ function isAgentFieldUsed(agent, field) {
52276
+ switch (field) {
52277
+ case "own_artifacts":
52278
+ return agent.own_artifacts.length > 0;
52279
+ case "can_read_artifacts":
52280
+ return agent.can_read_artifacts.length > 0;
52281
+ case "can_write_artifacts":
52282
+ return agent.can_write_artifacts.length > 0;
52283
+ }
52284
+ }
52285
+ var deprecatedOwnershipFieldsRule = {
52286
+ id: "deprecated-ownership-fields",
52287
+ description: "Warn when deprecated ownership/permission fields are used instead of artifact_bindings + artifact_slots",
52288
+ run(dsl) {
52289
+ const diagnostics = [];
52290
+ for (const [artId, artifact] of Object.entries(dsl.artifacts)) {
52291
+ for (const field of ARTIFACT_FIELDS) {
52292
+ if (isArtifactFieldUsed(artifact, field)) {
52293
+ diagnostics.push({
52294
+ ruleId: "deprecated-ownership-fields",
52295
+ severity: "warning",
52296
+ path: `artifacts.${artId}.${field}`,
52297
+ message: `Artifact "${artId}" uses deprecated field "${field}". Ownership is derived from artifact_bindings + artifact_slots in the binding model.`
52298
+ });
52299
+ }
52300
+ }
52301
+ }
52302
+ for (const [agentId, agent] of Object.entries(dsl.agents)) {
52303
+ for (const field of AGENT_FIELDS) {
52304
+ if (isAgentFieldUsed(agent, field)) {
52305
+ diagnostics.push({
52306
+ ruleId: "deprecated-ownership-fields",
52307
+ severity: "warning",
52308
+ path: `agents.${agentId}.${field}`,
52309
+ message: `Agent "${agentId}" uses deprecated field "${field}". Artifact permissions are derived from artifact_bindings + artifact_slots in the binding model.`
52310
+ });
52311
+ }
52312
+ }
52313
+ }
52314
+ return diagnostics;
52315
+ }
52316
+ };
52317
+
52117
52318
  // src/linter/rules/extension-consumption.ts
52118
52319
  function isRecord4(v2) {
52119
52320
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
@@ -52284,6 +52485,194 @@ var extensionUndeclaredUsageRule = {
52284
52485
  }
52285
52486
  };
52286
52487
 
52488
+ // src/navigation-index/cli-contract-loader.ts
52489
+ import { existsSync, readFileSync } from "fs";
52490
+ import { isAbsolute, resolve as resolve4 } from "path";
52491
+ import { parse as parseYaml2 } from "yaml";
52492
+ function extractStringArray(value) {
52493
+ if (!Array.isArray(value)) return [];
52494
+ return value.filter((item) => typeof item === "string");
52495
+ }
52496
+ function extractArtifactSlots(doc) {
52497
+ const slots = doc.artifact_slots;
52498
+ if (!slots || typeof slots !== "object") return null;
52499
+ const result = {};
52500
+ for (const [name, slotDef] of Object.entries(slots)) {
52501
+ if (!slotDef || typeof slotDef !== "object") continue;
52502
+ const direction = slotDef.direction;
52503
+ if (direction === "read" || direction === "write" || direction === "readwrite") {
52504
+ result[name] = { direction };
52505
+ }
52506
+ }
52507
+ return Object.keys(result).length > 0 ? result : null;
52508
+ }
52509
+ function extractCommandEffects(doc) {
52510
+ const result = {};
52511
+ const commandSets = doc.command_sets;
52512
+ if (!commandSets || typeof commandSets !== "object") return result;
52513
+ for (const setDef of Object.values(commandSets)) {
52514
+ if (!setDef || typeof setDef !== "object") continue;
52515
+ const commands = setDef.commands;
52516
+ if (!commands || typeof commands !== "object") continue;
52517
+ for (const [cmdName, cmdDef] of Object.entries(commands)) {
52518
+ if (!cmdDef || typeof cmdDef !== "object") continue;
52519
+ const effects = cmdDef.effects;
52520
+ if (!effects || typeof effects !== "object") continue;
52521
+ result[cmdName] = {
52522
+ reads: extractStringArray(effects.reads),
52523
+ writes: extractStringArray(effects.writes)
52524
+ };
52525
+ }
52526
+ }
52527
+ return result;
52528
+ }
52529
+ function resolveCliContractPath(cliContractPath) {
52530
+ return isAbsolute(cliContractPath) ? cliContractPath : resolve4(process.cwd(), cliContractPath);
52531
+ }
52532
+ function loadCliContractSlots(cliContractPath) {
52533
+ const filePath = resolveCliContractPath(cliContractPath);
52534
+ if (!existsSync(filePath)) return null;
52535
+ let doc;
52536
+ try {
52537
+ doc = parseYaml2(readFileSync(filePath, "utf8"));
52538
+ } catch {
52539
+ return null;
52540
+ }
52541
+ if (!doc || typeof doc !== "object") return null;
52542
+ const artifactSlots = extractArtifactSlots(doc);
52543
+ if (!artifactSlots) return null;
52544
+ return {
52545
+ artifactSlots,
52546
+ commandEffects: extractCommandEffects(doc)
52547
+ };
52548
+ }
52549
+ function resolveSlotDirection(slot, command, slotInfo) {
52550
+ const cmdEffects = slotInfo.commandEffects[command];
52551
+ if (cmdEffects) {
52552
+ if (cmdEffects.writes.includes(slot)) return "write";
52553
+ if (cmdEffects.reads.includes(slot)) return "read";
52554
+ }
52555
+ const slotDecl = slotInfo.artifactSlots[slot];
52556
+ if (slotDecl) {
52557
+ if (slotDecl.direction === "write" || slotDecl.direction === "readwrite") {
52558
+ return "write";
52559
+ }
52560
+ return "read";
52561
+ }
52562
+ return "read";
52563
+ }
52564
+
52565
+ // src/linter/rules/binding-completeness.ts
52566
+ var bindingCompletenessRule = {
52567
+ id: "binding-completeness",
52568
+ description: "Check that artifact_bindings cover all slots referenced in the cli-contract command effects",
52569
+ run(dsl) {
52570
+ const diagnostics = [];
52571
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
52572
+ if (!tool.cli_contract || !tool.artifact_bindings) continue;
52573
+ const slotInfo = loadCliContractSlots(tool.cli_contract);
52574
+ if (!slotInfo?.artifactSlots) continue;
52575
+ const command = tool.command ?? "";
52576
+ const effects = slotInfo.commandEffects[command];
52577
+ if (!effects) continue;
52578
+ const referencedSlots = [...effects.reads, ...effects.writes];
52579
+ const boundSlots = new Set(Object.keys(tool.artifact_bindings));
52580
+ for (const slot of referencedSlots) {
52581
+ if (boundSlots.has(slot)) continue;
52582
+ diagnostics.push({
52583
+ ruleId: "binding-completeness",
52584
+ severity: "warning",
52585
+ path: `tools.${toolId}.artifact_bindings`,
52586
+ message: `Command "${command}" references slot "${slot}" but tool has no artifact_bindings entry for it`
52587
+ });
52588
+ }
52589
+ }
52590
+ return diagnostics;
52591
+ }
52592
+ };
52593
+
52594
+ // src/linter/rules/binding-direction-match.ts
52595
+ function agentCanWriteArtifact(agentId, artifactId, dsl) {
52596
+ const agent = dsl.agents[agentId];
52597
+ if (!agent) return false;
52598
+ return agent.can_write_artifacts.includes(artifactId) || agent.own_artifacts.includes(artifactId);
52599
+ }
52600
+ var bindingDirectionMatchRule = {
52601
+ id: "binding-direction-match",
52602
+ description: "Check that agents invoking a tool can write artifacts bound via write slots",
52603
+ run(dsl) {
52604
+ const diagnostics = [];
52605
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
52606
+ if (!tool.cli_contract || !tool.artifact_bindings) continue;
52607
+ const slotInfo = loadCliContractSlots(tool.cli_contract);
52608
+ if (!slotInfo) continue;
52609
+ const command = tool.command ?? "";
52610
+ for (const [slot, artifactId] of Object.entries(tool.artifact_bindings)) {
52611
+ const direction = resolveSlotDirection(slot, command, slotInfo);
52612
+ if (direction !== "write") continue;
52613
+ for (const agentId of tool.invokable_by) {
52614
+ if (agentCanWriteArtifact(agentId, artifactId, dsl)) continue;
52615
+ diagnostics.push({
52616
+ ruleId: "binding-direction-match",
52617
+ severity: "warning",
52618
+ path: `tools.${toolId}.artifact_bindings.${slot}`,
52619
+ message: `Agent "${agentId}" invokes tool "${toolId}" which writes to artifact "${artifactId}" via slot "${slot}", but agent lacks can_write_artifacts or own_artifacts for it`
52620
+ });
52621
+ }
52622
+ }
52623
+ }
52624
+ return diagnostics;
52625
+ }
52626
+ };
52627
+
52628
+ // src/linter/rules/slot-declaration-exists.ts
52629
+ var slotDeclarationExistsRule = {
52630
+ id: "slot-declaration-exists",
52631
+ description: "Check that artifact_bindings keys reference slot names declared in the cli-contract",
52632
+ run(dsl) {
52633
+ const diagnostics = [];
52634
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
52635
+ if (!tool.cli_contract || !tool.artifact_bindings) continue;
52636
+ const slotInfo = loadCliContractSlots(tool.cli_contract);
52637
+ if (!slotInfo?.artifactSlots) continue;
52638
+ for (const slot of Object.keys(tool.artifact_bindings)) {
52639
+ if (slot in slotInfo.artifactSlots) continue;
52640
+ diagnostics.push({
52641
+ ruleId: "slot-declaration-exists",
52642
+ severity: "warning",
52643
+ path: `tools.${toolId}.artifact_bindings.${slot}`,
52644
+ message: `artifact_bindings key "${slot}" is not declared in cli-contract artifactSlots`
52645
+ });
52646
+ }
52647
+ }
52648
+ return diagnostics;
52649
+ }
52650
+ };
52651
+
52652
+ // src/linter/rules/config-path-consistency.ts
52653
+ var configPathConsistencyRule = {
52654
+ id: "config-path-consistency",
52655
+ description: "Check that control-authority artifacts bound by tools have path_patterns defined",
52656
+ run(dsl) {
52657
+ const diagnostics = [];
52658
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
52659
+ if (!tool.artifact_bindings) continue;
52660
+ for (const [slot, artifactId] of Object.entries(tool.artifact_bindings)) {
52661
+ const artifact = dsl.artifacts[artifactId];
52662
+ if (!artifact || artifact.authority !== "control") continue;
52663
+ if (artifact.path_patterns && artifact.path_patterns.length > 0) continue;
52664
+ diagnostics.push({
52665
+ ruleId: "config-path-consistency",
52666
+ severity: "info",
52667
+ path: `tools.${toolId}.artifact_bindings.${slot}`,
52668
+ message: `Config artifact "${artifactId}" has no path_patterns; consider adding them for path-based lookup`
52669
+ });
52670
+ }
52671
+ }
52672
+ return diagnostics;
52673
+ }
52674
+ };
52675
+
52287
52676
  // src/linter/linter.ts
52288
52677
  var builtinRules = [
52289
52678
  validationCoverageRule,
@@ -52302,9 +52691,14 @@ var builtinRules = [
52302
52691
  guardrailOrphanedRule,
52303
52692
  validationExecutorNoContextRule,
52304
52693
  artifactOwnershipConsistencyRule,
52694
+ deprecatedOwnershipFieldsRule,
52305
52695
  extensionDeclaredButUnusedRule,
52306
52696
  extensionScopeMismatchRule,
52307
- extensionUndeclaredUsageRule
52697
+ extensionUndeclaredUsageRule,
52698
+ bindingCompletenessRule,
52699
+ bindingDirectionMatchRule,
52700
+ slotDeclarationExistsRule,
52701
+ configPathConsistencyRule
52308
52702
  ];
52309
52703
  function lint(dsl, rules = builtinRules) {
52310
52704
  const diagnostics = [];
@@ -52358,9 +52752,18 @@ var ref_exists_default = (0, import_spectral_core.createRulesetFunction)(
52358
52752
 
52359
52753
  // src/linter/spectral/functions/editors-not-empty.ts
52360
52754
  var import_spectral_core2 = __toESM(require_dist9(), 1);
52755
+ function allDeprecatedOwnershipFieldsEmpty(art) {
52756
+ return !art.owner && (art.producers?.length ?? 0) === 0 && (art.editors?.length ?? 0) === 0 && (art.consumers?.length ?? 0) === 0;
52757
+ }
52361
52758
  var editors_not_empty_default = (0, import_spectral_core2.createRulesetFunction)(
52362
52759
  { input: { type: "array" }, options: null },
52363
- (targetVal, _options, _context) => {
52760
+ (targetVal, _options, context) => {
52761
+ const root = context.document.data;
52762
+ const artId = context.path.length >= 2 ? String(context.path[1]) : void 0;
52763
+ const artifact = artId && root.artifacts ? root.artifacts[artId] : void 0;
52764
+ if (artifact && allDeprecatedOwnershipFieldsEmpty(artifact)) {
52765
+ return [];
52766
+ }
52364
52767
  if (targetVal.length === 0) {
52365
52768
  return [{ message: "editors must not be empty" }];
52366
52769
  }
@@ -52392,6 +52795,7 @@ var prerequisite_readable_default = (0, import_spectral_core4.createRulesetFunct
52392
52795
  (targetVal, _options, context) => {
52393
52796
  const readable = new Set(targetVal.can_read_artifacts ?? []);
52394
52797
  const prereqs = targetVal.prerequisites ?? [];
52798
+ if (readable.size === 0) return [];
52395
52799
  const results = [];
52396
52800
  for (let i3 = 0; i3 < prereqs.length; i3++) {
52397
52801
  const p2 = prereqs[i3];
@@ -52793,7 +53197,7 @@ var ruleset = {
52793
53197
  },
52794
53198
  "artifact-owner-exists": {
52795
53199
  description: "(deprecated) Every artifact must have an owner",
52796
- severity: "warn",
53200
+ severity: "off",
52797
53201
  given: "$.artifacts.*",
52798
53202
  then: {
52799
53203
  field: "owner",
@@ -53667,7 +54071,7 @@ function emitExecutionStep(es, agentAlias2, participants, lines, indent) {
53667
54071
  }
53668
54072
  function emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent) {
53669
54073
  const val = dsl.validations[step.validation];
53670
- if (!val) return;
54074
+ if (!val || !val.executor) return;
53671
54075
  const executorAlias = participantAlias(participants, val.executor);
53672
54076
  const artifactAlias = participantAlias(participants, val.target_artifact);
53673
54077
  const fromAlias = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
@@ -53970,6 +54374,299 @@ function generateOverviewFlowchart(dsl) {
53970
54374
  return sections.join("\n\n");
53971
54375
  }
53972
54376
 
54377
+ // src/navigation-index/builder.ts
54378
+ var VALIDATOR_KINDS = /* @__PURE__ */ new Set(["linter", "checker", "validator", "test"]);
54379
+ var VALIDATION_TERMS = ["lint", "check", "validate", "test", "verify", "audit"];
54380
+ function sortUnique(values) {
54381
+ return [...new Set(values)].sort();
54382
+ }
54383
+ function matchesValidationTerm(value) {
54384
+ const lower = value.toLowerCase();
54385
+ return VALIDATION_TERMS.some((term) => lower.includes(term));
54386
+ }
54387
+ function isValidatorTool(tool) {
54388
+ if (tool.kind && VALIDATOR_KINDS.has(tool.kind)) {
54389
+ return true;
54390
+ }
54391
+ if (tool.command && matchesValidationTerm(tool.command)) {
54392
+ return true;
54393
+ }
54394
+ for (const cmd of tool.commands ?? []) {
54395
+ if (matchesValidationTerm(cmd.category) || matchesValidationTerm(cmd.command)) {
54396
+ return true;
54397
+ }
54398
+ }
54399
+ return false;
54400
+ }
54401
+ function extractToolArtifactLinks(toolId, tool) {
54402
+ const links = [];
54403
+ if (tool.cli_contract) {
54404
+ const command = tool.command ?? "";
54405
+ const slotInfo = loadCliContractSlots(tool.cli_contract);
54406
+ for (const [slot, artifactId] of Object.entries(tool.artifact_bindings ?? {})) {
54407
+ const direction = slotInfo ? resolveSlotDirection(slot, command, slotInfo) : "read";
54408
+ links.push({
54409
+ toolId,
54410
+ artifactId,
54411
+ direction,
54412
+ slot,
54413
+ command
54414
+ });
54415
+ }
54416
+ return links;
54417
+ }
54418
+ for (const cmd of tool.commands ?? []) {
54419
+ for (const artifactId of cmd.reads ?? []) {
54420
+ links.push({
54421
+ toolId,
54422
+ artifactId,
54423
+ direction: "read",
54424
+ slot: "",
54425
+ command: cmd.command
54426
+ });
54427
+ }
54428
+ for (const artifactId of cmd.writes ?? []) {
54429
+ links.push({
54430
+ toolId,
54431
+ artifactId,
54432
+ direction: "write",
54433
+ slot: "",
54434
+ command: cmd.command
54435
+ });
54436
+ }
54437
+ }
54438
+ return links;
54439
+ }
54440
+ function buildOperation(toolId, tool, link) {
54441
+ return {
54442
+ tool: toolId,
54443
+ cli_contract: tool.cli_contract ?? "",
54444
+ command: link.command || tool.command || "",
54445
+ slot: link.slot,
54446
+ invokable_by: [...tool.invokable_by ?? []]
54447
+ };
54448
+ }
54449
+ function operationKey(op) {
54450
+ return `${op.tool}:${op.command}:${op.slot}`;
54451
+ }
54452
+ function dedupeOperations(operations) {
54453
+ const seen = /* @__PURE__ */ new Set();
54454
+ const result = [];
54455
+ for (const op of operations) {
54456
+ const key = operationKey(op);
54457
+ if (seen.has(key)) continue;
54458
+ seen.add(key);
54459
+ result.push(op);
54460
+ }
54461
+ return result.sort((a3, b3) => a3.tool.localeCompare(b3.tool) || a3.slot.localeCompare(b3.slot));
54462
+ }
54463
+ function buildAgentMapping(dsl, artifactId) {
54464
+ const owners = [];
54465
+ const editors = [];
54466
+ const readers = [];
54467
+ for (const [agentId, agent] of Object.entries(dsl.agents)) {
54468
+ if (agent.own_artifacts?.includes(artifactId)) owners.push(agentId);
54469
+ if (agent.can_write_artifacts?.includes(artifactId)) editors.push(agentId);
54470
+ if (agent.can_read_artifacts?.includes(artifactId)) readers.push(agentId);
54471
+ }
54472
+ return {
54473
+ owners: sortUnique(owners),
54474
+ editors: sortUnique(editors),
54475
+ readers: sortUnique(readers)
54476
+ };
54477
+ }
54478
+ function buildRelations(artifactId, authority, linksByArtifact, allLinks) {
54479
+ const sourceArtifacts = /* @__PURE__ */ new Set();
54480
+ const derivedArtifacts = /* @__PURE__ */ new Set();
54481
+ const writesToThis = allLinks.filter(
54482
+ (link) => link.artifactId === artifactId && link.direction === "write"
54483
+ );
54484
+ if (authority === "generated" || authority === "derived") {
54485
+ for (const writeLink of writesToThis) {
54486
+ for (const readLink of allLinks) {
54487
+ if (readLink.toolId === writeLink.toolId && readLink.direction === "read") {
54488
+ sourceArtifacts.add(readLink.artifactId);
54489
+ }
54490
+ }
54491
+ }
54492
+ }
54493
+ const readsThis = allLinks.filter(
54494
+ (link) => link.artifactId === artifactId && link.direction === "read"
54495
+ );
54496
+ for (const readLink of readsThis) {
54497
+ for (const writeLink of allLinks) {
54498
+ if (writeLink.toolId === readLink.toolId && writeLink.direction === "write") {
54499
+ derivedArtifacts.add(writeLink.artifactId);
54500
+ }
54501
+ }
54502
+ }
54503
+ const knownArtifacts = new Set(linksByArtifact.keys());
54504
+ return {
54505
+ source_artifacts: sortUnique(
54506
+ [...sourceArtifacts].filter((id) => id !== artifactId && knownArtifacts.has(id))
54507
+ ),
54508
+ derived_artifacts: sortUnique(
54509
+ [...derivedArtifacts].filter((id) => id !== artifactId && knownArtifacts.has(id))
54510
+ )
54511
+ };
54512
+ }
54513
+ function buildValidateRoutes(validators) {
54514
+ return validators.map((validator) => ({
54515
+ purpose: "validate",
54516
+ steps: [
54517
+ {
54518
+ type: "run_operation",
54519
+ operation: validator.tool,
54520
+ candidate_agents: [...validator.invokable_by]
54521
+ }
54522
+ ]
54523
+ }));
54524
+ }
54525
+ function buildRegenerateRoutes(sourceArtifacts, producers, agentsByArtifact) {
54526
+ if (producers.length === 0) return [];
54527
+ const editSteps = sourceArtifacts.map((artifactId) => ({
54528
+ type: "edit_artifact",
54529
+ artifact: artifactId,
54530
+ candidate_agents: agentsByArtifact.get(artifactId)?.editors ?? []
54531
+ }));
54532
+ const runSteps = producers.map((producer) => ({
54533
+ type: "run_operation",
54534
+ operation: producer.tool,
54535
+ candidate_agents: [...producer.invokable_by]
54536
+ }));
54537
+ return [
54538
+ {
54539
+ purpose: "regenerate",
54540
+ steps: [...editSteps, ...runSteps]
54541
+ }
54542
+ ];
54543
+ }
54544
+ function buildUpdateRoutes(artifactId, validators, editors) {
54545
+ const steps = [
54546
+ {
54547
+ type: "edit_artifact",
54548
+ artifact: artifactId,
54549
+ candidate_agents: [...editors]
54550
+ }
54551
+ ];
54552
+ for (const validator of validators) {
54553
+ steps.push({
54554
+ type: "run_operation",
54555
+ operation: validator.tool,
54556
+ candidate_agents: [...validator.invokable_by]
54557
+ });
54558
+ }
54559
+ return [
54560
+ {
54561
+ purpose: "update",
54562
+ steps
54563
+ }
54564
+ ];
54565
+ }
54566
+ function defaultProperties(artifact) {
54567
+ return {
54568
+ type: artifact.type,
54569
+ authority: artifact.authority ?? "canonical",
54570
+ manual_edit: artifact.manual_edit ?? "allowed",
54571
+ change_control: artifact.change_control ?? "none"
54572
+ };
54573
+ }
54574
+ function buildNavigationIndex(dsl) {
54575
+ const resolvedTools = resolveToolExtends(dsl.tools);
54576
+ const allLinks = [];
54577
+ for (const [toolId, tool] of Object.entries(resolvedTools)) {
54578
+ allLinks.push(...extractToolArtifactLinks(toolId, tool));
54579
+ }
54580
+ const linksByArtifact = /* @__PURE__ */ new Map();
54581
+ for (const link of allLinks) {
54582
+ const existing = linksByArtifact.get(link.artifactId) ?? [];
54583
+ existing.push(link);
54584
+ linksByArtifact.set(link.artifactId, existing);
54585
+ }
54586
+ const toolWrites = /* @__PURE__ */ new Map();
54587
+ for (const link of allLinks) {
54588
+ if (link.direction !== "write") continue;
54589
+ const writes = toolWrites.get(link.toolId) ?? /* @__PURE__ */ new Set();
54590
+ writes.add(link.artifactId);
54591
+ toolWrites.set(link.toolId, writes);
54592
+ }
54593
+ const artifacts = {};
54594
+ const agentsByArtifact = /* @__PURE__ */ new Map();
54595
+ for (const [artifactId, artifactDef] of Object.entries(dsl.artifacts)) {
54596
+ const properties = defaultProperties(artifactDef);
54597
+ const agents = buildAgentMapping(dsl, artifactId);
54598
+ agentsByArtifact.set(artifactId, agents);
54599
+ const artifactLinks = linksByArtifact.get(artifactId) ?? [];
54600
+ const producers = [];
54601
+ const validators = [];
54602
+ const consumers = [];
54603
+ const processedPairs = /* @__PURE__ */ new Set();
54604
+ for (const link of artifactLinks) {
54605
+ const tool = resolvedTools[link.toolId];
54606
+ if (!tool) continue;
54607
+ const pairKey = `${link.toolId}:${link.direction}:${link.slot}:${link.command}`;
54608
+ if (processedPairs.has(pairKey)) continue;
54609
+ processedPairs.add(pairKey);
54610
+ const operation = buildOperation(link.toolId, tool, link);
54611
+ const toolWritesArtifacts = toolWrites.get(link.toolId) ?? /* @__PURE__ */ new Set();
54612
+ if (link.direction === "write" || toolWritesArtifacts.has(artifactId)) {
54613
+ producers.push(operation);
54614
+ } else if (isValidatorTool(tool)) {
54615
+ validators.push(operation);
54616
+ } else if (link.direction === "read") {
54617
+ consumers.push(operation);
54618
+ }
54619
+ }
54620
+ const relations = buildRelations(
54621
+ artifactId,
54622
+ properties.authority,
54623
+ linksByArtifact,
54624
+ allLinks
54625
+ );
54626
+ const routes = {};
54627
+ const dedupedValidators = dedupeOperations(validators);
54628
+ const dedupedProducers = dedupeOperations(producers);
54629
+ if (dedupedValidators.length > 0) {
54630
+ routes.validate = buildValidateRoutes(dedupedValidators);
54631
+ }
54632
+ if (properties.authority === "generated" && dedupedProducers.length > 0 && relations.source_artifacts.length > 0) {
54633
+ routes.regenerate = buildRegenerateRoutes(
54634
+ relations.source_artifacts,
54635
+ dedupedProducers,
54636
+ agentsByArtifact
54637
+ );
54638
+ }
54639
+ if (properties.authority === "canonical") {
54640
+ routes.update = buildUpdateRoutes(artifactId, dedupedValidators, agents.editors);
54641
+ }
54642
+ artifacts[artifactId] = {
54643
+ id: artifactId,
54644
+ files: {
54645
+ path_patterns: artifactDef.path_patterns ?? [],
54646
+ exclude_patterns: artifactDef.exclude_patterns ?? []
54647
+ },
54648
+ properties,
54649
+ relations,
54650
+ operations: {
54651
+ producers: dedupeOperations(producers),
54652
+ validators: dedupedValidators,
54653
+ consumers: dedupeOperations(consumers)
54654
+ },
54655
+ agents,
54656
+ routes
54657
+ };
54658
+ }
54659
+ return {
54660
+ version: "1.0.0",
54661
+ generated_at: (/* @__PURE__ */ new Date()).toISOString(),
54662
+ system: {
54663
+ id: dsl.system.id,
54664
+ name: dsl.system.name
54665
+ },
54666
+ artifacts
54667
+ };
54668
+ }
54669
+
53973
54670
  // src/renderer/renderer.ts
53974
54671
  Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
53975
54672
  Handlebars.registerHelper("notEmpty", (obj) => {
@@ -54279,6 +54976,8 @@ function buildEntityContext(dsl, context, entityId) {
54279
54976
  return buildGuardrailPolicyContext(dsl, entityId);
54280
54977
  case "system":
54281
54978
  return buildSystemContext(dsl);
54979
+ case "navigation_index":
54980
+ return buildNavigationIndex(dsl);
54282
54981
  }
54283
54982
  }
54284
54983
  async function loadTemplate(templatePath) {
@@ -54298,8 +54997,8 @@ async function renderFromConfig(dsl, renderTargets, options) {
54298
54997
  for (const target of renderTargets) {
54299
54998
  const templateContent = await loadTemplate(target.template);
54300
54999
  const compiled = Handlebars.compile(templateContent, { noEscape: false });
54301
- if (target.context === "system") {
54302
- const ctx = buildSystemContext(dsl, options);
55000
+ if (target.context === "system" || target.context === "navigation_index") {
55001
+ const ctx = target.context === "system" ? buildSystemContext(dsl, options) : buildNavigationIndex(dsl);
54303
55002
  const output = compiled(ctx);
54304
55003
  if (target.skip_empty && isEffectivelyEmpty(output)) {
54305
55004
  await removeIfExists(target.output);
@@ -54355,8 +55054,8 @@ async function checkDriftFromConfig(dsl, renderTargets, options) {
54355
55054
  for (const target of renderTargets) {
54356
55055
  const templateContent = await loadTemplate(target.template);
54357
55056
  const compiled = Handlebars.compile(templateContent, { noEscape: false });
54358
- if (target.context === "system") {
54359
- const ctx = buildSystemContext(dsl, options);
55057
+ if (target.context === "system" || target.context === "navigation_index") {
55058
+ const ctx = target.context === "system" ? buildSystemContext(dsl, options) : buildNavigationIndex(dsl);
54360
55059
  const expected = compiled(ctx);
54361
55060
  await checkExpectedVsExisting(expected, target.output, target.skip_empty, diffs);
54362
55061
  } else {
@@ -54378,14 +55077,14 @@ async function checkDriftFromConfig(dsl, renderTargets, options) {
54378
55077
 
54379
55078
  // src/config/binding-loader.ts
54380
55079
  import { readFile as readFile4 } from "fs/promises";
54381
- import { dirname as dirname5, resolve as resolve5 } from "path";
55080
+ import { dirname as dirname5, resolve as resolve6 } from "path";
54382
55081
  import { stat as stat2 } from "fs/promises";
54383
- import { parse as parseYaml3 } from "yaml";
55082
+ import { parse as parseYaml4 } from "yaml";
54384
55083
 
54385
55084
  // src/config/loader.ts
54386
55085
  import { readFile as readFile3, access } from "fs/promises";
54387
- import { resolve as resolve4, dirname as dirname4 } from "path";
54388
- import { parse as parseYaml2 } from "yaml";
55086
+ import { resolve as resolve5, dirname as dirname4 } from "path";
55087
+ import { parse as parseYaml3 } from "yaml";
54389
55088
 
54390
55089
  // src/config/types.ts
54391
55090
  import { z as z19 } from "zod";
@@ -54486,24 +55185,24 @@ function resolveTeamConfigs(teams, configDir) {
54486
55185
  for (const [key, team] of Object.entries(teams)) {
54487
55186
  if (key === "_defaults") continue;
54488
55187
  const mergedBindings = [...defaults?.bindings ?? [], ...team.bindings].map(
54489
- (b3) => resolve4(configDir, b3)
55188
+ (b3) => resolve5(configDir, b3)
54490
55189
  );
54491
55190
  const mergedVars = defaults?.vars || team.vars ? { ...defaults?.vars ?? {}, ...team.vars ?? {} } : void 0;
54492
55191
  const mergedPaths = defaults?.paths || team.paths ? { ...defaults?.paths ?? {}, ...team.paths ?? {} } : void 0;
54493
55192
  result[key] = {
54494
- dsl: resolve4(configDir, team.dsl),
55193
+ dsl: resolve5(configDir, team.dsl),
54495
55194
  bindings: mergedBindings,
54496
55195
  vars: mergedVars,
54497
55196
  activeGuardrailPolicy: team.active_guardrail_policy ?? defaults?.active_guardrail_policy,
54498
55197
  paths: mergedPaths,
54499
- interfaceOutput: team.interface_output ? resolve4(configDir, team.interface_output) : void 0
55198
+ interfaceOutput: team.interface_output ? resolve5(configDir, team.interface_output) : void 0
54500
55199
  };
54501
55200
  }
54502
55201
  return result;
54503
55202
  }
54504
55203
  async function loadConfig(configPath) {
54505
55204
  const isExplicit = configPath !== void 0;
54506
- const targetPath = resolve4(configPath ?? DEFAULT_CONFIG_NAME);
55205
+ const targetPath = resolve5(configPath ?? DEFAULT_CONFIG_NAME);
54507
55206
  if (!await fileExists2(targetPath)) {
54508
55207
  if (isExplicit) {
54509
55208
  throw new ConfigLoadError(
@@ -54524,7 +55223,7 @@ async function loadConfig(configPath) {
54524
55223
  }
54525
55224
  let raw;
54526
55225
  try {
54527
- raw = parseYaml2(content);
55226
+ raw = parseYaml3(content);
54528
55227
  } catch (err) {
54529
55228
  const msg = err instanceof Error ? err.message : String(err);
54530
55229
  throw new ConfigLoadError(
@@ -54545,8 +55244,8 @@ ${issues}`,
54545
55244
  const config = result.data;
54546
55245
  const renders = config.renders.map((r3) => ({
54547
55246
  ...r3,
54548
- template: resolve4(configDir, r3.template),
54549
- output: resolve4(configDir, r3.output)
55247
+ template: resolve5(configDir, r3.template),
55248
+ output: resolve5(configDir, r3.output)
54550
55249
  }));
54551
55250
  if (config.teams) {
54552
55251
  return {
@@ -54562,11 +55261,11 @@ ${issues}`,
54562
55261
  };
54563
55262
  }
54564
55263
  return {
54565
- dsl: resolve4(configDir, config.dsl),
55264
+ dsl: resolve5(configDir, config.dsl),
54566
55265
  vars: config.vars,
54567
55266
  renders,
54568
55267
  configDir,
54569
- bindings: (config.bindings ?? []).map((b3) => resolve4(configDir, b3)),
55268
+ bindings: (config.bindings ?? []).map((b3) => resolve5(configDir, b3)),
54570
55269
  activeGuardrailPolicy: config.active_guardrail_policy,
54571
55270
  paths: config.paths,
54572
55271
  audit: config.audit ?? void 0
@@ -54574,12 +55273,12 @@ ${issues}`,
54574
55273
  }
54575
55274
  function resolveDslPath(dirArg, dirArgDefault, config) {
54576
55275
  if (dirArg !== void 0 && dirArg !== dirArgDefault) {
54577
- return resolve4(dirArg);
55276
+ return resolve5(dirArg);
54578
55277
  }
54579
55278
  if (config) {
54580
55279
  return config.dsl;
54581
55280
  }
54582
- return resolve4(dirArgDefault);
55281
+ return resolve5(dirArgDefault);
54583
55282
  }
54584
55283
 
54585
55284
  // src/config/binding-merger.ts
@@ -54618,7 +55317,7 @@ async function loadRawBinding(filePath) {
54618
55317
  );
54619
55318
  }
54620
55319
  try {
54621
- return parseYaml3(content);
55320
+ return parseYaml4(content);
54622
55321
  } catch (err) {
54623
55322
  const msg = err instanceof Error ? err.message : String(err);
54624
55323
  throw new ConfigLoadError(
@@ -54635,7 +55334,7 @@ async function resolveBindingExtends(raw, filePath, seen) {
54635
55334
  const bindingDir = dirname5(filePath);
54636
55335
  let basePath;
54637
55336
  if (extendsValue.startsWith("./") || extendsValue.startsWith("../")) {
54638
- basePath = resolve5(bindingDir, extendsValue);
55337
+ basePath = resolve6(bindingDir, extendsValue);
54639
55338
  } else {
54640
55339
  try {
54641
55340
  const resolved = import.meta.resolve(extendsValue);
@@ -54653,7 +55352,7 @@ async function resolveBindingExtends(raw, filePath, seen) {
54653
55352
  const candidates = ["binding.yaml", "binding.yml"];
54654
55353
  let found = false;
54655
55354
  for (const name of candidates) {
54656
- const candidate = resolve5(basePath, name);
55355
+ const candidate = resolve6(basePath, name);
54657
55356
  try {
54658
55357
  const cs = await stat2(candidate);
54659
55358
  if (cs.isFile()) {
@@ -55075,10 +55774,10 @@ function collectAllXUsages(dsl) {
55075
55774
  function extractTemplateXReferences(config) {
55076
55775
  const refs = [];
55077
55776
  try {
55078
- const { readFileSync } = __require("fs");
55777
+ const { readFileSync: readFileSync2 } = __require("fs");
55079
55778
  for (const target of config.renders) {
55080
55779
  try {
55081
- const content = readFileSync(target.template, "utf8");
55780
+ const content = readFileSync2(target.template, "utf8");
55082
55781
  const matches = content.matchAll(/\{\{[^}]*?(x-[\w-]+)[^}]*?\}\}/g);
55083
55782
  for (const m2 of matches) refs.push(m2[1]);
55084
55783
  } catch {
@@ -55603,7 +56302,7 @@ var DslTaskResultSchema = z20.object({
55603
56302
  });
55604
56303
  var AuditResultSchema = z20.object({
55605
56304
  summary: z20.string(),
55606
- riskLevel: z20.enum(["low", "medium", "high", "critical"]),
56305
+ risk_level: z20.enum(["low", "medium", "high", "critical"]),
55607
56306
  findings: z20.array(z20.object({
55608
56307
  id: z20.string().optional(),
55609
56308
  severity: z20.enum(["info", "warning", "error", "critical"]),
@@ -55621,7 +56320,7 @@ var AuditResultSchema = z20.object({
55621
56320
  })).optional(),
55622
56321
  details: z20.record(z20.string(), z20.unknown()).optional()
55623
56322
  })),
55624
- recommendedActions: z20.array(z20.object({
56323
+ recommended_actions: z20.array(z20.object({
55625
56324
  kind: z20.enum(["run_command", "edit_file", "review", "confirm", "block", "ignore"]),
55626
56325
  title: z20.string(),
55627
56326
  command: z20.string().optional(),
@@ -55632,7 +56331,7 @@ var AuditResultSchema = z20.object({
55632
56331
  tool: z20.string().optional(),
55633
56332
  command: z20.string().optional(),
55634
56333
  version: z20.string().optional(),
55635
- generatedAt: z20.string().optional(),
56334
+ generated_at: z20.string().optional(),
55636
56335
  adapter: z20.string().optional(),
55637
56336
  model: z20.string().optional()
55638
56337
  }).optional()
@@ -55911,7 +56610,7 @@ function computeExitCode(results, failOn) {
55911
56610
 
55912
56611
  // src/guardrail-generator/generator.ts
55913
56612
  import { readFile as readFile6, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2, copyFile } from "fs/promises";
55914
- import { resolve as resolve6, dirname as dirname6 } from "path";
56613
+ import { resolve as resolve7, dirname as dirname6 } from "path";
55915
56614
  import Handlebars2 from "handlebars";
55916
56615
  import YAML from "yaml";
55917
56616
 
@@ -56133,9 +56832,9 @@ async function generateGuardrails(options) {
56133
56832
  if (pathResult.diagnostics.some((d2) => d2.severity === "error")) {
56134
56833
  continue;
56135
56834
  }
56136
- const targetPath = resolve6(config.configDir, pathResult.resolved);
56835
+ const targetPath = resolve7(config.configDir, pathResult.resolved);
56137
56836
  if (outputDef.source) {
56138
- const sourcePath = resolve6(config.configDir, outputDef.source);
56837
+ const sourcePath = resolve7(config.configDir, outputDef.source);
56139
56838
  if (!dryRun) {
56140
56839
  try {
56141
56840
  await mkdir2(dirname6(targetPath), { recursive: true });
@@ -56171,7 +56870,7 @@ async function generateGuardrails(options) {
56171
56870
  });
56172
56871
  continue;
56173
56872
  }
56174
- const templatePath = resolve6(config.configDir, outputDef.template);
56873
+ const templatePath = resolve7(config.configDir, outputDef.template);
56175
56874
  try {
56176
56875
  templateContent = await readFile6(templatePath, "utf8");
56177
56876
  } catch {
@@ -56210,7 +56909,7 @@ async function generateGuardrails(options) {
56210
56909
  };
56211
56910
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
56212
56911
  const rendered = compiled(groupCtx);
56213
- const groupTarget = resolve6(targetPath, groupKey);
56912
+ const groupTarget = resolve7(targetPath, groupKey);
56214
56913
  if (shouldSkipEmpty && rendered.trim().length === 0) {
56215
56914
  if (!dryRun) {
56216
56915
  try {
@@ -56258,7 +56957,7 @@ async function generateGuardrails(options) {
56258
56957
  if (renderTarget.inline_template) {
56259
56958
  templateContent = renderTarget.inline_template;
56260
56959
  } else if (renderTarget.template) {
56261
- const templatePath = resolve6(config.configDir, renderTarget.template);
56960
+ const templatePath = resolve7(config.configDir, renderTarget.template);
56262
56961
  try {
56263
56962
  templateContent = await readFile6(templatePath, "utf8");
56264
56963
  } catch {
@@ -56280,12 +56979,12 @@ async function generateGuardrails(options) {
56280
56979
  const compiled = Handlebars2.compile(templateContent, { noEscape: true });
56281
56980
  const shouldSkipEmpty = renderTarget.skip_empty === true;
56282
56981
  const context = renderTarget.context;
56283
- if (context === "system") {
56284
- const sysCtx = buildSystemContext(dsl);
56285
- const mergedCtx = { ...sysCtx, vars, paths, binding, resolved_checks: checkResult.resolved };
56982
+ if (context === "system" || context === "navigation_index") {
56983
+ const baseCtx = context === "system" ? buildSystemContext(dsl) : buildNavigationIndex(dsl);
56984
+ const mergedCtx = { ...baseCtx, vars, paths, binding, resolved_checks: checkResult.resolved };
56286
56985
  const rendered = compiled(mergedCtx);
56287
56986
  const resolvedOutput = resolveBindingRenderOutputPath(renderTarget.output, paths);
56288
- const outputPath = resolve6(config.configDir, resolvedOutput);
56987
+ const outputPath = resolve7(config.configDir, resolvedOutput);
56289
56988
  if (shouldSkipEmpty && rendered.trim().length === 0) {
56290
56989
  if (!dryRun) {
56291
56990
  try {
@@ -56315,7 +57014,7 @@ async function generateGuardrails(options) {
56315
57014
  const expandedOutput = expandOutputPath(renderTarget.output, context, entityId, entity);
56316
57015
  if (hasUnresolvedPathVars(expandedOutput)) continue;
56317
57016
  const resolvedOutput = resolveBindingRenderOutputPath(expandedOutput, paths);
56318
- const outputPath = resolve6(config.configDir, resolvedOutput);
57017
+ const outputPath = resolve7(config.configDir, resolvedOutput);
56319
57018
  if (shouldSkipEmpty && rendered.trim().length === 0) {
56320
57019
  if (!dryRun) {
56321
57020
  try {
@@ -56405,6 +57104,7 @@ export {
56405
57104
  buildGuardrailContext,
56406
57105
  buildGuardrailPolicyContext,
56407
57106
  buildHandoffTypeContext,
57107
+ buildNavigationIndex,
56408
57108
  buildPerAgentContext,
56409
57109
  buildPolicyContext,
56410
57110
  buildSystemContext,