agent-contracts 0.14.0 → 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 +65 -3
- package/dist/cli.js +592 -73
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +85 -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
|
|
@@ -50479,6 +50479,12 @@ var AgentSchema = z.object({
|
|
|
50479
50479
|
rules: z.array(RuleSchema).optional(),
|
|
50480
50480
|
anti_patterns: z.array(z.string()).optional(),
|
|
50481
50481
|
escalation_criteria: z.array(EscalationCriterionSchema).optional(),
|
|
50482
|
+
sections: z.array(
|
|
50483
|
+
z.object({
|
|
50484
|
+
title: z.string(),
|
|
50485
|
+
content: z.string()
|
|
50486
|
+
})
|
|
50487
|
+
).optional(),
|
|
50482
50488
|
prerequisites: z.array(PrerequisiteSchema).optional(),
|
|
50483
50489
|
guardrails: z.array(z.string()).optional()
|
|
50484
50490
|
}).passthrough();
|
|
@@ -50955,13 +50961,51 @@ var RenderTargetSchema = z15.object({
|
|
|
50955
50961
|
},
|
|
50956
50962
|
{ message: "include/exclude cannot be used with context: system" }
|
|
50957
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
|
+
});
|
|
50958
50972
|
var AgentContractsConfigSchema = z15.object({
|
|
50959
|
-
dsl: z15.string(),
|
|
50973
|
+
dsl: z15.string().optional(),
|
|
50960
50974
|
vars: z15.record(z15.string(), z15.string()).optional(),
|
|
50961
50975
|
renders: z15.array(RenderTargetSchema).default([]),
|
|
50962
50976
|
bindings: z15.array(z15.string()).default([]),
|
|
50963
50977
|
active_guardrail_policy: z15.string().optional(),
|
|
50964
|
-
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
|
+
}
|
|
50965
51009
|
});
|
|
50966
51010
|
|
|
50967
51011
|
// src/config/loader.ts
|
|
@@ -50982,6 +51026,27 @@ async function fileExists(filePath) {
|
|
|
50982
51026
|
return false;
|
|
50983
51027
|
}
|
|
50984
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
|
+
}
|
|
50985
51050
|
async function loadConfig(configPath) {
|
|
50986
51051
|
const isExplicit = configPath !== void 0;
|
|
50987
51052
|
const targetPath = resolve(configPath ?? DEFAULT_CONFIG_NAME);
|
|
@@ -51024,14 +51089,27 @@ ${issues}`,
|
|
|
51024
51089
|
}
|
|
51025
51090
|
const configDir = dirname(targetPath);
|
|
51026
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
|
+
}
|
|
51027
51109
|
return {
|
|
51028
51110
|
dsl: resolve(configDir, config.dsl),
|
|
51029
51111
|
vars: config.vars,
|
|
51030
|
-
renders
|
|
51031
|
-
...r3,
|
|
51032
|
-
template: resolve(configDir, r3.template),
|
|
51033
|
-
output: resolve(configDir, r3.output)
|
|
51034
|
-
})),
|
|
51112
|
+
renders,
|
|
51035
51113
|
configDir,
|
|
51036
51114
|
bindings: (config.bindings ?? []).map((b3) => resolve(configDir, b3)),
|
|
51037
51115
|
activeGuardrailPolicy: config.active_guardrail_policy,
|
|
@@ -51853,28 +51931,79 @@ ${issues}`,
|
|
|
51853
51931
|
|
|
51854
51932
|
// src/cli/commands/resolve.ts
|
|
51855
51933
|
import { stringify } from "yaml";
|
|
51856
|
-
|
|
51857
|
-
|
|
51858
|
-
|
|
51859
|
-
|
|
51860
|
-
|
|
51861
|
-
|
|
51862
|
-
|
|
51863
|
-
|
|
51864
|
-
|
|
51865
|
-
|
|
51866
|
-
if (
|
|
51867
|
-
|
|
51868
|
-
|
|
51869
|
-
|
|
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
|
+
);
|
|
51870
51948
|
}
|
|
51871
|
-
|
|
51872
|
-
|
|
51873
|
-
|
|
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}
|
|
51874
52002
|
`);
|
|
51875
|
-
|
|
52003
|
+
process.exit(1);
|
|
52004
|
+
}
|
|
51876
52005
|
}
|
|
51877
|
-
|
|
52006
|
+
);
|
|
51878
52007
|
|
|
51879
52008
|
// src/cli/commands/validate.ts
|
|
51880
52009
|
import { Command as Command2 } from "commander";
|
|
@@ -52954,44 +53083,88 @@ function formatDiagnostics(diagnostics, options) {
|
|
|
52954
53083
|
|
|
52955
53084
|
// src/cli/commands/validate.ts
|
|
52956
53085
|
var DIR_DEFAULT2 = "agent-contracts.yaml";
|
|
52957
|
-
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(
|
|
52958
|
-
|
|
52959
|
-
|
|
52960
|
-
|
|
52961
|
-
|
|
52962
|
-
|
|
52963
|
-
|
|
52964
|
-
|
|
52965
|
-
|
|
52966
|
-
|
|
52967
|
-
|
|
52968
|
-
|
|
52969
|
-
|
|
52970
|
-
|
|
52971
|
-
|
|
52972
|
-
|
|
52973
|
-
|
|
52974
|
-
|
|
52975
|
-
|
|
52976
|
-
|
|
52977
|
-
|
|
52978
|
-
|
|
52979
|
-
|
|
52980
|
-
|
|
52981
|
-
|
|
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");
|
|
52982
53142
|
process.exit(1);
|
|
52983
53143
|
}
|
|
52984
|
-
|
|
52985
|
-
|
|
52986
|
-
|
|
52987
|
-
|
|
52988
|
-
|
|
52989
|
-
|
|
52990
|
-
|
|
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}
|
|
52991
53163
|
`);
|
|
52992
|
-
|
|
53164
|
+
process.exit(1);
|
|
53165
|
+
}
|
|
52993
53166
|
}
|
|
52994
|
-
|
|
53167
|
+
);
|
|
52995
53168
|
|
|
52996
53169
|
// src/cli/commands/lint.ts
|
|
52997
53170
|
import { Command as Command3 } from "commander";
|
|
@@ -54389,10 +54562,63 @@ async function spectralLint(dslObject) {
|
|
|
54389
54562
|
|
|
54390
54563
|
// src/cli/commands/lint.ts
|
|
54391
54564
|
var DIR_DEFAULT3 = "agent-contracts.yaml";
|
|
54392
|
-
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(
|
|
54393
54566
|
async (dir, opts) => {
|
|
54394
54567
|
try {
|
|
54395
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
|
+
}
|
|
54396
54622
|
const dslPath = resolveDslPath(dir, DIR_DEFAULT3, config);
|
|
54397
54623
|
const resolved = await resolve4(dslPath);
|
|
54398
54624
|
const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
@@ -55826,7 +56052,7 @@ async function checkDriftFromConfig(dsl, renderTargets, options) {
|
|
|
55826
56052
|
}
|
|
55827
56053
|
|
|
55828
56054
|
// src/cli/commands/render.ts
|
|
55829
|
-
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(
|
|
55830
56056
|
async (opts) => {
|
|
55831
56057
|
try {
|
|
55832
56058
|
const config = await loadConfig(opts.config);
|
|
@@ -55836,6 +56062,68 @@ var renderCommand = new Command4("render").description("Render resolved DSL with
|
|
|
55836
56062
|
);
|
|
55837
56063
|
process.exit(1);
|
|
55838
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
|
+
}
|
|
55839
56127
|
const resolved = await resolve4(config.dsl);
|
|
55840
56128
|
const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
55841
56129
|
const schemaResult = validateSchema(data);
|
|
@@ -55901,7 +56189,9 @@ var renderCommand = new Command4("render").description("Render resolved DSL with
|
|
|
55901
56189
|
|
|
55902
56190
|
// src/cli/commands/check.ts
|
|
55903
56191
|
import { Command as Command5 } from "commander";
|
|
55904
|
-
|
|
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(
|
|
55905
56195
|
async (opts) => {
|
|
55906
56196
|
let hasErrors = false;
|
|
55907
56197
|
try {
|
|
@@ -55912,6 +56202,111 @@ var checkCommand = new Command5("check").description("Run full pipeline: resolve
|
|
|
55912
56202
|
);
|
|
55913
56203
|
process.exit(1);
|
|
55914
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
|
+
}
|
|
55915
56310
|
const resolved = await resolve4(config.dsl);
|
|
55916
56311
|
const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
55917
56312
|
const schemaResult = validateSchema(data);
|
|
@@ -55999,7 +56394,7 @@ import { Command as Command6 } from "commander";
|
|
|
55999
56394
|
|
|
56000
56395
|
// src/guardrail-generator/generator.ts
|
|
56001
56396
|
import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2, chmod, unlink as unlink2, copyFile } from "fs/promises";
|
|
56002
|
-
import { resolve as resolve6, dirname as
|
|
56397
|
+
import { resolve as resolve6, dirname as dirname7 } from "path";
|
|
56003
56398
|
import Handlebars2 from "handlebars";
|
|
56004
56399
|
import YAML from "yaml";
|
|
56005
56400
|
|
|
@@ -56226,7 +56621,7 @@ async function generateGuardrails(options) {
|
|
|
56226
56621
|
const sourcePath = resolve6(config.configDir, outputDef.source);
|
|
56227
56622
|
if (!dryRun) {
|
|
56228
56623
|
try {
|
|
56229
|
-
await mkdir2(
|
|
56624
|
+
await mkdir2(dirname7(targetPath), { recursive: true });
|
|
56230
56625
|
await copyFile(sourcePath, targetPath);
|
|
56231
56626
|
if (outputDef.executable) {
|
|
56232
56627
|
await chmod(targetPath, 493);
|
|
@@ -56310,7 +56705,7 @@ async function generateGuardrails(options) {
|
|
|
56310
56705
|
}
|
|
56311
56706
|
const output = isPatch && !dryRun ? await applyPatch(groupTarget, rendered, outputDef) : rendered;
|
|
56312
56707
|
if (!dryRun) {
|
|
56313
|
-
await mkdir2(
|
|
56708
|
+
await mkdir2(dirname7(groupTarget), { recursive: true });
|
|
56314
56709
|
await writeFile2(groupTarget, output, "utf8");
|
|
56315
56710
|
if (outputDef.executable) {
|
|
56316
56711
|
await chmod(groupTarget, 493);
|
|
@@ -56331,7 +56726,7 @@ async function generateGuardrails(options) {
|
|
|
56331
56726
|
} else {
|
|
56332
56727
|
const output = isPatch && !dryRun ? await applyPatch(targetPath, rendered, outputDef) : rendered;
|
|
56333
56728
|
if (!dryRun) {
|
|
56334
|
-
await mkdir2(
|
|
56729
|
+
await mkdir2(dirname7(targetPath), { recursive: true });
|
|
56335
56730
|
await writeFile2(targetPath, output, "utf8");
|
|
56336
56731
|
if (outputDef.executable) {
|
|
56337
56732
|
await chmod(targetPath, 493);
|
|
@@ -56384,7 +56779,7 @@ async function generateGuardrails(options) {
|
|
|
56384
56779
|
continue;
|
|
56385
56780
|
}
|
|
56386
56781
|
if (!dryRun) {
|
|
56387
|
-
await mkdir2(
|
|
56782
|
+
await mkdir2(dirname7(outputPath), { recursive: true });
|
|
56388
56783
|
await writeFile2(outputPath, rendered, "utf8");
|
|
56389
56784
|
if (renderTarget.executable) {
|
|
56390
56785
|
await chmod(outputPath, 493);
|
|
@@ -56414,7 +56809,7 @@ async function generateGuardrails(options) {
|
|
|
56414
56809
|
continue;
|
|
56415
56810
|
}
|
|
56416
56811
|
if (!dryRun) {
|
|
56417
|
-
await mkdir2(
|
|
56812
|
+
await mkdir2(dirname7(outputPath), { recursive: true });
|
|
56418
56813
|
await writeFile2(outputPath, rendered, "utf8");
|
|
56419
56814
|
if (renderTarget.executable) {
|
|
56420
56815
|
await chmod(outputPath, 493);
|
|
@@ -56435,7 +56830,18 @@ function resolveBindingRenderOutputPath(output, paths) {
|
|
|
56435
56830
|
}
|
|
56436
56831
|
|
|
56437
56832
|
// src/cli/commands/generate-guardrails.ts
|
|
56438
|
-
|
|
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(
|
|
56439
56845
|
async (type, opts) => {
|
|
56440
56846
|
if (type !== "guardrails") {
|
|
56441
56847
|
process.stderr.write(`Unknown generate type: ${type}
|
|
@@ -56450,6 +56856,73 @@ var generateGuardrailsCommand = new Command6("generate").description("Generate g
|
|
|
56450
56856
|
);
|
|
56451
56857
|
process.exit(1);
|
|
56452
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
|
+
}
|
|
56453
56926
|
const resolved = await resolve4(config.dsl);
|
|
56454
56927
|
const data = config.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
56455
56928
|
const schemaResult = validateSchema(data);
|
|
@@ -56855,10 +57328,56 @@ function formatText(result) {
|
|
|
56855
57328
|
}
|
|
56856
57329
|
return lines.join("\n");
|
|
56857
57330
|
}
|
|
56858
|
-
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(
|
|
56859
57332
|
async (dir, opts) => {
|
|
56860
57333
|
try {
|
|
56861
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
|
+
}
|
|
56862
57381
|
const dslPath = resolveDslPath(dir, DIR_DEFAULT4, config);
|
|
56863
57382
|
const resolved = await resolve4(dslPath);
|
|
56864
57383
|
const data = config?.vars ? substituteVars(resolved.data, config.vars) : resolved.data;
|
|
@@ -56903,7 +57422,7 @@ ${issues}
|
|
|
56903
57422
|
);
|
|
56904
57423
|
|
|
56905
57424
|
// src/cli/cli.ts
|
|
56906
|
-
var __dirname =
|
|
57425
|
+
var __dirname = dirname8(fileURLToPath(import.meta.url));
|
|
56907
57426
|
var pkg = JSON.parse(readFileSync(resolve7(__dirname, "../package.json"), "utf8"));
|
|
56908
57427
|
var program = new Command8();
|
|
56909
57428
|
program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version(pkg.version);
|