agent-contracts 0.21.0 → 0.22.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/cli.js CHANGED
@@ -7367,7 +7367,7 @@ var init_dist = __esm({
7367
7367
  var require_stable = __commonJS({
7368
7368
  "node_modules/safe-stable-stringify/stable.js"(exports, module) {
7369
7369
  "use strict";
7370
- module.exports = stringify5;
7370
+ module.exports = stringify4;
7371
7371
  var indentation = "";
7372
7372
  var strEscapeSequencesRegExp = /[\x00-\x1f\x22\x5c]/;
7373
7373
  var strEscapeSequencesReplacer = /[\x00-\x1f\x22\x5c]/g;
@@ -7943,7 +7943,7 @@ ${originalIndentation}`;
7943
7943
  }
7944
7944
  return arr;
7945
7945
  }
7946
- function stringify5(value, replacer, spacer) {
7946
+ function stringify4(value, replacer, spacer) {
7947
7947
  var i3;
7948
7948
  var indent = "";
7949
7949
  indentation = "";
@@ -7982,9 +7982,9 @@ ${originalIndentation}`;
7982
7982
  var require_safe_stable_stringify = __commonJS({
7983
7983
  "node_modules/safe-stable-stringify/index.js"(exports, module) {
7984
7984
  "use strict";
7985
- var stringify5 = require_stable();
7986
- module.exports = stringify5;
7987
- stringify5.default = stringify5;
7985
+ var stringify4 = require_stable();
7986
+ module.exports = stringify4;
7987
+ stringify4.default = stringify4;
7988
7988
  }
7989
7989
  });
7990
7990
 
@@ -34148,7 +34148,7 @@ var require_astring = __commonJS({
34148
34148
  if (staticProps) _defineProperties(Constructor, staticProps);
34149
34149
  return Constructor;
34150
34150
  }
34151
- var stringify5 = JSON.stringify;
34151
+ var stringify4 = JSON.stringify;
34152
34152
  if (!String.prototype.repeat) {
34153
34153
  throw new Error("String.prototype.repeat is undefined, see https://github.com/davidbonnet/astring#installation");
34154
34154
  }
@@ -35070,7 +35070,7 @@ var require_astring = __commonJS({
35070
35070
  } else if (node.bigint != null) {
35071
35071
  state.write(node.bigint + "n", node);
35072
35072
  } else {
35073
- state.write(stringify5(node.value), node);
35073
+ state.write(stringify4(node.value), node);
35074
35074
  }
35075
35075
  },
35076
35076
  RegExpLiteral: function RegExpLiteral(node, state) {
@@ -48892,11 +48892,579 @@ var require_dist14 = __commonJS({
48892
48892
  import { readFileSync as readFileSync2 } from "fs";
48893
48893
  import { fileURLToPath } from "url";
48894
48894
  import { resolve as resolve8, dirname as dirname8 } from "path";
48895
- import { Command as Command9 } from "commander";
48896
48895
 
48897
- // src/cli/commands/resolve.ts
48896
+ // src/generated/cli-contract/program.ts
48898
48897
  import { Command } from "commander";
48899
48898
 
48899
+ // src/generated/cli-contract/policy.ts
48900
+ import { derivePolicy, isOptionActive } from "cli-contracts/policy";
48901
+ var commandDefinitions = {
48902
+ "resolve": {
48903
+ "options": [
48904
+ {
48905
+ "name": "config",
48906
+ "schema": {
48907
+ "type": "string"
48908
+ },
48909
+ "file": {
48910
+ "mode": "read",
48911
+ "exists": false,
48912
+ "mediaType": "application/yaml",
48913
+ "encoding": "utf-8"
48914
+ }
48915
+ },
48916
+ {
48917
+ "name": "team",
48918
+ "schema": {
48919
+ "type": "string"
48920
+ }
48921
+ },
48922
+ {
48923
+ "name": "format",
48924
+ "schema": {
48925
+ "type": "string",
48926
+ "enum": [
48927
+ "text",
48928
+ "json"
48929
+ ],
48930
+ "default": "text"
48931
+ }
48932
+ },
48933
+ {
48934
+ "name": "expand-defaults",
48935
+ "schema": {
48936
+ "type": "boolean",
48937
+ "default": false
48938
+ }
48939
+ }
48940
+ ]
48941
+ },
48942
+ "validate": {
48943
+ "options": [
48944
+ {
48945
+ "name": "config",
48946
+ "schema": {
48947
+ "type": "string"
48948
+ },
48949
+ "file": {
48950
+ "mode": "read",
48951
+ "exists": false,
48952
+ "mediaType": "application/yaml",
48953
+ "encoding": "utf-8"
48954
+ }
48955
+ },
48956
+ {
48957
+ "name": "team",
48958
+ "schema": {
48959
+ "type": "string"
48960
+ }
48961
+ },
48962
+ {
48963
+ "name": "format",
48964
+ "schema": {
48965
+ "type": "string",
48966
+ "enum": [
48967
+ "text",
48968
+ "json"
48969
+ ],
48970
+ "default": "text"
48971
+ }
48972
+ },
48973
+ {
48974
+ "name": "quiet",
48975
+ "schema": {
48976
+ "type": "boolean",
48977
+ "default": false
48978
+ }
48979
+ },
48980
+ {
48981
+ "name": "strict",
48982
+ "schema": {
48983
+ "type": "boolean",
48984
+ "default": false
48985
+ }
48986
+ }
48987
+ ]
48988
+ },
48989
+ "lint": {
48990
+ "options": [
48991
+ {
48992
+ "name": "config",
48993
+ "schema": {
48994
+ "type": "string"
48995
+ },
48996
+ "file": {
48997
+ "mode": "read",
48998
+ "exists": false,
48999
+ "mediaType": "application/yaml",
49000
+ "encoding": "utf-8"
49001
+ }
49002
+ },
49003
+ {
49004
+ "name": "team",
49005
+ "schema": {
49006
+ "type": "string"
49007
+ }
49008
+ },
49009
+ {
49010
+ "name": "format",
49011
+ "schema": {
49012
+ "type": "string",
49013
+ "enum": [
49014
+ "text",
49015
+ "json"
49016
+ ],
49017
+ "default": "text"
49018
+ }
49019
+ },
49020
+ {
49021
+ "name": "quiet",
49022
+ "schema": {
49023
+ "type": "boolean",
49024
+ "default": false
49025
+ }
49026
+ },
49027
+ {
49028
+ "name": "strict",
49029
+ "schema": {
49030
+ "type": "boolean",
49031
+ "default": false
49032
+ }
49033
+ }
49034
+ ]
49035
+ },
49036
+ "render": {
49037
+ "effects": {
49038
+ "riskLevel": "medium",
49039
+ "writes": [
49040
+ {
49041
+ "target": "configured render output paths",
49042
+ "description": "rendered template files from DSL input",
49043
+ "overwrite": true,
49044
+ "idempotent": true,
49045
+ "idempotentNote": "Output is deterministic from DSL input and templates. Repeated runs produce identical files."
49046
+ }
49047
+ ]
49048
+ },
49049
+ "options": [
49050
+ {
49051
+ "name": "config",
49052
+ "schema": {
49053
+ "type": "string"
49054
+ },
49055
+ "file": {
49056
+ "mode": "read",
49057
+ "exists": false,
49058
+ "mediaType": "application/yaml",
49059
+ "encoding": "utf-8"
49060
+ }
49061
+ },
49062
+ {
49063
+ "name": "team",
49064
+ "schema": {
49065
+ "type": "string"
49066
+ }
49067
+ },
49068
+ {
49069
+ "name": "check",
49070
+ "schema": {
49071
+ "type": "boolean",
49072
+ "default": false
49073
+ }
49074
+ },
49075
+ {
49076
+ "name": "quiet",
49077
+ "schema": {
49078
+ "type": "boolean",
49079
+ "default": false
49080
+ }
49081
+ }
49082
+ ]
49083
+ },
49084
+ "check": {
49085
+ "options": [
49086
+ {
49087
+ "name": "config",
49088
+ "schema": {
49089
+ "type": "string"
49090
+ },
49091
+ "file": {
49092
+ "mode": "read",
49093
+ "exists": false,
49094
+ "mediaType": "application/yaml",
49095
+ "encoding": "utf-8"
49096
+ }
49097
+ },
49098
+ {
49099
+ "name": "team",
49100
+ "schema": {
49101
+ "type": "string"
49102
+ }
49103
+ },
49104
+ {
49105
+ "name": "format",
49106
+ "schema": {
49107
+ "type": "string",
49108
+ "enum": [
49109
+ "text",
49110
+ "json"
49111
+ ],
49112
+ "default": "text"
49113
+ }
49114
+ },
49115
+ {
49116
+ "name": "quiet",
49117
+ "schema": {
49118
+ "type": "boolean",
49119
+ "default": false
49120
+ }
49121
+ },
49122
+ {
49123
+ "name": "strict",
49124
+ "schema": {
49125
+ "type": "boolean",
49126
+ "default": false
49127
+ }
49128
+ }
49129
+ ]
49130
+ },
49131
+ "score": {
49132
+ "options": [
49133
+ {
49134
+ "name": "config",
49135
+ "schema": {
49136
+ "type": "string"
49137
+ },
49138
+ "file": {
49139
+ "mode": "read",
49140
+ "exists": false,
49141
+ "mediaType": "application/yaml",
49142
+ "encoding": "utf-8"
49143
+ }
49144
+ },
49145
+ {
49146
+ "name": "team",
49147
+ "schema": {
49148
+ "type": "string"
49149
+ }
49150
+ },
49151
+ {
49152
+ "name": "format",
49153
+ "schema": {
49154
+ "type": "string",
49155
+ "enum": [
49156
+ "text",
49157
+ "json"
49158
+ ],
49159
+ "default": "text"
49160
+ }
49161
+ },
49162
+ {
49163
+ "name": "threshold",
49164
+ "schema": {
49165
+ "type": "integer"
49166
+ }
49167
+ }
49168
+ ]
49169
+ },
49170
+ "audit": {
49171
+ "effects": {
49172
+ "riskLevel": "medium",
49173
+ "network": {
49174
+ "description": "LLM API calls to configured adapter (e.g. OpenAI, Gemini, Cursor). Incurs token cost and sends DSL content to the LLM provider.",
49175
+ "idempotent": false,
49176
+ "idempotentNote": "LLM inference is non-deterministic \u2014 identical inputs may produce different findings across runs."
49177
+ }
49178
+ },
49179
+ "options": [
49180
+ {
49181
+ "name": "config",
49182
+ "schema": {
49183
+ "type": "string"
49184
+ },
49185
+ "file": {
49186
+ "mode": "read",
49187
+ "exists": false,
49188
+ "mediaType": "application/yaml",
49189
+ "encoding": "utf-8"
49190
+ }
49191
+ },
49192
+ {
49193
+ "name": "team",
49194
+ "schema": {
49195
+ "type": "string"
49196
+ }
49197
+ },
49198
+ {
49199
+ "name": "format",
49200
+ "schema": {
49201
+ "type": "string",
49202
+ "enum": [
49203
+ "text",
49204
+ "json",
49205
+ "markdown"
49206
+ ],
49207
+ "default": "text"
49208
+ }
49209
+ },
49210
+ {
49211
+ "name": "scope",
49212
+ "schema": {
49213
+ "type": "string"
49214
+ }
49215
+ },
49216
+ {
49217
+ "name": "dry-run",
49218
+ "schema": {
49219
+ "type": "boolean",
49220
+ "default": false
49221
+ }
49222
+ },
49223
+ {
49224
+ "name": "adapter",
49225
+ "schema": {
49226
+ "type": "string"
49227
+ }
49228
+ },
49229
+ {
49230
+ "name": "model",
49231
+ "schema": {
49232
+ "type": "string"
49233
+ }
49234
+ },
49235
+ {
49236
+ "name": "fail-on",
49237
+ "schema": {
49238
+ "type": "string",
49239
+ "enum": [
49240
+ "info",
49241
+ "warning",
49242
+ "error",
49243
+ "critical"
49244
+ ],
49245
+ "default": "critical"
49246
+ }
49247
+ },
49248
+ {
49249
+ "name": "output",
49250
+ "schema": {
49251
+ "type": "string"
49252
+ },
49253
+ "file": {
49254
+ "mode": "write",
49255
+ "encoding": "utf-8"
49256
+ }
49257
+ },
49258
+ {
49259
+ "name": "report-format",
49260
+ "schema": {
49261
+ "type": "string",
49262
+ "enum": [
49263
+ "text",
49264
+ "json",
49265
+ "markdown"
49266
+ ],
49267
+ "default": "text"
49268
+ }
49269
+ }
49270
+ ]
49271
+ },
49272
+ "generate": {
49273
+ "effects": {
49274
+ "riskLevel": "low",
49275
+ "writes": [
49276
+ {
49277
+ "target": "configured render, guardrail, and interface output paths",
49278
+ "description": "template files, guardrail binding files, and/or team interface files generated from DSL input",
49279
+ "overwrite": true,
49280
+ "idempotent": true,
49281
+ "idempotentNote": "Output is deterministic from DSL input, templates, policies, and bindings. Repeated runs produce identical files."
49282
+ }
49283
+ ]
49284
+ },
49285
+ "options": [
49286
+ {
49287
+ "name": "config",
49288
+ "schema": {
49289
+ "type": "string"
49290
+ },
49291
+ "file": {
49292
+ "mode": "read",
49293
+ "exists": false,
49294
+ "mediaType": "application/yaml",
49295
+ "encoding": "utf-8"
49296
+ }
49297
+ },
49298
+ {
49299
+ "name": "team",
49300
+ "schema": {
49301
+ "type": "string"
49302
+ }
49303
+ },
49304
+ {
49305
+ "name": "check",
49306
+ "schema": {
49307
+ "type": "boolean",
49308
+ "default": false
49309
+ }
49310
+ },
49311
+ {
49312
+ "name": "binding",
49313
+ "schema": {
49314
+ "type": "string"
49315
+ },
49316
+ "repeatable": true
49317
+ },
49318
+ {
49319
+ "name": "output",
49320
+ "schema": {
49321
+ "type": "string"
49322
+ },
49323
+ "file": {
49324
+ "mode": "write",
49325
+ "mediaType": "application/yaml",
49326
+ "encoding": "utf-8"
49327
+ }
49328
+ },
49329
+ {
49330
+ "name": "format",
49331
+ "schema": {
49332
+ "type": "string",
49333
+ "enum": [
49334
+ "yaml",
49335
+ "json"
49336
+ ],
49337
+ "default": "yaml"
49338
+ }
49339
+ },
49340
+ {
49341
+ "name": "dry-run",
49342
+ "schema": {
49343
+ "type": "boolean",
49344
+ "default": false
49345
+ }
49346
+ },
49347
+ {
49348
+ "name": "quiet",
49349
+ "schema": {
49350
+ "type": "boolean",
49351
+ "default": false
49352
+ }
49353
+ }
49354
+ ]
49355
+ }
49356
+ };
49357
+ function deriveCommandPolicy(commandId, optionValues) {
49358
+ const def = commandDefinitions[commandId];
49359
+ if (!def) throw new Error(`Unknown command: ${commandId}`);
49360
+ const cmdDef = def;
49361
+ const options = {};
49362
+ const activeOptions = [];
49363
+ for (const optDef of cmdDef.options ?? []) {
49364
+ const value = optionValues[optDef.name];
49365
+ const specified = optDef.name in optionValues && value !== void 0;
49366
+ options[optDef.name] = { value, specified, definition: optDef };
49367
+ if (isOptionActive(optDef, value, specified)) {
49368
+ activeOptions.push(optDef.name);
49369
+ }
49370
+ }
49371
+ const policy = derivePolicy({
49372
+ commandId,
49373
+ commandEffects: cmdDef.effects,
49374
+ options,
49375
+ env: cmdDef.env
49376
+ });
49377
+ return { command: commandId, activeOptions, policy };
49378
+ }
49379
+
49380
+ // src/generated/cli-contract/program.ts
49381
+ function createProgram(handlers2, version) {
49382
+ const program2 = new Command();
49383
+ program2.name("agent-contracts").version(version, "-V, --version").description("Agent contracts tooling \u2014 validate, lint, render DSL files.");
49384
+ program2.option("--introspect", "Output derived policy as JSON without executing the command");
49385
+ program2.command("resolve").description("Resolve DSL (load + merge extends) and output YAML.").argument("[dir]", "Path to agent-contracts.yaml.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--expand-defaults", "Expand all Zod default values in output. Fields like required_validations, tags, and can_read_artifacts are written explicitly instead of relying on schema defaults.", false).action(async (dir, opts, cmd) => {
49386
+ const globalOpts = cmd.optsWithGlobals();
49387
+ if (globalOpts.introspect) {
49388
+ const policy = deriveCommandPolicy("resolve", opts);
49389
+ console.log(JSON.stringify(policy, null, 2));
49390
+ return;
49391
+ }
49392
+ await handlers2.resolve(dir, opts, globalOpts);
49393
+ });
49394
+ program2.command("validate").description("Validate DSL against schema and check references.").argument("[dir]", "Path to agent-contracts.yaml.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Diagnostic output format.", "text").option("--quiet", "Suppress output on success.", false).option("--strict", "Treat warnings as errors.", false).action(async (dir, opts, cmd) => {
49395
+ const globalOpts = cmd.optsWithGlobals();
49396
+ if (globalOpts.introspect) {
49397
+ const policy = deriveCommandPolicy("validate", opts);
49398
+ console.log(JSON.stringify(policy, null, 2));
49399
+ return;
49400
+ }
49401
+ await handlers2.validate(dir, opts, globalOpts);
49402
+ });
49403
+ program2.command("lint").description("Run semantic lint rules on resolved DSL.").argument("[dir]", "Path to agent-contracts.yaml.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--quiet", "Suppress output on success.", false).option("--strict", "Treat warnings as errors.", false).action(async (dir, opts, cmd) => {
49404
+ const globalOpts = cmd.optsWithGlobals();
49405
+ if (globalOpts.introspect) {
49406
+ const policy = deriveCommandPolicy("lint", opts);
49407
+ console.log(JSON.stringify(policy, null, 2));
49408
+ return;
49409
+ }
49410
+ await handlers2.lint(dir, opts, globalOpts);
49411
+ });
49412
+ program2.command("render").description("(deprecated) Alias for 'generate templates'.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--check", "Check for template drift without writing files.", false).option("--quiet", "Suppress output on success.", false).action(async (opts, cmd) => {
49413
+ const globalOpts = cmd.optsWithGlobals();
49414
+ if (globalOpts.introspect) {
49415
+ const policy = deriveCommandPolicy("render", opts);
49416
+ console.log(JSON.stringify(policy, null, 2));
49417
+ return;
49418
+ }
49419
+ await handlers2.render(opts, globalOpts);
49420
+ });
49421
+ program2.command("check").description("Run full pipeline \u2014 resolve, validate, lint, render --check.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Diagnostic output format.", "text").option("--quiet", "Suppress output on success.", false).option("--strict", "Treat warnings as errors.", false).action(async (opts, cmd) => {
49422
+ const globalOpts = cmd.optsWithGlobals();
49423
+ if (globalOpts.introspect) {
49424
+ const policy = deriveCommandPolicy("check", opts);
49425
+ console.log(JSON.stringify(policy, null, 2));
49426
+ return;
49427
+ }
49428
+ await handlers2.check(opts, globalOpts);
49429
+ });
49430
+ program2.command("score").description("Calculate DSL completeness score.").argument("[dir]", "Path to agent-contracts.yaml.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--threshold <number>", "Minimum score; exit 1 if below (for CI gates).").action(async (dir, opts, cmd) => {
49431
+ const globalOpts = cmd.optsWithGlobals();
49432
+ if (globalOpts.introspect) {
49433
+ const policy = deriveCommandPolicy("score", opts);
49434
+ console.log(JSON.stringify(policy, null, 2));
49435
+ return;
49436
+ }
49437
+ await handlers2.score(dir, opts, globalOpts);
49438
+ });
49439
+ program2.command("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs.").argument("[type]", "Audit type to run: render (semantic diff of generated outputs vs DSL), dsl (design coherence review), prompt (generated prompt fidelity check), or all (run all three).").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--format <format>", "Output format.", "text").option("--scope <entities>", "Limit audit scope to specified entities (e.g. agents:architect,implementer).").option("--dry-run", "Output the audit prompt without calling LLM.", false).option("--adapter <name>", "SDK adapter to use for LLM calls (overrides config audit.adapter).").option("--model <name>", "LLM model override (overrides config audit.model).").option("--fail-on <level>", "Minimum finding severity that causes exit 10 (info|warning|error|critical).", "critical").option("-o, --output <file>", "Write result to a file instead of stdout.").option("--report-format <fmt>", "Alias for --format. When both are specified, --report-format takes precedence.", "text").action(async (type, opts, cmd) => {
49440
+ const globalOpts = cmd.optsWithGlobals();
49441
+ if (globalOpts.introspect) {
49442
+ const policy = deriveCommandPolicy("audit", opts);
49443
+ console.log(JSON.stringify(policy, null, 2));
49444
+ return;
49445
+ }
49446
+ await handlers2.audit(type, opts, globalOpts);
49447
+ });
49448
+ program2.command("generate").description("Generate artifacts from DSL \u2014 templates, guardrails, and/or interface.").argument("[type]", "Type of artifacts to generate. Omit to run all targets.").option("-c, --config <path>", "Path to agent-contracts.config.yaml.").option("--team <id>", "Limit to one team (multi-team config only).").option("--check", "Check for template drift without writing files. Only applies to the templates target.", false).option("--binding <name...>", "Filter to specific software binding(s). Guardrails type only.").option("-o, --output <path>", "Output path for generated team interface. Interface type only.").option("--format <format>", "Output format for team interface (yaml or json). Interface type only.", "yaml").option("--dry-run", "Print what would be generated without writing files.", false).option("--quiet", "Suppress output on success.", false).action(async (type, opts, cmd) => {
49449
+ const globalOpts = cmd.optsWithGlobals();
49450
+ if (globalOpts.introspect) {
49451
+ const policy = deriveCommandPolicy("generate", opts);
49452
+ console.log(JSON.stringify(policy, null, 2));
49453
+ return;
49454
+ }
49455
+ await handlers2.generate(type, opts, globalOpts);
49456
+ });
49457
+ return program2;
49458
+ }
49459
+
49460
+ // src/cli/handlers.ts
49461
+ import { writeFileSync as writeFileSync2 } from "fs";
49462
+ import { existsSync, readFileSync } from "fs";
49463
+ import { join as join3, dirname as dirname7 } from "path";
49464
+ import { resolve as pathResolve } from "path";
49465
+ import { access as access2 } from "fs/promises";
49466
+ import { stringify as stringify3, parse as parseYaml4 } from "yaml";
49467
+
48900
49468
  // src/config/binding-loader.ts
48901
49469
  import { readFile as readFile3 } from "fs/promises";
48902
49470
  import { dirname as dirname4, resolve as resolve5 } from "path";
@@ -50472,85 +51040,6 @@ ${issues}`,
50472
51040
  return results;
50473
51041
  }
50474
51042
 
50475
- // src/cli/commands/resolve.ts
50476
- import { stringify } from "yaml";
50477
-
50478
- // src/cli/multi-team.ts
50479
- function isMultiTeamConfig(config) {
50480
- return config.teams !== void 0 && Object.keys(config.teams).length > 0;
50481
- }
50482
- function getTeamEntries(config, teamFilter) {
50483
- if (!config.teams) return [];
50484
- const entries = Object.entries(config.teams);
50485
- if (teamFilter) {
50486
- const found = entries.filter(([k2]) => k2 === teamFilter);
50487
- if (found.length === 0) {
50488
- throw new Error(
50489
- `Team "${teamFilter}" not found. Available teams: ${entries.map(([k2]) => k2).join(", ")}`
50490
- );
50491
- }
50492
- return found;
50493
- }
50494
- return entries;
50495
- }
50496
-
50497
- // src/cli/commands/resolve.ts
50498
- var DIR_DEFAULT = "agent-contracts.yaml";
50499
- var resolveCommand = new Command("resolve").description("Resolve DSL (load + merge extends) and output YAML").argument("[dir]", "Path to agent-contracts.yaml", DIR_DEFAULT).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json)", "text").option("--expand-defaults", "Expand all Zod default values in output", false).action(
50500
- async (dir, opts) => {
50501
- try {
50502
- const config = await loadConfig(opts.config);
50503
- if (config !== null && isMultiTeamConfig(config)) {
50504
- const teamEntries = getTeamEntries(config, opts.team);
50505
- if (opts.format === "json") {
50506
- const out = {};
50507
- for (const [teamId, teamConfig] of teamEntries) {
50508
- const result2 = await resolve4(teamConfig.dsl);
50509
- let data2 = teamConfig.vars ? substituteVars(result2.data, teamConfig.vars) : result2.data;
50510
- if (opts.expandDefaults) {
50511
- data2 = expandDefaults(data2);
50512
- }
50513
- out[teamId] = data2;
50514
- }
50515
- process.stdout.write(JSON.stringify(out, null, 2) + "\n");
50516
- } else {
50517
- for (const [teamId, teamConfig] of teamEntries) {
50518
- process.stdout.write(`
50519
- --- Team: ${teamId} ---
50520
- `);
50521
- const result2 = await resolve4(teamConfig.dsl);
50522
- let data2 = teamConfig.vars ? substituteVars(result2.data, teamConfig.vars) : result2.data;
50523
- if (opts.expandDefaults) {
50524
- data2 = expandDefaults(data2);
50525
- }
50526
- process.stdout.write(stringify(data2));
50527
- }
50528
- }
50529
- return;
50530
- }
50531
- const dslPath = resolveDslPath(dir, DIR_DEFAULT, config);
50532
- const result = await resolve4(dslPath);
50533
- let data = config?.vars ? substituteVars(result.data, config.vars) : result.data;
50534
- if (opts.expandDefaults) {
50535
- data = expandDefaults(data);
50536
- }
50537
- if (opts.format === "json") {
50538
- process.stdout.write(JSON.stringify(data, null, 2) + "\n");
50539
- } else {
50540
- process.stdout.write(stringify(data));
50541
- }
50542
- } catch (err) {
50543
- const msg = err instanceof Error ? err.message : String(err);
50544
- process.stderr.write(`Error: ${msg}
50545
- `);
50546
- process.exit(1);
50547
- }
50548
- }
50549
- );
50550
-
50551
- // src/cli/commands/validate.ts
50552
- import { Command as Command2 } from "commander";
50553
-
50554
51043
  // src/validator/schema-validator.ts
50555
51044
  import Ajv from "ajv";
50556
51045
  import { z as z18 } from "zod";
@@ -51672,107 +52161,6 @@ function validateHandoffSchemas(dsl) {
51672
52161
  return diagnostics;
51673
52162
  }
51674
52163
 
51675
- // src/cli/format.ts
51676
- function formatDiagnostics(diagnostics, options) {
51677
- if (options.quiet && diagnostics.length === 0) return "";
51678
- if (options.format === "json") {
51679
- return JSON.stringify(diagnostics, null, 2);
51680
- }
51681
- return diagnostics.map((d2) => {
51682
- const severity = d2.severity ?? d2.code ?? "error";
51683
- const rule = d2.ruleId ?? d2.code ?? "";
51684
- return `${d2.path}: ${severity} [${rule}] ${d2.message}`;
51685
- }).join("\n");
51686
- }
51687
-
51688
- // src/cli/commands/validate.ts
51689
- var DIR_DEFAULT2 = "agent-contracts.yaml";
51690
- var validateCommand = new Command2("validate").description("Validate DSL against schema and check references").argument("[dir]", "Path to agent-contracts.yaml", DIR_DEFAULT2).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json)", "text").option("--quiet", "Suppress output on success", false).option("--strict", "Treat warnings as errors", false).action(
51691
- async (dir, opts) => {
51692
- try {
51693
- const config = await loadConfig(opts.config);
51694
- if (config !== null && isMultiTeamConfig(config)) {
51695
- const teamEntries = getTeamEntries(config, opts.team);
51696
- let hasErrors = false;
51697
- let allTeamsFullyClean = true;
51698
- for (const [teamId, teamConfig] of teamEntries) {
51699
- if (!opts.quiet) process.stdout.write(`
51700
- --- Team: ${teamId} ---
51701
- `);
51702
- const resolved2 = await resolve4(teamConfig.dsl);
51703
- const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
51704
- const schemaResult2 = validateSchema(data2);
51705
- const schemaWarnings2 = schemaResult2.diagnostics.filter(
51706
- (d2) => d2.severity === "warning"
51707
- );
51708
- if (!schemaResult2.success) {
51709
- const output = formatDiagnostics(schemaResult2.diagnostics, opts);
51710
- if (output) process.stderr.write(output + "\n");
51711
- hasErrors = true;
51712
- allTeamsFullyClean = false;
51713
- continue;
51714
- }
51715
- const refDiags2 = checkReferences(schemaResult2.data);
51716
- const handoffDiags2 = validateHandoffSchemas(schemaResult2.data);
51717
- const allDiags2 = [...refDiags2, ...handoffDiags2, ...schemaWarnings2];
51718
- const hasWarnings2 = allDiags2.some(
51719
- (d2) => "severity" in d2 && d2.severity === "warning"
51720
- );
51721
- if (allDiags2.length > 0) {
51722
- allTeamsFullyClean = false;
51723
- const output = formatDiagnostics(allDiags2, opts);
51724
- if (output) process.stderr.write(output + "\n");
51725
- if (refDiags2.length > 0 || handoffDiags2.length > 0 || opts.strict && hasWarnings2) {
51726
- hasErrors = true;
51727
- }
51728
- }
51729
- }
51730
- if (hasErrors) process.exit(1);
51731
- if (!opts.quiet && allTeamsFullyClean) {
51732
- process.stdout.write("Validation passed.\n");
51733
- }
51734
- return;
51735
- }
51736
- const dslPath = resolveDslPath(dir, DIR_DEFAULT2, config);
51737
- const resolved = await resolve4(dslPath);
51738
- const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
51739
- const schemaResult = validateSchema(data);
51740
- const schemaWarnings = schemaResult.diagnostics.filter(
51741
- (d2) => d2.severity === "warning"
51742
- );
51743
- if (!schemaResult.success) {
51744
- const output = formatDiagnostics(schemaResult.diagnostics, opts);
51745
- if (output) process.stderr.write(output + "\n");
51746
- process.exit(1);
51747
- }
51748
- const refDiags = checkReferences(schemaResult.data);
51749
- const handoffDiags = validateHandoffSchemas(schemaResult.data);
51750
- const allDiags = [...refDiags, ...handoffDiags, ...schemaWarnings];
51751
- const hasWarnings = allDiags.some(
51752
- (d2) => "severity" in d2 && d2.severity === "warning"
51753
- );
51754
- if (allDiags.length > 0) {
51755
- const output = formatDiagnostics(allDiags, opts);
51756
- if (output) process.stderr.write(output + "\n");
51757
- if (refDiags.length > 0 || handoffDiags.length > 0 || opts.strict && hasWarnings) {
51758
- process.exit(1);
51759
- }
51760
- }
51761
- if (!opts.quiet && allDiags.length === 0) {
51762
- process.stdout.write("Validation passed.\n");
51763
- }
51764
- } catch (err) {
51765
- const msg = err instanceof Error ? err.message : String(err);
51766
- process.stderr.write(`Error: ${msg}
51767
- `);
51768
- process.exit(1);
51769
- }
51770
- }
51771
- );
51772
-
51773
- // src/cli/commands/lint.ts
51774
- import { Command as Command3 } from "commander";
51775
-
51776
52164
  // src/linter/rules/validation-coverage.ts
51777
52165
  var validationCoverageRule = {
51778
52166
  id: "validation-coverage",
@@ -53164,173 +53552,6 @@ async function spectralLint(dslObject) {
53164
53552
  }));
53165
53553
  }
53166
53554
 
53167
- // src/cli/commands/lint.ts
53168
- var DIR_DEFAULT3 = "agent-contracts.yaml";
53169
- var lintCommand = new Command3("lint").description("Run semantic lint rules on resolved DSL").argument("[dir]", "Path to agent-contracts.yaml", DIR_DEFAULT3).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json)", "text").option("--quiet", "Suppress output on success", false).option("--strict", "Treat warnings as errors", false).action(
53170
- async (dir, opts) => {
53171
- try {
53172
- const config = await loadConfig(opts.config);
53173
- if (config !== null && isMultiTeamConfig(config)) {
53174
- const teamEntries = getTeamEntries(config, opts.team);
53175
- let hasErrors = false;
53176
- let allClean = true;
53177
- for (const [teamId, teamConfig] of teamEntries) {
53178
- if (!opts.quiet) process.stdout.write(`
53179
- --- Team: ${teamId} ---
53180
- `);
53181
- const resolved2 = await resolve4(teamConfig.dsl);
53182
- const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
53183
- const schemaResult2 = validateSchema(data2);
53184
- const schemaWarnings2 = schemaResult2.diagnostics.filter(
53185
- (d2) => d2.severity === "warning"
53186
- );
53187
- if (!schemaResult2.success) {
53188
- const output = formatDiagnostics(schemaResult2.diagnostics, {
53189
- format: opts.format,
53190
- quiet: opts.quiet
53191
- });
53192
- if (output) process.stderr.write(output + "\n");
53193
- hasErrors = true;
53194
- allClean = false;
53195
- continue;
53196
- }
53197
- const tsDiagnostics2 = lint(schemaResult2.data);
53198
- const spectralDiagnostics2 = await spectralLint(
53199
- schemaResult2.data
53200
- );
53201
- const diagnostics2 = [
53202
- ...tsDiagnostics2,
53203
- ...spectralDiagnostics2,
53204
- ...schemaWarnings2
53205
- ];
53206
- if (diagnostics2.length > 0) {
53207
- allClean = false;
53208
- const output = formatDiagnostics(diagnostics2, {
53209
- format: opts.format,
53210
- quiet: opts.quiet
53211
- });
53212
- if (output) process.stderr.write(output + "\n");
53213
- const teamHasErrors = diagnostics2.some((d2) => d2.severity === "error");
53214
- const teamHasWarnings = diagnostics2.some((d2) => d2.severity === "warning");
53215
- if (teamHasErrors || opts.strict && teamHasWarnings) {
53216
- hasErrors = true;
53217
- }
53218
- }
53219
- }
53220
- if (hasErrors) process.exit(1);
53221
- if (!opts.quiet && allClean) {
53222
- process.stdout.write("Lint passed.\n");
53223
- }
53224
- return;
53225
- }
53226
- const dslPath = resolveDslPath(dir, DIR_DEFAULT3, config);
53227
- const resolved = await resolve4(dslPath);
53228
- const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
53229
- const schemaResult = validateSchema(data);
53230
- const schemaWarnings = schemaResult.diagnostics.filter(
53231
- (d2) => d2.severity === "warning"
53232
- );
53233
- if (!schemaResult.success) {
53234
- const output = formatDiagnostics(schemaResult.diagnostics, {
53235
- format: opts.format,
53236
- quiet: opts.quiet
53237
- });
53238
- if (output) process.stderr.write(output + "\n");
53239
- process.exit(1);
53240
- }
53241
- const tsDiagnostics = lint(schemaResult.data);
53242
- const spectralDiagnostics = await spectralLint(schemaResult.data);
53243
- const diagnostics = [...tsDiagnostics, ...spectralDiagnostics, ...schemaWarnings];
53244
- if (diagnostics.length > 0) {
53245
- const output = formatDiagnostics(diagnostics, {
53246
- format: opts.format,
53247
- quiet: opts.quiet
53248
- });
53249
- if (output) process.stderr.write(output + "\n");
53250
- const hasErrors = diagnostics.some((d2) => d2.severity === "error");
53251
- const hasWarnings = diagnostics.some((d2) => d2.severity === "warning");
53252
- if (hasErrors || opts.strict && hasWarnings) {
53253
- process.exit(1);
53254
- }
53255
- }
53256
- if (!opts.quiet && diagnostics.length === 0) {
53257
- process.stdout.write("Lint passed.\n");
53258
- }
53259
- } catch (err) {
53260
- const msg = err instanceof Error ? err.message : String(err);
53261
- process.stderr.write(`Error: ${msg}
53262
- `);
53263
- process.exit(1);
53264
- }
53265
- }
53266
- );
53267
-
53268
- // src/cli/commands/render.ts
53269
- import { Command as Command5 } from "commander";
53270
-
53271
- // src/cli/commands/generate.ts
53272
- import { Command as Command4 } from "commander";
53273
-
53274
- // src/guardrail-generator/generator.ts
53275
- import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2, copyFile } from "fs/promises";
53276
- import { resolve as resolve6, dirname as dirname6 } from "path";
53277
- import Handlebars2 from "handlebars";
53278
- import YAML from "yaml";
53279
-
53280
- // src/guardrail-generator/resolve-checks.ts
53281
- function resolveChecks(dsl, binding, policy) {
53282
- const resolved = [];
53283
- const diagnostics = [];
53284
- const guardrailImpl = binding.guardrail_impl ?? {};
53285
- for (const [guardrailId, impl] of Object.entries(guardrailImpl)) {
53286
- const guardrail = dsl.guardrails[guardrailId];
53287
- if (!guardrail) {
53288
- diagnostics.push({
53289
- path: `binding.${binding.software}.guardrail_impl.${guardrailId}`,
53290
- message: `Binding "${binding.software}" implements guardrail "${guardrailId}" which is not defined in the DSL`,
53291
- severity: "error"
53292
- });
53293
- continue;
53294
- }
53295
- const policyRule = policy.rules.find((r3) => r3.guardrail === guardrailId);
53296
- if (!policyRule) {
53297
- diagnostics.push({
53298
- path: `binding.${binding.software}.guardrail_impl.${guardrailId}`,
53299
- message: `Guardrail "${guardrailId}" has no policy rule in the active policy \u2014 skipping`,
53300
- severity: "info"
53301
- });
53302
- continue;
53303
- }
53304
- for (const check of impl.checks) {
53305
- resolved.push({
53306
- guardrail_id: guardrailId,
53307
- guardrail,
53308
- policy_rule: policyRule,
53309
- check
53310
- });
53311
- }
53312
- }
53313
- return { resolved, diagnostics };
53314
- }
53315
-
53316
- // src/guardrail-generator/resolve-paths.ts
53317
- function resolveBindingTargetPath(target, paths, bindingSoftware) {
53318
- const diagnostics = [];
53319
- const resolved = target.replace(/\{(\w+)\}/g, (match, varName) => {
53320
- const value = paths[varName];
53321
- if (value === void 0) {
53322
- diagnostics.push({
53323
- path: `binding.${bindingSoftware}.outputs`,
53324
- message: `Path variable "${varName}" used in target "${target}" but not defined in config.paths`,
53325
- severity: "error"
53326
- });
53327
- return match;
53328
- }
53329
- return value;
53330
- });
53331
- return { resolved, diagnostics };
53332
- }
53333
-
53334
53555
  // src/renderer/renderer.ts
53335
53556
  import { readFile as readFile4, writeFile, mkdir, unlink } from "fs/promises";
53336
53557
  import { dirname as dirname5 } from "path";
@@ -54724,6 +54945,378 @@ async function checkDriftFromConfig(dsl, renderTargets, options) {
54724
54945
  return { hasDrift: diffs.length > 0, diffs };
54725
54946
  }
54726
54947
 
54948
+ // src/scorer/scorer.ts
54949
+ function pct(n3, d2) {
54950
+ return d2 === 0 ? 100 : Math.round(n3 / d2 * 100);
54951
+ }
54952
+ function artifactValidationCoverage(dsl) {
54953
+ const entries = Object.entries(dsl.artifacts);
54954
+ const total = entries.length;
54955
+ const covered = entries.filter(
54956
+ ([, a3]) => a3.required_validations.length > 0
54957
+ ).length;
54958
+ const missing = entries.filter(([, a3]) => a3.required_validations.length === 0).map(([id]) => id);
54959
+ return {
54960
+ id: "artifact-validation-coverage",
54961
+ label: "Artifact validation coverage",
54962
+ score: covered,
54963
+ total,
54964
+ percent: pct(covered, total),
54965
+ weight: 3,
54966
+ recommendations: missing.length > 0 ? [`${missing.length} artifacts missing required_validations: ${missing.join(", ")}`] : []
54967
+ };
54968
+ }
54969
+ function taskValidationCoverage(dsl) {
54970
+ const entries = Object.entries(dsl.tasks);
54971
+ const total = entries.length;
54972
+ const covered = entries.filter(([, t3]) => t3.validations.length > 0).length;
54973
+ const missing = entries.filter(([, t3]) => t3.validations.length === 0).map(([id]) => id);
54974
+ return {
54975
+ id: "task-validation-coverage",
54976
+ label: "Task validation coverage",
54977
+ score: covered,
54978
+ total,
54979
+ percent: pct(covered, total),
54980
+ weight: 3,
54981
+ recommendations: missing.length > 0 ? [`${missing.length} tasks missing validations: ${missing.join(", ")}`] : []
54982
+ };
54983
+ }
54984
+ function guardrailPolicyCoverage(dsl) {
54985
+ const guardrailIds = Object.keys(dsl.guardrails);
54986
+ const total = guardrailIds.length;
54987
+ const referenced = /* @__PURE__ */ new Set();
54988
+ for (const policy of Object.values(dsl.guardrail_policies)) {
54989
+ for (const rule of policy.rules) {
54990
+ referenced.add(rule.guardrail);
54991
+ }
54992
+ }
54993
+ const covered = guardrailIds.filter((id) => referenced.has(id)).length;
54994
+ const missing = guardrailIds.filter((id) => !referenced.has(id));
54995
+ return {
54996
+ id: "guardrail-policy-coverage",
54997
+ label: "Guardrail policy coverage",
54998
+ score: covered,
54999
+ total,
55000
+ percent: pct(covered, total),
55001
+ weight: 2,
55002
+ recommendations: missing.length > 0 ? [`${missing.length} guardrails not in any policy: ${missing.join(", ")}`] : []
55003
+ };
55004
+ }
55005
+ function workflowValidationIntegration(dsl) {
55006
+ const blockingValidations = Object.entries(dsl.validations).filter(
55007
+ ([, v2]) => v2.blocking
55008
+ );
55009
+ const total = blockingValidations.length;
55010
+ const referenced = /* @__PURE__ */ new Set();
55011
+ for (const wf of Object.values(dsl.workflow)) {
55012
+ for (const step of wf.steps) {
55013
+ if (step.type === "validation") {
55014
+ referenced.add(step.validation);
55015
+ }
55016
+ }
55017
+ }
55018
+ for (const task of Object.values(dsl.tasks)) {
55019
+ for (const valId of task.validations) {
55020
+ referenced.add(valId);
55021
+ }
55022
+ }
55023
+ const covered = blockingValidations.filter(
55024
+ ([id]) => referenced.has(id)
55025
+ ).length;
55026
+ const missing = blockingValidations.filter(([id]) => !referenced.has(id)).map(([id]) => id);
55027
+ return {
55028
+ id: "workflow-validation-integration",
55029
+ label: "Workflow validation integration",
55030
+ score: covered,
55031
+ total,
55032
+ percent: pct(covered, total),
55033
+ weight: 3,
55034
+ recommendations: missing.length > 0 ? [`${missing.length} blocking validations not wired: ${missing.join(", ")}`] : []
55035
+ };
55036
+ }
55037
+ var OPTIONAL_ENTITY_FIELDS = {
55038
+ agents: {
55039
+ section: "agents",
55040
+ fields: ["responsibilities", "constraints", "rules"]
55041
+ },
55042
+ tasks: {
55043
+ section: "tasks",
55044
+ fields: ["description", "responsibilities", "execution_steps", "completion_criteria"]
55045
+ },
55046
+ artifacts: {
55047
+ section: "artifacts",
55048
+ fields: ["description", "visibility"]
55049
+ },
55050
+ tools: {
55051
+ section: "tools",
55052
+ fields: ["description", "commands"]
55053
+ },
55054
+ workflow: {
55055
+ section: "workflow",
55056
+ fields: ["description", "trigger", "entry_conditions"]
55057
+ },
55058
+ guardrails: {
55059
+ section: "guardrails",
55060
+ fields: ["rationale", "tags"]
55061
+ }
55062
+ };
55063
+ function hasNonEmpty(obj, field) {
55064
+ const val = obj[field];
55065
+ if (val === void 0 || val === null) return false;
55066
+ if (typeof val === "string") return val.length > 0;
55067
+ if (Array.isArray(val)) return val.length > 0;
55068
+ return true;
55069
+ }
55070
+ function schemaCompleteness(dsl) {
55071
+ let totalSlots = 0;
55072
+ let filledSlots = 0;
55073
+ const lowSections = [];
55074
+ for (const [sectionKey, meta] of Object.entries(OPTIONAL_ENTITY_FIELDS)) {
55075
+ const entities = dsl[meta.section];
55076
+ if (!entities) continue;
55077
+ let sectionTotal = 0;
55078
+ let sectionFilled = 0;
55079
+ for (const entity of Object.values(entities)) {
55080
+ for (const field of meta.fields) {
55081
+ sectionTotal++;
55082
+ totalSlots++;
55083
+ if (hasNonEmpty(entity, field)) {
55084
+ sectionFilled++;
55085
+ filledSlots++;
55086
+ }
55087
+ }
55088
+ }
55089
+ if (sectionTotal > 0 && pct(sectionFilled, sectionTotal) < 50) {
55090
+ lowSections.push(sectionKey);
55091
+ }
55092
+ }
55093
+ return {
55094
+ id: "schema-completeness",
55095
+ label: "Schema completeness",
55096
+ score: filledSlots,
55097
+ total: totalSlots,
55098
+ percent: pct(filledSlots, totalSlots),
55099
+ weight: 1,
55100
+ recommendations: lowSections.length > 0 ? [`Low optional field coverage in: ${lowSections.join(", ")}`] : []
55101
+ };
55102
+ }
55103
+ function crossReferenceBidirectionality(dsl) {
55104
+ let totalChecks = 0;
55105
+ let passedChecks = 0;
55106
+ const issues = [];
55107
+ for (const [agentId, agent] of Object.entries(dsl.agents)) {
55108
+ for (const toolId of agent.can_execute_tools) {
55109
+ totalChecks++;
55110
+ const tool = dsl.tools[toolId];
55111
+ if (tool && tool.invokable_by.includes(agentId)) {
55112
+ passedChecks++;
55113
+ } else {
55114
+ issues.push(`agent ${agentId} \u2192 tool ${toolId}`);
55115
+ }
55116
+ }
55117
+ for (const artId of agent.can_write_artifacts) {
55118
+ totalChecks++;
55119
+ const art = dsl.artifacts[artId];
55120
+ if (art && (art.producers.includes(agentId) || art.editors.includes(agentId))) {
55121
+ passedChecks++;
55122
+ } else {
55123
+ issues.push(`agent ${agentId} \u2192 artifact ${artId} (write)`);
55124
+ }
55125
+ }
55126
+ for (const artId of agent.can_read_artifacts) {
55127
+ totalChecks++;
55128
+ const art = dsl.artifacts[artId];
55129
+ if (art && (art.consumers.includes(agentId) || art.producers.includes(agentId) || art.editors.includes(agentId))) {
55130
+ passedChecks++;
55131
+ } else {
55132
+ issues.push(`agent ${agentId} \u2192 artifact ${artId} (read)`);
55133
+ }
55134
+ }
55135
+ }
55136
+ for (const [toolId, tool] of Object.entries(dsl.tools)) {
55137
+ for (const agentId of tool.invokable_by) {
55138
+ totalChecks++;
55139
+ const agent = dsl.agents[agentId];
55140
+ if (agent && agent.can_execute_tools.includes(toolId)) {
55141
+ passedChecks++;
55142
+ } else {
55143
+ issues.push(`tool ${toolId} \u2192 agent ${agentId}`);
55144
+ }
55145
+ }
55146
+ }
55147
+ return {
55148
+ id: "cross-reference-bidirectionality",
55149
+ label: "Cross-reference bidirectionality",
55150
+ score: passedChecks,
55151
+ total: totalChecks,
55152
+ percent: pct(passedChecks, totalChecks),
55153
+ weight: 2,
55154
+ recommendations: issues.length > 0 ? [`${issues.length} unreciprocated cross-references: ${issues.slice(0, 5).join(", ")}${issues.length > 5 ? `, ... (${issues.length - 5} more)` : ""}`] : []
55155
+ };
55156
+ }
55157
+ function entityGuardrailCoverage(dsl) {
55158
+ const entitySections = [
55159
+ { name: "agents", entities: dsl.agents },
55160
+ { name: "tasks", entities: dsl.tasks },
55161
+ { name: "tools", entities: dsl.tools },
55162
+ { name: "artifacts", entities: dsl.artifacts }
55163
+ ];
55164
+ const scopeBindings = {
55165
+ agents: /* @__PURE__ */ new Set(),
55166
+ tasks: /* @__PURE__ */ new Set(),
55167
+ tools: /* @__PURE__ */ new Set(),
55168
+ artifacts: /* @__PURE__ */ new Set()
55169
+ };
55170
+ for (const guardrail of Object.values(dsl.guardrails)) {
55171
+ for (const key of Object.keys(scopeBindings)) {
55172
+ const ids = guardrail.scope[key];
55173
+ if (ids) {
55174
+ for (const id of ids) scopeBindings[key].add(id);
55175
+ }
55176
+ }
55177
+ }
55178
+ let total = 0;
55179
+ let covered = 0;
55180
+ const missing = [];
55181
+ for (const { name, entities } of entitySections) {
55182
+ for (const [entityId, entity] of Object.entries(entities)) {
55183
+ total++;
55184
+ const hasEntitySide = (entity.guardrails ?? []).length > 0;
55185
+ const hasScopeSide = scopeBindings[name].has(entityId);
55186
+ if (hasEntitySide || hasScopeSide) {
55187
+ covered++;
55188
+ } else {
55189
+ missing.push(`${name}.${entityId}`);
55190
+ }
55191
+ }
55192
+ }
55193
+ return {
55194
+ id: "entity-guardrail-coverage",
55195
+ label: "Entity guardrail coverage",
55196
+ score: covered,
55197
+ total,
55198
+ percent: pct(covered, total),
55199
+ weight: 1,
55200
+ recommendations: missing.length > 0 ? [`${missing.length} entities without guardrails: ${missing.slice(0, 5).join(", ")}${missing.length > 5 ? `, ... (${missing.length - 5} more)` : ""}`] : []
55201
+ };
55202
+ }
55203
+ function guardrailScopeResolution(dsl) {
55204
+ let totalRefs = 0;
55205
+ let resolvedRefs = 0;
55206
+ const unresolved = [];
55207
+ const sectionMap = {
55208
+ agents: dsl.agents,
55209
+ tasks: dsl.tasks,
55210
+ tools: dsl.tools,
55211
+ artifacts: dsl.artifacts,
55212
+ workflows: dsl.workflow
55213
+ };
55214
+ for (const [guardrailId, guardrail] of Object.entries(dsl.guardrails)) {
55215
+ const scope = guardrail.scope;
55216
+ for (const [scopeKey, entityIds] of Object.entries(scope)) {
55217
+ if (!Array.isArray(entityIds)) continue;
55218
+ const section = sectionMap[scopeKey];
55219
+ if (!section) continue;
55220
+ for (const entityId of entityIds) {
55221
+ totalRefs++;
55222
+ if (section[entityId]) {
55223
+ resolvedRefs++;
55224
+ } else {
55225
+ unresolved.push(`${guardrailId}.scope.${scopeKey}: ${entityId}`);
55226
+ }
55227
+ }
55228
+ }
55229
+ }
55230
+ return {
55231
+ id: "guardrail-scope-resolution",
55232
+ label: "Guardrail scope resolution",
55233
+ score: resolvedRefs,
55234
+ total: totalRefs,
55235
+ percent: pct(resolvedRefs, totalRefs),
55236
+ weight: 2,
55237
+ recommendations: unresolved.length > 0 ? [`${unresolved.length} unresolved scope refs: ${unresolved.join(", ")}`] : []
55238
+ };
55239
+ }
55240
+ function score(dsl) {
55241
+ const dimensions = [
55242
+ artifactValidationCoverage(dsl),
55243
+ taskValidationCoverage(dsl),
55244
+ guardrailPolicyCoverage(dsl),
55245
+ workflowValidationIntegration(dsl),
55246
+ schemaCompleteness(dsl),
55247
+ crossReferenceBidirectionality(dsl),
55248
+ guardrailScopeResolution(dsl),
55249
+ entityGuardrailCoverage(dsl)
55250
+ ];
55251
+ const totalWeight = dimensions.reduce((s2, d2) => s2 + d2.weight, 0);
55252
+ const weightedSum = dimensions.reduce(
55253
+ (s2, d2) => s2 + d2.percent * d2.weight,
55254
+ 0
55255
+ );
55256
+ const overall = totalWeight === 0 ? 100 : Math.round(weightedSum / totalWeight);
55257
+ return { overall, dimensions };
55258
+ }
55259
+
55260
+ // src/guardrail-generator/generator.ts
55261
+ import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2, copyFile } from "fs/promises";
55262
+ import { resolve as resolve6, dirname as dirname6 } from "path";
55263
+ import Handlebars2 from "handlebars";
55264
+ import YAML from "yaml";
55265
+
55266
+ // src/guardrail-generator/resolve-checks.ts
55267
+ function resolveChecks(dsl, binding, policy) {
55268
+ const resolved = [];
55269
+ const diagnostics = [];
55270
+ const guardrailImpl = binding.guardrail_impl ?? {};
55271
+ for (const [guardrailId, impl] of Object.entries(guardrailImpl)) {
55272
+ const guardrail = dsl.guardrails[guardrailId];
55273
+ if (!guardrail) {
55274
+ diagnostics.push({
55275
+ path: `binding.${binding.software}.guardrail_impl.${guardrailId}`,
55276
+ message: `Binding "${binding.software}" implements guardrail "${guardrailId}" which is not defined in the DSL`,
55277
+ severity: "error"
55278
+ });
55279
+ continue;
55280
+ }
55281
+ const policyRule = policy.rules.find((r3) => r3.guardrail === guardrailId);
55282
+ if (!policyRule) {
55283
+ diagnostics.push({
55284
+ path: `binding.${binding.software}.guardrail_impl.${guardrailId}`,
55285
+ message: `Guardrail "${guardrailId}" has no policy rule in the active policy \u2014 skipping`,
55286
+ severity: "info"
55287
+ });
55288
+ continue;
55289
+ }
55290
+ for (const check of impl.checks) {
55291
+ resolved.push({
55292
+ guardrail_id: guardrailId,
55293
+ guardrail,
55294
+ policy_rule: policyRule,
55295
+ check
55296
+ });
55297
+ }
55298
+ }
55299
+ return { resolved, diagnostics };
55300
+ }
55301
+
55302
+ // src/guardrail-generator/resolve-paths.ts
55303
+ function resolveBindingTargetPath(target, paths, bindingSoftware) {
55304
+ const diagnostics = [];
55305
+ const resolved = target.replace(/\{(\w+)\}/g, (match, varName) => {
55306
+ const value = paths[varName];
55307
+ if (value === void 0) {
55308
+ diagnostics.push({
55309
+ path: `binding.${bindingSoftware}.outputs`,
55310
+ message: `Path variable "${varName}" used in target "${target}" but not defined in config.paths`,
55311
+ severity: "error"
55312
+ });
55313
+ return match;
55314
+ }
55315
+ return value;
55316
+ });
55317
+ return { resolved, diagnostics };
55318
+ }
55319
+
54727
55320
  // src/guardrail-generator/generator.ts
54728
55321
  Handlebars2.registerHelper("json", (value) => {
54729
55322
  return new Handlebars2.SafeString(JSON.stringify(value, null, 2));
@@ -55101,12 +55694,8 @@ function resolveBindingRenderOutputPath(output, paths) {
55101
55694
  });
55102
55695
  }
55103
55696
 
55104
- // src/cli/commands/generate-interface.ts
55105
- import { writeFileSync } from "fs";
55106
- import { resolve as resolve7 } from "path";
55107
-
55108
55697
  // src/interface-generator/generator.ts
55109
- import { stringify as stringify2 } from "yaml";
55698
+ import { stringify } from "yaml";
55110
55699
  function buildInterfaceDocument(dsl, generatedAt) {
55111
55700
  const ti = dsl.team_interface;
55112
55701
  const doc = {
@@ -55123,1081 +55712,63 @@ function buildInterfaceDocument(dsl, generatedAt) {
55123
55712
  }
55124
55713
  const handoffKeys = /* @__PURE__ */ new Set();
55125
55714
  if (ti.accepts?.workflows) {
55126
- for (const spec of Object.values(ti.accepts.workflows)) {
55127
- handoffKeys.add(spec.input_handoff);
55128
- handoffKeys.add(spec.output_handoff);
55129
- }
55130
- }
55131
- const handoff_types = {};
55132
- for (const k2 of [...handoffKeys].sort()) {
55133
- const ht = dsl.handoff_types[k2];
55134
- if (ht) {
55135
- const entry = {
55136
- version: ht.version,
55137
- schema: ht.schema
55138
- };
55139
- if (ht.description !== void 0) {
55140
- entry.description = ht.description;
55141
- }
55142
- handoff_types[k2] = entry;
55143
- }
55144
- }
55145
- if (Object.keys(handoff_types).length > 0) {
55146
- doc.handoff_types = handoff_types;
55147
- }
55148
- const artifactsOut = {};
55149
- if (ti.exposes?.artifacts) {
55150
- for (const key of [...ti.exposes.artifacts].sort()) {
55151
- const art = dsl.artifacts[key];
55152
- if (art) {
55153
- const entry = {
55154
- type: art.type,
55155
- states: art.states
55156
- };
55157
- if (art.description !== void 0) {
55158
- entry.description = art.description;
55159
- }
55160
- artifactsOut[key] = entry;
55161
- }
55162
- }
55163
- }
55164
- if (Object.keys(artifactsOut).length > 0) {
55165
- doc.exposes = { artifacts: artifactsOut };
55166
- }
55167
- if (ti.constraints !== void 0 && ti.constraints.length > 0) {
55168
- doc.constraints = ti.constraints;
55169
- }
55170
- return doc;
55171
- }
55172
- function generateInterface(options) {
55173
- if (!options.dsl.team_interface) {
55174
- throw new Error("DSL has no team_interface section");
55175
- }
55176
- const doc = buildInterfaceDocument(options.dsl, (/* @__PURE__ */ new Date()).toISOString());
55177
- const content = options.format === "json" ? `${JSON.stringify(doc, null, 2)}
55178
- ` : `${stringify2(doc, { sortMapEntries: true })}
55179
- `;
55180
- const outputPath = options.output ?? "team-interface.yaml";
55181
- return { outputPath, content };
55182
- }
55183
-
55184
- // src/cli/commands/generate-interface.ts
55185
- function runGenerateInterfaceCli(opts) {
55186
- if (!opts.dsl.team_interface) {
55187
- process.stderr.write("Error: DSL has no team_interface section.\n");
55188
- process.exit(1);
55189
- }
55190
- const outputPath = resolve7(process.cwd(), opts.output ?? "team-interface.yaml");
55191
- const result = generateInterface({
55192
- dsl: opts.dsl,
55193
- output: outputPath,
55194
- dryRun: opts.dryRun,
55195
- format: opts.format
55196
- });
55197
- if (opts.dryRun) {
55198
- process.stdout.write(result.content);
55199
- return;
55200
- }
55201
- writeFileSync(result.outputPath, result.content, "utf8");
55202
- if (!opts.quiet) {
55203
- process.stdout.write(`Wrote ${result.outputPath}
55204
- `);
55205
- }
55206
- }
55207
-
55208
- // src/cli/commands/generate.ts
55209
- var VALID_TYPES = ["templates", "guardrails", "interface"];
55210
- function resolvedConfigForTeam(workspace, teamConfig) {
55211
- return {
55212
- dsl: "",
55213
- vars: teamConfig.vars,
55214
- renders: workspace.renders,
55215
- configDir: workspace.configDir,
55216
- bindings: teamConfig.bindings,
55217
- activeGuardrailPolicy: teamConfig.activeGuardrailPolicy,
55218
- paths: teamConfig.paths
55219
- };
55220
- }
55221
- async function runGenerate(type, opts) {
55222
- if (type !== void 0 && !VALID_TYPES.includes(type)) {
55223
- process.stderr.write(`Unknown generate type: ${type}
55224
- `);
55225
- process.exit(1);
55226
- }
55227
- if (opts.format !== "yaml" && opts.format !== "json") {
55228
- process.stderr.write(
55229
- `Invalid --format: expected yaml or json, got ${opts.format}
55230
- `
55231
- );
55232
- process.exit(1);
55233
- }
55234
- const normalizedType = type;
55235
- const targets = {
55236
- templates: normalizedType === void 0 || normalizedType === "templates",
55237
- guardrails: normalizedType === void 0 || normalizedType === "guardrails",
55238
- interface: normalizedType === void 0 || normalizedType === "interface"
55239
- };
55240
- try {
55241
- const config = await loadConfig(opts.config);
55242
- if (!config) {
55243
- process.stderr.write(
55244
- "Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
55245
- );
55246
- process.exit(1);
55247
- }
55248
- if (isMultiTeamConfig(config)) {
55249
- await runMultiTeam(config, targets, normalizedType, opts);
55250
- return;
55251
- }
55252
- await runSingleTeam(config, targets, normalizedType, opts);
55253
- } catch (err) {
55254
- if (err instanceof ConfigLoadError) {
55255
- process.stderr.write(`Config error: ${err.message}
55256
- `);
55257
- process.exit(1);
55258
- }
55259
- const msg = err instanceof Error ? err.message : String(err);
55260
- process.stderr.write(`Error: ${msg}
55261
- `);
55262
- process.exit(1);
55263
- }
55264
- }
55265
- async function runMultiTeam(config, targets, normalizedType, opts) {
55266
- const teamEntries = getTeamEntries(config, opts.team);
55267
- let exitWithError = false;
55268
- for (const [teamId, teamConfig] of teamEntries) {
55269
- if (!opts.quiet) process.stdout.write(`
55270
- --- Team: ${teamId} ---
55271
- `);
55272
- const resolved = await resolve4(teamConfig.dsl);
55273
- const data = teamConfig.vars ? substituteVars(resolved.data, teamConfig.vars) : resolved.data;
55274
- const schemaResult = validateSchema(data);
55275
- if (!schemaResult.success) {
55276
- process.stderr.write(
55277
- `Schema validation failed for team ${teamId}. Run 'agent-contracts validate' for details.
55278
- `
55279
- );
55280
- exitWithError = true;
55281
- continue;
55282
- }
55283
- if (targets.templates) {
55284
- let renderOptions;
55285
- if (teamConfig.bindings.length > 0) {
55286
- const loadedBindings = await loadBindings(teamConfig.bindings);
55287
- renderOptions = {
55288
- loadedBindings,
55289
- activeGuardrailPolicy: teamConfig.activeGuardrailPolicy
55290
- };
55291
- }
55292
- if (opts.check) {
55293
- const drift = await checkDriftFromConfig(
55294
- schemaResult.data,
55295
- config.renders,
55296
- renderOptions
55297
- );
55298
- if (drift.hasDrift) {
55299
- process.stderr.write(
55300
- `Drift detected for team ${teamId} in the following files:
55301
- `
55302
- );
55303
- for (const f2 of drift.diffs) {
55304
- process.stderr.write(` ${f2}
55305
- `);
55306
- }
55307
- exitWithError = true;
55308
- } else if (!opts.quiet) {
55309
- process.stdout.write("No drift detected.\n");
55310
- }
55311
- } else {
55312
- const files = await renderFromConfig(
55313
- schemaResult.data,
55314
- config.renders,
55315
- renderOptions
55316
- );
55317
- if (!opts.quiet) {
55318
- process.stdout.write(`Rendered ${files.length} file(s):
55319
- `);
55320
- for (const f2 of files) {
55321
- process.stdout.write(` ${f2}
55322
- `);
55323
- }
55324
- }
55325
- }
55326
- }
55327
- if (targets.interface) {
55328
- if (schemaResult.data.team_interface) {
55329
- runGenerateInterfaceCli({
55330
- dsl: schemaResult.data,
55331
- output: teamConfig.interfaceOutput ?? opts.output,
55332
- dryRun: opts.dryRun,
55333
- format: opts.format,
55334
- quiet: opts.quiet
55335
- });
55336
- } else if (normalizedType === "interface") {
55337
- process.stderr.write("Error: DSL has no team_interface section.\n");
55338
- exitWithError = true;
55339
- }
55340
- }
55341
- if (targets.guardrails) {
55342
- const loadedBindings = await loadBindings(teamConfig.bindings);
55343
- const result = await generateGuardrails({
55344
- dsl: schemaResult.data,
55345
- config: resolvedConfigForTeam(config, teamConfig),
55346
- loadedBindings,
55347
- filterBindings: opts.binding,
55348
- dryRun: opts.dryRun
55349
- });
55350
- const errors = result.diagnostics.filter((d2) => d2.severity === "error");
55351
- const warnings = result.diagnostics.filter((d2) => d2.severity === "warning");
55352
- const infos = result.diagnostics.filter((d2) => d2.severity === "info");
55353
- if (errors.length > 0) {
55354
- process.stderr.write(`Errors (team ${teamId}):
55355
- `);
55356
- for (const d2 of errors) {
55357
- process.stderr.write(` error [${d2.path}] ${d2.message}
55358
- `);
55359
- }
55360
- exitWithError = true;
55361
- }
55362
- if (warnings.length > 0 && !opts.quiet) {
55363
- process.stderr.write(`Warnings (team ${teamId}):
55364
- `);
55365
- for (const d2 of warnings) {
55366
- process.stderr.write(` warning [${d2.path}] ${d2.message}
55367
- `);
55368
- }
55369
- }
55370
- if (infos.length > 0 && !opts.quiet) {
55371
- for (const d2 of infos) {
55372
- process.stderr.write(` info [${d2.path}] ${d2.message}
55373
- `);
55374
- }
55375
- }
55376
- if (!opts.quiet) {
55377
- const action = opts.dryRun ? "Would generate" : "Generated";
55378
- process.stdout.write(
55379
- `${action} ${result.outputFiles.length} file(s):
55380
- `
55381
- );
55382
- for (const f2 of result.outputFiles) {
55383
- process.stdout.write(` ${f2}
55384
- `);
55385
- }
55386
- }
55387
- }
55388
- }
55389
- if (exitWithError) process.exit(1);
55390
- }
55391
- async function runSingleTeam(config, targets, normalizedType, opts) {
55392
- const resolved = await resolve4(config.dsl);
55393
- const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
55394
- const schemaResult = validateSchema(data);
55395
- if (!schemaResult.success) {
55396
- process.stderr.write(
55397
- "Schema validation failed. Run 'agent-contracts validate' for details.\n"
55398
- );
55399
- process.exit(1);
55400
- }
55401
- let exitWithError = false;
55402
- if (targets.templates) {
55403
- let renderOptions;
55404
- if (config.bindings.length > 0) {
55405
- const loadedBindings = await loadBindings(config.bindings);
55406
- renderOptions = {
55407
- loadedBindings,
55408
- activeGuardrailPolicy: config.activeGuardrailPolicy
55409
- };
55410
- }
55411
- if (opts.check) {
55412
- const drift = await checkDriftFromConfig(
55413
- schemaResult.data,
55414
- config.renders,
55415
- renderOptions
55416
- );
55417
- if (drift.hasDrift) {
55418
- process.stderr.write("Drift detected in the following files:\n");
55419
- for (const f2 of drift.diffs) {
55420
- process.stderr.write(` ${f2}
55421
- `);
55422
- }
55423
- exitWithError = true;
55424
- } else if (!opts.quiet) {
55425
- process.stdout.write("No drift detected.\n");
55426
- }
55427
- } else {
55428
- const files = await renderFromConfig(
55429
- schemaResult.data,
55430
- config.renders,
55431
- renderOptions
55432
- );
55433
- if (!opts.quiet) {
55434
- process.stdout.write(`Rendered ${files.length} file(s):
55435
- `);
55436
- for (const f2 of files) {
55437
- process.stdout.write(` ${f2}
55438
- `);
55439
- }
55440
- }
55441
- }
55442
- }
55443
- if (targets.interface) {
55444
- if (schemaResult.data.team_interface) {
55445
- runGenerateInterfaceCli({
55446
- dsl: schemaResult.data,
55447
- output: opts.output,
55448
- dryRun: opts.dryRun,
55449
- format: opts.format,
55450
- quiet: opts.quiet
55451
- });
55452
- } else if (normalizedType === "interface") {
55453
- process.stderr.write("Error: DSL has no team_interface section.\n");
55454
- process.exit(1);
55455
- }
55456
- }
55457
- if (targets.guardrails) {
55458
- const loadedBindings = await loadBindings(config.bindings);
55459
- const result = await generateGuardrails({
55460
- dsl: schemaResult.data,
55461
- config,
55462
- loadedBindings,
55463
- filterBindings: opts.binding,
55464
- dryRun: opts.dryRun
55465
- });
55466
- const errors = result.diagnostics.filter((d2) => d2.severity === "error");
55467
- const warnings = result.diagnostics.filter((d2) => d2.severity === "warning");
55468
- const infos = result.diagnostics.filter((d2) => d2.severity === "info");
55469
- if (errors.length > 0) {
55470
- process.stderr.write("Errors:\n");
55471
- for (const d2 of errors) {
55472
- process.stderr.write(` error [${d2.path}] ${d2.message}
55473
- `);
55474
- }
55475
- exitWithError = true;
55476
- }
55477
- if (warnings.length > 0 && !opts.quiet) {
55478
- process.stderr.write("Warnings:\n");
55479
- for (const d2 of warnings) {
55480
- process.stderr.write(` warning [${d2.path}] ${d2.message}
55481
- `);
55482
- }
55483
- }
55484
- if (infos.length > 0 && !opts.quiet) {
55485
- for (const d2 of infos) {
55486
- process.stderr.write(` info [${d2.path}] ${d2.message}
55487
- `);
55488
- }
55489
- }
55490
- if (!opts.quiet) {
55491
- const action = opts.dryRun ? "Would generate" : "Generated";
55492
- process.stdout.write(
55493
- `${action} ${result.outputFiles.length} file(s):
55494
- `
55495
- );
55496
- for (const f2 of result.outputFiles) {
55497
- process.stdout.write(` ${f2}
55498
- `);
55499
- }
55500
- }
55501
- }
55502
- if (exitWithError) process.exit(1);
55503
- }
55504
- var generateCommand = new Command4("generate").description("Generate artifacts from DSL \u2014 templates, guardrails, and/or interface").argument(
55505
- "[type]",
55506
- "Type of artifacts to generate (templates|guardrails|interface). Omit to run all."
55507
- ).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option(
55508
- "--check",
55509
- "Check for template drift without writing files (templates only)",
55510
- false
55511
- ).option("--binding <name...>", "Filter to specific software binding(s) (guardrails only)").option(
55512
- "-o, --output <path>",
55513
- "Output path for generated team interface (interface only)"
55514
- ).option(
55515
- "--format <format>",
55516
- "Output format for team interface: yaml or json",
55517
- "yaml"
55518
- ).option("--dry-run", "Print what would be generated without writing files", false).option("--quiet", "Suppress output on success", false).action(runGenerate);
55519
-
55520
- // src/cli/commands/render.ts
55521
- var renderCommand = new Command5("render").description("(deprecated) Alias for 'generate templates'. Use 'generate templates' instead.").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--check", "Check for template drift without writing files", false).option("--quiet", "Suppress output on success", false).action(
55522
- async (opts) => {
55523
- process.stderr.write(
55524
- "Warning: 'render' is deprecated. Use 'agent-contracts generate templates' instead.\n"
55525
- );
55526
- await runGenerate("templates", {
55527
- ...opts,
55528
- binding: void 0,
55529
- output: void 0,
55530
- format: "yaml",
55531
- dryRun: false
55532
- });
55533
- }
55534
- );
55535
-
55536
- // src/cli/commands/check.ts
55537
- import { existsSync, readFileSync } from "fs";
55538
- import { join as join3 } from "path";
55539
- import { Command as Command6 } from "commander";
55540
- import { parse as parseYaml4, stringify as stringify3 } from "yaml";
55541
- import { access as access2 } from "fs/promises";
55542
- import { resolve as pathResolve, dirname as dirname7 } from "path";
55543
- var checkCommand = new Command6("check").description("Run full pipeline: resolve \u2192 validate \u2192 lint \u2192 render --check").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json)", "text").option("--quiet", "Suppress output on success", false).option("--strict", "Treat warnings as errors", false).action(
55544
- async (opts) => {
55545
- let hasErrors = false;
55546
- try {
55547
- const config = await loadConfig(opts.config);
55548
- if (!config) {
55549
- process.stderr.write(
55550
- "Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
55551
- );
55552
- process.exit(1);
55553
- }
55554
- if (isMultiTeamConfig(config)) {
55555
- const teamEntries = getTeamEntries(config, opts.team);
55556
- for (const [teamId, teamConfig] of teamEntries) {
55557
- if (!opts.quiet) process.stderr.write(`
55558
- --- Team: ${teamId} ---
55559
- `);
55560
- const resolved2 = await resolve4(teamConfig.dsl);
55561
- const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
55562
- const schemaResult2 = validateSchema(data2);
55563
- const schemaWarnings2 = schemaResult2.diagnostics.filter(
55564
- (d2) => d2.severity === "warning"
55565
- );
55566
- if (!schemaResult2.success) {
55567
- const output = formatDiagnostics(schemaResult2.diagnostics, {
55568
- format: opts.format,
55569
- quiet: opts.quiet
55570
- });
55571
- if (output) process.stderr.write(output + "\n");
55572
- hasErrors = true;
55573
- continue;
55574
- }
55575
- const refDiags2 = checkReferences(schemaResult2.data);
55576
- const handoffDiags2 = validateHandoffSchemas(schemaResult2.data);
55577
- const allRefDiags2 = [...refDiags2, ...handoffDiags2, ...schemaWarnings2];
55578
- if (allRefDiags2.length > 0) {
55579
- const output = formatDiagnostics(allRefDiags2, {
55580
- format: opts.format,
55581
- quiet: opts.quiet
55582
- });
55583
- if (output) process.stderr.write(output + "\n");
55584
- hasErrors = true;
55585
- }
55586
- const tsLintDiags2 = lint(schemaResult2.data);
55587
- const spectralDiags2 = await spectralLint(
55588
- schemaResult2.data
55589
- );
55590
- const lintDiags2 = [...tsLintDiags2, ...spectralDiags2];
55591
- if (lintDiags2.length > 0) {
55592
- const output = formatDiagnostics(lintDiags2, {
55593
- format: opts.format,
55594
- quiet: opts.quiet
55595
- });
55596
- if (output) process.stderr.write(output + "\n");
55597
- if (lintDiags2.some((d2) => d2.severity === "error")) {
55598
- hasErrors = true;
55599
- }
55600
- if (opts.strict && lintDiags2.some((d2) => d2.severity === "warning")) {
55601
- hasErrors = true;
55602
- }
55603
- }
55604
- let renderOptions2;
55605
- if (teamConfig.bindings.length > 0) {
55606
- const loadedBindings = await loadBindings(teamConfig.bindings);
55607
- renderOptions2 = {
55608
- loadedBindings,
55609
- activeGuardrailPolicy: teamConfig.activeGuardrailPolicy
55610
- };
55611
- }
55612
- const drift2 = await checkDriftFromConfig(
55613
- schemaResult2.data,
55614
- config.renders,
55615
- renderOptions2
55616
- );
55617
- if (drift2.hasDrift) {
55618
- process.stderr.write(`Drift detected for team ${teamId} in:
55619
- `);
55620
- for (const f2 of drift2.diffs) {
55621
- process.stderr.write(` ${f2}
55622
- `);
55623
- }
55624
- hasErrors = true;
55625
- }
55626
- }
55627
- if (!hasErrors) {
55628
- for (const [teamId, teamConfig] of teamEntries) {
55629
- const resolved2 = await resolve4(teamConfig.dsl);
55630
- const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
55631
- const schemaResult2 = validateSchema(data2);
55632
- if (!schemaResult2.success || !schemaResult2.data) continue;
55633
- const dsl = schemaResult2.data;
55634
- const imports = dsl.imports;
55635
- if (!imports) continue;
55636
- for (const [importName, importDef] of Object.entries(imports)) {
55637
- const interfacePathRel = importDef?.interface;
55638
- if (typeof interfacePathRel !== "string") continue;
55639
- const interfacePath = pathResolve(
55640
- dirname7(teamConfig.dsl),
55641
- interfacePathRel
55642
- );
55643
- try {
55644
- await access2(interfacePath);
55645
- } catch {
55646
- process.stderr.write(
55647
- `Cross-team error: Team "${teamId}" imports "${importName}" but interface file not found: ${interfacePath}
55648
- `
55649
- );
55650
- hasErrors = true;
55651
- }
55652
- }
55653
- }
55654
- }
55655
- if (hasErrors) process.exit(1);
55656
- if (!opts.quiet) process.stdout.write("All checks passed.\n");
55657
- return;
55658
- }
55659
- const resolved = await resolve4(config.dsl);
55660
- const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
55661
- const schemaResult = validateSchema(data);
55662
- const schemaWarnings = schemaResult.diagnostics.filter(
55663
- (d2) => d2.severity === "warning"
55664
- );
55665
- if (!schemaResult.success) {
55666
- const output = formatDiagnostics(schemaResult.diagnostics, {
55667
- format: opts.format,
55668
- quiet: opts.quiet
55669
- });
55670
- if (output) process.stderr.write(output + "\n");
55671
- process.exit(1);
55672
- }
55673
- const refDiags = checkReferences(schemaResult.data);
55674
- const handoffDiags = validateHandoffSchemas(schemaResult.data);
55675
- const allRefDiags = [...refDiags, ...handoffDiags, ...schemaWarnings];
55676
- if (allRefDiags.length > 0) {
55677
- const output = formatDiagnostics(allRefDiags, {
55678
- format: opts.format,
55679
- quiet: opts.quiet
55680
- });
55681
- if (output) process.stderr.write(output + "\n");
55682
- hasErrors = true;
55683
- }
55684
- const tsLintDiags = lint(schemaResult.data);
55685
- const spectralDiags = await spectralLint(schemaResult.data);
55686
- const lintDiags = [...tsLintDiags, ...spectralDiags];
55687
- if (lintDiags.length > 0) {
55688
- const output = formatDiagnostics(lintDiags, {
55689
- format: opts.format,
55690
- quiet: opts.quiet
55691
- });
55692
- if (output) process.stderr.write(output + "\n");
55693
- if (lintDiags.some((d2) => d2.severity === "error")) {
55694
- hasErrors = true;
55695
- }
55696
- if (opts.strict && lintDiags.some((d2) => d2.severity === "warning")) {
55697
- hasErrors = true;
55698
- }
55699
- }
55700
- let renderOptions;
55701
- if (config.bindings.length > 0) {
55702
- const loadedBindings = await loadBindings(config.bindings);
55703
- renderOptions = {
55704
- loadedBindings,
55705
- activeGuardrailPolicy: config.activeGuardrailPolicy
55706
- };
55707
- }
55708
- const drift = await checkDriftFromConfig(
55709
- schemaResult.data,
55710
- config.renders,
55711
- renderOptions
55712
- );
55713
- if (drift.hasDrift) {
55714
- process.stderr.write("Drift detected in:\n");
55715
- for (const f2 of drift.diffs) {
55716
- process.stderr.write(` ${f2}
55717
- `);
55718
- }
55719
- hasErrors = true;
55720
- }
55721
- if (schemaResult.data.team_interface) {
55722
- const interfacePath = join3(config.configDir, "team-interface.yaml");
55723
- if (existsSync(interfacePath)) {
55724
- const result = generateInterface({
55725
- dsl: schemaResult.data,
55726
- dryRun: true,
55727
- format: "yaml"
55728
- });
55729
- const existing = readFileSync(interfacePath, "utf8");
55730
- const normalize = (raw) => {
55731
- try {
55732
- const parsed = parseYaml4(raw);
55733
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
55734
- const { generated_at: _t, ...rest } = parsed;
55735
- return `${stringify3(rest, { sortMapEntries: true })}
55736
- `;
55737
- }
55738
- } catch {
55739
- }
55740
- return raw.trim();
55741
- };
55742
- if (normalize(existing) !== normalize(result.content)) {
55743
- process.stderr.write("Drift detected in team-interface.yaml\n");
55744
- hasErrors = true;
55745
- }
55746
- }
55747
- }
55748
- if (hasErrors) {
55749
- process.exit(1);
55750
- }
55751
- if (!opts.quiet) {
55752
- process.stdout.write("All checks passed.\n");
55753
- }
55754
- } catch (err) {
55755
- if (err instanceof ConfigLoadError) {
55756
- process.stderr.write(`Config error: ${err.message}
55757
- `);
55758
- process.exit(1);
55759
- }
55760
- const msg = err instanceof Error ? err.message : String(err);
55761
- process.stderr.write(`Error: ${msg}
55762
- `);
55763
- process.exit(1);
55764
- }
55765
- }
55766
- );
55767
-
55768
- // src/cli/commands/score.ts
55769
- import { Command as Command7 } from "commander";
55770
-
55771
- // src/scorer/scorer.ts
55772
- function pct(n3, d2) {
55773
- return d2 === 0 ? 100 : Math.round(n3 / d2 * 100);
55774
- }
55775
- function artifactValidationCoverage(dsl) {
55776
- const entries = Object.entries(dsl.artifacts);
55777
- const total = entries.length;
55778
- const covered = entries.filter(
55779
- ([, a3]) => a3.required_validations.length > 0
55780
- ).length;
55781
- const missing = entries.filter(([, a3]) => a3.required_validations.length === 0).map(([id]) => id);
55782
- return {
55783
- id: "artifact-validation-coverage",
55784
- label: "Artifact validation coverage",
55785
- score: covered,
55786
- total,
55787
- percent: pct(covered, total),
55788
- weight: 3,
55789
- recommendations: missing.length > 0 ? [`${missing.length} artifacts missing required_validations: ${missing.join(", ")}`] : []
55790
- };
55791
- }
55792
- function taskValidationCoverage(dsl) {
55793
- const entries = Object.entries(dsl.tasks);
55794
- const total = entries.length;
55795
- const covered = entries.filter(([, t3]) => t3.validations.length > 0).length;
55796
- const missing = entries.filter(([, t3]) => t3.validations.length === 0).map(([id]) => id);
55797
- return {
55798
- id: "task-validation-coverage",
55799
- label: "Task validation coverage",
55800
- score: covered,
55801
- total,
55802
- percent: pct(covered, total),
55803
- weight: 3,
55804
- recommendations: missing.length > 0 ? [`${missing.length} tasks missing validations: ${missing.join(", ")}`] : []
55805
- };
55806
- }
55807
- function guardrailPolicyCoverage(dsl) {
55808
- const guardrailIds = Object.keys(dsl.guardrails);
55809
- const total = guardrailIds.length;
55810
- const referenced = /* @__PURE__ */ new Set();
55811
- for (const policy of Object.values(dsl.guardrail_policies)) {
55812
- for (const rule of policy.rules) {
55813
- referenced.add(rule.guardrail);
55814
- }
55815
- }
55816
- const covered = guardrailIds.filter((id) => referenced.has(id)).length;
55817
- const missing = guardrailIds.filter((id) => !referenced.has(id));
55818
- return {
55819
- id: "guardrail-policy-coverage",
55820
- label: "Guardrail policy coverage",
55821
- score: covered,
55822
- total,
55823
- percent: pct(covered, total),
55824
- weight: 2,
55825
- recommendations: missing.length > 0 ? [`${missing.length} guardrails not in any policy: ${missing.join(", ")}`] : []
55826
- };
55827
- }
55828
- function workflowValidationIntegration(dsl) {
55829
- const blockingValidations = Object.entries(dsl.validations).filter(
55830
- ([, v2]) => v2.blocking
55831
- );
55832
- const total = blockingValidations.length;
55833
- const referenced = /* @__PURE__ */ new Set();
55834
- for (const wf of Object.values(dsl.workflow)) {
55835
- for (const step of wf.steps) {
55836
- if (step.type === "validation") {
55837
- referenced.add(step.validation);
55838
- }
55839
- }
55840
- }
55841
- for (const task of Object.values(dsl.tasks)) {
55842
- for (const valId of task.validations) {
55843
- referenced.add(valId);
55844
- }
55845
- }
55846
- const covered = blockingValidations.filter(
55847
- ([id]) => referenced.has(id)
55848
- ).length;
55849
- const missing = blockingValidations.filter(([id]) => !referenced.has(id)).map(([id]) => id);
55850
- return {
55851
- id: "workflow-validation-integration",
55852
- label: "Workflow validation integration",
55853
- score: covered,
55854
- total,
55855
- percent: pct(covered, total),
55856
- weight: 3,
55857
- recommendations: missing.length > 0 ? [`${missing.length} blocking validations not wired: ${missing.join(", ")}`] : []
55858
- };
55859
- }
55860
- var OPTIONAL_ENTITY_FIELDS = {
55861
- agents: {
55862
- section: "agents",
55863
- fields: ["responsibilities", "constraints", "rules"]
55864
- },
55865
- tasks: {
55866
- section: "tasks",
55867
- fields: ["description", "responsibilities", "execution_steps", "completion_criteria"]
55868
- },
55869
- artifacts: {
55870
- section: "artifacts",
55871
- fields: ["description", "visibility"]
55872
- },
55873
- tools: {
55874
- section: "tools",
55875
- fields: ["description", "commands"]
55876
- },
55877
- workflow: {
55878
- section: "workflow",
55879
- fields: ["description", "trigger", "entry_conditions"]
55880
- },
55881
- guardrails: {
55882
- section: "guardrails",
55883
- fields: ["rationale", "tags"]
55884
- }
55885
- };
55886
- function hasNonEmpty(obj, field) {
55887
- const val = obj[field];
55888
- if (val === void 0 || val === null) return false;
55889
- if (typeof val === "string") return val.length > 0;
55890
- if (Array.isArray(val)) return val.length > 0;
55891
- return true;
55892
- }
55893
- function schemaCompleteness(dsl) {
55894
- let totalSlots = 0;
55895
- let filledSlots = 0;
55896
- const lowSections = [];
55897
- for (const [sectionKey, meta] of Object.entries(OPTIONAL_ENTITY_FIELDS)) {
55898
- const entities = dsl[meta.section];
55899
- if (!entities) continue;
55900
- let sectionTotal = 0;
55901
- let sectionFilled = 0;
55902
- for (const entity of Object.values(entities)) {
55903
- for (const field of meta.fields) {
55904
- sectionTotal++;
55905
- totalSlots++;
55906
- if (hasNonEmpty(entity, field)) {
55907
- sectionFilled++;
55908
- filledSlots++;
55909
- }
55910
- }
55911
- }
55912
- if (sectionTotal > 0 && pct(sectionFilled, sectionTotal) < 50) {
55913
- lowSections.push(sectionKey);
55914
- }
55915
- }
55916
- return {
55917
- id: "schema-completeness",
55918
- label: "Schema completeness",
55919
- score: filledSlots,
55920
- total: totalSlots,
55921
- percent: pct(filledSlots, totalSlots),
55922
- weight: 1,
55923
- recommendations: lowSections.length > 0 ? [`Low optional field coverage in: ${lowSections.join(", ")}`] : []
55924
- };
55925
- }
55926
- function crossReferenceBidirectionality(dsl) {
55927
- let totalChecks = 0;
55928
- let passedChecks = 0;
55929
- const issues = [];
55930
- for (const [agentId, agent] of Object.entries(dsl.agents)) {
55931
- for (const toolId of agent.can_execute_tools) {
55932
- totalChecks++;
55933
- const tool = dsl.tools[toolId];
55934
- if (tool && tool.invokable_by.includes(agentId)) {
55935
- passedChecks++;
55936
- } else {
55937
- issues.push(`agent ${agentId} \u2192 tool ${toolId}`);
55938
- }
55939
- }
55940
- for (const artId of agent.can_write_artifacts) {
55941
- totalChecks++;
55942
- const art = dsl.artifacts[artId];
55943
- if (art && (art.producers.includes(agentId) || art.editors.includes(agentId))) {
55944
- passedChecks++;
55945
- } else {
55946
- issues.push(`agent ${agentId} \u2192 artifact ${artId} (write)`);
55947
- }
55948
- }
55949
- for (const artId of agent.can_read_artifacts) {
55950
- totalChecks++;
55951
- const art = dsl.artifacts[artId];
55952
- if (art && (art.consumers.includes(agentId) || art.producers.includes(agentId) || art.editors.includes(agentId))) {
55953
- passedChecks++;
55954
- } else {
55955
- issues.push(`agent ${agentId} \u2192 artifact ${artId} (read)`);
55956
- }
55957
- }
55958
- }
55959
- for (const [toolId, tool] of Object.entries(dsl.tools)) {
55960
- for (const agentId of tool.invokable_by) {
55961
- totalChecks++;
55962
- const agent = dsl.agents[agentId];
55963
- if (agent && agent.can_execute_tools.includes(toolId)) {
55964
- passedChecks++;
55965
- } else {
55966
- issues.push(`tool ${toolId} \u2192 agent ${agentId}`);
55967
- }
55968
- }
55969
- }
55970
- return {
55971
- id: "cross-reference-bidirectionality",
55972
- label: "Cross-reference bidirectionality",
55973
- score: passedChecks,
55974
- total: totalChecks,
55975
- percent: pct(passedChecks, totalChecks),
55976
- weight: 2,
55977
- recommendations: issues.length > 0 ? [`${issues.length} unreciprocated cross-references: ${issues.slice(0, 5).join(", ")}${issues.length > 5 ? `, ... (${issues.length - 5} more)` : ""}`] : []
55978
- };
55979
- }
55980
- function entityGuardrailCoverage(dsl) {
55981
- const entitySections = [
55982
- { name: "agents", entities: dsl.agents },
55983
- { name: "tasks", entities: dsl.tasks },
55984
- { name: "tools", entities: dsl.tools },
55985
- { name: "artifacts", entities: dsl.artifacts }
55986
- ];
55987
- const scopeBindings = {
55988
- agents: /* @__PURE__ */ new Set(),
55989
- tasks: /* @__PURE__ */ new Set(),
55990
- tools: /* @__PURE__ */ new Set(),
55991
- artifacts: /* @__PURE__ */ new Set()
55992
- };
55993
- for (const guardrail of Object.values(dsl.guardrails)) {
55994
- for (const key of Object.keys(scopeBindings)) {
55995
- const ids = guardrail.scope[key];
55996
- if (ids) {
55997
- for (const id of ids) scopeBindings[key].add(id);
55998
- }
55999
- }
56000
- }
56001
- let total = 0;
56002
- let covered = 0;
56003
- const missing = [];
56004
- for (const { name, entities } of entitySections) {
56005
- for (const [entityId, entity] of Object.entries(entities)) {
56006
- total++;
56007
- const hasEntitySide = (entity.guardrails ?? []).length > 0;
56008
- const hasScopeSide = scopeBindings[name].has(entityId);
56009
- if (hasEntitySide || hasScopeSide) {
56010
- covered++;
56011
- } else {
56012
- missing.push(`${name}.${entityId}`);
56013
- }
56014
- }
56015
- }
56016
- return {
56017
- id: "entity-guardrail-coverage",
56018
- label: "Entity guardrail coverage",
56019
- score: covered,
56020
- total,
56021
- percent: pct(covered, total),
56022
- weight: 1,
56023
- recommendations: missing.length > 0 ? [`${missing.length} entities without guardrails: ${missing.slice(0, 5).join(", ")}${missing.length > 5 ? `, ... (${missing.length - 5} more)` : ""}`] : []
56024
- };
56025
- }
56026
- function guardrailScopeResolution(dsl) {
56027
- let totalRefs = 0;
56028
- let resolvedRefs = 0;
56029
- const unresolved = [];
56030
- const sectionMap = {
56031
- agents: dsl.agents,
56032
- tasks: dsl.tasks,
56033
- tools: dsl.tools,
56034
- artifacts: dsl.artifacts,
56035
- workflows: dsl.workflow
56036
- };
56037
- for (const [guardrailId, guardrail] of Object.entries(dsl.guardrails)) {
56038
- const scope = guardrail.scope;
56039
- for (const [scopeKey, entityIds] of Object.entries(scope)) {
56040
- if (!Array.isArray(entityIds)) continue;
56041
- const section = sectionMap[scopeKey];
56042
- if (!section) continue;
56043
- for (const entityId of entityIds) {
56044
- totalRefs++;
56045
- if (section[entityId]) {
56046
- resolvedRefs++;
56047
- } else {
56048
- unresolved.push(`${guardrailId}.scope.${scopeKey}: ${entityId}`);
56049
- }
56050
- }
56051
- }
56052
- }
56053
- return {
56054
- id: "guardrail-scope-resolution",
56055
- label: "Guardrail scope resolution",
56056
- score: resolvedRefs,
56057
- total: totalRefs,
56058
- percent: pct(resolvedRefs, totalRefs),
56059
- weight: 2,
56060
- recommendations: unresolved.length > 0 ? [`${unresolved.length} unresolved scope refs: ${unresolved.join(", ")}`] : []
56061
- };
56062
- }
56063
- function score(dsl) {
56064
- const dimensions = [
56065
- artifactValidationCoverage(dsl),
56066
- taskValidationCoverage(dsl),
56067
- guardrailPolicyCoverage(dsl),
56068
- workflowValidationIntegration(dsl),
56069
- schemaCompleteness(dsl),
56070
- crossReferenceBidirectionality(dsl),
56071
- guardrailScopeResolution(dsl),
56072
- entityGuardrailCoverage(dsl)
56073
- ];
56074
- const totalWeight = dimensions.reduce((s2, d2) => s2 + d2.weight, 0);
56075
- const weightedSum = dimensions.reduce(
56076
- (s2, d2) => s2 + d2.percent * d2.weight,
56077
- 0
56078
- );
56079
- const overall = totalWeight === 0 ? 100 : Math.round(weightedSum / totalWeight);
56080
- return { overall, dimensions };
56081
- }
56082
-
56083
- // src/cli/commands/score.ts
56084
- var DIR_DEFAULT4 = "agent-contracts.yaml";
56085
- function formatText(result) {
56086
- const lines = [];
56087
- lines.push(`DSL Completeness Score: ${result.overall}/100`);
56088
- lines.push("");
56089
- for (const d2 of result.dimensions) {
56090
- const detail = d2.total > 0 ? ` (${d2.score}/${d2.total} ${d2.id.split("-")[0]})` : "";
56091
- lines.push(
56092
- ` ${d2.label.padEnd(40)} ${String(d2.percent).padStart(3)}%${detail}`
56093
- );
56094
- }
56095
- const allRecs = result.dimensions.flatMap((d2) => d2.recommendations);
56096
- if (allRecs.length > 0) {
56097
- lines.push("");
56098
- lines.push("Recommendations:");
56099
- for (const rec of allRecs) {
56100
- lines.push(` - ${rec}`);
55715
+ for (const spec of Object.values(ti.accepts.workflows)) {
55716
+ handoffKeys.add(spec.input_handoff);
55717
+ handoffKeys.add(spec.output_handoff);
56101
55718
  }
56102
55719
  }
56103
- return lines.join("\n");
56104
- }
56105
- var scoreCommand = new Command7("score").description("Calculate DSL completeness score").argument("[dir]", "Path to agent-contracts.yaml", DIR_DEFAULT4).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json)", "text").option("--threshold <number>", "Minimum score (exit 1 if below)", void 0).action(
56106
- async (dir, opts) => {
56107
- try {
56108
- const config = await loadConfig(opts.config);
56109
- if (config !== null && isMultiTeamConfig(config)) {
56110
- const teamEntries = getTeamEntries(config, opts.team);
56111
- let thresholdNum;
56112
- if (opts.threshold !== void 0) {
56113
- thresholdNum = parseInt(opts.threshold, 10);
56114
- if (isNaN(thresholdNum)) {
56115
- process.stderr.write(
56116
- `Error: --threshold must be a number, got "${opts.threshold}"
56117
- `
56118
- );
56119
- process.exit(1);
56120
- }
56121
- }
56122
- let hasErrors = false;
56123
- for (const [teamId, teamConfig] of teamEntries) {
56124
- process.stdout.write(`
56125
- --- Team: ${teamId} ---
56126
- `);
56127
- const resolved2 = await resolve4(teamConfig.dsl);
56128
- const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
56129
- const schemaResult2 = validateSchema(data2);
56130
- if (!schemaResult2.success) {
56131
- const issues = schemaResult2.diagnostics.map((d2) => ` ${d2.path}: ${d2.message}`).join("\n");
56132
- process.stderr.write(`Schema validation failed:
56133
- ${issues}
56134
- `);
56135
- hasErrors = true;
56136
- continue;
56137
- }
56138
- const result2 = score(schemaResult2.data);
56139
- if (opts.format === "json") {
56140
- process.stdout.write(JSON.stringify(result2, null, 2) + "\n");
56141
- } else {
56142
- process.stdout.write(formatText(result2) + "\n");
56143
- }
56144
- if (thresholdNum !== void 0 && result2.overall < thresholdNum) {
56145
- process.stderr.write(
56146
- `Score ${result2.overall} is below threshold ${thresholdNum}
56147
- `
56148
- );
56149
- hasErrors = true;
56150
- }
56151
- }
56152
- if (hasErrors) process.exit(1);
56153
- return;
56154
- }
56155
- const dslPath = resolveDslPath(dir, DIR_DEFAULT4, config);
56156
- const resolved = await resolve4(dslPath);
56157
- const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
56158
- const schemaResult = validateSchema(data);
56159
- if (!schemaResult.success) {
56160
- const issues = schemaResult.diagnostics.map((d2) => ` ${d2.path}: ${d2.message}`).join("\n");
56161
- process.stderr.write(`Schema validation failed:
56162
- ${issues}
56163
- `);
56164
- process.exit(1);
56165
- }
56166
- const result = score(schemaResult.data);
56167
- if (opts.format === "json") {
56168
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
56169
- } else {
56170
- process.stdout.write(formatText(result) + "\n");
55720
+ const handoff_types = {};
55721
+ for (const k2 of [...handoffKeys].sort()) {
55722
+ const ht = dsl.handoff_types[k2];
55723
+ if (ht) {
55724
+ const entry = {
55725
+ version: ht.version,
55726
+ schema: ht.schema
55727
+ };
55728
+ if (ht.description !== void 0) {
55729
+ entry.description = ht.description;
56171
55730
  }
56172
- if (opts.threshold !== void 0) {
56173
- const threshold = parseInt(opts.threshold, 10);
56174
- if (isNaN(threshold)) {
56175
- process.stderr.write(
56176
- `Error: --threshold must be a number, got "${opts.threshold}"
56177
- `
56178
- );
56179
- process.exit(1);
56180
- }
56181
- if (result.overall < threshold) {
56182
- process.stderr.write(
56183
- `Score ${result.overall} is below threshold ${threshold}
56184
- `
56185
- );
56186
- process.exit(1);
55731
+ handoff_types[k2] = entry;
55732
+ }
55733
+ }
55734
+ if (Object.keys(handoff_types).length > 0) {
55735
+ doc.handoff_types = handoff_types;
55736
+ }
55737
+ const artifactsOut = {};
55738
+ if (ti.exposes?.artifacts) {
55739
+ for (const key of [...ti.exposes.artifacts].sort()) {
55740
+ const art = dsl.artifacts[key];
55741
+ if (art) {
55742
+ const entry = {
55743
+ type: art.type,
55744
+ states: art.states
55745
+ };
55746
+ if (art.description !== void 0) {
55747
+ entry.description = art.description;
56187
55748
  }
55749
+ artifactsOut[key] = entry;
56188
55750
  }
56189
- } catch (err) {
56190
- const msg = err instanceof Error ? err.message : String(err);
56191
- process.stderr.write(`Error: ${msg}
56192
- `);
56193
- process.exit(1);
56194
55751
  }
56195
55752
  }
56196
- );
56197
-
56198
- // src/cli/commands/audit.ts
56199
- import { writeFileSync as writeFileSync2 } from "fs";
56200
- import { Command as Command8 } from "commander";
55753
+ if (Object.keys(artifactsOut).length > 0) {
55754
+ doc.exposes = { artifacts: artifactsOut };
55755
+ }
55756
+ if (ti.constraints !== void 0 && ti.constraints.length > 0) {
55757
+ doc.constraints = ti.constraints;
55758
+ }
55759
+ return doc;
55760
+ }
55761
+ function generateInterface(options) {
55762
+ if (!options.dsl.team_interface) {
55763
+ throw new Error("DSL has no team_interface section");
55764
+ }
55765
+ const doc = buildInterfaceDocument(options.dsl, (/* @__PURE__ */ new Date()).toISOString());
55766
+ const content = options.format === "json" ? `${JSON.stringify(doc, null, 2)}
55767
+ ` : `${stringify(doc, { sortMapEntries: true })}
55768
+ `;
55769
+ const outputPath = options.output ?? "team-interface.yaml";
55770
+ return { outputPath, content };
55771
+ }
56201
55772
 
56202
55773
  // src/auditor/context-builder.ts
56203
55774
  import { readFile as readFile6 } from "fs/promises";
@@ -56952,11 +56523,579 @@ function computeExitCode(results, failOn) {
56952
56523
  return 0;
56953
56524
  }
56954
56525
 
56955
- // src/cli/commands/audit.ts
56526
+ // src/cli/format.ts
56527
+ function formatDiagnostics(diagnostics, options) {
56528
+ if (options.quiet && diagnostics.length === 0) return "";
56529
+ if (options.format === "json") {
56530
+ return JSON.stringify(diagnostics, null, 2);
56531
+ }
56532
+ return diagnostics.map((d2) => {
56533
+ const severity = d2.severity ?? d2.code ?? "error";
56534
+ const rule = d2.ruleId ?? d2.code ?? "";
56535
+ return `${d2.path}: ${severity} [${rule}] ${d2.message}`;
56536
+ }).join("\n");
56537
+ }
56538
+
56539
+ // src/cli/multi-team.ts
56540
+ function isMultiTeamConfig(config) {
56541
+ return config.teams !== void 0 && Object.keys(config.teams).length > 0;
56542
+ }
56543
+ function getTeamEntries(config, teamFilter) {
56544
+ if (!config.teams) return [];
56545
+ const entries = Object.entries(config.teams);
56546
+ if (teamFilter) {
56547
+ const found = entries.filter(([k2]) => k2 === teamFilter);
56548
+ if (found.length === 0) {
56549
+ throw new Error(
56550
+ `Team "${teamFilter}" not found. Available teams: ${entries.map(([k2]) => k2).join(", ")}`
56551
+ );
56552
+ }
56553
+ return found;
56554
+ }
56555
+ return entries;
56556
+ }
56557
+
56558
+ // src/cli/commands/generate-interface.ts
56559
+ import { writeFileSync } from "fs";
56560
+ import { resolve as resolve7 } from "path";
56561
+ function runGenerateInterfaceCli(opts) {
56562
+ if (!opts.dsl.team_interface) {
56563
+ process.stderr.write("Error: DSL has no team_interface section.\n");
56564
+ process.exit(1);
56565
+ }
56566
+ const outputPath = resolve7(process.cwd(), opts.output ?? "team-interface.yaml");
56567
+ const result = generateInterface({
56568
+ dsl: opts.dsl,
56569
+ output: outputPath,
56570
+ dryRun: opts.dryRun,
56571
+ format: opts.format
56572
+ });
56573
+ if (opts.dryRun) {
56574
+ process.stdout.write(result.content);
56575
+ return;
56576
+ }
56577
+ writeFileSync(result.outputPath, result.content, "utf8");
56578
+ if (!opts.quiet) {
56579
+ process.stdout.write(`Wrote ${result.outputPath}
56580
+ `);
56581
+ }
56582
+ }
56583
+
56584
+ // src/cli/handlers.ts
56585
+ var DIR_DEFAULT = "agent-contracts.yaml";
56586
+ var handleResolve = async (dir, opts) => {
56587
+ try {
56588
+ const config = await loadConfig(opts.config);
56589
+ if (config !== null && isMultiTeamConfig(config)) {
56590
+ const teamEntries = getTeamEntries(config, opts.team);
56591
+ if (opts.format === "json") {
56592
+ const out = {};
56593
+ for (const [teamId, teamConfig] of teamEntries) {
56594
+ const result2 = await resolve4(teamConfig.dsl);
56595
+ let data2 = teamConfig.vars ? substituteVars(result2.data, teamConfig.vars) : result2.data;
56596
+ if (opts.expandDefaults) data2 = expandDefaults(data2);
56597
+ out[teamId] = data2;
56598
+ }
56599
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
56600
+ } else {
56601
+ for (const [teamId, teamConfig] of teamEntries) {
56602
+ process.stdout.write(`
56603
+ --- Team: ${teamId} ---
56604
+ `);
56605
+ const result2 = await resolve4(teamConfig.dsl);
56606
+ let data2 = teamConfig.vars ? substituteVars(result2.data, teamConfig.vars) : result2.data;
56607
+ if (opts.expandDefaults) data2 = expandDefaults(data2);
56608
+ process.stdout.write(stringify3(data2));
56609
+ }
56610
+ }
56611
+ return;
56612
+ }
56613
+ const dslPath = resolveDslPath(dir ?? DIR_DEFAULT, DIR_DEFAULT, config);
56614
+ const result = await resolve4(dslPath);
56615
+ let data = config?.vars ? substituteVars(result.data, config.vars) : result.data;
56616
+ if (opts.expandDefaults) data = expandDefaults(data);
56617
+ if (opts.format === "json") {
56618
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
56619
+ } else {
56620
+ process.stdout.write(stringify3(data));
56621
+ }
56622
+ } catch (err) {
56623
+ const msg = err instanceof Error ? err.message : String(err);
56624
+ process.stderr.write(`Error: ${msg}
56625
+ `);
56626
+ process.exit(1);
56627
+ }
56628
+ };
56629
+ var handleValidate = async (dir, opts) => {
56630
+ try {
56631
+ const config = await loadConfig(opts.config);
56632
+ if (config !== null && isMultiTeamConfig(config)) {
56633
+ const teamEntries = getTeamEntries(config, opts.team);
56634
+ let hasErrors = false;
56635
+ let allTeamsFullyClean = true;
56636
+ for (const [teamId, teamConfig] of teamEntries) {
56637
+ if (!opts.quiet) process.stdout.write(`
56638
+ --- Team: ${teamId} ---
56639
+ `);
56640
+ const resolved2 = await resolve4(teamConfig.dsl);
56641
+ const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
56642
+ const schemaResult2 = validateSchema(data2);
56643
+ const schemaWarnings2 = schemaResult2.diagnostics.filter(
56644
+ (d2) => d2.severity === "warning"
56645
+ );
56646
+ if (!schemaResult2.success) {
56647
+ const output = formatDiagnostics(schemaResult2.diagnostics, {
56648
+ format: opts.format ?? "text",
56649
+ quiet: !!opts.quiet
56650
+ });
56651
+ if (output) process.stderr.write(output + "\n");
56652
+ hasErrors = true;
56653
+ allTeamsFullyClean = false;
56654
+ continue;
56655
+ }
56656
+ const refDiags2 = checkReferences(schemaResult2.data);
56657
+ const handoffDiags2 = validateHandoffSchemas(schemaResult2.data);
56658
+ const allDiags2 = [...refDiags2, ...handoffDiags2, ...schemaWarnings2];
56659
+ if (allDiags2.length > 0) {
56660
+ allTeamsFullyClean = false;
56661
+ const output = formatDiagnostics(allDiags2, {
56662
+ format: opts.format ?? "text",
56663
+ quiet: !!opts.quiet
56664
+ });
56665
+ if (output) process.stderr.write(output + "\n");
56666
+ const hasWarnings2 = allDiags2.some(
56667
+ (d2) => "severity" in d2 && d2.severity === "warning"
56668
+ );
56669
+ if (refDiags2.length > 0 || handoffDiags2.length > 0 || opts.strict && hasWarnings2) {
56670
+ hasErrors = true;
56671
+ }
56672
+ }
56673
+ }
56674
+ if (hasErrors) process.exit(1);
56675
+ if (!opts.quiet && allTeamsFullyClean) process.stdout.write("Validation passed.\n");
56676
+ return;
56677
+ }
56678
+ const dslPath = resolveDslPath(dir ?? DIR_DEFAULT, DIR_DEFAULT, config);
56679
+ const resolved = await resolve4(dslPath);
56680
+ const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
56681
+ const schemaResult = validateSchema(data);
56682
+ const schemaWarnings = schemaResult.diagnostics.filter(
56683
+ (d2) => d2.severity === "warning"
56684
+ );
56685
+ if (!schemaResult.success) {
56686
+ const output = formatDiagnostics(schemaResult.diagnostics, {
56687
+ format: opts.format ?? "text",
56688
+ quiet: !!opts.quiet
56689
+ });
56690
+ if (output) process.stderr.write(output + "\n");
56691
+ process.exit(1);
56692
+ }
56693
+ const refDiags = checkReferences(schemaResult.data);
56694
+ const handoffDiags = validateHandoffSchemas(schemaResult.data);
56695
+ const allDiags = [...refDiags, ...handoffDiags, ...schemaWarnings];
56696
+ const hasWarnings = allDiags.some(
56697
+ (d2) => "severity" in d2 && d2.severity === "warning"
56698
+ );
56699
+ if (allDiags.length > 0) {
56700
+ const output = formatDiagnostics(allDiags, {
56701
+ format: opts.format ?? "text",
56702
+ quiet: !!opts.quiet
56703
+ });
56704
+ if (output) process.stderr.write(output + "\n");
56705
+ if (refDiags.length > 0 || handoffDiags.length > 0 || opts.strict && hasWarnings) {
56706
+ process.exit(1);
56707
+ }
56708
+ }
56709
+ if (!opts.quiet && allDiags.length === 0) process.stdout.write("Validation passed.\n");
56710
+ } catch (err) {
56711
+ const msg = err instanceof Error ? err.message : String(err);
56712
+ process.stderr.write(`Error: ${msg}
56713
+ `);
56714
+ process.exit(1);
56715
+ }
56716
+ };
56717
+ var handleLint = async (dir, opts) => {
56718
+ try {
56719
+ const config = await loadConfig(opts.config);
56720
+ if (config !== null && isMultiTeamConfig(config)) {
56721
+ const teamEntries = getTeamEntries(config, opts.team);
56722
+ let hasErrors = false;
56723
+ let allClean = true;
56724
+ for (const [teamId, teamConfig] of teamEntries) {
56725
+ if (!opts.quiet) process.stdout.write(`
56726
+ --- Team: ${teamId} ---
56727
+ `);
56728
+ const resolved2 = await resolve4(teamConfig.dsl);
56729
+ const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
56730
+ const schemaResult2 = validateSchema(data2);
56731
+ const schemaWarnings2 = schemaResult2.diagnostics.filter(
56732
+ (d2) => d2.severity === "warning"
56733
+ );
56734
+ if (!schemaResult2.success) {
56735
+ const output = formatDiagnostics(schemaResult2.diagnostics, {
56736
+ format: opts.format ?? "text",
56737
+ quiet: !!opts.quiet
56738
+ });
56739
+ if (output) process.stderr.write(output + "\n");
56740
+ hasErrors = true;
56741
+ allClean = false;
56742
+ continue;
56743
+ }
56744
+ const tsDiagnostics2 = lint(schemaResult2.data);
56745
+ const spectralDiagnostics2 = await spectralLint(
56746
+ schemaResult2.data
56747
+ );
56748
+ const diagnostics2 = [...tsDiagnostics2, ...spectralDiagnostics2, ...schemaWarnings2];
56749
+ if (diagnostics2.length > 0) {
56750
+ allClean = false;
56751
+ const output = formatDiagnostics(diagnostics2, {
56752
+ format: opts.format ?? "text",
56753
+ quiet: !!opts.quiet
56754
+ });
56755
+ if (output) process.stderr.write(output + "\n");
56756
+ if (diagnostics2.some((d2) => d2.severity === "error")) hasErrors = true;
56757
+ if (opts.strict && diagnostics2.some((d2) => d2.severity === "warning")) hasErrors = true;
56758
+ }
56759
+ }
56760
+ if (hasErrors) process.exit(1);
56761
+ if (!opts.quiet && allClean) process.stdout.write("Lint passed.\n");
56762
+ return;
56763
+ }
56764
+ const dslPath = resolveDslPath(dir ?? DIR_DEFAULT, DIR_DEFAULT, config);
56765
+ const resolved = await resolve4(dslPath);
56766
+ const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
56767
+ const schemaResult = validateSchema(data);
56768
+ const schemaWarnings = schemaResult.diagnostics.filter(
56769
+ (d2) => d2.severity === "warning"
56770
+ );
56771
+ if (!schemaResult.success) {
56772
+ const output = formatDiagnostics(schemaResult.diagnostics, {
56773
+ format: opts.format ?? "text",
56774
+ quiet: !!opts.quiet
56775
+ });
56776
+ if (output) process.stderr.write(output + "\n");
56777
+ process.exit(1);
56778
+ }
56779
+ const tsDiagnostics = lint(schemaResult.data);
56780
+ const spectralDiagnostics = await spectralLint(
56781
+ schemaResult.data
56782
+ );
56783
+ const diagnostics = [...tsDiagnostics, ...spectralDiagnostics, ...schemaWarnings];
56784
+ if (diagnostics.length > 0) {
56785
+ const output = formatDiagnostics(diagnostics, {
56786
+ format: opts.format ?? "text",
56787
+ quiet: !!opts.quiet
56788
+ });
56789
+ if (output) process.stderr.write(output + "\n");
56790
+ if (diagnostics.some((d2) => d2.severity === "error")) process.exit(1);
56791
+ if (opts.strict && diagnostics.some((d2) => d2.severity === "warning")) process.exit(1);
56792
+ }
56793
+ if (!opts.quiet && diagnostics.length === 0) process.stdout.write("Lint passed.\n");
56794
+ } catch (err) {
56795
+ const msg = err instanceof Error ? err.message : String(err);
56796
+ process.stderr.write(`Error: ${msg}
56797
+ `);
56798
+ process.exit(1);
56799
+ }
56800
+ };
56801
+ var handleRender = async (opts) => {
56802
+ process.stderr.write(
56803
+ "Warning: 'render' is deprecated. Use 'agent-contracts generate templates' instead.\n"
56804
+ );
56805
+ await handleGenerate("templates", {
56806
+ config: opts.config,
56807
+ team: opts.team,
56808
+ check: opts.check,
56809
+ format: "yaml",
56810
+ dryRun: false,
56811
+ quiet: opts.quiet
56812
+ }, {});
56813
+ };
56814
+ var handleCheck = async (opts) => {
56815
+ let hasErrors = false;
56816
+ try {
56817
+ const config = await loadConfig(opts.config);
56818
+ if (!config) {
56819
+ process.stderr.write(
56820
+ "Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
56821
+ );
56822
+ process.exit(1);
56823
+ }
56824
+ if (isMultiTeamConfig(config)) {
56825
+ const teamEntries = getTeamEntries(config, opts.team);
56826
+ for (const [teamId, teamConfig] of teamEntries) {
56827
+ if (!opts.quiet) process.stderr.write(`
56828
+ --- Team: ${teamId} ---
56829
+ `);
56830
+ const resolved2 = await resolve4(teamConfig.dsl);
56831
+ const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
56832
+ const schemaResult2 = validateSchema(data2);
56833
+ const schemaWarnings2 = schemaResult2.diagnostics.filter((d2) => d2.severity === "warning");
56834
+ if (!schemaResult2.success) {
56835
+ const output = formatDiagnostics(schemaResult2.diagnostics, {
56836
+ format: opts.format ?? "text",
56837
+ quiet: !!opts.quiet
56838
+ });
56839
+ if (output) process.stderr.write(output + "\n");
56840
+ hasErrors = true;
56841
+ continue;
56842
+ }
56843
+ const refDiags2 = checkReferences(schemaResult2.data);
56844
+ const handoffDiags2 = validateHandoffSchemas(schemaResult2.data);
56845
+ const allRefDiags2 = [...refDiags2, ...handoffDiags2, ...schemaWarnings2];
56846
+ if (allRefDiags2.length > 0) {
56847
+ const output = formatDiagnostics(allRefDiags2, {
56848
+ format: opts.format ?? "text",
56849
+ quiet: !!opts.quiet
56850
+ });
56851
+ if (output) process.stderr.write(output + "\n");
56852
+ hasErrors = true;
56853
+ }
56854
+ const tsLintDiags2 = lint(schemaResult2.data);
56855
+ const spectralDiags2 = await spectralLint(
56856
+ schemaResult2.data
56857
+ );
56858
+ const lintDiags2 = [...tsLintDiags2, ...spectralDiags2];
56859
+ if (lintDiags2.length > 0) {
56860
+ const output = formatDiagnostics(lintDiags2, {
56861
+ format: opts.format ?? "text",
56862
+ quiet: !!opts.quiet
56863
+ });
56864
+ if (output) process.stderr.write(output + "\n");
56865
+ if (lintDiags2.some((d2) => d2.severity === "error")) hasErrors = true;
56866
+ if (opts.strict && lintDiags2.some((d2) => d2.severity === "warning")) hasErrors = true;
56867
+ }
56868
+ let renderOptions2;
56869
+ if (teamConfig.bindings.length > 0) {
56870
+ const loadedBindings = await loadBindings(teamConfig.bindings);
56871
+ renderOptions2 = { loadedBindings, activeGuardrailPolicy: teamConfig.activeGuardrailPolicy };
56872
+ }
56873
+ const drift2 = await checkDriftFromConfig(schemaResult2.data, config.renders, renderOptions2);
56874
+ if (drift2.hasDrift) {
56875
+ process.stderr.write(`Drift detected for team ${teamId} in:
56876
+ `);
56877
+ for (const f2 of drift2.diffs) process.stderr.write(` ${f2}
56878
+ `);
56879
+ hasErrors = true;
56880
+ }
56881
+ }
56882
+ if (!hasErrors) {
56883
+ for (const [teamId, teamConfig] of teamEntries) {
56884
+ const resolved2 = await resolve4(teamConfig.dsl);
56885
+ const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
56886
+ const schemaResult2 = validateSchema(data2);
56887
+ if (!schemaResult2.success || !schemaResult2.data) continue;
56888
+ const dsl = schemaResult2.data;
56889
+ const imports = dsl.imports;
56890
+ if (!imports) continue;
56891
+ for (const [importName, importDef] of Object.entries(imports)) {
56892
+ const interfacePathRel = importDef?.interface;
56893
+ if (typeof interfacePathRel !== "string") continue;
56894
+ const interfacePath = pathResolve(dirname7(teamConfig.dsl), interfacePathRel);
56895
+ try {
56896
+ await access2(interfacePath);
56897
+ } catch {
56898
+ process.stderr.write(
56899
+ `Cross-team error: Team "${teamId}" imports "${importName}" but interface file not found: ${interfacePath}
56900
+ `
56901
+ );
56902
+ hasErrors = true;
56903
+ }
56904
+ }
56905
+ }
56906
+ }
56907
+ if (hasErrors) process.exit(1);
56908
+ if (!opts.quiet) process.stdout.write("All checks passed.\n");
56909
+ return;
56910
+ }
56911
+ const resolved = await resolve4(config.dsl);
56912
+ const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
56913
+ const schemaResult = validateSchema(data);
56914
+ const schemaWarnings = schemaResult.diagnostics.filter((d2) => d2.severity === "warning");
56915
+ if (!schemaResult.success) {
56916
+ const output = formatDiagnostics(schemaResult.diagnostics, {
56917
+ format: opts.format ?? "text",
56918
+ quiet: !!opts.quiet
56919
+ });
56920
+ if (output) process.stderr.write(output + "\n");
56921
+ process.exit(1);
56922
+ }
56923
+ const refDiags = checkReferences(schemaResult.data);
56924
+ const handoffDiags = validateHandoffSchemas(schemaResult.data);
56925
+ const allRefDiags = [...refDiags, ...handoffDiags, ...schemaWarnings];
56926
+ if (allRefDiags.length > 0) {
56927
+ const output = formatDiagnostics(allRefDiags, {
56928
+ format: opts.format ?? "text",
56929
+ quiet: !!opts.quiet
56930
+ });
56931
+ if (output) process.stderr.write(output + "\n");
56932
+ hasErrors = true;
56933
+ }
56934
+ const tsLintDiags = lint(schemaResult.data);
56935
+ const spectralDiags = await spectralLint(
56936
+ schemaResult.data
56937
+ );
56938
+ const lintDiags = [...tsLintDiags, ...spectralDiags];
56939
+ if (lintDiags.length > 0) {
56940
+ const output = formatDiagnostics(lintDiags, {
56941
+ format: opts.format ?? "text",
56942
+ quiet: !!opts.quiet
56943
+ });
56944
+ if (output) process.stderr.write(output + "\n");
56945
+ if (lintDiags.some((d2) => d2.severity === "error")) hasErrors = true;
56946
+ if (opts.strict && lintDiags.some((d2) => d2.severity === "warning")) hasErrors = true;
56947
+ }
56948
+ let renderOptions;
56949
+ if (config.bindings.length > 0) {
56950
+ const loadedBindings = await loadBindings(config.bindings);
56951
+ renderOptions = { loadedBindings, activeGuardrailPolicy: config.activeGuardrailPolicy };
56952
+ }
56953
+ const drift = await checkDriftFromConfig(schemaResult.data, config.renders, renderOptions);
56954
+ if (drift.hasDrift) {
56955
+ process.stderr.write("Drift detected in:\n");
56956
+ for (const f2 of drift.diffs) process.stderr.write(` ${f2}
56957
+ `);
56958
+ hasErrors = true;
56959
+ }
56960
+ if (schemaResult.data.team_interface) {
56961
+ const interfacePath = join3(config.configDir, "team-interface.yaml");
56962
+ if (existsSync(interfacePath)) {
56963
+ const result = generateInterface({ dsl: schemaResult.data, dryRun: true, format: "yaml" });
56964
+ const existing = readFileSync(interfacePath, "utf8");
56965
+ const normalize = (raw) => {
56966
+ try {
56967
+ const parsed = parseYaml4(raw);
56968
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
56969
+ const { generated_at: _t, ...rest } = parsed;
56970
+ return `${stringify3(rest, { sortMapEntries: true })}
56971
+ `;
56972
+ }
56973
+ } catch {
56974
+ }
56975
+ return raw.trim();
56976
+ };
56977
+ if (normalize(existing) !== normalize(result.content)) {
56978
+ process.stderr.write("Drift detected in team-interface.yaml\n");
56979
+ hasErrors = true;
56980
+ }
56981
+ }
56982
+ }
56983
+ if (hasErrors) process.exit(1);
56984
+ if (!opts.quiet) process.stdout.write("All checks passed.\n");
56985
+ } catch (err) {
56986
+ if (err instanceof ConfigLoadError) {
56987
+ process.stderr.write(`Config error: ${err.message}
56988
+ `);
56989
+ process.exit(1);
56990
+ }
56991
+ const msg = err instanceof Error ? err.message : String(err);
56992
+ process.stderr.write(`Error: ${msg}
56993
+ `);
56994
+ process.exit(1);
56995
+ }
56996
+ };
56997
+ function formatScoreText(result) {
56998
+ const lines = [];
56999
+ lines.push(`DSL Completeness Score: ${result.overall}/100`);
57000
+ lines.push("");
57001
+ for (const d2 of result.dimensions) {
57002
+ const detail = d2.total > 0 ? ` (${d2.score}/${d2.total} ${d2.id.split("-")[0]})` : "";
57003
+ lines.push(` ${d2.label.padEnd(40)} ${String(d2.percent).padStart(3)}%${detail}`);
57004
+ }
57005
+ const allRecs = result.dimensions.flatMap((d2) => d2.recommendations);
57006
+ if (allRecs.length > 0) {
57007
+ lines.push("");
57008
+ lines.push("Recommendations:");
57009
+ for (const rec of allRecs) lines.push(` - ${rec}`);
57010
+ }
57011
+ return lines.join("\n");
57012
+ }
57013
+ var handleScore = async (dir, opts) => {
57014
+ try {
57015
+ const config = await loadConfig(opts.config);
57016
+ if (config !== null && isMultiTeamConfig(config)) {
57017
+ const teamEntries = getTeamEntries(config, opts.team);
57018
+ let thresholdNum;
57019
+ if (opts.threshold !== void 0) {
57020
+ thresholdNum = parseInt(String(opts.threshold), 10);
57021
+ if (isNaN(thresholdNum)) {
57022
+ process.stderr.write(`Error: --threshold must be a number, got "${opts.threshold}"
57023
+ `);
57024
+ process.exit(1);
57025
+ }
57026
+ }
57027
+ let hasErrors = false;
57028
+ for (const [teamId, teamConfig] of teamEntries) {
57029
+ process.stdout.write(`
57030
+ --- Team: ${teamId} ---
57031
+ `);
57032
+ const resolved2 = await resolve4(teamConfig.dsl);
57033
+ const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
57034
+ const schemaResult2 = validateSchema(data2);
57035
+ if (!schemaResult2.success) {
57036
+ const issues = schemaResult2.diagnostics.map((d2) => ` ${d2.path}: ${d2.message}`).join("\n");
57037
+ process.stderr.write(`Schema validation failed:
57038
+ ${issues}
57039
+ `);
57040
+ hasErrors = true;
57041
+ continue;
57042
+ }
57043
+ const result2 = score(schemaResult2.data);
57044
+ if (opts.format === "json") {
57045
+ process.stdout.write(JSON.stringify(result2, null, 2) + "\n");
57046
+ } else {
57047
+ process.stdout.write(formatScoreText(result2) + "\n");
57048
+ }
57049
+ if (thresholdNum !== void 0 && result2.overall < thresholdNum) {
57050
+ process.stderr.write(`Score ${result2.overall} is below threshold ${thresholdNum}
57051
+ `);
57052
+ hasErrors = true;
57053
+ }
57054
+ }
57055
+ if (hasErrors) process.exit(1);
57056
+ return;
57057
+ }
57058
+ const dslPath = resolveDslPath(dir ?? DIR_DEFAULT, DIR_DEFAULT, config);
57059
+ const resolved = await resolve4(dslPath);
57060
+ const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
57061
+ const schemaResult = validateSchema(data);
57062
+ if (!schemaResult.success) {
57063
+ const issues = schemaResult.diagnostics.map((d2) => ` ${d2.path}: ${d2.message}`).join("\n");
57064
+ process.stderr.write(`Schema validation failed:
57065
+ ${issues}
57066
+ `);
57067
+ process.exit(1);
57068
+ }
57069
+ const result = score(schemaResult.data);
57070
+ if (opts.format === "json") {
57071
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
57072
+ } else {
57073
+ process.stdout.write(formatScoreText(result) + "\n");
57074
+ }
57075
+ if (opts.threshold !== void 0) {
57076
+ const threshold = parseInt(String(opts.threshold), 10);
57077
+ if (isNaN(threshold)) {
57078
+ process.stderr.write(`Error: --threshold must be a number, got "${opts.threshold}"
57079
+ `);
57080
+ process.exit(1);
57081
+ }
57082
+ if (result.overall < threshold) {
57083
+ process.stderr.write(`Score ${result.overall} is below threshold ${threshold}
57084
+ `);
57085
+ process.exit(1);
57086
+ }
57087
+ }
57088
+ } catch (err) {
57089
+ const msg = err instanceof Error ? err.message : String(err);
57090
+ process.stderr.write(`Error: ${msg}
57091
+ `);
57092
+ process.exit(1);
57093
+ }
57094
+ };
56956
57095
  var AUDIT_TYPES = ["render", "dsl", "prompt", "all"];
56957
- function parseAuditConfig(config) {
56958
- if (!config) return {};
56959
- const audit = config;
57096
+ function parseAuditConfig(configObj) {
57097
+ if (!configObj) return {};
57098
+ const audit = configObj;
56960
57099
  return {
56961
57100
  adapter: audit.adapter,
56962
57101
  model: audit.model,
@@ -56964,7 +57103,7 @@ function parseAuditConfig(config) {
56964
57103
  cache_dir: audit.cache_dir
56965
57104
  };
56966
57105
  }
56967
- async function runAuditForDsl(dslPath, vars, configObj, auditType, opts, failOn) {
57106
+ async function runAuditForDsl(dslPath, vars, configObj, auditType, auditOpts, failOn) {
56968
57107
  const resolved = await resolve4(dslPath);
56969
57108
  const data = vars ? substituteVars(resolved.data, vars) : resolved.data;
56970
57109
  const schemaResult = validateSchema(data);
@@ -56975,122 +57114,283 @@ async function runAuditForDsl(dslPath, vars, configObj, auditType, opts, failOn)
56975
57114
  const auditConfig = parseAuditConfig(
56976
57115
  configObj.audit
56977
57116
  );
56978
- if (opts.adapter) auditConfig.adapter = opts.adapter;
56979
- if (opts.model) auditConfig.model = opts.model;
57117
+ if (auditOpts.adapter) auditConfig.adapter = auditOpts.adapter;
57118
+ if (auditOpts.model) auditConfig.model = auditOpts.model;
56980
57119
  if (auditType === "all") {
56981
57120
  const results = await runAllAudits(schemaResult.data, configObj, auditConfig, {
56982
- format: opts.format,
56983
- scope: opts.scope,
56984
- dryRun: opts.dryRun
57121
+ format: auditOpts.format,
57122
+ scope: auditOpts.scope,
57123
+ dryRun: auditOpts.dryRun
56985
57124
  });
56986
57125
  let output2;
56987
- if (opts.dryRun) {
56988
- output2 = results.map(
56989
- (r3) => `
57126
+ if (auditOpts.dryRun) {
57127
+ output2 = results.map((r3) => `
56990
57128
  --- Audit prompt: ${r3.auditType} ---
56991
57129
  ${r3.prompt}
56992
- `
56993
- ).join("");
57130
+ `).join("");
56994
57131
  } else {
56995
- output2 = formatAuditResults(results, opts.format) + "\n";
57132
+ output2 = formatAuditResults(results, auditOpts.format) + "\n";
56996
57133
  }
56997
57134
  return { exitCode: computeExitCode(results, failOn), output: output2 };
56998
57135
  }
56999
57136
  const result = await runAudit(schemaResult.data, configObj, auditConfig, {
57000
57137
  auditType,
57001
- format: opts.format,
57002
- scope: opts.scope,
57003
- dryRun: opts.dryRun
57138
+ format: auditOpts.format,
57139
+ scope: auditOpts.scope,
57140
+ dryRun: auditOpts.dryRun
57004
57141
  });
57005
57142
  let output;
57006
- if (opts.dryRun) {
57143
+ if (auditOpts.dryRun) {
57007
57144
  output = result.prompt + "\n";
57008
57145
  } else {
57009
- output = formatAuditResult(result, opts.format) + "\n";
57146
+ output = formatAuditResult(result, auditOpts.format) + "\n";
57010
57147
  }
57011
57148
  return { exitCode: computeExitCode([result], failOn), output };
57012
57149
  }
57013
- var auditCommand = new Command8("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs").argument("[type]", `Audit type: ${AUDIT_TYPES.join(", ")}`, "all").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json|markdown)", "text").option("--scope <entities>", "Limit audit scope (e.g. agents:architect,implementer)").option("--dry-run", "Output the audit prompt without calling LLM", false).option("--adapter <name>", "SDK adapter to use (default from config)").option("--model <name>", "LLM model override").option("--fail-on <level>", "Minimum severity that causes exit 10 (info|warning|error|critical)", "critical").option("-o, --output <file>", "Write result to a file instead of stdout").option("--report-format <fmt>", "Alias for --format (for cli-contracts standard conformance)").action(
57014
- async (type, opts) => {
57015
- if (!AUDIT_TYPES.includes(type)) {
57016
- process.stderr.write(
57017
- `Unknown audit type: "${type}". Use one of: ${AUDIT_TYPES.join(", ")}
57150
+ var handleAudit = async (type, opts) => {
57151
+ const auditType = type ?? "all";
57152
+ if (!AUDIT_TYPES.includes(auditType)) {
57153
+ process.stderr.write(
57154
+ `Unknown audit type: "${auditType}". Use one of: ${AUDIT_TYPES.join(", ")}
57018
57155
  `
57156
+ );
57157
+ process.exit(1);
57158
+ }
57159
+ const format2 = opts.reportFormat ?? opts.format ?? "text";
57160
+ try {
57161
+ const config = await loadConfig(opts.config);
57162
+ if (!config) {
57163
+ process.stderr.write(
57164
+ "Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
57019
57165
  );
57020
57166
  process.exit(1);
57021
57167
  }
57022
- const format2 = opts.reportFormat ?? opts.format;
57023
- try {
57024
- const config = await loadConfig(opts.config);
57025
- if (!config) {
57026
- process.stderr.write(
57027
- "Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
57168
+ if (isMultiTeamConfig(config)) {
57169
+ const teamEntries = getTeamEntries(config, opts.team);
57170
+ let maxExit = 0;
57171
+ const allOutput = [];
57172
+ for (const [teamId, teamConfig] of teamEntries) {
57173
+ process.stderr.write(`
57174
+ --- Team: ${teamId} ---
57175
+ `);
57176
+ const result2 = await runAuditForDsl(
57177
+ teamConfig.dsl,
57178
+ teamConfig.vars,
57179
+ config,
57180
+ auditType,
57181
+ { format: format2, scope: opts.scope, dryRun: !!opts.dryRun, adapter: opts.adapter, model: opts.model },
57182
+ opts.failOn
57028
57183
  );
57029
- process.exit(1);
57184
+ process.stdout.write(result2.output);
57185
+ allOutput.push(result2.output);
57186
+ if (result2.exitCode > maxExit) maxExit = result2.exitCode;
57030
57187
  }
57031
- if (isMultiTeamConfig(config)) {
57032
- const teamEntries = getTeamEntries(config, opts.team);
57033
- let maxExit = 0;
57034
- const allOutput = [];
57035
- for (const [teamId, teamConfig] of teamEntries) {
57036
- process.stderr.write(`
57037
- --- Team: ${teamId} ---
57188
+ if (opts.output) writeFileSync2(opts.output, allOutput.join(""), "utf8");
57189
+ process.exit(maxExit);
57190
+ }
57191
+ const result = await runAuditForDsl(
57192
+ config.dsl,
57193
+ config.vars,
57194
+ config,
57195
+ auditType,
57196
+ { format: format2, scope: opts.scope, dryRun: !!opts.dryRun, adapter: opts.adapter, model: opts.model },
57197
+ opts.failOn
57198
+ );
57199
+ process.stdout.write(result.output);
57200
+ if (opts.output) writeFileSync2(opts.output, result.output, "utf8");
57201
+ process.exit(result.exitCode);
57202
+ } catch (err) {
57203
+ if (err instanceof ConfigLoadError) {
57204
+ process.stderr.write(`Config error: ${err.message}
57038
57205
  `);
57039
- const result2 = await runAuditForDsl(
57040
- teamConfig.dsl,
57041
- teamConfig.vars,
57042
- config,
57043
- type,
57044
- { format: format2, scope: opts.scope, dryRun: opts.dryRun, adapter: opts.adapter, model: opts.model },
57045
- opts.failOn
57046
- );
57047
- process.stdout.write(result2.output);
57048
- allOutput.push(result2.output);
57049
- if (result2.exitCode > maxExit) maxExit = result2.exitCode;
57050
- }
57051
- if (opts.output) writeFileSync2(opts.output, allOutput.join(""), "utf8");
57052
- process.exit(maxExit);
57053
- }
57054
- const result = await runAuditForDsl(
57055
- config.dsl,
57056
- config.vars,
57057
- config,
57058
- type,
57059
- { format: format2, scope: opts.scope, dryRun: opts.dryRun, adapter: opts.adapter, model: opts.model },
57060
- opts.failOn
57206
+ process.exit(1);
57207
+ }
57208
+ const msg = err instanceof Error ? err.message : String(err);
57209
+ process.stderr.write(`Error: ${msg}
57210
+ `);
57211
+ if (msg.includes("not installed")) process.exit(11);
57212
+ if (msg.includes("adapter") || msg.includes("API")) process.exit(12);
57213
+ process.exit(1);
57214
+ }
57215
+ };
57216
+ var VALID_TYPES = ["templates", "guardrails", "interface"];
57217
+ function resolvedConfigForTeam(workspace, teamConfig) {
57218
+ return {
57219
+ dsl: "",
57220
+ vars: teamConfig.vars,
57221
+ renders: workspace.renders,
57222
+ configDir: workspace.configDir,
57223
+ bindings: teamConfig.bindings,
57224
+ activeGuardrailPolicy: teamConfig.activeGuardrailPolicy,
57225
+ paths: teamConfig.paths
57226
+ };
57227
+ }
57228
+ var handleGenerate = async (type, opts) => {
57229
+ if (type !== void 0 && !VALID_TYPES.includes(type)) {
57230
+ process.stderr.write(`Unknown generate type: ${type}
57231
+ `);
57232
+ process.exit(1);
57233
+ }
57234
+ const fmt = opts.format ?? "yaml";
57235
+ if (fmt !== "yaml" && fmt !== "json") {
57236
+ process.stderr.write(`Invalid --format: expected yaml or json, got ${fmt}
57237
+ `);
57238
+ process.exit(1);
57239
+ }
57240
+ const normalizedType = type;
57241
+ const targets = {
57242
+ templates: normalizedType === void 0 || normalizedType === "templates",
57243
+ guardrails: normalizedType === void 0 || normalizedType === "guardrails",
57244
+ interface: normalizedType === void 0 || normalizedType === "interface"
57245
+ };
57246
+ try {
57247
+ const config = await loadConfig(opts.config);
57248
+ if (!config) {
57249
+ process.stderr.write(
57250
+ "Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
57061
57251
  );
57062
- process.stdout.write(result.output);
57063
- if (opts.output) writeFileSync2(opts.output, result.output, "utf8");
57064
- process.exit(result.exitCode);
57065
- } catch (err) {
57066
- if (err instanceof ConfigLoadError) {
57067
- process.stderr.write(`Config error: ${err.message}
57252
+ process.exit(1);
57253
+ }
57254
+ const processTeam = async (teamConfig, teamLabel) => {
57255
+ let exitWithError = false;
57256
+ const resolved = await resolve4(teamConfig.dsl);
57257
+ const data = teamConfig.vars ? substituteVars(resolved.data, teamConfig.vars) : resolved.data;
57258
+ const schemaResult = validateSchema(data);
57259
+ if (!schemaResult.success) {
57260
+ process.stderr.write(
57261
+ `Schema validation failed${teamLabel ? ` for team ${teamLabel}` : ""}. Run 'agent-contracts validate' for details.
57262
+ `
57263
+ );
57264
+ return true;
57265
+ }
57266
+ if (targets.templates) {
57267
+ let renderOptions;
57268
+ if (teamConfig.bindings.length > 0) {
57269
+ const loadedBindings = await loadBindings(teamConfig.bindings);
57270
+ renderOptions = { loadedBindings, activeGuardrailPolicy: teamConfig.activeGuardrailPolicy };
57271
+ }
57272
+ if (opts.check) {
57273
+ const drift = await checkDriftFromConfig(schemaResult.data, config.renders, renderOptions);
57274
+ if (drift.hasDrift) {
57275
+ process.stderr.write(`Drift detected${teamLabel ? ` for team ${teamLabel}` : ""} in the following files:
57068
57276
  `);
57069
- process.exit(1);
57277
+ for (const f2 of drift.diffs) process.stderr.write(` ${f2}
57278
+ `);
57279
+ exitWithError = true;
57280
+ } else if (!opts.quiet) {
57281
+ process.stdout.write("No drift detected.\n");
57282
+ }
57283
+ } else {
57284
+ const files = await renderFromConfig(schemaResult.data, config.renders, renderOptions);
57285
+ if (!opts.quiet) {
57286
+ process.stdout.write(`Rendered ${files.length} file(s):
57287
+ `);
57288
+ for (const f2 of files) process.stdout.write(` ${f2}
57289
+ `);
57290
+ }
57291
+ }
57292
+ }
57293
+ if (targets.interface) {
57294
+ if (schemaResult.data.team_interface) {
57295
+ runGenerateInterfaceCli({
57296
+ dsl: schemaResult.data,
57297
+ output: teamConfig.interfaceOutput ?? opts.output,
57298
+ dryRun: !!opts.dryRun,
57299
+ format: fmt,
57300
+ quiet: !!opts.quiet
57301
+ });
57302
+ } else if (normalizedType === "interface") {
57303
+ process.stderr.write("Error: DSL has no team_interface section.\n");
57304
+ exitWithError = true;
57305
+ }
57306
+ }
57307
+ if (targets.guardrails) {
57308
+ const loadedBindings = await loadBindings(teamConfig.bindings);
57309
+ const cfgForTeam = teamLabel ? resolvedConfigForTeam(config, teamConfig) : config;
57310
+ const result = await generateGuardrails({
57311
+ dsl: schemaResult.data,
57312
+ config: cfgForTeam,
57313
+ loadedBindings,
57314
+ filterBindings: opts.binding ? [opts.binding] : void 0,
57315
+ dryRun: !!opts.dryRun
57316
+ });
57317
+ const errors = result.diagnostics.filter((d2) => d2.severity === "error");
57318
+ const warnings = result.diagnostics.filter((d2) => d2.severity === "warning");
57319
+ const infos = result.diagnostics.filter((d2) => d2.severity === "info");
57320
+ if (errors.length > 0) {
57321
+ process.stderr.write(`Errors${teamLabel ? ` (team ${teamLabel})` : ""}:
57322
+ `);
57323
+ for (const d2 of errors) process.stderr.write(` error [${d2.path}] ${d2.message}
57324
+ `);
57325
+ exitWithError = true;
57326
+ }
57327
+ if (warnings.length > 0 && !opts.quiet) {
57328
+ process.stderr.write(`Warnings${teamLabel ? ` (team ${teamLabel})` : ""}:
57329
+ `);
57330
+ for (const d2 of warnings) process.stderr.write(` warning [${d2.path}] ${d2.message}
57331
+ `);
57332
+ }
57333
+ if (infos.length > 0 && !opts.quiet) {
57334
+ for (const d2 of infos) process.stderr.write(` info [${d2.path}] ${d2.message}
57335
+ `);
57336
+ }
57337
+ if (!opts.quiet) {
57338
+ const action = opts.dryRun ? "Would generate" : "Generated";
57339
+ process.stdout.write(`${action} ${result.outputFiles.length} file(s):
57340
+ `);
57341
+ for (const f2 of result.outputFiles) process.stdout.write(` ${f2}
57342
+ `);
57343
+ }
57344
+ }
57345
+ return exitWithError;
57346
+ };
57347
+ if (isMultiTeamConfig(config)) {
57348
+ const teamEntries = getTeamEntries(config, opts.team);
57349
+ let exitWithError = false;
57350
+ for (const [teamId, teamConfig] of teamEntries) {
57351
+ if (!opts.quiet) process.stdout.write(`
57352
+ --- Team: ${teamId} ---
57353
+ `);
57354
+ if (await processTeam(teamConfig, teamId)) exitWithError = true;
57070
57355
  }
57071
- const msg = err instanceof Error ? err.message : String(err);
57072
- process.stderr.write(`Error: ${msg}
57356
+ if (exitWithError) process.exit(1);
57357
+ return;
57358
+ }
57359
+ const singleTeamConfig = {
57360
+ dsl: config.dsl,
57361
+ vars: config.vars,
57362
+ bindings: config.bindings,
57363
+ activeGuardrailPolicy: config.activeGuardrailPolicy,
57364
+ paths: config.paths
57365
+ };
57366
+ if (await processTeam(singleTeamConfig, void 0)) process.exit(1);
57367
+ } catch (err) {
57368
+ if (err instanceof ConfigLoadError) {
57369
+ process.stderr.write(`Config error: ${err.message}
57073
57370
  `);
57074
- if (msg.includes("not installed")) process.exit(11);
57075
- if (msg.includes("adapter") || msg.includes("API")) process.exit(12);
57076
57371
  process.exit(1);
57077
57372
  }
57373
+ const msg = err instanceof Error ? err.message : String(err);
57374
+ process.stderr.write(`Error: ${msg}
57375
+ `);
57376
+ process.exit(1);
57078
57377
  }
57079
- );
57378
+ };
57379
+ var handlers = {
57380
+ resolve: handleResolve,
57381
+ validate: handleValidate,
57382
+ lint: handleLint,
57383
+ render: handleRender,
57384
+ check: handleCheck,
57385
+ score: handleScore,
57386
+ audit: handleAudit,
57387
+ generate: handleGenerate
57388
+ };
57080
57389
 
57081
57390
  // src/cli/cli.ts
57082
57391
  var __dirname = dirname8(fileURLToPath(import.meta.url));
57083
57392
  var pkg = JSON.parse(readFileSync2(resolve8(__dirname, "../package.json"), "utf8"));
57084
- var program = new Command9();
57085
- program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version(pkg.version);
57086
- program.addCommand(resolveCommand);
57087
- program.addCommand(validateCommand);
57088
- program.addCommand(lintCommand);
57089
- program.addCommand(renderCommand);
57090
- program.addCommand(checkCommand);
57091
- program.addCommand(generateCommand);
57092
- program.addCommand(scoreCommand);
57093
- program.addCommand(auditCommand);
57393
+ var program = createProgram(handlers, pkg.version);
57094
57394
  program.parse();
57095
57395
  /*! Bundled license information:
57096
57396