agent-contracts 0.19.3 → 0.19.5
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/cli-contract.yaml +56 -19
- package/dist/cli.js +73 -35
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +36 -11
- package/dist/index.js.map +1 -1
- package/dsl_base/agent-contracts.yaml +18 -0
- package/dsl_base/agent-runtime.config.yaml +2 -0
- package/dsl_base/agents/dsl-auditor.yaml +176 -0
- package/dsl_base/agents/dsl-designer.yaml +433 -0
- package/dsl_base/artifacts.yaml +73 -0
- package/dsl_base/audit-test.config.yaml +2 -0
- package/dsl_base/components.yaml +110 -0
- package/dsl_base/guardrail-policies.yaml +18 -0
- package/dsl_base/guardrails.yaml +46 -0
- package/dsl_base/handoff-types.yaml +182 -0
- package/dsl_base/tasks.yaml +269 -0
- package/dsl_base/tools.yaml +50 -0
- package/dsl_base/validations.yaml +66 -0
- package/dsl_base/workflow.yaml +91 -0
- package/package.json +3 -2
package/cli-contract.yaml
CHANGED
|
@@ -3,7 +3,7 @@ cliContracts: 0.1.0
|
|
|
3
3
|
|
|
4
4
|
info:
|
|
5
5
|
title: agent-contracts CLI
|
|
6
|
-
version: 0.19.
|
|
6
|
+
version: 0.19.4
|
|
7
7
|
description: >-
|
|
8
8
|
Declarative YAML DSL toolkit for defining, validating, and rendering
|
|
9
9
|
multi-agent development workflows. Provides static validation,
|
|
@@ -625,44 +625,81 @@ commandSets:
|
|
|
625
625
|
schema:
|
|
626
626
|
type: string
|
|
627
627
|
|
|
628
|
+
- name: fail-on
|
|
629
|
+
description: >-
|
|
630
|
+
Minimum finding severity that causes exit 10
|
|
631
|
+
(info|warning|error|critical).
|
|
632
|
+
valueName: level
|
|
633
|
+
schema:
|
|
634
|
+
type: string
|
|
635
|
+
enum: [info, warning, error, critical]
|
|
636
|
+
default: critical
|
|
637
|
+
|
|
638
|
+
- name: output
|
|
639
|
+
aliases: [o]
|
|
640
|
+
description: Write result to a file instead of stdout.
|
|
641
|
+
valueName: file
|
|
642
|
+
schema:
|
|
643
|
+
type: string
|
|
644
|
+
file:
|
|
645
|
+
mode: write
|
|
646
|
+
encoding: utf-8
|
|
647
|
+
|
|
648
|
+
- name: report-format
|
|
649
|
+
description: >-
|
|
650
|
+
Alias for --format. When both are specified, --report-format
|
|
651
|
+
takes precedence.
|
|
652
|
+
valueName: fmt
|
|
653
|
+
schema:
|
|
654
|
+
type: string
|
|
655
|
+
enum: [text, json, markdown]
|
|
656
|
+
default: text
|
|
657
|
+
|
|
628
658
|
exits:
|
|
629
659
|
'0':
|
|
630
|
-
description: No
|
|
660
|
+
description: Audit succeeded. No findings at or above --fail-on threshold.
|
|
631
661
|
stdout:
|
|
632
662
|
format: '{options.format}'
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
output. Format depends on --format option (text, json, or
|
|
636
|
-
markdown).
|
|
663
|
+
schema:
|
|
664
|
+
$ref: './dsl_base/components.yaml#/schemas/agent-audit-result'
|
|
637
665
|
|
|
638
666
|
'1':
|
|
639
|
-
description:
|
|
667
|
+
description: Unexpected error (invalid input, config error, or internal failure).
|
|
640
668
|
stderr:
|
|
641
669
|
format: text
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
670
|
+
|
|
671
|
+
'10':
|
|
672
|
+
description: Findings at or above --fail-on severity threshold detected.
|
|
645
673
|
stdout:
|
|
646
674
|
format: '{options.format}'
|
|
675
|
+
schema:
|
|
676
|
+
$ref: './dsl_base/components.yaml#/schemas/agent-audit-result'
|
|
677
|
+
stderr:
|
|
678
|
+
format: text
|
|
647
679
|
schemaNote: >-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
are valid structured data, not error messages.
|
|
680
|
+
Summary diagnostic on stderr. Structured findings are
|
|
681
|
+
emitted on stdout in the requested format.
|
|
651
682
|
|
|
652
|
-
'
|
|
653
|
-
description:
|
|
683
|
+
'11':
|
|
684
|
+
description: >-
|
|
685
|
+
Runtime dependency missing (agent-contracts-runtime not installed).
|
|
654
686
|
stderr:
|
|
655
687
|
format: text
|
|
656
688
|
|
|
657
|
-
'
|
|
658
|
-
description: LLM adapter error (API failure,
|
|
689
|
+
'12':
|
|
690
|
+
description: LLM provider or adapter error (API failure, auth error).
|
|
659
691
|
stderr:
|
|
660
692
|
format: text
|
|
661
693
|
|
|
662
694
|
x-agent:
|
|
663
695
|
riskLevel: medium
|
|
664
696
|
requiresConfirmation: false
|
|
665
|
-
idempotent:
|
|
697
|
+
idempotent: false
|
|
698
|
+
idempotentNote: >-
|
|
699
|
+
Safe to repeat (no persistent side effects beyond network calls),
|
|
700
|
+
but LLM inference is non-deterministic — identical inputs may
|
|
701
|
+
produce different findings, severity assignments, and
|
|
702
|
+
recommendation text across runs.
|
|
666
703
|
sideEffects:
|
|
667
704
|
- network
|
|
668
705
|
sideEffectNote: >-
|
|
@@ -671,7 +708,7 @@ commandSets:
|
|
|
671
708
|
cost and sends DSL content to the LLM provider.
|
|
672
709
|
safeDryRunOption: dry-run
|
|
673
710
|
expectedDurationMs: 120000
|
|
674
|
-
retryableExitCodes: [
|
|
711
|
+
retryableExitCodes: [12]
|
|
675
712
|
recommendedBeforeUse:
|
|
676
713
|
- Ensure agent-contracts.config.yaml exists with render targets.
|
|
677
714
|
- Run validate first to confirm DSL is valid.
|
package/dist/cli.js
CHANGED
|
@@ -49565,18 +49565,27 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
|
|
|
49565
49565
|
}
|
|
49566
49566
|
resolving.add(refValue);
|
|
49567
49567
|
const target = resolveJsonPointer(rootDoc, refValue);
|
|
49568
|
-
const
|
|
49568
|
+
const resolved = await resolveRefsDeep(
|
|
49569
49569
|
deepClone(target),
|
|
49570
49570
|
baseDir,
|
|
49571
49571
|
resolving,
|
|
49572
49572
|
rootDoc
|
|
49573
49573
|
);
|
|
49574
49574
|
resolving.delete(refValue);
|
|
49575
|
-
return
|
|
49575
|
+
return resolved;
|
|
49576
49576
|
}
|
|
49577
|
-
const
|
|
49577
|
+
const hashIdx = refValue.indexOf("#");
|
|
49578
|
+
const filePart = hashIdx >= 0 ? refValue.slice(0, hashIdx) : refValue;
|
|
49579
|
+
const fragment = hashIdx >= 0 ? refValue.slice(hashIdx) : null;
|
|
49580
|
+
const refTarget = resolve2(baseDir, filePart);
|
|
49578
49581
|
const s2 = await fsStat(refTarget).catch(() => null);
|
|
49579
49582
|
if (s2?.isDirectory()) {
|
|
49583
|
+
if (fragment) {
|
|
49584
|
+
throw new DslLoadError(
|
|
49585
|
+
`Cannot use JSON Pointer fragment with directory $ref: ${refValue}`,
|
|
49586
|
+
refTarget
|
|
49587
|
+
);
|
|
49588
|
+
}
|
|
49580
49589
|
if (resolving.has(refTarget)) {
|
|
49581
49590
|
throw new DslLoadError(
|
|
49582
49591
|
`Circular $ref detected: ${refTarget}`,
|
|
@@ -49599,14 +49608,24 @@ async function resolveRefsDeep(data, baseDir, resolving, rootDoc) {
|
|
|
49599
49608
|
}
|
|
49600
49609
|
resolving.add(refTarget);
|
|
49601
49610
|
const content = await readYaml(refTarget);
|
|
49602
|
-
const
|
|
49611
|
+
const fileRoot = fragment ? content : rootDoc;
|
|
49612
|
+
let fileData = await resolveRefsDeep(
|
|
49603
49613
|
content,
|
|
49604
49614
|
dirname2(refTarget),
|
|
49605
49615
|
resolving,
|
|
49606
|
-
|
|
49616
|
+
fileRoot
|
|
49607
49617
|
);
|
|
49608
49618
|
resolving.delete(refTarget);
|
|
49609
|
-
|
|
49619
|
+
if (fragment && fragment.startsWith("#/")) {
|
|
49620
|
+
if (!isRecord(fileData)) {
|
|
49621
|
+
throw new DslLoadError(
|
|
49622
|
+
`Cannot resolve fragment "${fragment}" in ${refTarget}: file content is not an object`,
|
|
49623
|
+
refTarget
|
|
49624
|
+
);
|
|
49625
|
+
}
|
|
49626
|
+
fileData = resolveJsonPointer(fileData, fragment);
|
|
49627
|
+
}
|
|
49628
|
+
return fileData;
|
|
49610
49629
|
}
|
|
49611
49630
|
let obj = data;
|
|
49612
49631
|
if (hasRefs(obj)) {
|
|
@@ -55898,6 +55917,7 @@ ${issues}
|
|
|
55898
55917
|
);
|
|
55899
55918
|
|
|
55900
55919
|
// src/cli/commands/audit.ts
|
|
55920
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
55901
55921
|
import { Command as Command8 } from "commander";
|
|
55902
55922
|
|
|
55903
55923
|
// src/auditor/context-builder.ts
|
|
@@ -56632,16 +56652,22 @@ function formatAuditResults(results, format2) {
|
|
|
56632
56652
|
}
|
|
56633
56653
|
return results.map((r3) => formatAuditResult(r3, format2)).join("\n\n");
|
|
56634
56654
|
}
|
|
56635
|
-
function computeExitCode(results) {
|
|
56655
|
+
function computeExitCode(results, failOn) {
|
|
56636
56656
|
for (const r3 of results) {
|
|
56637
56657
|
if (r3.status === "error") {
|
|
56638
|
-
if (r3.errorMessage?.includes("not installed")
|
|
56639
|
-
return
|
|
56658
|
+
if (r3.errorMessage?.includes("not installed")) return 11;
|
|
56659
|
+
if (r3.errorMessage?.includes("adapter") || r3.errorMessage?.includes("API")) return 12;
|
|
56660
|
+
return 1;
|
|
56640
56661
|
}
|
|
56641
56662
|
}
|
|
56663
|
+
const severityRank = { info: 0, warning: 1, error: 2, critical: 3 };
|
|
56664
|
+
const threshold = severityRank[failOn ?? "critical"] ?? 3;
|
|
56642
56665
|
for (const r3 of results) {
|
|
56643
|
-
if (r3.data?.critical_gaps
|
|
56644
|
-
|
|
56666
|
+
if (r3.data?.critical_gaps) {
|
|
56667
|
+
for (const gap of r3.data.critical_gaps) {
|
|
56668
|
+
const rank = severityRank[gap.severity ?? ""] ?? 0;
|
|
56669
|
+
if (rank >= threshold) return 10;
|
|
56670
|
+
}
|
|
56645
56671
|
}
|
|
56646
56672
|
}
|
|
56647
56673
|
return 0;
|
|
@@ -56659,13 +56685,13 @@ function parseAuditConfig(config) {
|
|
|
56659
56685
|
cache_dir: audit.cache_dir
|
|
56660
56686
|
};
|
|
56661
56687
|
}
|
|
56662
|
-
async function runAuditForDsl(dslPath, vars, configObj, auditType, opts) {
|
|
56688
|
+
async function runAuditForDsl(dslPath, vars, configObj, auditType, opts, failOn) {
|
|
56663
56689
|
const resolved = await resolve4(dslPath);
|
|
56664
56690
|
const data = vars ? substituteVars(resolved.data, vars) : resolved.data;
|
|
56665
56691
|
const schemaResult = validateSchema(data);
|
|
56666
56692
|
if (!schemaResult.success) {
|
|
56667
56693
|
process.stderr.write("Schema validation failed. Run 'agent-contracts validate' first.\n");
|
|
56668
|
-
return
|
|
56694
|
+
return { exitCode: 1, output: "" };
|
|
56669
56695
|
}
|
|
56670
56696
|
const auditConfig = parseAuditConfig(
|
|
56671
56697
|
configObj.audit
|
|
@@ -56678,17 +56704,18 @@ async function runAuditForDsl(dslPath, vars, configObj, auditType, opts) {
|
|
|
56678
56704
|
scope: opts.scope,
|
|
56679
56705
|
dryRun: opts.dryRun
|
|
56680
56706
|
});
|
|
56707
|
+
let output2;
|
|
56681
56708
|
if (opts.dryRun) {
|
|
56682
|
-
|
|
56683
|
-
|
|
56709
|
+
output2 = results.map(
|
|
56710
|
+
(r3) => `
|
|
56684
56711
|
--- Audit prompt: ${r3.auditType} ---
|
|
56685
|
-
|
|
56686
|
-
|
|
56687
|
-
|
|
56712
|
+
${r3.prompt}
|
|
56713
|
+
`
|
|
56714
|
+
).join("");
|
|
56688
56715
|
} else {
|
|
56689
|
-
|
|
56716
|
+
output2 = formatAuditResults(results, opts.format) + "\n";
|
|
56690
56717
|
}
|
|
56691
|
-
return computeExitCode(results);
|
|
56718
|
+
return { exitCode: computeExitCode(results, failOn), output: output2 };
|
|
56692
56719
|
}
|
|
56693
56720
|
const result = await runAudit(schemaResult.data, configObj, auditConfig, {
|
|
56694
56721
|
auditType,
|
|
@@ -56696,67 +56723,78 @@ async function runAuditForDsl(dslPath, vars, configObj, auditType, opts) {
|
|
|
56696
56723
|
scope: opts.scope,
|
|
56697
56724
|
dryRun: opts.dryRun
|
|
56698
56725
|
});
|
|
56726
|
+
let output;
|
|
56699
56727
|
if (opts.dryRun) {
|
|
56700
|
-
|
|
56728
|
+
output = result.prompt + "\n";
|
|
56701
56729
|
} else {
|
|
56702
|
-
|
|
56730
|
+
output = formatAuditResult(result, opts.format) + "\n";
|
|
56703
56731
|
}
|
|
56704
|
-
return computeExitCode([result]);
|
|
56732
|
+
return { exitCode: computeExitCode([result], failOn), output };
|
|
56705
56733
|
}
|
|
56706
|
-
var auditCommand = new Command8("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs").argument("[type]", `Audit type: ${AUDIT_TYPES.join(", ")}`, "all").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json|markdown)", "text").option("--scope <entities>", "Limit audit scope (e.g. agents:architect,implementer)").option("--dry-run", "Output the audit prompt without calling LLM", false).option("--adapter <name>", "SDK adapter to use (default from config)").option("--model <name>", "LLM model override").action(
|
|
56734
|
+
var auditCommand = new Command8("audit").description("Run LLM-based semantic audit on DSL definitions and generated outputs").argument("[type]", `Audit type: ${AUDIT_TYPES.join(", ")}`, "all").option("-c, --config <path>", "Path to agent-contracts.config.yaml").option("--team <id>", "Limit to one team (multi-team config only)").option("--format <format>", "Output format (text|json|markdown)", "text").option("--scope <entities>", "Limit audit scope (e.g. agents:architect,implementer)").option("--dry-run", "Output the audit prompt without calling LLM", false).option("--adapter <name>", "SDK adapter to use (default from config)").option("--model <name>", "LLM model override").option("--fail-on <level>", "Minimum severity that causes exit 10 (info|warning|error|critical)", "critical").option("-o, --output <file>", "Write result to a file instead of stdout").option("--report-format <fmt>", "Alias for --format (for cli-contracts standard conformance)").action(
|
|
56707
56735
|
async (type, opts) => {
|
|
56708
56736
|
if (!AUDIT_TYPES.includes(type)) {
|
|
56709
56737
|
process.stderr.write(
|
|
56710
56738
|
`Unknown audit type: "${type}". Use one of: ${AUDIT_TYPES.join(", ")}
|
|
56711
56739
|
`
|
|
56712
56740
|
);
|
|
56713
|
-
process.exit(
|
|
56741
|
+
process.exit(1);
|
|
56714
56742
|
}
|
|
56715
|
-
const format2 = opts.format;
|
|
56743
|
+
const format2 = opts.reportFormat ?? opts.format;
|
|
56716
56744
|
try {
|
|
56717
56745
|
const config = await loadConfig(opts.config);
|
|
56718
56746
|
if (!config) {
|
|
56719
56747
|
process.stderr.write(
|
|
56720
56748
|
"Error: agent-contracts.config.yaml not found. Use --config to specify path.\n"
|
|
56721
56749
|
);
|
|
56722
|
-
process.exit(
|
|
56750
|
+
process.exit(1);
|
|
56723
56751
|
}
|
|
56724
56752
|
if (isMultiTeamConfig(config)) {
|
|
56725
56753
|
const teamEntries = getTeamEntries(config, opts.team);
|
|
56726
56754
|
let maxExit = 0;
|
|
56755
|
+
const allOutput = [];
|
|
56727
56756
|
for (const [teamId, teamConfig] of teamEntries) {
|
|
56728
56757
|
process.stderr.write(`
|
|
56729
56758
|
--- Team: ${teamId} ---
|
|
56730
56759
|
`);
|
|
56731
|
-
const
|
|
56760
|
+
const result2 = await runAuditForDsl(
|
|
56732
56761
|
teamConfig.dsl,
|
|
56733
56762
|
teamConfig.vars,
|
|
56734
56763
|
config,
|
|
56735
56764
|
type,
|
|
56736
|
-
{ format: format2, scope: opts.scope, dryRun: opts.dryRun, adapter: opts.adapter, model: opts.model }
|
|
56765
|
+
{ format: format2, scope: opts.scope, dryRun: opts.dryRun, adapter: opts.adapter, model: opts.model },
|
|
56766
|
+
opts.failOn
|
|
56737
56767
|
);
|
|
56738
|
-
|
|
56768
|
+
process.stdout.write(result2.output);
|
|
56769
|
+
allOutput.push(result2.output);
|
|
56770
|
+
if (result2.exitCode > maxExit) maxExit = result2.exitCode;
|
|
56739
56771
|
}
|
|
56772
|
+
if (opts.output) writeFileSync2(opts.output, allOutput.join(""), "utf8");
|
|
56740
56773
|
process.exit(maxExit);
|
|
56741
56774
|
}
|
|
56742
|
-
const
|
|
56775
|
+
const result = await runAuditForDsl(
|
|
56743
56776
|
config.dsl,
|
|
56744
56777
|
config.vars,
|
|
56745
56778
|
config,
|
|
56746
56779
|
type,
|
|
56747
|
-
{ format: format2, scope: opts.scope, dryRun: opts.dryRun, adapter: opts.adapter, model: opts.model }
|
|
56780
|
+
{ format: format2, scope: opts.scope, dryRun: opts.dryRun, adapter: opts.adapter, model: opts.model },
|
|
56781
|
+
opts.failOn
|
|
56748
56782
|
);
|
|
56749
|
-
process.
|
|
56783
|
+
process.stdout.write(result.output);
|
|
56784
|
+
if (opts.output) writeFileSync2(opts.output, result.output, "utf8");
|
|
56785
|
+
process.exit(result.exitCode);
|
|
56750
56786
|
} catch (err) {
|
|
56751
56787
|
if (err instanceof ConfigLoadError) {
|
|
56752
56788
|
process.stderr.write(`Config error: ${err.message}
|
|
56753
56789
|
`);
|
|
56754
|
-
process.exit(
|
|
56790
|
+
process.exit(1);
|
|
56755
56791
|
}
|
|
56756
56792
|
const msg = err instanceof Error ? err.message : String(err);
|
|
56757
56793
|
process.stderr.write(`Error: ${msg}
|
|
56758
56794
|
`);
|
|
56759
|
-
|
|
56795
|
+
if (msg.includes("not installed")) process.exit(11);
|
|
56796
|
+
if (msg.includes("adapter") || msg.includes("API")) process.exit(12);
|
|
56797
|
+
process.exit(1);
|
|
56760
56798
|
}
|
|
56761
56799
|
}
|
|
56762
56800
|
);
|