Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cli-contract.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cli_contracts: 0.1.0

info:
title: micro-contracts CLI
version: 0.15.0
version: 0.17.10
description: >-
Contract-first OpenAPI toolchain for TypeScript Web/API systems.
Generates contract packages, server routes, and frontend clients
Expand Down Expand Up @@ -933,6 +933,7 @@ command_sets:
idempotent: true

x-agent:
dsl_task: audit-openapi-design
expectedDurationMs: 120000
retryableExitCodes: [12]

Expand Down Expand Up @@ -1061,6 +1062,7 @@ command_sets:
idempotent: true

x-agent:
dsl_task: audit-published-api
expectedDurationMs: 120000
retryableExitCodes: [12]

Expand Down Expand Up @@ -1190,6 +1192,7 @@ command_sets:
idempotent: true

x-agent:
dsl_task: propose-overlay-candidates
expectedDurationMs: 120000
retryableExitCodes: [12]

Expand Down Expand Up @@ -1323,6 +1326,7 @@ command_sets:
idempotent: true

x-agent:
dsl_task: audit-guardrails-coverage
expectedDurationMs: 120000
retryableExitCodes: [12]

Expand Down
6 changes: 5 additions & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Contract-first OpenAPI toolchain for TypeScript Web/API systems. Generates contract packages, server routes, and frontend clients from OpenAPI specifications with enforceable guardrails.

**Version:** 0.15.0
**Version:** 0.17.10

## Table of Contents

Expand Down Expand Up @@ -630,6 +630,7 @@ micro-contracts audit-openapi --show-prompt

```yaml
x-agent:
dsl_task: audit-openapi-design
expectedDurationMs: 120000
retryableExitCodes:
- 12
Expand Down Expand Up @@ -698,6 +699,7 @@ micro-contracts review-published --adapter claude --report-format json

```yaml
x-agent:
dsl_task: audit-published-api
expectedDurationMs: 120000
retryableExitCodes:
- 12
Expand Down Expand Up @@ -766,6 +768,7 @@ micro-contracts propose-overlays --adapter openai --report-format json

```yaml
x-agent:
dsl_task: propose-overlay-candidates
expectedDurationMs: 120000
retryableExitCodes:
- 12
Expand Down Expand Up @@ -831,6 +834,7 @@ micro-contracts audit-guardrails --adapter mock --report-format json

```yaml
x-agent:
dsl_task: audit-guardrails-coverage
expectedDurationMs: 120000
retryableExitCodes:
- 12
Expand Down
6 changes: 3 additions & 3 deletions examples/packages/.generated-manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.0",
"generatorVersion": "0.17.9",
"generatorVersion": "0.17.10",
"files": {
"contract-published/billing/docs/api-reference.html": {
"sha256": "5b69e88fc9f60578261a8231132678550a40a70eb52dfcc611f48937f448ca44"
Expand Down Expand Up @@ -144,6 +144,6 @@
"sha256": "d791f51b36215aba3e7cf7c5f69fc4b9fd6d4f2cf515718fdc93589fa05e2608"
}
},
"inputHash": "b0a2477d56cac19d923f7bc82fafcdae5e8c1fda2f6d2d333e1803457279da72",
"updatedAt": "2026-06-06T17:28:35.552Z"
"inputHash": "dc8b577380034ddd95c7deda27cf6084a16dc879af579db1d9fba2b7b24c61de",
"updatedAt": "2026-06-07T06:02:07.134Z"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "micro-contracts",
"version": "0.17.9",
"version": "0.17.10",
"description": "Contract-first OpenAPI toolchain that keeps TypeScript UI and microservices aligned via code generation",
"type": "module",
"main": "dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions src/agents/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { runAgentTask, EXIT_RUNTIME_MISSING, EXIT_ADAPTER_ERROR } from "./orchestrator.js";
export { computeExitCode, formatResultText, formatResultJson, formatResultYaml, formatResult, writeOutput } from "./formatter.js";
export type { ReportFormat } from "./formatter.js";
export { TASK_IDS } from "./types.js";
export type { TaskId, AuditConfig, AuditOptions, AuditRunResult } from "./types.js";
14 changes: 9 additions & 5 deletions src/agents/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { OpenapiAuditResult } from "../generated/dsl/handoffs.js";
import { taskRegistry } from "../generated/dsl/tasks.js";

export type TaskId =
| "audit-openapi-design"
| "audit-published-api"
| "propose-overlay-candidates"
| "audit-guardrails-coverage";
export type TaskId = keyof typeof taskRegistry;

export const TASK_IDS = {
auditOpenapi: "audit-openapi-design",
reviewPublished: "audit-published-api",
proposeOverlays: "propose-overlay-candidates",
auditGuardrails: "audit-guardrails-coverage",
} as const satisfies Record<string, TaskId>;

export interface AuditConfig {
adapter?: string;
Expand Down
3 changes: 2 additions & 1 deletion src/commands/audit-guardrails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import chalk from "chalk";
import { buildAuditGuardrailsContext } from "../agents/context-builder.js";
import {
runAgentTask,
TASK_IDS,
computeExitCode,
formatResult,
writeOutput,
Expand Down Expand Up @@ -40,7 +41,7 @@ export async function commandAuditGuardrails(opts: CommandAuditGuardrailsOptions
try {
const result = await runAgentTask(
context,
"audit-guardrails-coverage",
TASK_IDS.auditGuardrails,
auditConfig,
auditOpts,
);
Expand Down
3 changes: 2 additions & 1 deletion src/commands/audit-openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import chalk from "chalk";
import { buildAuditOpenapiContext } from "../agents/context-builder.js";
import {
runAgentTask,
TASK_IDS,
computeExitCode,
formatResult,
writeOutput,
Expand Down Expand Up @@ -40,7 +41,7 @@ export async function commandAuditOpenapi(opts: CommandAuditOpenapiOptions): Pro
try {
const result = await runAgentTask(
context,
"audit-openapi-design",
TASK_IDS.auditOpenapi,
auditConfig,
auditOpts,
);
Expand Down
3 changes: 2 additions & 1 deletion src/commands/propose-overlays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import chalk from "chalk";
import { buildProposeOverlaysContext } from "../agents/context-builder.js";
import {
runAgentTask,
TASK_IDS,
computeExitCode,
formatResult,
writeOutput,
Expand Down Expand Up @@ -40,7 +41,7 @@ export async function commandProposeOverlays(opts: CommandProposeOverlaysOptions
try {
const result = await runAgentTask(
context,
"propose-overlay-candidates",
TASK_IDS.proposeOverlays,
auditConfig,
auditOpts,
);
Expand Down
3 changes: 2 additions & 1 deletion src/commands/review-published.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import chalk from "chalk";
import { buildReviewPublishedContext } from "../agents/context-builder.js";
import {
runAgentTask,
TASK_IDS,
computeExitCode,
formatResult,
writeOutput,
Expand Down Expand Up @@ -40,7 +41,7 @@ export async function commandReviewPublished(opts: CommandReviewPublishedOptions
try {
const result = await runAgentTask(
context,
"audit-published-api",
TASK_IDS.reviewPublished,
auditConfig,
auditOpts,
);
Expand Down
4 changes: 2 additions & 2 deletions src/generated/contract.ts

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions tests/agents/dsl-task-binding.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { parse as parseYaml } from "yaml";
import { taskRegistry } from "../../src/generated/dsl/tasks.js";
import { TASK_IDS } from "../../src/agents/types.js";

const contractPath = resolve(import.meta.dirname, "../../cli-contract.yaml");
const contract = parseYaml(readFileSync(contractPath, "utf8"));

function getCommands(): Record<string, { "x-agent"?: { dsl_task?: string } }> {
const sets = contract.command_sets ?? {};
const commands: Record<string, { "x-agent"?: { dsl_task?: string } }> = {};
for (const setDef of Object.values(sets) as Array<{ commands?: Record<string, unknown> }>) {
if (setDef.commands) {
Object.assign(commands, setDef.commands);
}
}
return commands;
}

describe("dsl_task binding consistency", () => {
const commands = getCommands();

const llmCommands = Object.entries(commands).filter(
([, cmd]) => cmd["x-agent"]?.dsl_task,
);

it("all LLM commands declare dsl_task in x-agent", () => {
expect(llmCommands.length).toBe(4);
});

it.each(llmCommands)(
"%s x-agent.dsl_task matches DSL task registry",
(cmdName, cmd) => {
const dslTask = cmd["x-agent"]!.dsl_task!;
expect(taskRegistry[dslTask]).toBeDefined();
expect(taskRegistry[dslTask].id).toBe(dslTask);
},
);

it("TASK_IDS values all exist in the DSL task registry", () => {
for (const [key, taskId] of Object.entries(TASK_IDS)) {
expect(taskRegistry[taskId]).toBeDefined();
expect(taskRegistry[taskId].id).toBe(taskId);
}
});

it("TASK_IDS covers all dsl_task declarations in the contract", () => {
const contractTaskIds = llmCommands.map(([, cmd]) => cmd["x-agent"]!.dsl_task!);
const registeredTaskIds = Object.values(TASK_IDS);
for (const taskId of contractTaskIds) {
expect(registeredTaskIds).toContain(taskId);
}
});
});
Loading