agent-contracts 0.11.3 → 0.11.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/README.md +79 -11
- package/dist/cli.js +163 -45
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +34 -4
- package/dist/index.js +117 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -221,12 +221,13 @@ A **Workflow** defines a phase-level execution sequence:
|
|
|
221
221
|
* `entry_conditions`
|
|
222
222
|
* `trigger`
|
|
223
223
|
* `external_participants` — actors/participants outside the agent system (e.g., User, external advisory)
|
|
224
|
-
* ordered steps (
|
|
224
|
+
* ordered steps (delegate, gate, validation, decision)
|
|
225
225
|
|
|
226
226
|
Workflow steps support additional properties:
|
|
227
227
|
|
|
228
228
|
* `group` — consecutive steps with the same group are rendered as `par` (parallel) blocks in sequence diagrams
|
|
229
|
-
* `retry` (
|
|
229
|
+
* `retry` (delegate steps) — defines a conditional retry loop with `condition`, `fix_task`, and optional `revalidate_task`
|
|
230
|
+
* `routing_key` (decision steps) — the field that determines branch selection. The legacy field `on` is still accepted but deprecated due to YAML 1.1 reserved word collision
|
|
230
231
|
|
|
231
232
|
### Guardrail
|
|
232
233
|
|
|
@@ -305,6 +306,9 @@ Design regressions become testable.
|
|
|
305
306
|
* **Software bindings** (DI) for tool-specific guardrail implementation (Cursor, Git, GitHub)
|
|
306
307
|
* **Guardrail generation** from DSL + policy + bindings via `generate guardrails`
|
|
307
308
|
* **Flexible file splitting** via `$ref` (replacement), `$refs` (import + deep-merge), and JSON Pointer `$ref` (in-document)
|
|
309
|
+
* **YAML safety linting** for reserved word collision detection across YAML 1.1/1.2
|
|
310
|
+
* **`x-extensions` declarations** for documenting project-specific custom extension fields
|
|
311
|
+
* **`resolve --expand-defaults`** to materialize all Zod schema defaults in output
|
|
308
312
|
* **JSON Schema for editor support and external tooling**
|
|
309
313
|
* **CI-friendly workflow checks**
|
|
310
314
|
|
|
@@ -342,6 +346,16 @@ guardrails: {}
|
|
|
342
346
|
guardrail_policies: {}
|
|
343
347
|
components:
|
|
344
348
|
schemas: {}
|
|
349
|
+
|
|
350
|
+
# Optional: declare project-specific x-* extensions
|
|
351
|
+
x-extensions:
|
|
352
|
+
x-flags:
|
|
353
|
+
type: array
|
|
354
|
+
items: string
|
|
355
|
+
description: "CLI flags for tool commands"
|
|
356
|
+
x-check-script:
|
|
357
|
+
type: string
|
|
358
|
+
description: "Path to hook check script"
|
|
345
359
|
````
|
|
346
360
|
|
|
347
361
|
This makes definitions easy to merge, extend, and reference by stable identifiers.
|
|
@@ -572,6 +586,23 @@ tasks:
|
|
|
572
586
|
`x-` prefixed custom properties work at any nesting level — including inside
|
|
573
587
|
`execution_steps`, `rules`, `workflow.steps`, and other nested objects.
|
|
574
588
|
|
|
589
|
+
### `x-extensions` declarations
|
|
590
|
+
|
|
591
|
+
Projects can optionally declare their custom `x-*` extension fields in the DSL using `x-extensions`. This makes extensions discoverable and self-documenting:
|
|
592
|
+
|
|
593
|
+
````yaml
|
|
594
|
+
x-extensions:
|
|
595
|
+
x-flags:
|
|
596
|
+
type: array
|
|
597
|
+
items: string
|
|
598
|
+
description: "CLI flags for tool commands"
|
|
599
|
+
x-check-script:
|
|
600
|
+
type: string
|
|
601
|
+
description: "Path to hook check script"
|
|
602
|
+
````
|
|
603
|
+
|
|
604
|
+
Each key must start with `x-` (validated at schema level). The `type`, `items`, and `description` fields describe the expected shape. This declaration is informational today; future versions may validate `x-*` field values against their declared schemas.
|
|
605
|
+
|
|
575
606
|
---
|
|
576
607
|
|
|
577
608
|
## Example: Artifact definition
|
|
@@ -602,21 +633,20 @@ workflow:
|
|
|
602
633
|
- User story or feature request received
|
|
603
634
|
trigger: "User invokes /speckit.specify or asks to create a feature spec."
|
|
604
635
|
steps:
|
|
605
|
-
- type:
|
|
606
|
-
handoff_kind: delegation
|
|
636
|
+
- type: delegate
|
|
607
637
|
task: specify-feature
|
|
608
638
|
from_agent: main-architect
|
|
609
639
|
- type: validation
|
|
610
|
-
|
|
640
|
+
validation: spec-semantic-review
|
|
611
641
|
- type: decision
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
- label: revise
|
|
617
|
-
retry_from_step: 0
|
|
642
|
+
routing_key: evidence-gate-verdict.verdict
|
|
643
|
+
branches:
|
|
644
|
+
PASS: [plan]
|
|
645
|
+
REVISE: [specify-feature]
|
|
618
646
|
````
|
|
619
647
|
|
|
648
|
+
Decision steps use `routing_key` to specify the field that determines branching. The legacy `on` field is still accepted but deprecated — see [YAML safety](#yaml-safety) below.
|
|
649
|
+
|
|
620
650
|
---
|
|
621
651
|
|
|
622
652
|
## Example: Handoff type definition
|
|
@@ -819,10 +849,19 @@ npx agent-contracts
|
|
|
819
849
|
The `[path]` argument defaults to `agent-contracts.yaml` in the current directory.
|
|
820
850
|
If `-c` / `--config` is specified, the DSL path from the config file is used.
|
|
821
851
|
|
|
852
|
+
#### `resolve` options
|
|
853
|
+
|
|
854
|
+
| Option | Description |
|
|
855
|
+
|--------|-------------|
|
|
856
|
+
| `--format <text\|json>` | Output format (default: `text`) |
|
|
857
|
+
| `--expand-defaults` | Expand all Zod default values in output. Fields like `required_validations: []`, `tags: []`, and `can_read_artifacts: []` are written explicitly instead of being silently applied by schema defaults. |
|
|
858
|
+
| `-c, --config <path>` | Path to `agent-contracts.config.yaml` |
|
|
859
|
+
|
|
822
860
|
### Common usage
|
|
823
861
|
|
|
824
862
|
````bash
|
|
825
863
|
agent-contracts resolve
|
|
864
|
+
agent-contracts resolve --expand-defaults --format json
|
|
826
865
|
agent-contracts validate
|
|
827
866
|
agent-contracts lint --strict
|
|
828
867
|
agent-contracts render -c agent-contracts.config.yaml
|
|
@@ -1153,6 +1192,34 @@ Checks:
|
|
|
1153
1192
|
|
|
1154
1193
|
Custom properties with `x-` prefix are allowed on any object in the DSL — top-level entities (agents, tasks, artifacts, …), nested objects (rules, execution steps, workflow steps, …), and the root DSL itself.
|
|
1155
1194
|
|
|
1195
|
+
### YAML safety
|
|
1196
|
+
|
|
1197
|
+
The DSL is expressed in YAML, which introduces risks from YAML 1.1's implicit type coercion. The `yaml-reserved-key-safety` lint rule warns when reserved words appear in positions that may be misinterpreted by non-1.2 parsers.
|
|
1198
|
+
|
|
1199
|
+
The most notable case is the `on` field in decision steps. In YAML 1.1, bare `on` as a mapping key is interpreted as boolean `true`. While `agent-contracts` uses a YAML 1.2 parser internally, DSL consumers (CI tools, editors, other parsers) may use YAML 1.1 parsers.
|
|
1200
|
+
|
|
1201
|
+
To address this:
|
|
1202
|
+
|
|
1203
|
+
* Decision steps now support `routing_key` as the preferred field name (replacing `on`)
|
|
1204
|
+
* The legacy `on` field is still accepted for backward compatibility but triggers a lint warning
|
|
1205
|
+
* Branch keys like `yes`, `no`, `true`, `false` also trigger warnings
|
|
1206
|
+
|
|
1207
|
+
````yaml
|
|
1208
|
+
# Preferred — safe across all YAML versions
|
|
1209
|
+
- type: decision
|
|
1210
|
+
routing_key: evidence-gate-verdict.verdict
|
|
1211
|
+
branches:
|
|
1212
|
+
PASS: [release]
|
|
1213
|
+
FAIL: [fix-violations]
|
|
1214
|
+
|
|
1215
|
+
# Deprecated — works but triggers yaml-reserved-key-safety warning
|
|
1216
|
+
- type: decision
|
|
1217
|
+
on: evidence-gate-verdict.verdict
|
|
1218
|
+
branches:
|
|
1219
|
+
PASS: [release]
|
|
1220
|
+
FAIL: [fix-violations]
|
|
1221
|
+
````
|
|
1222
|
+
|
|
1156
1223
|
### Reference integrity
|
|
1157
1224
|
|
|
1158
1225
|
Checks:
|
|
@@ -1174,6 +1241,7 @@ Checks:
|
|
|
1174
1241
|
* prerequisite readability
|
|
1175
1242
|
* artifact ownership — `produces_artifact`/`reads_artifact` in execution steps vs. artifact producers/editors/consumers
|
|
1176
1243
|
* tool commands — `commands[].reads`/`commands[].writes` reference valid artifacts and align with `output_artifacts`
|
|
1244
|
+
* YAML safety — warns when YAML 1.1 reserved words (`on`, `yes`, `no`, `true`, `false`, etc.) are used in positions where they may be misinterpreted by non-1.2 parsers
|
|
1177
1245
|
* naming/style issues through Spectral rules
|
|
1178
1246
|
|
|
1179
1247
|
---
|
package/dist/cli.js
CHANGED
|
@@ -159,11 +159,11 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
159
159
|
}
|
|
160
160
|
function __awaiter(thisArg, _arguments, P2, generator) {
|
|
161
161
|
function adopt(value) {
|
|
162
|
-
return value instanceof P2 ? value : new P2(function(
|
|
163
|
-
|
|
162
|
+
return value instanceof P2 ? value : new P2(function(resolve8) {
|
|
163
|
+
resolve8(value);
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
|
-
return new (P2 || (P2 = Promise))(function(
|
|
166
|
+
return new (P2 || (P2 = Promise))(function(resolve8, reject) {
|
|
167
167
|
function fulfilled(value) {
|
|
168
168
|
try {
|
|
169
169
|
step(generator.next(value));
|
|
@@ -179,7 +179,7 @@ function __awaiter(thisArg, _arguments, P2, generator) {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
function step(result) {
|
|
182
|
-
result.done ?
|
|
182
|
+
result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
183
183
|
}
|
|
184
184
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
185
185
|
});
|
|
@@ -370,14 +370,14 @@ function __asyncValues(o3) {
|
|
|
370
370
|
}, i3);
|
|
371
371
|
function verb(n3) {
|
|
372
372
|
i3[n3] = o3[n3] && function(v2) {
|
|
373
|
-
return new Promise(function(
|
|
374
|
-
v2 = o3[n3](v2), settle(
|
|
373
|
+
return new Promise(function(resolve8, reject) {
|
|
374
|
+
v2 = o3[n3](v2), settle(resolve8, reject, v2.done, v2.value);
|
|
375
375
|
});
|
|
376
376
|
};
|
|
377
377
|
}
|
|
378
|
-
function settle(
|
|
378
|
+
function settle(resolve8, reject, d2, v2) {
|
|
379
379
|
Promise.resolve(v2).then(function(v3) {
|
|
380
|
-
|
|
380
|
+
resolve8({ value: v3, done: d2 });
|
|
381
381
|
}, reject);
|
|
382
382
|
}
|
|
383
383
|
}
|
|
@@ -13033,11 +13033,11 @@ function __metadata2(metadataKey, metadataValue) {
|
|
|
13033
13033
|
}
|
|
13034
13034
|
function __awaiter2(thisArg, _arguments, P2, generator) {
|
|
13035
13035
|
function adopt(value) {
|
|
13036
|
-
return value instanceof P2 ? value : new P2(function(
|
|
13037
|
-
|
|
13036
|
+
return value instanceof P2 ? value : new P2(function(resolve8) {
|
|
13037
|
+
resolve8(value);
|
|
13038
13038
|
});
|
|
13039
13039
|
}
|
|
13040
|
-
return new (P2 || (P2 = Promise))(function(
|
|
13040
|
+
return new (P2 || (P2 = Promise))(function(resolve8, reject) {
|
|
13041
13041
|
function fulfilled(value) {
|
|
13042
13042
|
try {
|
|
13043
13043
|
step(generator.next(value));
|
|
@@ -13053,7 +13053,7 @@ function __awaiter2(thisArg, _arguments, P2, generator) {
|
|
|
13053
13053
|
}
|
|
13054
13054
|
}
|
|
13055
13055
|
function step(result) {
|
|
13056
|
-
result.done ?
|
|
13056
|
+
result.done ? resolve8(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
13057
13057
|
}
|
|
13058
13058
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
13059
13059
|
});
|
|
@@ -13231,14 +13231,14 @@ function __asyncValues2(o3) {
|
|
|
13231
13231
|
}, i3);
|
|
13232
13232
|
function verb(n3) {
|
|
13233
13233
|
i3[n3] = o3[n3] && function(v2) {
|
|
13234
|
-
return new Promise(function(
|
|
13235
|
-
v2 = o3[n3](v2), settle(
|
|
13234
|
+
return new Promise(function(resolve8, reject) {
|
|
13235
|
+
v2 = o3[n3](v2), settle(resolve8, reject, v2.done, v2.value);
|
|
13236
13236
|
});
|
|
13237
13237
|
};
|
|
13238
13238
|
}
|
|
13239
|
-
function settle(
|
|
13239
|
+
function settle(resolve8, reject, d2, v2) {
|
|
13240
13240
|
Promise.resolve(v2).then(function(v3) {
|
|
13241
|
-
|
|
13241
|
+
resolve8({ value: v3, done: d2 });
|
|
13242
13242
|
}, reject);
|
|
13243
13243
|
}
|
|
13244
13244
|
}
|
|
@@ -15152,7 +15152,7 @@ function consumeBody() {
|
|
|
15152
15152
|
let accum = [];
|
|
15153
15153
|
let accumBytes = 0;
|
|
15154
15154
|
let abort = false;
|
|
15155
|
-
return new Body.Promise(function(
|
|
15155
|
+
return new Body.Promise(function(resolve8, reject) {
|
|
15156
15156
|
let resTimeout;
|
|
15157
15157
|
if (_this4.timeout) {
|
|
15158
15158
|
resTimeout = setTimeout(function() {
|
|
@@ -15186,7 +15186,7 @@ function consumeBody() {
|
|
|
15186
15186
|
}
|
|
15187
15187
|
clearTimeout(resTimeout);
|
|
15188
15188
|
try {
|
|
15189
|
-
|
|
15189
|
+
resolve8(Buffer.concat(accum, accumBytes));
|
|
15190
15190
|
} catch (err) {
|
|
15191
15191
|
reject(new FetchError(`Could not create Buffer from response body for ${_this4.url}: ${err.message}`, "system", err));
|
|
15192
15192
|
}
|
|
@@ -15449,7 +15449,7 @@ function fetch(url, opts) {
|
|
|
15449
15449
|
throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
|
|
15450
15450
|
}
|
|
15451
15451
|
Body.Promise = fetch.Promise;
|
|
15452
|
-
return new fetch.Promise(function(
|
|
15452
|
+
return new fetch.Promise(function(resolve8, reject) {
|
|
15453
15453
|
const request = new Request(url, opts);
|
|
15454
15454
|
const options = getNodeRequestOptions(request);
|
|
15455
15455
|
const send = (options.protocol === "https:" ? https : http).request;
|
|
@@ -15582,7 +15582,7 @@ function fetch(url, opts) {
|
|
|
15582
15582
|
requestOpts.body = void 0;
|
|
15583
15583
|
requestOpts.headers.delete("content-length");
|
|
15584
15584
|
}
|
|
15585
|
-
|
|
15585
|
+
resolve8(fetch(new Request(locationURL, requestOpts)));
|
|
15586
15586
|
finalize();
|
|
15587
15587
|
return;
|
|
15588
15588
|
}
|
|
@@ -15603,7 +15603,7 @@ function fetch(url, opts) {
|
|
|
15603
15603
|
const codings = headers.get("Content-Encoding");
|
|
15604
15604
|
if (!request.compress || request.method === "HEAD" || codings === null || res.statusCode === 204 || res.statusCode === 304) {
|
|
15605
15605
|
response = new Response(body, response_options);
|
|
15606
|
-
|
|
15606
|
+
resolve8(response);
|
|
15607
15607
|
return;
|
|
15608
15608
|
}
|
|
15609
15609
|
const zlibOptions = {
|
|
@@ -15613,7 +15613,7 @@ function fetch(url, opts) {
|
|
|
15613
15613
|
if (codings == "gzip" || codings == "x-gzip") {
|
|
15614
15614
|
body = body.pipe(zlib.createGunzip(zlibOptions));
|
|
15615
15615
|
response = new Response(body, response_options);
|
|
15616
|
-
|
|
15616
|
+
resolve8(response);
|
|
15617
15617
|
return;
|
|
15618
15618
|
}
|
|
15619
15619
|
if (codings == "deflate" || codings == "x-deflate") {
|
|
@@ -15625,12 +15625,12 @@ function fetch(url, opts) {
|
|
|
15625
15625
|
body = body.pipe(zlib.createInflateRaw());
|
|
15626
15626
|
}
|
|
15627
15627
|
response = new Response(body, response_options);
|
|
15628
|
-
|
|
15628
|
+
resolve8(response);
|
|
15629
15629
|
});
|
|
15630
15630
|
raw.on("end", function() {
|
|
15631
15631
|
if (!response) {
|
|
15632
15632
|
response = new Response(body, response_options);
|
|
15633
|
-
|
|
15633
|
+
resolve8(response);
|
|
15634
15634
|
}
|
|
15635
15635
|
});
|
|
15636
15636
|
return;
|
|
@@ -15638,11 +15638,11 @@ function fetch(url, opts) {
|
|
|
15638
15638
|
if (codings == "br" && typeof zlib.createBrotliDecompress === "function") {
|
|
15639
15639
|
body = body.pipe(zlib.createBrotliDecompress());
|
|
15640
15640
|
response = new Response(body, response_options);
|
|
15641
|
-
|
|
15641
|
+
resolve8(response);
|
|
15642
15642
|
return;
|
|
15643
15643
|
}
|
|
15644
15644
|
response = new Response(body, response_options);
|
|
15645
|
-
|
|
15645
|
+
resolve8(response);
|
|
15646
15646
|
});
|
|
15647
15647
|
writeToStream(req, request);
|
|
15648
15648
|
});
|
|
@@ -16355,13 +16355,13 @@ var require_file = __commonJS({
|
|
|
16355
16355
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16356
16356
|
var fs_1 = __require("fs");
|
|
16357
16357
|
function resolveFile(ref) {
|
|
16358
|
-
return new Promise((
|
|
16358
|
+
return new Promise((resolve8, reject) => {
|
|
16359
16359
|
const path = ref.href();
|
|
16360
16360
|
fs_1.readFile(path, "utf8", (err, data) => {
|
|
16361
16361
|
if (err) {
|
|
16362
16362
|
reject(err);
|
|
16363
16363
|
} else {
|
|
16364
|
-
|
|
16364
|
+
resolve8(data);
|
|
16365
16365
|
}
|
|
16366
16366
|
});
|
|
16367
16367
|
});
|
|
@@ -23964,12 +23964,12 @@ var require_reader = __commonJS({
|
|
|
23964
23964
|
}
|
|
23965
23965
|
} else {
|
|
23966
23966
|
try {
|
|
23967
|
-
return await new Promise((
|
|
23967
|
+
return await new Promise((resolve8, reject) => {
|
|
23968
23968
|
fs.readFile(name, opts.encoding, (err, data) => {
|
|
23969
23969
|
if (err !== null) {
|
|
23970
23970
|
reject(err);
|
|
23971
23971
|
} else {
|
|
23972
|
-
|
|
23972
|
+
resolve8(data);
|
|
23973
23973
|
}
|
|
23974
23974
|
});
|
|
23975
23975
|
});
|
|
@@ -40854,14 +40854,14 @@ var require_AsyncFromSyncIteratorContinuation = __commonJS({
|
|
|
40854
40854
|
if (!$Promise) {
|
|
40855
40855
|
throw new $SyntaxError("This environment does not support Promises.");
|
|
40856
40856
|
}
|
|
40857
|
-
return new $Promise(function(
|
|
40857
|
+
return new $Promise(function(resolve8) {
|
|
40858
40858
|
var done = IteratorComplete(result);
|
|
40859
40859
|
var value = IteratorValue(result);
|
|
40860
40860
|
var valueWrapper = PromiseResolve($Promise, value);
|
|
40861
40861
|
var onFulfilled = function(value2) {
|
|
40862
40862
|
return CreateIteratorResultObject(value2, done);
|
|
40863
40863
|
};
|
|
40864
|
-
|
|
40864
|
+
resolve8($then(valueWrapper, onFulfilled));
|
|
40865
40865
|
});
|
|
40866
40866
|
};
|
|
40867
40867
|
}
|
|
@@ -41409,7 +41409,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
|
|
|
41409
41409
|
var O2 = this;
|
|
41410
41410
|
SLOT.assert(O2, "[[SyncIteratorRecord]]");
|
|
41411
41411
|
var argsLength = arguments.length;
|
|
41412
|
-
return new $Promise(function(
|
|
41412
|
+
return new $Promise(function(resolve8) {
|
|
41413
41413
|
var syncIteratorRecord = SLOT.get(O2, "[[SyncIteratorRecord]]");
|
|
41414
41414
|
var result;
|
|
41415
41415
|
if (argsLength > 0) {
|
|
@@ -41417,7 +41417,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
|
|
|
41417
41417
|
} else {
|
|
41418
41418
|
result = IteratorNext(syncIteratorRecord);
|
|
41419
41419
|
}
|
|
41420
|
-
|
|
41420
|
+
resolve8(AsyncFromSyncIteratorContinuation(result));
|
|
41421
41421
|
});
|
|
41422
41422
|
},
|
|
41423
41423
|
"return": function() {
|
|
@@ -41428,12 +41428,12 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
|
|
|
41428
41428
|
SLOT.assert(O2, "[[SyncIteratorRecord]]");
|
|
41429
41429
|
var valueIsPresent = arguments.length > 0;
|
|
41430
41430
|
var value = valueIsPresent ? arguments[0] : void 0;
|
|
41431
|
-
return new $Promise(function(
|
|
41431
|
+
return new $Promise(function(resolve8, reject) {
|
|
41432
41432
|
var syncIterator = SLOT.get(O2, "[[SyncIteratorRecord]]")["[[Iterator]]"];
|
|
41433
41433
|
var iteratorReturn = GetMethod(syncIterator, "return");
|
|
41434
41434
|
if (typeof iteratorReturn === "undefined") {
|
|
41435
41435
|
var iterResult = CreateIteratorResultObject(value, true);
|
|
41436
|
-
Call(
|
|
41436
|
+
Call(resolve8, void 0, [iterResult]);
|
|
41437
41437
|
return;
|
|
41438
41438
|
}
|
|
41439
41439
|
var result;
|
|
@@ -41446,7 +41446,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
|
|
|
41446
41446
|
Call(reject, void 0, [new $TypeError("Iterator `return` method returned a non-object value.")]);
|
|
41447
41447
|
return;
|
|
41448
41448
|
}
|
|
41449
|
-
|
|
41449
|
+
resolve8(AsyncFromSyncIteratorContinuation(result));
|
|
41450
41450
|
});
|
|
41451
41451
|
},
|
|
41452
41452
|
"throw": function() {
|
|
@@ -41457,7 +41457,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
|
|
|
41457
41457
|
SLOT.assert(O2, "[[SyncIteratorRecord]]");
|
|
41458
41458
|
var valueIsPresent = arguments.length > 0;
|
|
41459
41459
|
var value = valueIsPresent ? arguments[0] : void 0;
|
|
41460
|
-
return new $Promise(function(
|
|
41460
|
+
return new $Promise(function(resolve8, reject) {
|
|
41461
41461
|
var syncIterator = SLOT.get(O2, "[[SyncIteratorRecord]]")["[[Iterator]]"];
|
|
41462
41462
|
var throwMethod = GetMethod(syncIterator, "throw");
|
|
41463
41463
|
if (typeof throwMethod === "undefined") {
|
|
@@ -41474,7 +41474,7 @@ var require_CreateAsyncFromSyncIterator = __commonJS({
|
|
|
41474
41474
|
Call(reject, void 0, [new $TypeError("Iterator `throw` method returned a non-object value.")]);
|
|
41475
41475
|
return;
|
|
41476
41476
|
}
|
|
41477
|
-
|
|
41477
|
+
resolve8(AsyncFromSyncIteratorContinuation(
|
|
41478
41478
|
result
|
|
41479
41479
|
/* , promiseCapability */
|
|
41480
41480
|
));
|
|
@@ -50425,6 +50425,9 @@ var require_dist13 = __commonJS({
|
|
|
50425
50425
|
});
|
|
50426
50426
|
|
|
50427
50427
|
// src/cli/cli.ts
|
|
50428
|
+
import { readFileSync } from "fs";
|
|
50429
|
+
import { fileURLToPath } from "url";
|
|
50430
|
+
import { resolve as resolve7, dirname as dirname7 } from "path";
|
|
50428
50431
|
import { Command as Command7 } from "commander";
|
|
50429
50432
|
|
|
50430
50433
|
// src/cli/commands/resolve.ts
|
|
@@ -50725,7 +50728,9 @@ var WorkflowValidationStepSchema = z11.object({
|
|
|
50725
50728
|
var WorkflowDecisionStepSchema = z11.object({
|
|
50726
50729
|
type: z11.literal("decision"),
|
|
50727
50730
|
description: z11.string().optional(),
|
|
50728
|
-
on
|
|
50731
|
+
/** @deprecated Use `routing_key` instead. `on` is kept for backward compatibility. */
|
|
50732
|
+
on: z11.string().optional(),
|
|
50733
|
+
routing_key: z11.string().optional(),
|
|
50729
50734
|
branches: z11.record(z11.string(), z11.array(z11.string())),
|
|
50730
50735
|
group: z11.string().optional()
|
|
50731
50736
|
}).passthrough();
|
|
@@ -50748,6 +50753,11 @@ var WorkflowSchema = z11.object({
|
|
|
50748
50753
|
var ComponentsSchema = z12.object({
|
|
50749
50754
|
schemas: z12.record(z12.string(), z12.record(z12.string(), z12.any())).default({})
|
|
50750
50755
|
}).passthrough();
|
|
50756
|
+
var XExtensionDeclSchema = z12.object({
|
|
50757
|
+
type: z12.string(),
|
|
50758
|
+
items: z12.string().optional(),
|
|
50759
|
+
description: z12.string().optional()
|
|
50760
|
+
});
|
|
50751
50761
|
var DslSchema = z12.object({
|
|
50752
50762
|
version: z12.literal(1),
|
|
50753
50763
|
extends: z12.string().optional(),
|
|
@@ -50762,7 +50772,8 @@ var DslSchema = z12.object({
|
|
|
50762
50772
|
policies: z12.record(z12.string(), PolicySchema).default({}),
|
|
50763
50773
|
guardrails: z12.record(z12.string(), GuardrailSchema).default({}),
|
|
50764
50774
|
guardrail_policies: z12.record(z12.string(), GuardrailPolicySchema).default({}),
|
|
50765
|
-
components: ComponentsSchema.default({ schemas: {} })
|
|
50775
|
+
components: ComponentsSchema.default({ schemas: {} }),
|
|
50776
|
+
"x-extensions": z12.record(z12.string(), XExtensionDeclSchema).optional()
|
|
50766
50777
|
}).passthrough();
|
|
50767
50778
|
|
|
50768
50779
|
// src/schema/json-schema-utils.ts
|
|
@@ -51617,6 +51628,13 @@ function substituteVars(data, vars) {
|
|
|
51617
51628
|
return walk(data, vars);
|
|
51618
51629
|
}
|
|
51619
51630
|
|
|
51631
|
+
// src/resolver/expand-defaults.ts
|
|
51632
|
+
function expandDefaults(data) {
|
|
51633
|
+
const result = DslSchema.safeParse(data);
|
|
51634
|
+
if (!result.success) return data;
|
|
51635
|
+
return JSON.parse(JSON.stringify(result.data));
|
|
51636
|
+
}
|
|
51637
|
+
|
|
51620
51638
|
// src/config/binding-merger.ts
|
|
51621
51639
|
function isRecord3(v2) {
|
|
51622
51640
|
return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
|
|
@@ -51757,12 +51775,15 @@ ${issues}`,
|
|
|
51757
51775
|
// src/cli/commands/resolve.ts
|
|
51758
51776
|
import { stringify } from "yaml";
|
|
51759
51777
|
var DIR_DEFAULT = "agent-contracts.yaml";
|
|
51760
|
-
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("--format <format>", "Output format (text|json)", "text").action(async (dir, opts) => {
|
|
51778
|
+
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("--format <format>", "Output format (text|json)", "text").option("--expand-defaults", "Expand all Zod default values in output", false).action(async (dir, opts) => {
|
|
51761
51779
|
try {
|
|
51762
51780
|
const config = await loadConfig(opts.config);
|
|
51763
51781
|
const dslPath = resolveDslPath(dir, DIR_DEFAULT, config);
|
|
51764
51782
|
const result = await resolve4(dslPath);
|
|
51765
|
-
|
|
51783
|
+
let data = config?.vars ? substituteVars(result.data, config.vars) : result.data;
|
|
51784
|
+
if (opts.expandDefaults) {
|
|
51785
|
+
data = expandDefaults(data);
|
|
51786
|
+
}
|
|
51766
51787
|
if (opts.format === "json") {
|
|
51767
51788
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
51768
51789
|
} else {
|
|
@@ -51841,6 +51862,47 @@ function checkCustomPropsRecursive(data, schema, path) {
|
|
|
51841
51862
|
}
|
|
51842
51863
|
return [];
|
|
51843
51864
|
}
|
|
51865
|
+
function checkXExtensionsKeys(data) {
|
|
51866
|
+
const extensions = data["x-extensions"];
|
|
51867
|
+
if (typeof extensions !== "object" || extensions === null) return [];
|
|
51868
|
+
const diagnostics = [];
|
|
51869
|
+
for (const key of Object.keys(extensions)) {
|
|
51870
|
+
if (!key.startsWith("x-")) {
|
|
51871
|
+
diagnostics.push({
|
|
51872
|
+
path: `x-extensions.${key}`,
|
|
51873
|
+
message: `Extension key "${key}" must start with "x-" prefix.`,
|
|
51874
|
+
code: "x-extension-key-prefix"
|
|
51875
|
+
});
|
|
51876
|
+
}
|
|
51877
|
+
}
|
|
51878
|
+
return diagnostics;
|
|
51879
|
+
}
|
|
51880
|
+
function checkDecisionStepRoutingKey(data) {
|
|
51881
|
+
const workflow = data["workflow"];
|
|
51882
|
+
if (typeof workflow !== "object" || workflow === null) return [];
|
|
51883
|
+
const diagnostics = [];
|
|
51884
|
+
for (const [wfKey, wf] of Object.entries(
|
|
51885
|
+
workflow
|
|
51886
|
+
)) {
|
|
51887
|
+
if (typeof wf !== "object" || wf === null) continue;
|
|
51888
|
+
const steps = wf["steps"];
|
|
51889
|
+
if (!Array.isArray(steps)) continue;
|
|
51890
|
+
for (let i3 = 0; i3 < steps.length; i3++) {
|
|
51891
|
+
const step = steps[i3];
|
|
51892
|
+
if (typeof step !== "object" || step === null) continue;
|
|
51893
|
+
const s2 = step;
|
|
51894
|
+
if (s2["type"] !== "decision") continue;
|
|
51895
|
+
if (s2["routing_key"] === void 0 && s2["on"] === void 0) {
|
|
51896
|
+
diagnostics.push({
|
|
51897
|
+
path: `workflow.${wfKey}.steps[${i3}]`,
|
|
51898
|
+
message: 'Decision step requires "routing_key" (or deprecated "on"). Prefer "routing_key".',
|
|
51899
|
+
code: "decision-missing-routing-key"
|
|
51900
|
+
});
|
|
51901
|
+
}
|
|
51902
|
+
}
|
|
51903
|
+
}
|
|
51904
|
+
return diagnostics;
|
|
51905
|
+
}
|
|
51844
51906
|
function validateSchema(data) {
|
|
51845
51907
|
const result = DslSchema.safeParse(data);
|
|
51846
51908
|
if (!result.success) {
|
|
@@ -51855,6 +51917,14 @@ function validateSchema(data) {
|
|
|
51855
51917
|
if (customPropDiagnostics.length > 0) {
|
|
51856
51918
|
return { success: false, diagnostics: customPropDiagnostics };
|
|
51857
51919
|
}
|
|
51920
|
+
const decisionDiagnostics = checkDecisionStepRoutingKey(data);
|
|
51921
|
+
if (decisionDiagnostics.length > 0) {
|
|
51922
|
+
return { success: false, diagnostics: decisionDiagnostics };
|
|
51923
|
+
}
|
|
51924
|
+
const xExtDiagnostics = checkXExtensionsKeys(data);
|
|
51925
|
+
if (xExtDiagnostics.length > 0) {
|
|
51926
|
+
return { success: false, diagnostics: xExtDiagnostics };
|
|
51927
|
+
}
|
|
51858
51928
|
return { success: true, data: result.data, diagnostics: [] };
|
|
51859
51929
|
}
|
|
51860
51930
|
|
|
@@ -52580,6 +52650,51 @@ var guardrailPolicyCoverageRule = {
|
|
|
52580
52650
|
}
|
|
52581
52651
|
};
|
|
52582
52652
|
|
|
52653
|
+
// src/linter/rules/yaml-reserved-key-safety.ts
|
|
52654
|
+
var YAML_11_RESERVED_KEYS = /* @__PURE__ */ new Set([
|
|
52655
|
+
"on",
|
|
52656
|
+
"off",
|
|
52657
|
+
"yes",
|
|
52658
|
+
"no",
|
|
52659
|
+
"true",
|
|
52660
|
+
"false",
|
|
52661
|
+
"y",
|
|
52662
|
+
"n"
|
|
52663
|
+
]);
|
|
52664
|
+
var yamlReservedKeySafetyRule = {
|
|
52665
|
+
id: "yaml-reserved-key-safety",
|
|
52666
|
+
description: "Warns when YAML 1.1 reserved words are used as field values in positions where they may be misinterpreted by non-1.2 parsers",
|
|
52667
|
+
run(dsl) {
|
|
52668
|
+
const diagnostics = [];
|
|
52669
|
+
for (const [wfKey, wf] of Object.entries(dsl.workflow)) {
|
|
52670
|
+
for (let i3 = 0; i3 < wf.steps.length; i3++) {
|
|
52671
|
+
const step = wf.steps[i3];
|
|
52672
|
+
if (step.type !== "decision") continue;
|
|
52673
|
+
if (step.on !== void 0 && step.routing_key === void 0) {
|
|
52674
|
+
diagnostics.push({
|
|
52675
|
+
ruleId: "yaml-reserved-key-safety",
|
|
52676
|
+
severity: "warning",
|
|
52677
|
+
path: `workflow.${wfKey}.steps[${i3}].on`,
|
|
52678
|
+
message: 'Field name "on" is a YAML 1.1 reserved word and may be interpreted as boolean true by some parsers. Use "routing_key" instead.'
|
|
52679
|
+
});
|
|
52680
|
+
}
|
|
52681
|
+
const branchKeys = Object.keys(step.branches);
|
|
52682
|
+
for (const key of branchKeys) {
|
|
52683
|
+
if (YAML_11_RESERVED_KEYS.has(key.toLowerCase())) {
|
|
52684
|
+
diagnostics.push({
|
|
52685
|
+
ruleId: "yaml-reserved-key-safety",
|
|
52686
|
+
severity: "warning",
|
|
52687
|
+
path: `workflow.${wfKey}.steps[${i3}].branches.${key}`,
|
|
52688
|
+
message: `Branch key "${key}" is a YAML 1.1 reserved word and may be interpreted as a boolean by some parsers. Consider quoting or renaming.`
|
|
52689
|
+
});
|
|
52690
|
+
}
|
|
52691
|
+
}
|
|
52692
|
+
}
|
|
52693
|
+
}
|
|
52694
|
+
return diagnostics;
|
|
52695
|
+
}
|
|
52696
|
+
};
|
|
52697
|
+
|
|
52583
52698
|
// src/linter/linter.ts
|
|
52584
52699
|
var builtinRules = [
|
|
52585
52700
|
validationCoverageRule,
|
|
@@ -52588,7 +52703,8 @@ var builtinRules = [
|
|
|
52588
52703
|
mergeIntegrityRule,
|
|
52589
52704
|
artifactOwnershipRule,
|
|
52590
52705
|
toolCommandsRule,
|
|
52591
|
-
guardrailPolicyCoverageRule
|
|
52706
|
+
guardrailPolicyCoverageRule,
|
|
52707
|
+
yamlReservedKeySafetyRule
|
|
52592
52708
|
];
|
|
52593
52709
|
function lint(dsl, rules = builtinRules) {
|
|
52594
52710
|
const diagnostics = [];
|
|
@@ -54961,8 +55077,10 @@ var generateGuardrailsCommand = new Command6("generate").description("Generate g
|
|
|
54961
55077
|
);
|
|
54962
55078
|
|
|
54963
55079
|
// src/cli/cli.ts
|
|
55080
|
+
var __dirname = dirname7(fileURLToPath(import.meta.url));
|
|
55081
|
+
var pkg = JSON.parse(readFileSync(resolve7(__dirname, "../package.json"), "utf8"));
|
|
54964
55082
|
var program = new Command7();
|
|
54965
|
-
program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version(
|
|
55083
|
+
program.name("agent-contracts").description("Agent contracts tooling \u2014 validate, lint, render DSL files").version(pkg.version);
|
|
54966
55084
|
program.addCommand(resolveCommand);
|
|
54967
55085
|
program.addCommand(validateCommand);
|
|
54968
55086
|
program.addCommand(lintCommand);
|