agent-contracts 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/cli-contract.yaml +38 -89
- package/dist/cli.js +1813 -1513
- package/dist/cli.js.map +1 -1
- package/docs/cli-reference.md +1 -528
- package/package.json +4 -3
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 =
|
|
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
|
|
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
|
|
7986
|
-
module.exports =
|
|
7987
|
-
|
|
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
|
|
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(
|
|
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/
|
|
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
|
|
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
|
-
|
|
56104
|
-
|
|
56105
|
-
|
|
56106
|
-
|
|
56107
|
-
|
|
56108
|
-
|
|
56109
|
-
|
|
56110
|
-
|
|
56111
|
-
|
|
56112
|
-
|
|
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
|
-
|
|
56173
|
-
|
|
56174
|
-
|
|
56175
|
-
|
|
56176
|
-
|
|
56177
|
-
|
|
56178
|
-
|
|
56179
|
-
|
|
56180
|
-
|
|
56181
|
-
|
|
56182
|
-
|
|
56183
|
-
|
|
56184
|
-
|
|
56185
|
-
|
|
56186
|
-
|
|
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
|
-
|
|
56199
|
-
|
|
56200
|
-
|
|
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/
|
|
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(
|
|
56958
|
-
if (!
|
|
56959
|
-
const audit =
|
|
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,
|
|
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 (
|
|
56979
|
-
if (
|
|
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:
|
|
56983
|
-
scope:
|
|
56984
|
-
dryRun:
|
|
57121
|
+
format: auditOpts.format,
|
|
57122
|
+
scope: auditOpts.scope,
|
|
57123
|
+
dryRun: auditOpts.dryRun
|
|
56985
57124
|
});
|
|
56986
57125
|
let output2;
|
|
56987
|
-
if (
|
|
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,
|
|
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:
|
|
57002
|
-
scope:
|
|
57003
|
-
dryRun:
|
|
57138
|
+
format: auditOpts.format,
|
|
57139
|
+
scope: auditOpts.scope,
|
|
57140
|
+
dryRun: auditOpts.dryRun
|
|
57004
57141
|
});
|
|
57005
57142
|
let output;
|
|
57006
|
-
if (
|
|
57143
|
+
if (auditOpts.dryRun) {
|
|
57007
57144
|
output = result.prompt + "\n";
|
|
57008
57145
|
} else {
|
|
57009
|
-
output = formatAuditResult(result,
|
|
57146
|
+
output = formatAuditResult(result, auditOpts.format) + "\n";
|
|
57010
57147
|
}
|
|
57011
57148
|
return { exitCode: computeExitCode([result], failOn), output };
|
|
57012
57149
|
}
|
|
57013
|
-
var
|
|
57014
|
-
|
|
57015
|
-
|
|
57016
|
-
|
|
57017
|
-
|
|
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
|
-
|
|
57023
|
-
|
|
57024
|
-
|
|
57025
|
-
|
|
57026
|
-
|
|
57027
|
-
|
|
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.
|
|
57184
|
+
process.stdout.write(result2.output);
|
|
57185
|
+
allOutput.push(result2.output);
|
|
57186
|
+
if (result2.exitCode > maxExit) maxExit = result2.exitCode;
|
|
57030
57187
|
}
|
|
57031
|
-
if (
|
|
57032
|
-
|
|
57033
|
-
|
|
57034
|
-
|
|
57035
|
-
|
|
57036
|
-
|
|
57037
|
-
|
|
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
|
-
|
|
57040
|
-
|
|
57041
|
-
|
|
57042
|
-
|
|
57043
|
-
|
|
57044
|
-
|
|
57045
|
-
|
|
57046
|
-
|
|
57047
|
-
|
|
57048
|
-
|
|
57049
|
-
|
|
57050
|
-
|
|
57051
|
-
|
|
57052
|
-
|
|
57053
|
-
|
|
57054
|
-
|
|
57055
|
-
|
|
57056
|
-
|
|
57057
|
-
|
|
57058
|
-
|
|
57059
|
-
|
|
57060
|
-
|
|
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.
|
|
57063
|
-
|
|
57064
|
-
|
|
57065
|
-
|
|
57066
|
-
|
|
57067
|
-
|
|
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
|
-
|
|
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
|
-
|
|
57072
|
-
|
|
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 =
|
|
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
|
|