agent-contracts 0.14.1 → 0.15.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 +58 -0
- package/dist/cli.js +586 -73
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +79 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -50427,7 +50427,7 @@ var require_dist13 = __commonJS({
|
|
|
50427
50427
|
// src/cli/cli.ts
|
|
50428
50428
|
import { readFileSync } from "fs";
|
|
50429
50429
|
import { fileURLToPath } from "url";
|
|
50430
|
-
import { resolve as resolve7, dirname as
|
|
50430
|
+
import { resolve as resolve7, dirname as dirname8 } from "path";
|
|
50431
50431
|
import { Command as Command8 } from "commander";
|
|
50432
50432
|
|
|
50433
50433
|
// src/cli/commands/resolve.ts
|
|
@@ -50961,13 +50961,51 @@ var RenderTargetSchema = z15.object({
|
|
|
50961
50961
|
},
|
|
50962
50962
|
{ message: "include/exclude cannot be used with context: system" }
|
|
50963
50963
|
);
|
|
50964
|
+
var TeamConfigSchema = z15.object({
|
|
50965
|
+
dsl: z15.string().optional(),
|
|
50966
|
+
bindings: z15.array(z15.string()).default([]),
|
|
50967
|
+
vars: z15.record(z15.string(), z15.string()).optional(),
|
|
50968
|
+
paths: z15.record(z15.string(), z15.string()).optional(),
|
|
50969
|
+
active_guardrail_policy: z15.string().optional(),
|
|
50970
|
+
interface_output: z15.string().optional()
|
|
50971
|
+
});
|
|
50964
50972
|
var AgentContractsConfigSchema = z15.object({
|
|
50965
|
-
dsl: z15.string(),
|
|
50973
|
+
dsl: z15.string().optional(),
|
|
50966
50974
|
vars: z15.record(z15.string(), z15.string()).optional(),
|
|
50967
50975
|
renders: z15.array(RenderTargetSchema).default([]),
|
|
50968
50976
|
bindings: z15.array(z15.string()).default([]),
|
|
50969
50977
|
active_guardrail_policy: z15.string().optional(),
|
|
50970
|
-
paths: z15.record(z15.string(), z15.string()).optional()
|
|
50978
|
+
paths: z15.record(z15.string(), z15.string()).optional(),
|
|
50979
|
+
teams: z15.record(z15.string(), TeamConfigSchema).optional()
|
|
50980
|
+
}).superRefine((data, ctx) => {
|
|
50981
|
+
if (data.dsl !== void 0 && data.teams !== void 0) {
|
|
50982
|
+
ctx.addIssue({
|
|
50983
|
+
code: z15.ZodIssueCode.custom,
|
|
50984
|
+
message: "dsl and teams are mutually exclusive",
|
|
50985
|
+
path: ["teams"]
|
|
50986
|
+
});
|
|
50987
|
+
return;
|
|
50988
|
+
}
|
|
50989
|
+
if (data.dsl === void 0 && data.teams === void 0) {
|
|
50990
|
+
ctx.addIssue({
|
|
50991
|
+
code: z15.ZodIssueCode.custom,
|
|
50992
|
+
message: "Either dsl or teams must be specified",
|
|
50993
|
+
path: []
|
|
50994
|
+
});
|
|
50995
|
+
return;
|
|
50996
|
+
}
|
|
50997
|
+
if (data.teams) {
|
|
50998
|
+
for (const [key, team] of Object.entries(data.teams)) {
|
|
50999
|
+
if (key === "_defaults") continue;
|
|
51000
|
+
if (team.dsl === void 0) {
|
|
51001
|
+
ctx.addIssue({
|
|
51002
|
+
code: z15.ZodIssueCode.custom,
|
|
51003
|
+
message: `Team "${key}" must specify dsl`,
|
|
51004
|
+
path: ["teams", key, "dsl"]
|
|
51005
|
+
});
|
|
51006
|
+
}
|
|
51007
|
+
}
|
|
51008
|
+
}
|
|
50971
51009
|
});
|
|
50972
51010
|
|
|
50973
51011
|
// src/config/loader.ts
|
|
@@ -50988,6 +51026,27 @@ async function fileExists(filePath) {
|
|
|
50988
51026
|
return false;
|
|
50989
51027
|
}
|
|
50990
51028
|
}
|
|
51029
|
+
function resolveTeamConfigs(teams, configDir) {
|
|
51030
|
+
const defaults = teams._defaults;
|
|
51031
|
+
const result = {};
|
|
51032
|
+
for (const [key, team] of Object.entries(teams)) {
|
|
51033
|
+
if (key === "_defaults") continue;
|
|
51034
|
+
const mergedBindings = [...defaults?.bindings ?? [], ...team.bindings].map(
|
|
51035
|
+
(b3) => resolve(configDir, b3)
|
|
51036
|
+
);
|
|
51037
|
+
const mergedVars = defaults?.vars || team.vars ? { ...defaults?.vars ?? {}, ...team.vars ?? {} } : void 0;
|
|
51038
|
+
const mergedPaths = defaults?.paths || team.paths ? { ...defaults?.paths ?? {}, ...team.paths ?? {} } : void 0;
|
|
51039
|
+
result[key] = {
|
|
51040
|
+
dsl: resolve(configDir, team.dsl),
|
|
51041
|
+
bindings: mergedBindings,
|
|
51042
|
+
vars: mergedVars,
|
|
51043
|
+
activeGuardrailPolicy: team.active_guardrail_policy ?? defaults?.active_guardrail_policy,
|
|
51044
|
+
paths: mergedPaths,
|
|
51045
|
+
interfaceOutput: team.interface_output ? resolve(configDir, team.interface_output) : void 0
|
|
51046
|
+
};
|
|
51047
|
+
}
|
|
51048
|
+
return result;
|
|
51049
|
+
}
|
|
50991
51050
|
async function loadConfig(configPath) {
|
|
50992
51051
|
const isExplicit = configPath !== void 0;
|
|
50993
51052
|
const targetPath = resolve(configPath ?? DEFAULT_CONFIG_NAME);
|
|
@@ -51030,14 +51089,27 @@ ${issues}`,
|
|
|
51030
51089
|
}
|
|
51031
51090
|
const configDir = dirname(targetPath);
|
|
51032
51091
|
const config = result.data;
|
|
51092
|
+
const renders = config.renders.map((r3) => ({
|
|
51093
|
+
...r3,
|
|
51094
|
+
template: resolve(configDir, r3.template),
|
|
51095
|
+
output: resolve(configDir, r3.output)
|
|
51096
|
+
}));
|
|
51097
|
+
if (config.teams) {
|
|
51098
|
+
return {
|
|
51099
|
+
dsl: "",
|
|
51100
|
+
vars: void 0,
|
|
51101
|
+
renders,
|
|
51102
|
+
configDir,
|
|
51103
|
+
bindings: [],
|
|
51104
|
+
activeGuardrailPolicy: void 0,
|
|
51105
|
+
paths: void 0,
|
|
51106
|
+
teams: resolveTeamConfigs(config.teams, configDir)
|
|
51107
|
+
};
|
|
51108
|
+
}
|
|
51033
51109
|
return {
|
|
51034
51110
|
dsl: resolve(configDir, config.dsl),
|
|
51035
51111
|
vars: config.vars,
|
|
51036
|
-
renders
|
|
51037
|
-
...r3,
|
|
51038
|
-
template: resolve(configDir, r3.template),
|
|
51039
|
-
output: resolve(configDir, r3.output)
|
|
51040
|
-
})),
|
|
51112
|
+
renders,
|
|
51041
51113
|
configDir,
|
|
51042
51114
|
bindings: (config.bindings ?? []).map((b3) => resolve(configDir, b3)),
|
|
51043
51115
|
activeGuardrailPolicy: config.active_guardrail_policy,
|
|
@@ -51859,28 +51931,79 @@ ${issues}`,
|
|
|
51859
51931
|
|
|
51860
51932
|
// src/cli/commands/resolve.ts
|
|
51861
51933
|
import { stringify } from "yaml";
|
|
51862
|
-
|
|
51863
|
-
|
|
51864
|
-
|
|
51865
|
-
|
|
51866
|
-
|
|
51867
|
-
|
|
51868
|
-
|
|
51869
|
-
|
|
51870
|
-
|
|
51871
|
-
|
|
51872
|
-
if (
|
|
51873
|
-
|
|
51874
|
-
|
|
51875
|
-
|
|
51934
|
+
|
|
51935
|
+
// src/cli/multi-team.ts
|
|
51936
|
+
function isMultiTeamConfig(config) {
|
|
51937
|
+
return config.teams !== void 0 && Object.keys(config.teams).length > 0;
|
|
51938
|
+
}
|
|
51939
|
+
function getTeamEntries(config, teamFilter) {
|
|
51940
|
+
if (!config.teams) return [];
|
|
51941
|
+
const entries = Object.entries(config.teams);
|
|
51942
|
+
if (teamFilter) {
|
|
51943
|
+
const found = entries.filter(([k2]) => k2 === teamFilter);
|
|
51944
|
+
if (found.length === 0) {
|
|
51945
|
+
throw new Error(
|
|
51946
|
+
`Team "${teamFilter}" not found. Available teams: ${entries.map(([k2]) => k2).join(", ")}`
|
|
51947
|
+
);
|
|
51876
51948
|
}
|
|
51877
|
-
|
|
51878
|
-
|
|
51879
|
-
|
|
51949
|
+
return found;
|
|
51950
|
+
}
|
|
51951
|
+
return entries;
|
|
51952
|
+
}
|
|
51953
|
+
|
|
51954
|
+
// src/cli/commands/resolve.ts
|
|
51955
|
+
var DIR_DEFAULT = "agent-contracts.yaml";
|
|
51956
|
+
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(
|
|
51957
|
+
async (dir, opts) => {
|
|
51958
|
+
try {
|
|
51959
|
+
const config = await loadConfig(opts.config);
|
|
51960
|
+
if (config !== null && isMultiTeamConfig(config)) {
|
|
51961
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
51962
|
+
if (opts.format === "json") {
|
|
51963
|
+
const out = {};
|
|
51964
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
51965
|
+
const result2 = await resolve4(teamConfig.dsl);
|
|
51966
|
+
let data2 = teamConfig.vars ? substituteVars(result2.data, teamConfig.vars) : result2.data;
|
|
51967
|
+
if (opts.expandDefaults) {
|
|
51968
|
+
data2 = expandDefaults(data2);
|
|
51969
|
+
}
|
|
51970
|
+
out[teamId] = data2;
|
|
51971
|
+
}
|
|
51972
|
+
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
|
|
51973
|
+
} else {
|
|
51974
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
51975
|
+
process.stdout.write(`
|
|
51976
|
+
--- Team: ${teamId} ---
|
|
51977
|
+
`);
|
|
51978
|
+
const result2 = await resolve4(teamConfig.dsl);
|
|
51979
|
+
let data2 = teamConfig.vars ? substituteVars(result2.data, teamConfig.vars) : result2.data;
|
|
51980
|
+
if (opts.expandDefaults) {
|
|
51981
|
+
data2 = expandDefaults(data2);
|
|
51982
|
+
}
|
|
51983
|
+
process.stdout.write(stringify(data2));
|
|
51984
|
+
}
|
|
51985
|
+
}
|
|
51986
|
+
return;
|
|
51987
|
+
}
|
|
51988
|
+
const dslPath = resolveDslPath(dir, DIR_DEFAULT, config);
|
|
51989
|
+
const result = await resolve4(dslPath);
|
|
51990
|
+
let data = config?.vars ? substituteVars(result.data, config.vars) : result.data;
|
|
51991
|
+
if (opts.expandDefaults) {
|
|
51992
|
+
data = expandDefaults(data);
|
|
51993
|
+
}
|
|
51994
|
+
if (opts.format === "json") {
|
|
51995
|
+
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
51996
|
+
} else {
|
|
51997
|
+
process.stdout.write(stringify(data));
|
|
51998
|
+
}
|
|
51999
|
+
} catch (err) {
|
|
52000
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
52001
|
+
process.stderr.write(`Error: ${msg}
|
|
51880
52002
|
`);
|
|
51881
|
-
|
|
52003
|
+
process.exit(1);
|
|
52004
|
+
}
|
|
51882
52005
|
}
|
|
51883
|
-
|
|
52006
|
+
);
|
|
51884
52007
|
|
|
51885
52008
|
// src/cli/commands/validate.ts
|
|
51886
52009
|
import { Command as Command2 } from "commander";
|
|
@@ -52960,44 +53083,88 @@ function formatDiagnostics(diagnostics, options) {
|
|
|
52960
53083
|
|
|
52961
53084
|
// src/cli/commands/validate.ts
|
|
52962
53085
|
var DIR_DEFAULT2 = "agent-contracts.yaml";
|
|
52963
|
-
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("--format <format>", "Output format (text|json)", "text").option("--quiet", "Suppress output on success", false).option("--strict", "Treat warnings as errors", false).action(
|
|
52964
|
-
|
|
52965
|
-
|
|
52966
|
-
|
|
52967
|
-
|
|
52968
|
-
|
|
52969
|
-
|
|
52970
|
-
|
|
52971
|
-
|
|
52972
|
-
|
|
52973
|
-
|
|
52974
|
-
|
|
52975
|
-
|
|
52976
|
-
|
|
52977
|
-
|
|
52978
|
-
|
|
52979
|
-
|
|
52980
|
-
|
|
52981
|
-
|
|
52982
|
-
|
|
52983
|
-
|
|
52984
|
-
|
|
52985
|
-
|
|
52986
|
-
|
|
52987
|
-
|
|
53086
|
+
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(
|
|
53087
|
+
async (dir, opts) => {
|
|
53088
|
+
try {
|
|
53089
|
+
const config = await loadConfig(opts.config);
|
|
53090
|
+
if (config !== null && isMultiTeamConfig(config)) {
|
|
53091
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
53092
|
+
let hasErrors = false;
|
|
53093
|
+
let allTeamsFullyClean = true;
|
|
53094
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
53095
|
+
if (!opts.quiet) process.stdout.write(`
|
|
53096
|
+
--- Team: ${teamId} ---
|
|
53097
|
+
`);
|
|
53098
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
53099
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
53100
|
+
const schemaResult2 = validateSchema(data2);
|
|
53101
|
+
const schemaWarnings2 = schemaResult2.diagnostics.filter(
|
|
53102
|
+
(d2) => d2.severity === "warning"
|
|
53103
|
+
);
|
|
53104
|
+
if (!schemaResult2.success) {
|
|
53105
|
+
const output = formatDiagnostics(schemaResult2.diagnostics, opts);
|
|
53106
|
+
if (output) process.stderr.write(output + "\n");
|
|
53107
|
+
hasErrors = true;
|
|
53108
|
+
allTeamsFullyClean = false;
|
|
53109
|
+
continue;
|
|
53110
|
+
}
|
|
53111
|
+
const refDiags2 = checkReferences(schemaResult2.data);
|
|
53112
|
+
const handoffDiags2 = validateHandoffSchemas(schemaResult2.data);
|
|
53113
|
+
const allDiags2 = [...refDiags2, ...handoffDiags2, ...schemaWarnings2];
|
|
53114
|
+
const hasWarnings2 = allDiags2.some(
|
|
53115
|
+
(d2) => "severity" in d2 && d2.severity === "warning"
|
|
53116
|
+
);
|
|
53117
|
+
if (allDiags2.length > 0) {
|
|
53118
|
+
allTeamsFullyClean = false;
|
|
53119
|
+
const output = formatDiagnostics(allDiags2, opts);
|
|
53120
|
+
if (output) process.stderr.write(output + "\n");
|
|
53121
|
+
if (refDiags2.length > 0 || handoffDiags2.length > 0 || opts.strict && hasWarnings2) {
|
|
53122
|
+
hasErrors = true;
|
|
53123
|
+
}
|
|
53124
|
+
}
|
|
53125
|
+
}
|
|
53126
|
+
if (hasErrors) process.exit(1);
|
|
53127
|
+
if (!opts.quiet && allTeamsFullyClean) {
|
|
53128
|
+
process.stdout.write("Validation passed.\n");
|
|
53129
|
+
}
|
|
53130
|
+
return;
|
|
53131
|
+
}
|
|
53132
|
+
const dslPath = resolveDslPath(dir, DIR_DEFAULT2, config);
|
|
53133
|
+
const resolved = await resolve4(dslPath);
|
|
53134
|
+
const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
53135
|
+
const schemaResult = validateSchema(data);
|
|
53136
|
+
const schemaWarnings = schemaResult.diagnostics.filter(
|
|
53137
|
+
(d2) => d2.severity === "warning"
|
|
53138
|
+
);
|
|
53139
|
+
if (!schemaResult.success) {
|
|
53140
|
+
const output = formatDiagnostics(schemaResult.diagnostics, opts);
|
|
53141
|
+
if (output) process.stderr.write(output + "\n");
|
|
52988
53142
|
process.exit(1);
|
|
52989
53143
|
}
|
|
52990
|
-
|
|
52991
|
-
|
|
52992
|
-
|
|
52993
|
-
|
|
52994
|
-
|
|
52995
|
-
|
|
52996
|
-
|
|
53144
|
+
const refDiags = checkReferences(schemaResult.data);
|
|
53145
|
+
const handoffDiags = validateHandoffSchemas(schemaResult.data);
|
|
53146
|
+
const allDiags = [...refDiags, ...handoffDiags, ...schemaWarnings];
|
|
53147
|
+
const hasWarnings = allDiags.some(
|
|
53148
|
+
(d2) => "severity" in d2 && d2.severity === "warning"
|
|
53149
|
+
);
|
|
53150
|
+
if (allDiags.length > 0) {
|
|
53151
|
+
const output = formatDiagnostics(allDiags, opts);
|
|
53152
|
+
if (output) process.stderr.write(output + "\n");
|
|
53153
|
+
if (refDiags.length > 0 || handoffDiags.length > 0 || opts.strict && hasWarnings) {
|
|
53154
|
+
process.exit(1);
|
|
53155
|
+
}
|
|
53156
|
+
}
|
|
53157
|
+
if (!opts.quiet && allDiags.length === 0) {
|
|
53158
|
+
process.stdout.write("Validation passed.\n");
|
|
53159
|
+
}
|
|
53160
|
+
} catch (err) {
|
|
53161
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53162
|
+
process.stderr.write(`Error: ${msg}
|
|
52997
53163
|
`);
|
|
52998
|
-
|
|
53164
|
+
process.exit(1);
|
|
53165
|
+
}
|
|
52999
53166
|
}
|
|
53000
|
-
|
|
53167
|
+
);
|
|
53001
53168
|
|
|
53002
53169
|
// src/cli/commands/lint.ts
|
|
53003
53170
|
import { Command as Command3 } from "commander";
|
|
@@ -54395,10 +54562,63 @@ async function spectralLint(dslObject) {
|
|
|
54395
54562
|
|
|
54396
54563
|
// src/cli/commands/lint.ts
|
|
54397
54564
|
var DIR_DEFAULT3 = "agent-contracts.yaml";
|
|
54398
|
-
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("--format <format>", "Output format (text|json)", "text").option("--quiet", "Suppress output on success", false).option("--strict", "Treat warnings as errors", false).action(
|
|
54565
|
+
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(
|
|
54399
54566
|
async (dir, opts) => {
|
|
54400
54567
|
try {
|
|
54401
54568
|
const config = await loadConfig(opts.config);
|
|
54569
|
+
if (config !== null && isMultiTeamConfig(config)) {
|
|
54570
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
54571
|
+
let hasErrors = false;
|
|
54572
|
+
let allClean = true;
|
|
54573
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
54574
|
+
if (!opts.quiet) process.stdout.write(`
|
|
54575
|
+
--- Team: ${teamId} ---
|
|
54576
|
+
`);
|
|
54577
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
54578
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
54579
|
+
const schemaResult2 = validateSchema(data2);
|
|
54580
|
+
const schemaWarnings2 = schemaResult2.diagnostics.filter(
|
|
54581
|
+
(d2) => d2.severity === "warning"
|
|
54582
|
+
);
|
|
54583
|
+
if (!schemaResult2.success) {
|
|
54584
|
+
const output = formatDiagnostics(schemaResult2.diagnostics, {
|
|
54585
|
+
format: opts.format,
|
|
54586
|
+
quiet: opts.quiet
|
|
54587
|
+
});
|
|
54588
|
+
if (output) process.stderr.write(output + "\n");
|
|
54589
|
+
hasErrors = true;
|
|
54590
|
+
allClean = false;
|
|
54591
|
+
continue;
|
|
54592
|
+
}
|
|
54593
|
+
const tsDiagnostics2 = lint(schemaResult2.data);
|
|
54594
|
+
const spectralDiagnostics2 = await spectralLint(
|
|
54595
|
+
schemaResult2.data
|
|
54596
|
+
);
|
|
54597
|
+
const diagnostics2 = [
|
|
54598
|
+
...tsDiagnostics2,
|
|
54599
|
+
...spectralDiagnostics2,
|
|
54600
|
+
...schemaWarnings2
|
|
54601
|
+
];
|
|
54602
|
+
if (diagnostics2.length > 0) {
|
|
54603
|
+
allClean = false;
|
|
54604
|
+
const output = formatDiagnostics(diagnostics2, {
|
|
54605
|
+
format: opts.format,
|
|
54606
|
+
quiet: opts.quiet
|
|
54607
|
+
});
|
|
54608
|
+
if (output) process.stderr.write(output + "\n");
|
|
54609
|
+
const teamHasErrors = diagnostics2.some((d2) => d2.severity === "error");
|
|
54610
|
+
const teamHasWarnings = diagnostics2.some((d2) => d2.severity === "warning");
|
|
54611
|
+
if (teamHasErrors || opts.strict && teamHasWarnings) {
|
|
54612
|
+
hasErrors = true;
|
|
54613
|
+
}
|
|
54614
|
+
}
|
|
54615
|
+
}
|
|
54616
|
+
if (hasErrors) process.exit(1);
|
|
54617
|
+
if (!opts.quiet && allClean) {
|
|
54618
|
+
process.stdout.write("Lint passed.\n");
|
|
54619
|
+
}
|
|
54620
|
+
return;
|
|
54621
|
+
}
|
|
54402
54622
|
const dslPath = resolveDslPath(dir, DIR_DEFAULT3, config);
|
|
54403
54623
|
const resolved = await resolve4(dslPath);
|
|
54404
54624
|
const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
@@ -55832,7 +56052,7 @@ async function checkDriftFromConfig(dsl, renderTargets, options) {
|
|
|
55832
56052
|
}
|
|
55833
56053
|
|
|
55834
56054
|
// src/cli/commands/render.ts
|
|
55835
|
-
var renderCommand = new Command4("render").description("Render resolved DSL with Handlebars templates (requires config)").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--check", "Check for drift without writing files", false).option("--quiet", "Suppress output on success", false).action(
|
|
56055
|
+
var renderCommand = new Command4("render").description("Render resolved DSL with Handlebars templates (requires config)").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 drift without writing files", false).option("--quiet", "Suppress output on success", false).action(
|
|
55836
56056
|
async (opts) => {
|
|
55837
56057
|
try {
|
|
55838
56058
|
const config = await loadConfig(opts.config);
|
|
@@ -55842,6 +56062,68 @@ var renderCommand = new Command4("render").description("Render resolved DSL with
|
|
|
55842
56062
|
);
|
|
55843
56063
|
process.exit(1);
|
|
55844
56064
|
}
|
|
56065
|
+
if (isMultiTeamConfig(config)) {
|
|
56066
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
56067
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
56068
|
+
if (!opts.quiet) process.stdout.write(`
|
|
56069
|
+
--- Team: ${teamId} ---
|
|
56070
|
+
`);
|
|
56071
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
56072
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
56073
|
+
const schemaResult2 = validateSchema(data2);
|
|
56074
|
+
if (!schemaResult2.success) {
|
|
56075
|
+
process.stderr.write(
|
|
56076
|
+
`Schema validation failed for team ${teamId}. Run 'agent-contracts validate' for details.
|
|
56077
|
+
`
|
|
56078
|
+
);
|
|
56079
|
+
process.exit(1);
|
|
56080
|
+
}
|
|
56081
|
+
let renderOptions2;
|
|
56082
|
+
if (teamConfig.bindings.length > 0) {
|
|
56083
|
+
const loadedBindings = await loadBindings(teamConfig.bindings);
|
|
56084
|
+
renderOptions2 = {
|
|
56085
|
+
loadedBindings,
|
|
56086
|
+
activeGuardrailPolicy: teamConfig.activeGuardrailPolicy
|
|
56087
|
+
};
|
|
56088
|
+
}
|
|
56089
|
+
if (opts.check) {
|
|
56090
|
+
const drift = await checkDriftFromConfig(
|
|
56091
|
+
schemaResult2.data,
|
|
56092
|
+
config.renders,
|
|
56093
|
+
renderOptions2
|
|
56094
|
+
);
|
|
56095
|
+
if (drift.hasDrift) {
|
|
56096
|
+
process.stderr.write(
|
|
56097
|
+
`Drift detected for team ${teamId} in the following files:
|
|
56098
|
+
`
|
|
56099
|
+
);
|
|
56100
|
+
for (const f2 of drift.diffs) {
|
|
56101
|
+
process.stderr.write(` ${f2}
|
|
56102
|
+
`);
|
|
56103
|
+
}
|
|
56104
|
+
process.exit(1);
|
|
56105
|
+
}
|
|
56106
|
+
if (!opts.quiet) {
|
|
56107
|
+
process.stdout.write("No drift detected.\n");
|
|
56108
|
+
}
|
|
56109
|
+
} else {
|
|
56110
|
+
const files = await renderFromConfig(
|
|
56111
|
+
schemaResult2.data,
|
|
56112
|
+
config.renders,
|
|
56113
|
+
renderOptions2
|
|
56114
|
+
);
|
|
56115
|
+
if (!opts.quiet) {
|
|
56116
|
+
process.stdout.write(`Rendered ${files.length} file(s):
|
|
56117
|
+
`);
|
|
56118
|
+
for (const f2 of files) {
|
|
56119
|
+
process.stdout.write(` ${f2}
|
|
56120
|
+
`);
|
|
56121
|
+
}
|
|
56122
|
+
}
|
|
56123
|
+
}
|
|
56124
|
+
}
|
|
56125
|
+
return;
|
|
56126
|
+
}
|
|
55845
56127
|
const resolved = await resolve4(config.dsl);
|
|
55846
56128
|
const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
55847
56129
|
const schemaResult = validateSchema(data);
|
|
@@ -55907,7 +56189,9 @@ var renderCommand = new Command4("render").description("Render resolved DSL with
|
|
|
55907
56189
|
|
|
55908
56190
|
// src/cli/commands/check.ts
|
|
55909
56191
|
import { Command as Command5 } from "commander";
|
|
55910
|
-
|
|
56192
|
+
import { access as access2 } from "fs/promises";
|
|
56193
|
+
import { resolve as pathResolve, dirname as dirname6 } from "path";
|
|
56194
|
+
var checkCommand = new Command5("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(
|
|
55911
56195
|
async (opts) => {
|
|
55912
56196
|
let hasErrors = false;
|
|
55913
56197
|
try {
|
|
@@ -55918,6 +56202,111 @@ var checkCommand = new Command5("check").description("Run full pipeline: resolve
|
|
|
55918
56202
|
);
|
|
55919
56203
|
process.exit(1);
|
|
55920
56204
|
}
|
|
56205
|
+
if (isMultiTeamConfig(config)) {
|
|
56206
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
56207
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
56208
|
+
if (!opts.quiet) process.stderr.write(`
|
|
56209
|
+
--- Team: ${teamId} ---
|
|
56210
|
+
`);
|
|
56211
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
56212
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
56213
|
+
const schemaResult2 = validateSchema(data2);
|
|
56214
|
+
const schemaWarnings2 = schemaResult2.diagnostics.filter(
|
|
56215
|
+
(d2) => d2.severity === "warning"
|
|
56216
|
+
);
|
|
56217
|
+
if (!schemaResult2.success) {
|
|
56218
|
+
const output = formatDiagnostics(schemaResult2.diagnostics, {
|
|
56219
|
+
format: opts.format,
|
|
56220
|
+
quiet: opts.quiet
|
|
56221
|
+
});
|
|
56222
|
+
if (output) process.stderr.write(output + "\n");
|
|
56223
|
+
hasErrors = true;
|
|
56224
|
+
continue;
|
|
56225
|
+
}
|
|
56226
|
+
const refDiags2 = checkReferences(schemaResult2.data);
|
|
56227
|
+
const handoffDiags2 = validateHandoffSchemas(schemaResult2.data);
|
|
56228
|
+
const allRefDiags2 = [...refDiags2, ...handoffDiags2, ...schemaWarnings2];
|
|
56229
|
+
if (allRefDiags2.length > 0) {
|
|
56230
|
+
const output = formatDiagnostics(allRefDiags2, {
|
|
56231
|
+
format: opts.format,
|
|
56232
|
+
quiet: opts.quiet
|
|
56233
|
+
});
|
|
56234
|
+
if (output) process.stderr.write(output + "\n");
|
|
56235
|
+
hasErrors = true;
|
|
56236
|
+
}
|
|
56237
|
+
const tsLintDiags2 = lint(schemaResult2.data);
|
|
56238
|
+
const spectralDiags2 = await spectralLint(
|
|
56239
|
+
schemaResult2.data
|
|
56240
|
+
);
|
|
56241
|
+
const lintDiags2 = [...tsLintDiags2, ...spectralDiags2];
|
|
56242
|
+
if (lintDiags2.length > 0) {
|
|
56243
|
+
const output = formatDiagnostics(lintDiags2, {
|
|
56244
|
+
format: opts.format,
|
|
56245
|
+
quiet: opts.quiet
|
|
56246
|
+
});
|
|
56247
|
+
if (output) process.stderr.write(output + "\n");
|
|
56248
|
+
if (lintDiags2.some((d2) => d2.severity === "error")) {
|
|
56249
|
+
hasErrors = true;
|
|
56250
|
+
}
|
|
56251
|
+
if (opts.strict && lintDiags2.some((d2) => d2.severity === "warning")) {
|
|
56252
|
+
hasErrors = true;
|
|
56253
|
+
}
|
|
56254
|
+
}
|
|
56255
|
+
let renderOptions2;
|
|
56256
|
+
if (teamConfig.bindings.length > 0) {
|
|
56257
|
+
const loadedBindings = await loadBindings(teamConfig.bindings);
|
|
56258
|
+
renderOptions2 = {
|
|
56259
|
+
loadedBindings,
|
|
56260
|
+
activeGuardrailPolicy: teamConfig.activeGuardrailPolicy
|
|
56261
|
+
};
|
|
56262
|
+
}
|
|
56263
|
+
const drift2 = await checkDriftFromConfig(
|
|
56264
|
+
schemaResult2.data,
|
|
56265
|
+
config.renders,
|
|
56266
|
+
renderOptions2
|
|
56267
|
+
);
|
|
56268
|
+
if (drift2.hasDrift) {
|
|
56269
|
+
process.stderr.write(`Drift detected for team ${teamId} in:
|
|
56270
|
+
`);
|
|
56271
|
+
for (const f2 of drift2.diffs) {
|
|
56272
|
+
process.stderr.write(` ${f2}
|
|
56273
|
+
`);
|
|
56274
|
+
}
|
|
56275
|
+
hasErrors = true;
|
|
56276
|
+
}
|
|
56277
|
+
}
|
|
56278
|
+
if (!hasErrors) {
|
|
56279
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
56280
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
56281
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
56282
|
+
const schemaResult2 = validateSchema(data2);
|
|
56283
|
+
if (!schemaResult2.success || !schemaResult2.data) continue;
|
|
56284
|
+
const dsl = schemaResult2.data;
|
|
56285
|
+
const imports = dsl.imports;
|
|
56286
|
+
if (!imports) continue;
|
|
56287
|
+
for (const [importName, importDef] of Object.entries(imports)) {
|
|
56288
|
+
const interfacePathRel = importDef?.interface;
|
|
56289
|
+
if (typeof interfacePathRel !== "string") continue;
|
|
56290
|
+
const interfacePath = pathResolve(
|
|
56291
|
+
dirname6(teamConfig.dsl),
|
|
56292
|
+
interfacePathRel
|
|
56293
|
+
);
|
|
56294
|
+
try {
|
|
56295
|
+
await access2(interfacePath);
|
|
56296
|
+
} catch {
|
|
56297
|
+
process.stderr.write(
|
|
56298
|
+
`Cross-team error: Team "${teamId}" imports "${importName}" but interface file not found: ${interfacePath}
|
|
56299
|
+
`
|
|
56300
|
+
);
|
|
56301
|
+
hasErrors = true;
|
|
56302
|
+
}
|
|
56303
|
+
}
|
|
56304
|
+
}
|
|
56305
|
+
}
|
|
56306
|
+
if (hasErrors) process.exit(1);
|
|
56307
|
+
if (!opts.quiet) process.stdout.write("All checks passed.\n");
|
|
56308
|
+
return;
|
|
56309
|
+
}
|
|
55921
56310
|
const resolved = await resolve4(config.dsl);
|
|
55922
56311
|
const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
55923
56312
|
const schemaResult = validateSchema(data);
|
|
@@ -56005,7 +56394,7 @@ import { Command as Command6 } from "commander";
|
|
|
56005
56394
|
|
|
56006
56395
|
// src/guardrail-generator/generator.ts
|
|
56007
56396
|
import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2, copyFile } from "fs/promises";
|
|
56008
|
-
import { resolve as resolve6, dirname as
|
|
56397
|
+
import { resolve as resolve6, dirname as dirname7 } from "path";
|
|
56009
56398
|
import Handlebars2 from "handlebars";
|
|
56010
56399
|
import YAML from "yaml";
|
|
56011
56400
|
|
|
@@ -56232,7 +56621,7 @@ async function generateGuardrails(options) {
|
|
|
56232
56621
|
const sourcePath = resolve6(config.configDir, outputDef.source);
|
|
56233
56622
|
if (!dryRun) {
|
|
56234
56623
|
try {
|
|
56235
|
-
await mkdir2(
|
|
56624
|
+
await mkdir2(dirname7(targetPath), { recursive: true });
|
|
56236
56625
|
await copyFile(sourcePath, targetPath);
|
|
56237
56626
|
if (outputDef.executable) {
|
|
56238
56627
|
await chmod(targetPath, 493);
|
|
@@ -56316,7 +56705,7 @@ async function generateGuardrails(options) {
|
|
|
56316
56705
|
}
|
|
56317
56706
|
const output = isPatch && !dryRun ? await applyPatch(groupTarget, rendered, outputDef) : rendered;
|
|
56318
56707
|
if (!dryRun) {
|
|
56319
|
-
await mkdir2(
|
|
56708
|
+
await mkdir2(dirname7(groupTarget), { recursive: true });
|
|
56320
56709
|
await writeFile2(groupTarget, output, "utf8");
|
|
56321
56710
|
if (outputDef.executable) {
|
|
56322
56711
|
await chmod(groupTarget, 493);
|
|
@@ -56337,7 +56726,7 @@ async function generateGuardrails(options) {
|
|
|
56337
56726
|
} else {
|
|
56338
56727
|
const output = isPatch && !dryRun ? await applyPatch(targetPath, rendered, outputDef) : rendered;
|
|
56339
56728
|
if (!dryRun) {
|
|
56340
|
-
await mkdir2(
|
|
56729
|
+
await mkdir2(dirname7(targetPath), { recursive: true });
|
|
56341
56730
|
await writeFile2(targetPath, output, "utf8");
|
|
56342
56731
|
if (outputDef.executable) {
|
|
56343
56732
|
await chmod(targetPath, 493);
|
|
@@ -56390,7 +56779,7 @@ async function generateGuardrails(options) {
|
|
|
56390
56779
|
continue;
|
|
56391
56780
|
}
|
|
56392
56781
|
if (!dryRun) {
|
|
56393
|
-
await mkdir2(
|
|
56782
|
+
await mkdir2(dirname7(outputPath), { recursive: true });
|
|
56394
56783
|
await writeFile2(outputPath, rendered, "utf8");
|
|
56395
56784
|
if (renderTarget.executable) {
|
|
56396
56785
|
await chmod(outputPath, 493);
|
|
@@ -56420,7 +56809,7 @@ async function generateGuardrails(options) {
|
|
|
56420
56809
|
continue;
|
|
56421
56810
|
}
|
|
56422
56811
|
if (!dryRun) {
|
|
56423
|
-
await mkdir2(
|
|
56812
|
+
await mkdir2(dirname7(outputPath), { recursive: true });
|
|
56424
56813
|
await writeFile2(outputPath, rendered, "utf8");
|
|
56425
56814
|
if (renderTarget.executable) {
|
|
56426
56815
|
await chmod(outputPath, 493);
|
|
@@ -56441,7 +56830,18 @@ function resolveBindingRenderOutputPath(output, paths) {
|
|
|
56441
56830
|
}
|
|
56442
56831
|
|
|
56443
56832
|
// src/cli/commands/generate-guardrails.ts
|
|
56444
|
-
|
|
56833
|
+
function resolvedConfigForTeam(workspace, teamConfig) {
|
|
56834
|
+
return {
|
|
56835
|
+
dsl: "",
|
|
56836
|
+
vars: teamConfig.vars,
|
|
56837
|
+
renders: workspace.renders,
|
|
56838
|
+
configDir: workspace.configDir,
|
|
56839
|
+
bindings: teamConfig.bindings,
|
|
56840
|
+
activeGuardrailPolicy: teamConfig.activeGuardrailPolicy,
|
|
56841
|
+
paths: teamConfig.paths
|
|
56842
|
+
};
|
|
56843
|
+
}
|
|
56844
|
+
var generateGuardrailsCommand = new Command6("generate").description("Generate guardrail runtime artifacts from DSL, policies, and bindings").argument("[type]", "Type of artifacts to generate", "guardrails").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--binding <name...>", "Filter to specific software binding(s)").option("--dry-run", "Print what would be generated without writing files", false).option("--quiet", "Suppress output on success", false).action(
|
|
56445
56845
|
async (type, opts) => {
|
|
56446
56846
|
if (type !== "guardrails") {
|
|
56447
56847
|
process.stderr.write(`Unknown generate type: ${type}
|
|
@@ -56456,6 +56856,73 @@ var generateGuardrailsCommand = new Command6("generate").description("Generate g
|
|
|
56456
56856
|
);
|
|
56457
56857
|
process.exit(1);
|
|
56458
56858
|
}
|
|
56859
|
+
if (isMultiTeamConfig(config)) {
|
|
56860
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
56861
|
+
let exitWithError = false;
|
|
56862
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
56863
|
+
if (!opts.quiet) process.stdout.write(`
|
|
56864
|
+
--- Team: ${teamId} ---
|
|
56865
|
+
`);
|
|
56866
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
56867
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
56868
|
+
const schemaResult2 = validateSchema(data2);
|
|
56869
|
+
if (!schemaResult2.success) {
|
|
56870
|
+
process.stderr.write(
|
|
56871
|
+
`Schema validation failed for team ${teamId}. Run 'agent-contracts validate' for details.
|
|
56872
|
+
`
|
|
56873
|
+
);
|
|
56874
|
+
exitWithError = true;
|
|
56875
|
+
continue;
|
|
56876
|
+
}
|
|
56877
|
+
const loadedBindings2 = await loadBindings(teamConfig.bindings);
|
|
56878
|
+
const result2 = await generateGuardrails({
|
|
56879
|
+
dsl: schemaResult2.data,
|
|
56880
|
+
config: resolvedConfigForTeam(config, teamConfig),
|
|
56881
|
+
loadedBindings: loadedBindings2,
|
|
56882
|
+
filterBindings: opts.binding,
|
|
56883
|
+
dryRun: opts.dryRun
|
|
56884
|
+
});
|
|
56885
|
+
const errors2 = result2.diagnostics.filter((d2) => d2.severity === "error");
|
|
56886
|
+
const warnings2 = result2.diagnostics.filter((d2) => d2.severity === "warning");
|
|
56887
|
+
const infos2 = result2.diagnostics.filter((d2) => d2.severity === "info");
|
|
56888
|
+
if (errors2.length > 0) {
|
|
56889
|
+
process.stderr.write(`Errors (team ${teamId}):
|
|
56890
|
+
`);
|
|
56891
|
+
for (const d2 of errors2) {
|
|
56892
|
+
process.stderr.write(` error [${d2.path}] ${d2.message}
|
|
56893
|
+
`);
|
|
56894
|
+
}
|
|
56895
|
+
exitWithError = true;
|
|
56896
|
+
}
|
|
56897
|
+
if (warnings2.length > 0 && !opts.quiet) {
|
|
56898
|
+
process.stderr.write(`Warnings (team ${teamId}):
|
|
56899
|
+
`);
|
|
56900
|
+
for (const d2 of warnings2) {
|
|
56901
|
+
process.stderr.write(` warning [${d2.path}] ${d2.message}
|
|
56902
|
+
`);
|
|
56903
|
+
}
|
|
56904
|
+
}
|
|
56905
|
+
if (infos2.length > 0 && !opts.quiet) {
|
|
56906
|
+
for (const d2 of infos2) {
|
|
56907
|
+
process.stderr.write(` info [${d2.path}] ${d2.message}
|
|
56908
|
+
`);
|
|
56909
|
+
}
|
|
56910
|
+
}
|
|
56911
|
+
if (!opts.quiet) {
|
|
56912
|
+
const action = opts.dryRun ? "Would generate" : "Generated";
|
|
56913
|
+
process.stdout.write(
|
|
56914
|
+
`${action} ${result2.outputFiles.length} file(s):
|
|
56915
|
+
`
|
|
56916
|
+
);
|
|
56917
|
+
for (const f2 of result2.outputFiles) {
|
|
56918
|
+
process.stdout.write(` ${f2}
|
|
56919
|
+
`);
|
|
56920
|
+
}
|
|
56921
|
+
}
|
|
56922
|
+
}
|
|
56923
|
+
if (exitWithError) process.exit(1);
|
|
56924
|
+
return;
|
|
56925
|
+
}
|
|
56459
56926
|
const resolved = await resolve4(config.dsl);
|
|
56460
56927
|
const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
56461
56928
|
const schemaResult = validateSchema(data);
|
|
@@ -56861,10 +57328,56 @@ function formatText(result) {
|
|
|
56861
57328
|
}
|
|
56862
57329
|
return lines.join("\n");
|
|
56863
57330
|
}
|
|
56864
|
-
var scoreCommand = new Command7("score").description("Calculate DSL completeness score").argument("[dir]", "Path to agent-contracts.yaml", DIR_DEFAULT4).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--format <format>", "Output format (text|json)", "text").option("--threshold <number>", "Minimum score (exit 1 if below)", void 0).action(
|
|
57331
|
+
var scoreCommand = new Command7("score").description("Calculate DSL completeness score").argument("[dir]", "Path to agent-contracts.yaml", DIR_DEFAULT4).option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json)", "text").option("--threshold <number>", "Minimum score (exit 1 if below)", void 0).action(
|
|
56865
57332
|
async (dir, opts) => {
|
|
56866
57333
|
try {
|
|
56867
57334
|
const config = await loadConfig(opts.config);
|
|
57335
|
+
if (config !== null && isMultiTeamConfig(config)) {
|
|
57336
|
+
const teamEntries = getTeamEntries(config, opts.team);
|
|
57337
|
+
let thresholdNum;
|
|
57338
|
+
if (opts.threshold !== void 0) {
|
|
57339
|
+
thresholdNum = parseInt(opts.threshold, 10);
|
|
57340
|
+
if (isNaN(thresholdNum)) {
|
|
57341
|
+
process.stderr.write(
|
|
57342
|
+
`Error: --threshold must be a number, got "${opts.threshold}"
|
|
57343
|
+
`
|
|
57344
|
+
);
|
|
57345
|
+
process.exit(1);
|
|
57346
|
+
}
|
|
57347
|
+
}
|
|
57348
|
+
let hasErrors = false;
|
|
57349
|
+
for (const [teamId, teamConfig] of teamEntries) {
|
|
57350
|
+
process.stdout.write(`
|
|
57351
|
+
--- Team: ${teamId} ---
|
|
57352
|
+
`);
|
|
57353
|
+
const resolved2 = await resolve4(teamConfig.dsl);
|
|
57354
|
+
const data2 = teamConfig.vars ? substituteVars(resolved2.data, teamConfig.vars) : resolved2.data;
|
|
57355
|
+
const schemaResult2 = validateSchema(data2);
|
|
57356
|
+
if (!schemaResult2.success) {
|
|
57357
|
+
const issues = schemaResult2.diagnostics.map((d2) => ` ${d2.path}: ${d2.message}`).join("\n");
|
|
57358
|
+
process.stderr.write(`Schema validation failed:
|
|
57359
|
+
${issues}
|
|
57360
|
+
`);
|
|
57361
|
+
hasErrors = true;
|
|
57362
|
+
continue;
|
|
57363
|
+
}
|
|
57364
|
+
const result2 = score(schemaResult2.data);
|
|
57365
|
+
if (opts.format === "json") {
|
|
57366
|
+
process.stdout.write(JSON.stringify(result2, null, 2) + "\n");
|
|
57367
|
+
} else {
|
|
57368
|
+
process.stdout.write(formatText(result2) + "\n");
|
|
57369
|
+
}
|
|
57370
|
+
if (thresholdNum !== void 0 && result2.overall < thresholdNum) {
|
|
57371
|
+
process.stderr.write(
|
|
57372
|
+
`Score ${result2.overall} is below threshold ${thresholdNum}
|
|
57373
|
+
`
|
|
57374
|
+
);
|
|
57375
|
+
hasErrors = true;
|
|
57376
|
+
}
|
|
57377
|
+
}
|
|
57378
|
+
if (hasErrors) process.exit(1);
|
|
57379
|
+
return;
|
|
57380
|
+
}
|
|
56868
57381
|
const dslPath = resolveDslPath(dir, DIR_DEFAULT4, config);
|
|
56869
57382
|
const resolved = await resolve4(dslPath);
|
|
56870
57383
|
const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
@@ -56909,7 +57422,7 @@ ${issues}
|
|
|
56909
57422
|
);
|
|
56910
57423
|
|
|
56911
57424
|
// src/cli/cli.ts
|
|
56912
|
-
var __dirname =
|
|
57425
|
+
var __dirname = dirname8(fileURLToPath(import.meta.url));
|
|
56913
57426
|
var pkg = JSON.parse(readFileSync(resolve7(__dirname, "../package.json"), "utf8"));
|
|
56914
57427
|
var program = new Command8();
|
|
56915
57428
|
program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version(pkg.version);
|