ag-ui-validate 0.1.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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/catalog-BglXBNbL.js +472 -0
- package/dist/catalog-BglXBNbL.js.map +1 -0
- package/dist/catalog-Ci9dqc1a.cjs +495 -0
- package/dist/catalog-Ci9dqc1a.cjs.map +1 -0
- package/dist/cli.js +2783 -0
- package/dist/cli.js.map +1 -0
- package/dist/index-Hmqj3r_r.d.cts +52 -0
- package/dist/index-oNG1kOp9.d.ts +52 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/report.cjs +139 -0
- package/dist/report.cjs.map +1 -0
- package/dist/report.d.cts +85 -0
- package/dist/report.d.ts +85 -0
- package/dist/report.js +134 -0
- package/dist/report.js.map +1 -0
- package/dist/src-HmI-kxef.cjs +1596 -0
- package/dist/src-HmI-kxef.cjs.map +1 -0
- package/dist/src-rGZ2G4qA.js +1555 -0
- package/dist/src-rGZ2G4qA.js.map +1 -0
- package/dist/transport.cjs +329 -0
- package/dist/transport.cjs.map +1 -0
- package/dist/transport.d.cts +89 -0
- package/dist/transport.d.ts +89 -0
- package/dist/transport.js +323 -0
- package/dist/transport.js.map +1 -0
- package/dist/types-oH_QTnn2.d.cts +148 -0
- package/dist/types-oH_QTnn2.d.ts +148 -0
- package/dist/vitest.d.ts +28 -0
- package/dist/vitest.js +2089 -0
- package/dist/vitest.js.map +1 -0
- package/package.json +127 -0
- package/src/cli-args.ts +202 -0
- package/src/cli.ts +147 -0
- package/src/index.ts +465 -0
- package/src/protocol/event-table.ts +316 -0
- package/src/protocol/jsonpatch.ts +220 -0
- package/src/report/index.ts +10 -0
- package/src/report/json.ts +20 -0
- package/src/report/junit.ts +56 -0
- package/src/report/pretty.ts +59 -0
- package/src/report/sarif.ts +109 -0
- package/src/rules/catalog.json +431 -0
- package/src/rules/catalog.ts +84 -0
- package/src/rules/checks/context.ts +117 -0
- package/src/rules/checks/lifecycle.ts +59 -0
- package/src/rules/checks/reasoning.ts +97 -0
- package/src/rules/checks/state.ts +72 -0
- package/src/rules/checks/text.ts +109 -0
- package/src/rules/checks/toolcalls.ts +167 -0
- package/src/rules/checks/transport.ts +17 -0
- package/src/transport/index.ts +331 -0
- package/src/transport/ndjson.ts +25 -0
- package/src/transport/sse.ts +126 -0
- package/src/types.ts +136 -0
- package/src/vitest/index.ts +19 -0
- package/src/vitest/matcher.ts +77 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.js","names":["catalogJson"],"sources":["../src/cli-args.ts","../src/protocol/event-table.ts","../src/rules/catalog.json","../src/rules/catalog.ts","../src/rules/checks/context.ts","../src/rules/checks/lifecycle.ts","../src/rules/checks/reasoning.ts","../src/protocol/jsonpatch.ts","../src/rules/checks/state.ts","../src/rules/checks/text.ts","../src/rules/checks/toolcalls.ts","../src/rules/checks/transport.ts","../src/types.ts","../src/index.ts","../src/report/pretty.ts","../src/vitest/matcher.ts","../src/vitest/index.ts"],"sourcesContent":["// Pure CLI argument parsing — no Node APIs, so it obeys the core purity rules\n// and tests without spawning processes. The Node-only entry lives in cli.ts.\nimport type { Severity } from \"./types.js\"\n\nexport type CliFormat = \"pretty\" | \"json\" | \"sarif\" | \"junit\"\n\nexport interface CliConfig {\n /** URL, file path, or \"-\" for stdin. Empty only with --help/--version. */\n target: string\n format: CliFormat\n /** true/false forced; null = auto-detect from TTY. */\n color: boolean | null\n maxWarnings?: number\n timeoutMs?: number\n /** Header names lowercased. */\n headers: Record<string, string>\n features?: string[]\n severityOverrides: Record<string, Severity | \"off\">\n /** Write these formats to files in the same run, whatever stdout shows. */\n sarifFile?: string\n junitFile?: string\n jsonFile?: string\n help: boolean\n version: boolean\n}\n\nexport type ParseResult = { ok: true; config: CliConfig } | { ok: false; error: string }\n\nexport const USAGE = `ag-ui-validate — conformance validator for the AG-UI protocol\n\nUsage:\n ag-ui-validate <url> connect to a live endpoint and validate the stream\n ag-ui-validate <file> validate a recorded stream (SSE capture or NDJSON/JSONL)\n ag-ui-validate - read a recorded stream from stdin\n\nOutput (default: human-readable):\n --json machine-readable report on stdout\n --sarif SARIF 2.1.0 log on stdout (code scanning)\n --junit JUnit XML on stdout (CI test reports)\n --json-file <path> additionally write the JSON report to a file\n --sarif-file <path> additionally write a SARIF log to a file\n --junit-file <path> additionally write JUnit XML to a file\n --no-color disable ANSI colors\n\nRules:\n --rule AGUI###=<severity> override a rule's severity (error|warning|info|off)\n --off AGUI### shorthand for --rule AGUI###=off\n --features <a,b,...> declare exercised features (enables e.g. AGUI305)\n --max-warnings <n> exit 1 when warnings exceed n\n\nEndpoint options:\n --header \"Name: value\" extra request header (repeatable)\n --timeout <seconds> abort the request after this long\n\nExit codes: 0 clean, 1 findings at error level (or warnings over --max-warnings), 2 tool failure.\n`\n\nconst SEVERITIES = new Set([\"error\", \"warning\", \"info\", \"off\"])\nconst RULE_ID = /^AGUI\\d{3}$/\n\ninterface Flag {\n takesValue: boolean\n apply(config: CliConfig, value: string): string | null\n}\n\nconst FLAGS: Record<string, Flag> = {\n \"--help\": { takesValue: false, apply: (c) => ((c.help = true), null) },\n \"--version\": { takesValue: false, apply: (c) => ((c.version = true), null) },\n \"--no-color\": { takesValue: false, apply: (c) => ((c.color = false), null) },\n \"--json\": { takesValue: false, apply: (c) => setFormat(c, \"json\") },\n \"--sarif\": { takesValue: false, apply: (c) => setFormat(c, \"sarif\") },\n \"--junit\": { takesValue: false, apply: (c) => setFormat(c, \"junit\") },\n \"--off\": {\n takesValue: true,\n apply: (c, v) => {\n if (!RULE_ID.test(v)) return `--off expects a rule ID like AGUI203, got '${v}'`\n c.severityOverrides[v] = \"off\"\n return null\n },\n },\n \"--rule\": {\n takesValue: true,\n apply: (c, v) => {\n const eq = v.indexOf(\"=\")\n if (eq === -1) return `--rule expects ID=severity (e.g. AGUI105=warning), got '${v}'`\n const id = v.slice(0, eq)\n const severity = v.slice(eq + 1)\n if (!RULE_ID.test(id)) return `--rule expects a rule ID like AGUI105, got '${id}'`\n if (!SEVERITIES.has(severity)) {\n return `'${severity}' is not a severity; use error, warning, info, or off`\n }\n c.severityOverrides[id] = severity as Severity | \"off\"\n return null\n },\n },\n \"--max-warnings\": {\n takesValue: true,\n apply: (c, v) => {\n const n = Number(v)\n if (!Number.isInteger(n) || n < 0) return `--max-warnings expects a non-negative integer, got '${v}'`\n c.maxWarnings = n\n return null\n },\n },\n \"--timeout\": {\n takesValue: true,\n apply: (c, v) => {\n const n = Number(v)\n if (!Number.isFinite(n) || n <= 0) return `--timeout expects a positive number of seconds, got '${v}'`\n c.timeoutMs = Math.round(n * 1000)\n return null\n },\n },\n \"--header\": {\n takesValue: true,\n apply: (c, v) => {\n const colon = v.indexOf(\":\")\n if (colon <= 0) return `--header expects \"Name: value\", got '${v}'`\n c.headers[v.slice(0, colon).trim().toLowerCase()] = v.slice(colon + 1).trim()\n return null\n },\n },\n \"--sarif-file\": { takesValue: true, apply: (c, v) => ((c.sarifFile = v), null) },\n \"--junit-file\": { takesValue: true, apply: (c, v) => ((c.junitFile = v), null) },\n \"--json-file\": { takesValue: true, apply: (c, v) => ((c.jsonFile = v), null) },\n \"--features\": {\n takesValue: true,\n apply: (c, v) => {\n c.features = v\n .split(\",\")\n .map((f) => f.trim())\n .filter((f) => f !== \"\")\n return null\n },\n },\n}\n\nfunction setFormat(c: CliConfig, format: CliFormat): string | null {\n if (c.format !== \"pretty\" && c.format !== format) {\n return `pick at most one of --json, --sarif, --junit`\n }\n c.format = format\n return null\n}\n\nexport function parseCliArgs(argv: string[]): ParseResult {\n const config: CliConfig = {\n target: \"\",\n format: \"pretty\",\n color: null,\n headers: {},\n severityOverrides: {},\n help: false,\n version: false,\n }\n\n const targets: string[] = []\n for (let i = 0; i < argv.length; i += 1) {\n const arg = argv[i]!\n if (arg === \"-\" || !arg.startsWith(\"-\")) {\n targets.push(arg)\n continue\n }\n let name = arg\n let inlineValue: string | null = null\n const eq = arg.indexOf(\"=\")\n if (eq !== -1) {\n name = arg.slice(0, eq)\n inlineValue = arg.slice(eq + 1)\n }\n const flag = FLAGS[name]\n if (flag === undefined) return { ok: false, error: `unknown flag '${name}'` }\n let value = \"\"\n if (flag.takesValue) {\n if (inlineValue !== null) value = inlineValue\n else if (i + 1 < argv.length) value = argv[(i += 1)]!\n else return { ok: false, error: `${name} requires a value` }\n } else if (inlineValue !== null) {\n return { ok: false, error: `${name} does not take a value` }\n }\n const error = flag.apply(config, value)\n if (error !== null) return { ok: false, error }\n }\n\n if (targets.length > 1) {\n return { ok: false, error: `expected exactly one target, got ${targets.length}` }\n }\n if (targets.length === 1) config.target = targets[0]!\n else if (!config.help && !config.version) {\n return { ok: false, error: \"missing target: a URL, a file path, or - for stdin\" }\n }\n return { ok: true, config }\n}\n\nexport function decideExitCode(\n summary: { errors: number; warnings: number; info: number },\n maxWarnings?: number,\n): 0 | 1 {\n if (summary.errors > 0) return 1\n if (maxWarnings !== undefined && summary.warnings > maxWarnings) return 1\n return 0\n}\n","// AUTO-GENERATED from @ag-ui/core v0.0.58 — do not edit by hand.\n// Regenerate with: node scripts/generate-event-table.mjs\n// test/protocol-drift.test.ts fails if this file drifts from the installed SDK.\n\nexport type FieldKind = \"string\" | \"number\" | \"boolean\" | \"object\" | \"array\" | \"any\"\n\nexport type EventCategory =\n | \"lifecycle\"\n | \"text\"\n | \"toolcall\"\n | \"state\"\n | \"activity\"\n | \"reasoning\"\n | \"thinking\"\n | \"special\"\n\nexport interface FieldSpec {\n kind: FieldKind\n required: boolean\n enum?: readonly string[]\n}\n\nexport interface EventSpec {\n category: EventCategory\n /** Present when the SDK marks the event @deprecated; names the replacement. */\n deprecated?: string\n /** Docs section governing this event. */\n specUrl: string\n /** Wire fields beyond the base-event fields (type, timestamp, rawEvent). */\n fields: Readonly<Record<string, FieldSpec>>\n}\n\n/** Version of @ag-ui/core this table was derived from. */\nexport const SDK_VERSION = \"0.0.58\"\n\n/** Canonical wire event types and their schemas, derived from @ag-ui/core. */\nexport const EVENT_TABLE: Readonly<Record<string, EventSpec>> = {\n \"TEXT_MESSAGE_START\": {\n category: \"text\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#textmessagestart\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"role\": { kind: \"string\", required: false, enum: [\"developer\",\"system\",\"assistant\",\"user\"] },\n \"name\": { kind: \"string\", required: false },\n },\n },\n \"TEXT_MESSAGE_CONTENT\": {\n category: \"text\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#textmessagecontent\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"delta\": { kind: \"string\", required: true },\n },\n },\n \"TEXT_MESSAGE_END\": {\n category: \"text\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#textmessageend\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n },\n },\n \"TEXT_MESSAGE_CHUNK\": {\n category: \"text\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#textmessagechunk\",\n fields: {\n \"messageId\": { kind: \"string\", required: false },\n \"role\": { kind: \"string\", required: false, enum: [\"developer\",\"system\",\"assistant\",\"user\"] },\n \"delta\": { kind: \"string\", required: false },\n \"name\": { kind: \"string\", required: false },\n },\n },\n \"TOOL_CALL_START\": {\n category: \"toolcall\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#toolcallstart\",\n fields: {\n \"toolCallId\": { kind: \"string\", required: true },\n \"toolCallName\": { kind: \"string\", required: true },\n \"parentMessageId\": { kind: \"string\", required: false },\n },\n },\n \"TOOL_CALL_ARGS\": {\n category: \"toolcall\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#toolcallargs\",\n fields: {\n \"toolCallId\": { kind: \"string\", required: true },\n \"delta\": { kind: \"string\", required: true },\n },\n },\n \"TOOL_CALL_END\": {\n category: \"toolcall\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#toolcallend\",\n fields: {\n \"toolCallId\": { kind: \"string\", required: true },\n },\n },\n \"TOOL_CALL_CHUNK\": {\n category: \"toolcall\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#toolcallchunk\",\n fields: {\n \"toolCallId\": { kind: \"string\", required: false },\n \"toolCallName\": { kind: \"string\", required: false },\n \"parentMessageId\": { kind: \"string\", required: false },\n \"delta\": { kind: \"string\", required: false },\n },\n },\n \"TOOL_CALL_RESULT\": {\n category: \"toolcall\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#toolcallresult\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"toolCallId\": { kind: \"string\", required: true },\n \"content\": { kind: \"string\", required: true },\n \"role\": { kind: \"string\", required: false, enum: [\"tool\"] },\n },\n },\n \"THINKING_START\": {\n category: \"thinking\",\n deprecated: \"REASONING_START\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#thinking-events-deprecated\",\n fields: {\n \"title\": { kind: \"string\", required: false },\n },\n },\n \"THINKING_END\": {\n category: \"thinking\",\n deprecated: \"REASONING_END\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#thinking-events-deprecated\",\n fields: {\n },\n },\n \"THINKING_TEXT_MESSAGE_START\": {\n category: \"thinking\",\n deprecated: \"REASONING_MESSAGE_START\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#thinking-events-deprecated\",\n fields: {\n },\n },\n \"THINKING_TEXT_MESSAGE_CONTENT\": {\n category: \"thinking\",\n deprecated: \"REASONING_MESSAGE_CONTENT\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#thinking-events-deprecated\",\n fields: {\n \"delta\": { kind: \"string\", required: true },\n },\n },\n \"THINKING_TEXT_MESSAGE_END\": {\n category: \"thinking\",\n deprecated: \"REASONING_MESSAGE_END\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#thinking-events-deprecated\",\n fields: {\n },\n },\n \"STATE_SNAPSHOT\": {\n category: \"state\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#statesnapshot\",\n fields: {\n \"snapshot\": { kind: \"any\", required: true },\n },\n },\n \"STATE_DELTA\": {\n category: \"state\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#statedelta\",\n fields: {\n \"delta\": { kind: \"array\", required: true },\n },\n },\n \"MESSAGES_SNAPSHOT\": {\n category: \"state\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#messagessnapshot\",\n fields: {\n \"messages\": { kind: \"array\", required: true },\n },\n },\n \"ACTIVITY_SNAPSHOT\": {\n category: \"activity\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#activitysnapshot\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"activityType\": { kind: \"string\", required: true },\n \"content\": { kind: \"object\", required: true },\n \"replace\": { kind: \"boolean\", required: false },\n },\n },\n \"ACTIVITY_DELTA\": {\n category: \"activity\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#activitydelta\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"activityType\": { kind: \"string\", required: true },\n \"patch\": { kind: \"array\", required: true },\n },\n },\n \"RAW\": {\n category: \"special\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#raw\",\n fields: {\n \"event\": { kind: \"any\", required: true },\n \"source\": { kind: \"string\", required: false },\n },\n },\n \"CUSTOM\": {\n category: \"special\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#custom\",\n fields: {\n \"name\": { kind: \"string\", required: true },\n \"value\": { kind: \"any\", required: true },\n },\n },\n \"RUN_STARTED\": {\n category: \"lifecycle\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#runstarted\",\n fields: {\n \"threadId\": { kind: \"string\", required: true },\n \"runId\": { kind: \"string\", required: true },\n \"parentRunId\": { kind: \"string\", required: false },\n \"input\": { kind: \"object\", required: false },\n },\n },\n \"RUN_FINISHED\": {\n category: \"lifecycle\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#runfinished\",\n fields: {\n \"threadId\": { kind: \"string\", required: true },\n \"runId\": { kind: \"string\", required: true },\n \"result\": { kind: \"any\", required: false },\n \"outcome\": { kind: \"object\", required: false },\n \"usage\": { kind: \"array\", required: false },\n },\n },\n \"RUN_ERROR\": {\n category: \"lifecycle\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#runerror\",\n fields: {\n \"message\": { kind: \"string\", required: true },\n \"code\": { kind: \"string\", required: false },\n \"usage\": { kind: \"array\", required: false },\n },\n },\n \"STEP_STARTED\": {\n category: \"lifecycle\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#stepstarted\",\n fields: {\n \"stepName\": { kind: \"string\", required: true },\n },\n },\n \"STEP_FINISHED\": {\n category: \"lifecycle\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#stepfinished\",\n fields: {\n \"stepName\": { kind: \"string\", required: true },\n },\n },\n \"REASONING_START\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningstart\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n },\n },\n \"REASONING_MESSAGE_START\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningmessagestart\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"role\": { kind: \"string\", required: true, enum: [\"reasoning\"] },\n },\n },\n \"REASONING_MESSAGE_CONTENT\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningmessagecontent\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n \"delta\": { kind: \"string\", required: true },\n },\n },\n \"REASONING_MESSAGE_END\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningmessageend\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n },\n },\n \"REASONING_MESSAGE_CHUNK\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningmessagechunk\",\n fields: {\n \"messageId\": { kind: \"string\", required: false },\n \"delta\": { kind: \"string\", required: false },\n },\n },\n \"REASONING_END\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningend\",\n fields: {\n \"messageId\": { kind: \"string\", required: true },\n },\n },\n \"REASONING_ENCRYPTED_VALUE\": {\n category: \"reasoning\",\n specUrl: \"https://docs.ag-ui.com/concepts/events#reasoningencryptedvalue\",\n fields: {\n \"subtype\": { kind: \"string\", required: true, enum: [\"tool-call\",\"message\"] },\n \"entityId\": { kind: \"string\", required: true },\n \"encryptedValue\": { kind: \"string\", required: true },\n },\n },\n}\n\n/** All canonical wire `type` values, in @ag-ui/core enum order. */\nexport const EVENT_TYPES: readonly string[] = Object.keys(EVENT_TABLE)\n\n/**\n * Wire types documented as drafts (https://docs.ag-ui.com/drafts/overview) but\n * not yet in @ag-ui/core. Not errors: reported at info severity.\n */\nexport const DRAFT_EVENT_TYPES: readonly string[] = [\"META\"]\n","","// Typed loader for the rule catalog. The catalog itself is data\n// (catalog.json) so other implementations can share it; this module gives it\n// types and validates its invariants once at load time.\n//\n// Note the asymmetry: the validator never throws on stream input, but a\n// malformed catalog is a programming error in this package, so the loader\n// throws loudly at import time.\n\nimport catalogJson from \"./catalog.json\"\n\nexport type Severity = \"error\" | \"warning\" | \"info\"\nexport type SeverityOrOff = Severity | \"off\"\n\nconst SEVERITIES: readonly string[] = [\"error\", \"warning\", \"info\"]\nconst LAYERS: readonly string[] = [\"core\", \"transport\"]\n\nexport interface RuleDefinition {\n /** e.g. \"AGUI203\" */\n id: string\n severity: Severity\n title: string\n /** Human template with {placeholder} slots filled per diagnostic. */\n messageTemplate: string\n /** Governing spec section. Mandatory: rules that cannot cite one don't ship. */\n specUrl: string\n /** Exact sentence from the spec section, where one exists. */\n specQuote?: string\n since: string\n /** Canonical AG-UI feature this rule relates to, if any. */\n feature?: string\n /** True when the rule only fires if opts.features declares `feature`. */\n requiresFeature?: boolean\n /** Cross-reference into docs/spec-questions.md for downgraded/ambiguous rules. */\n specQuestion?: string\n /** Where the rule is evaluated. Transport rules are skipped (and the skip\n * reported) when validating recorded input with no transport in play. */\n checkedIn: \"core\" | \"transport\"\n}\n\nexport interface Catalog {\n catalogVersion: string\n spec: string\n rules: readonly RuleDefinition[]\n}\n\n/** Validates catalog data and returns it typed. Throws on structural problems. */\nexport function validateCatalog(data: unknown): Catalog {\n const problems: string[] = []\n const cat = data as Catalog\n if (typeof cat !== \"object\" || cat === null || !Array.isArray(cat.rules)) {\n throw new Error(\"rule catalog: expected an object with a rules array\")\n }\n const seen = new Set<string>()\n for (const rule of cat.rules) {\n const where = rule?.id ?? \"<missing id>\"\n if (!/^AGUI\\d{3}$/.test(rule.id ?? \"\")) problems.push(`${where}: id must match AGUI###`)\n if (seen.has(rule.id)) problems.push(`${where}: duplicate id`)\n seen.add(rule.id)\n if (!SEVERITIES.includes(rule.severity)) problems.push(`${where}: bad severity '${rule.severity}'`)\n if (!rule.title) problems.push(`${where}: missing title`)\n if (!rule.messageTemplate) problems.push(`${where}: missing messageTemplate`)\n if (!rule.specUrl?.startsWith(\"https://\")) problems.push(`${where}: specUrl must be an https URL`)\n if (!rule.since) problems.push(`${where}: missing since`)\n if (!LAYERS.includes(rule.checkedIn)) problems.push(`${where}: bad checkedIn '${rule.checkedIn}'`)\n if (rule.requiresFeature && !rule.feature) problems.push(`${where}: requiresFeature without feature`)\n }\n if (problems.length > 0) {\n throw new Error(`rule catalog is invalid:\\n ${problems.join(\"\\n \")}`)\n }\n return cat\n}\n\nexport const CATALOG: Catalog = validateCatalog(catalogJson)\n\nexport const RULES: ReadonlyMap<string, RuleDefinition> = new Map(\n CATALOG.rules.map((r) => [r.id, r]),\n)\n\n/** Fills a rule's messageTemplate. Unknown placeholders are left intact. */\nexport function formatMessage(rule: RuleDefinition, params: Record<string, unknown>): string {\n return rule.messageTemplate.replace(/\\{(\\w+)\\}/g, (whole, key: string) =>\n key in params ? String(params[key]) : whole,\n )\n}\n","// Internal validator state and the API each check module sees.\n// Everything here is engine-internal; the public surface lives in src/types.ts.\n\nimport type { CanonicalFeature } from \"../../types.js\"\n\n/** Emit a diagnostic for rule `id`; params fill the catalog messageTemplate. */\nexport type EmitFn = (\n ruleId: string,\n params: Record<string, unknown>,\n extra?: {\n eventIndex?: number\n pointer?: string\n relatedEventIndex?: number\n /** Instance-level severity floor (e.g. draft META downgrades AGUI503). */\n severity?: \"error\" | \"warning\" | \"info\"\n /** Instance-level spec link override (e.g. draft docs page). */\n specUrl?: string\n /** Appended to the formatted message (e.g. casing hints). */\n messageSuffix?: string\n },\n) => void\n\nexport interface OpenToolCall {\n startIndex: number\n args: string\n sawArgs: boolean\n}\n\nexport interface RunState {\n /** null while the run is implicit (stream opened without RUN_STARTED). */\n runId: string | null\n threadId: string | null\n startIndex: number\n implicit: boolean\n terminal: { type: string; index: number } | null\n\n openMessages: Map<string, { startIndex: number }>\n /** messageId -> index of the event that closed it. */\n closedMessages: Map<string, number>\n /** Every message id observed (starts, chunks, snapshots, tool results). */\n knownMessageIds: Set<string>\n\n openToolCalls: Map<string, OpenToolCall>\n closedToolCalls: Map<string, number>\n /** Ids also known from MESSAGES_SNAPSHOT history. */\n knownToolCallIds: Set<string>\n\n /** stepName -> re-entrant open count (SQ-10) and first-open index. */\n openSteps: Map<string, { count: number; firstIndex: number }>\n\n openReasoningBlocks: Map<string, number>\n openReasoningMessages: Map<string, number>\n\n state: {\n /** True once a STATE_SNAPSHOT established an observable base (SQ-1). */\n known: boolean\n value: unknown\n deltasSinceSnapshot: number\n snapshotSeen: boolean\n agui301Fired: boolean\n }\n\n /** Implicit streams opened by *_CHUNK events; closed by any other event. */\n textChunk: { messageId: string; startIndex: number } | null\n toolChunk: { toolCallId: string; startIndex: number; args: string; sawArgs: boolean } | null\n reasoningChunk: { messageId: string; startIndex: number } | null\n}\n\nexport function newRunState(init: {\n runId: string | null\n threadId: string | null\n startIndex: number\n implicit: boolean\n}): RunState {\n return {\n ...init,\n terminal: null,\n openMessages: new Map(),\n closedMessages: new Map(),\n knownMessageIds: new Set(),\n openToolCalls: new Map(),\n closedToolCalls: new Map(),\n knownToolCallIds: new Set(),\n openSteps: new Map(),\n openReasoningBlocks: new Map(),\n openReasoningMessages: new Map(),\n state: { known: false, value: undefined, deltasSinceSnapshot: 0, snapshotSeen: false, agui301Fired: false },\n textChunk: null,\n toolChunk: null,\n reasoningChunk: null,\n }\n}\n\nexport interface StreamState {\n eventCount: number\n sawTimestamp: boolean\n anySnapshot: boolean\n agui001Fired: boolean\n features: Set<CanonicalFeature>\n}\n\n/** What a per-event check handler receives. */\nexport interface CheckApi {\n index: number\n type: string\n event: Record<string, unknown>\n run: RunState\n stream: StreamState\n emit: EmitFn\n feature: (f: CanonicalFeature) => void\n}\n\n/** Reads a field only if it is a string (schema problems already reported). */\nexport function str(event: Record<string, unknown>, field: string): string | undefined {\n const v = event[field]\n return typeof v === \"string\" ? v : undefined\n}\n","// Lifecycle rules: AGUI001–AGUI008. Run open/terminate logic lives in the\n// engine (src/index.ts) because it owns run-scope resets; this module holds\n// the step pairing and the RUN_FINISHED id-stability check.\n\nimport type { CheckApi, RunState, EmitFn } from \"./context.js\"\nimport { str } from \"./context.js\"\n\nexport function handleStepEvent(api: CheckApi): void {\n const { type, event, run, emit, index } = api\n const stepName = str(event, \"stepName\")\n if (stepName === undefined) return\n\n if (type === \"STEP_STARTED\") {\n const open = run.openSteps.get(stepName)\n if (open !== undefined) {\n open.count += 1 // re-entrant same-name steps are tolerated (SQ-10)\n } else {\n run.openSteps.set(stepName, { count: 1, firstIndex: index })\n }\n return\n }\n\n if (type === \"STEP_FINISHED\") {\n const open = run.openSteps.get(stepName)\n if (open === undefined) {\n emit(\"AGUI006\", { stepName }, { pointer: \"/stepName\" })\n return\n }\n open.count -= 1\n if (open.count === 0) run.openSteps.delete(stepName)\n }\n}\n\n/** AGUI008 — RUN_FINISHED must carry the ids RUN_STARTED established. */\nexport function checkRunIdStability(api: CheckApi): void {\n const { event, run, emit } = api\n if (run.implicit) return // no RUN_STARTED to compare against\n for (const field of [\"threadId\", \"runId\"] as const) {\n const actual = str(api.event, field)\n const expected = field === \"threadId\" ? run.threadId : run.runId\n if (actual !== undefined && expected !== null && actual !== expected) {\n emit(\"AGUI008\", { field, actual, expected }, {\n pointer: `/${field}`,\n relatedEventIndex: run.startIndex,\n })\n }\n }\n void event\n}\n\n/** AGUI007 — open steps when the run reaches a clean end. */\nexport function endOfRunSteps(run: RunState, emit: EmitFn, atIndex: number): void {\n for (const [stepName, open] of run.openSteps) {\n emit(\"AGUI007\", { stepName }, {\n eventIndex: atIndex,\n relatedEventIndex: open.firstIndex,\n })\n }\n}\n","// Reasoning rules: AGUI401–AGUI402, plus REASONING_MESSAGE_CHUNK handling.\n//\n// Per SQ-4: block-level nesting (REASONING_MESSAGE_* inside\n// REASONING_START/END) is only described as \"a typical flow\" by the docs, so\n// it is NOT enforced. AGUI401 enforces the message-level pairing, mirroring\n// the text message rules; AGUI402 reports unterminated starts at warning.\n\nimport type { CheckApi, RunState, EmitFn } from \"./context.js\"\nimport { str } from \"./context.js\"\n\nexport function handleReasoningEvent(api: CheckApi): void {\n const { type, event, run, emit, index } = api\n\n switch (type) {\n case \"REASONING_START\": {\n const id = str(event, \"messageId\")\n if (id !== undefined) run.openReasoningBlocks.set(id, index)\n return\n }\n\n case \"REASONING_END\": {\n const id = str(event, \"messageId\")\n if (id !== undefined) run.openReasoningBlocks.delete(id)\n return\n }\n\n case \"REASONING_MESSAGE_START\": {\n const id = str(event, \"messageId\")\n if (id !== undefined) run.openReasoningMessages.set(id, index)\n return\n }\n\n case \"REASONING_MESSAGE_CONTENT\": {\n const id = str(event, \"messageId\")\n if (id === undefined) return\n const openChunk = run.reasoningChunk !== null && run.reasoningChunk.messageId === id\n if (!run.openReasoningMessages.has(id) && !openChunk) {\n emit(\"AGUI401\", { messageId: id }, { pointer: \"/messageId\" })\n }\n return\n }\n\n case \"REASONING_MESSAGE_END\": {\n const id = str(event, \"messageId\")\n if (id !== undefined) run.openReasoningMessages.delete(id)\n return\n }\n\n case \"REASONING_MESSAGE_CHUNK\": {\n const id = str(event, \"messageId\")\n if (id === undefined) {\n if (run.reasoningChunk === null) {\n emit(\"AGUI504\", { type, detail: \"first REASONING_MESSAGE_CHUNK must include messageId\" }, {\n pointer: \"/messageId\",\n })\n return\n }\n if (event.delta === \"\") run.reasoningChunk = null // documented implicit close\n return\n }\n if (run.reasoningChunk !== null && run.reasoningChunk.messageId !== id) {\n run.reasoningChunk = null\n }\n if (event.delta === \"\") {\n run.reasoningChunk = null // empty delta implicitly closes the message\n return\n }\n if (run.reasoningChunk === null) {\n run.reasoningChunk = { messageId: id, startIndex: index }\n }\n return\n }\n\n // REASONING_ENCRYPTED_VALUE: schema-checked only; no ordering rules cited.\n }\n}\n\n/** Chunked reasoning also closes on any non-reasoning event (documented). */\nexport function closeReasoningChunk(run: RunState): void {\n run.reasoningChunk = null\n}\n\n/** AGUI402 — unterminated reasoning at a clean run end. */\nexport function endOfRunReasoning(run: RunState, emit: EmitFn, atIndex: number): void {\n for (const [id, startIndex] of run.openReasoningBlocks) {\n emit(\"AGUI402\", { startType: \"REASONING_START\", messageId: id }, {\n eventIndex: atIndex,\n relatedEventIndex: startIndex,\n })\n }\n for (const [id, startIndex] of run.openReasoningMessages) {\n emit(\"AGUI402\", { startType: \"REASONING_MESSAGE_START\", messageId: id }, {\n eventIndex: atIndex,\n relatedEventIndex: startIndex,\n })\n }\n}\n","// Minimal RFC 6902 (JSON Patch) + RFC 6901 (JSON Pointer) implementation.\n// Hand-rolled so the core keeps zero runtime dependencies. Immutable: the\n// input document is never mutated; ops apply atomically (all or none).\n\nexport type PatchResult =\n | { ok: true; result: unknown }\n | { ok: false; error: string; opIndex: number }\n\nexport interface PatchShapeProblem {\n /** Human-readable problem. */\n error: string\n /** Index of the offending op, or -1 when the document itself is not an array. */\n opIndex: number\n /** RFC 6901 pointer into the patch document, e.g. \"/0/op\". */\n pointer: string\n}\n\nconst OPS = [\"add\", \"remove\", \"replace\", \"move\", \"copy\", \"test\"] as const\ntype OpName = (typeof OPS)[number]\n\n/** RFC 6901: \"\" → whole document; \"/a/b\" → [\"a\", \"b\"]. Returns null when invalid. */\nexport function parsePointer(pointer: unknown): string[] | null {\n if (typeof pointer !== \"string\") return null\n if (pointer === \"\") return []\n if (!pointer.startsWith(\"/\")) return null\n return pointer\n .slice(1)\n .split(\"/\")\n .map((t) => t.replace(/~1/g, \"/\").replace(/~0/g, \"~\"))\n}\n\n/** Structural validation of a patch document, without applying it. */\nexport function validatePatchShape(patch: unknown): PatchShapeProblem | null {\n if (!Array.isArray(patch)) {\n return { error: \"patch document must be an array of operations\", opIndex: -1, pointer: \"\" }\n }\n for (let i = 0; i < patch.length; i++) {\n const op = patch[i]\n if (typeof op !== \"object\" || op === null || Array.isArray(op)) {\n return { error: `operation ${i} is not an object`, opIndex: i, pointer: `/${i}` }\n }\n const o = op as Record<string, unknown>\n if (!OPS.includes(o.op as OpName)) {\n return { error: `operation ${i} has invalid op '${String(o.op)}'`, opIndex: i, pointer: `/${i}/op` }\n }\n if (parsePointer(o.path) === null) {\n return { error: `operation ${i} (${String(o.op)}) has invalid path`, opIndex: i, pointer: `/${i}/path` }\n }\n if ((o.op === \"add\" || o.op === \"replace\" || o.op === \"test\") && !(\"value\" in o)) {\n return { error: `operation ${i} (${String(o.op)}) is missing value`, opIndex: i, pointer: `/${i}` }\n }\n if ((o.op === \"move\" || o.op === \"copy\") && parsePointer(o.from) === null) {\n return { error: `operation ${i} (${String(o.op)}) is missing or has invalid from`, opIndex: i, pointer: `/${i}` }\n }\n }\n return null\n}\n\nfunction clone(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(clone)\n if (typeof value === \"object\" && value !== null) {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) out[k] = clone(v)\n return out\n }\n return value\n}\n\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]))\n }\n if (typeof a === \"object\" && a !== null && typeof b === \"object\" && b !== null && !Array.isArray(a) && !Array.isArray(b)) {\n const ka = Object.keys(a)\n const kb = Object.keys(b as object)\n return ka.length === kb.length && ka.every((k) => deepEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]))\n }\n return false\n}\n\nfunction arrayIndex(token: string, length: number, allowAppend: boolean): number | null {\n if (allowAppend && token === \"-\") return length\n if (!/^(0|[1-9]\\d*)$/.test(token)) return null\n const i = Number(token)\n return i > length ? null : i\n}\n\ninterface Located {\n parent: Record<string, unknown> | unknown[] | null // null → the document root itself\n key: string | number\n exists: boolean\n value: unknown\n}\n\nfunction locate(doc: unknown, tokens: string[], forAdd: boolean): Located | string {\n if (tokens.length === 0) return { parent: null, key: \"\", exists: true, value: doc }\n let current = doc\n for (let i = 0; i < tokens.length - 1; i++) {\n const token = tokens[i]!\n if (Array.isArray(current)) {\n const idx = arrayIndex(token, current.length, false)\n if (idx === null || idx >= current.length) return `path segment '/${token}' does not exist`\n current = current[idx]\n } else if (typeof current === \"object\" && current !== null) {\n const obj = current as Record<string, unknown>\n if (!(token in obj)) return `path segment '/${token}' does not exist`\n current = obj[token]\n } else {\n return `path segment '/${token}' is not an object or array`\n }\n }\n const last = tokens[tokens.length - 1]!\n if (Array.isArray(current)) {\n const idx = arrayIndex(last, current.length, forAdd)\n if (idx === null) return `'${last}' is not a valid index for an array of length ${current.length}`\n return { parent: current, key: idx, exists: idx < current.length, value: current[idx] }\n }\n if (typeof current === \"object\" && current !== null) {\n const obj = current as Record<string, unknown>\n return { parent: obj, key: last, exists: last in obj, value: obj[last] }\n }\n return `target of '/${last}' is not an object or array`\n}\n\n/** Applies an RFC 6902 patch. Validates shape first; never throws. */\nexport function applyPatch(doc: unknown, patch: unknown): PatchResult {\n const shape = validatePatchShape(patch)\n if (shape !== null) return { ok: false, error: shape.error, opIndex: shape.opIndex }\n\n let result = clone(doc)\n const ops = patch as Record<string, unknown>[]\n\n const getAt = (pointer: string): { ok: true; value: unknown } | { ok: false; error: string } => {\n const loc = locate(result, parsePointer(pointer)!, false)\n if (typeof loc === \"string\") return { ok: false, error: `${pointer}: ${loc}` }\n if (!loc.exists) return { ok: false, error: `${pointer} does not exist` }\n return { ok: true, value: loc.value }\n }\n\n const setAt = (pointer: string, value: unknown, mustExist: boolean): string | null => {\n const tokens = parsePointer(pointer)!\n if (tokens.length === 0) {\n result = value\n return null\n }\n const loc = locate(result, tokens, !mustExist)\n if (typeof loc === \"string\") return `${pointer}: ${loc}`\n if (mustExist && !loc.exists) return `${pointer} does not exist`\n if (Array.isArray(loc.parent)) {\n if (mustExist) loc.parent[loc.key as number] = value\n else loc.parent.splice(loc.key as number, 0, value)\n } else {\n loc.parent![loc.key as string] = value\n }\n return null\n }\n\n const removeAt = (pointer: string): { ok: true; removed: unknown } | { ok: false; error: string } => {\n const tokens = parsePointer(pointer)!\n if (tokens.length === 0) return { ok: false, error: \"cannot remove the whole document\" }\n const loc = locate(result, tokens, false)\n if (typeof loc === \"string\") return { ok: false, error: `${pointer}: ${loc}` }\n if (!loc.exists) return { ok: false, error: `${pointer} does not exist` }\n if (Array.isArray(loc.parent)) loc.parent.splice(loc.key as number, 1)\n else delete loc.parent![loc.key as string]\n return { ok: true, removed: loc.value }\n }\n\n for (let i = 0; i < ops.length; i++) {\n const op = ops[i]!\n const path = op.path as string\n let error: string | null = null\n\n switch (op.op as OpName) {\n case \"add\":\n error = setAt(path, clone(op.value), false)\n break\n case \"replace\":\n error = setAt(path, clone(op.value), true)\n break\n case \"remove\": {\n const r = removeAt(path)\n if (!r.ok) error = r.error\n break\n }\n case \"move\": {\n const from = op.from as string\n if (path.startsWith(`${from}/`)) {\n error = `cannot move ${from} into its own child ${path}`\n break\n }\n const r = removeAt(from)\n if (!r.ok) { error = r.error; break }\n error = setAt(path, r.removed, false)\n break\n }\n case \"copy\": {\n const r = getAt(op.from as string)\n if (!r.ok) { error = r.error; break }\n error = setAt(path, clone(r.value), false)\n break\n }\n case \"test\": {\n const r = getAt(path)\n if (!r.ok) error = r.error\n else if (!deepEqual(r.value, op.value)) error = `test failed at ${path}`\n break\n }\n }\n\n if (error !== null) return { ok: false, error, opIndex: i }\n }\n return { ok: true, result }\n}\n\n/** RFC 6901 token escaping, for building diagnostic pointers. */\nexport function escapePointerToken(token: string): string {\n return token.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")\n}\n","// State rules: AGUI301–AGUI305, plus MESSAGES_SNAPSHOT history harvesting.\n\nimport { applyPatch, validatePatchShape } from \"../../protocol/jsonpatch.js\"\nimport type { CheckApi } from \"./context.js\"\n\nexport function handleStateEvent(api: CheckApi): void {\n const { type, event, run, stream, emit } = api\n\n switch (type) {\n case \"STATE_SNAPSHOT\": {\n api.feature(\"shared-state\")\n if (run.state.deltasSinceSnapshot > 0) {\n emit(\"AGUI304\", { deltaCount: run.state.deltasSinceSnapshot }, {})\n }\n run.state.known = true\n run.state.value = event.snapshot\n run.state.snapshotSeen = true\n run.state.deltasSinceSnapshot = 0\n stream.anySnapshot = true\n return\n }\n\n case \"STATE_DELTA\": {\n api.feature(\"shared-state\")\n const delta = event.delta\n if (!Array.isArray(delta)) return // AGUI504 already reported the kind mismatch\n const shape = validatePatchShape(delta)\n if (shape !== null) {\n emit(\"AGUI303\", { error: shape.error }, { pointer: `/delta${shape.pointer}` })\n return\n }\n if (!run.state.snapshotSeen && !run.state.agui301Fired) {\n // The base may be seeded out-of-band via RunAgentInput.state (SQ-1),\n // so this is informational, and patch application is not judged until\n // a snapshot establishes an observable base.\n emit(\"AGUI301\", {}, {})\n run.state.agui301Fired = true\n }\n if (run.state.known) {\n const applied = applyPatch(run.state.value, delta)\n if (applied.ok) {\n run.state.value = applied.result\n } else {\n emit(\"AGUI302\", { error: applied.error }, { pointer: `/delta/${applied.opIndex}` })\n }\n }\n run.state.deltasSinceSnapshot += 1\n return\n }\n\n case \"MESSAGES_SNAPSHOT\": {\n // Snapshots can carry history from before this capture: harvest ids so\n // reference checks (AGUI207/AGUI208) don't false-positive on them.\n const messages = event.messages\n if (!Array.isArray(messages)) return\n for (const message of messages) {\n if (typeof message !== \"object\" || message === null) continue\n const m = message as Record<string, unknown>\n if (typeof m.id === \"string\") run.knownMessageIds.add(m.id)\n if (Array.isArray(m.toolCalls)) {\n for (const call of m.toolCalls) {\n if (typeof call === \"object\" && call !== null) {\n const id = (call as Record<string, unknown>).id\n if (typeof id === \"string\") run.knownToolCallIds.add(id)\n }\n }\n }\n }\n return\n }\n }\n}\n","// Text message rules: AGUI101–AGUI106, plus TEXT_MESSAGE_CHUNK stream handling.\n\nimport type { CheckApi, RunState, EmitFn } from \"./context.js\"\nimport { str } from \"./context.js\"\n\nexport function handleTextEvent(api: CheckApi): void {\n const { type, event, run, emit, index } = api\n api.feature(\"agentic-chat\")\n\n switch (type) {\n case \"TEXT_MESSAGE_START\": {\n const id = str(event, \"messageId\")\n if (id === undefined) return\n if (run.openMessages.has(id)) {\n emit(\"AGUI106\", { messageId: id }, {\n pointer: \"/messageId\",\n relatedEventIndex: run.openMessages.get(id)!.startIndex,\n })\n return\n }\n if (run.closedMessages.has(id)) {\n emit(\"AGUI104\", { messageId: id }, {\n pointer: \"/messageId\",\n relatedEventIndex: run.closedMessages.get(id)!,\n })\n return\n }\n run.openMessages.set(id, { startIndex: index })\n run.knownMessageIds.add(id)\n return\n }\n\n case \"TEXT_MESSAGE_CONTENT\": {\n const id = str(event, \"messageId\")\n if (id === undefined) return\n const open = run.openMessages.get(id)\n if (open === undefined) {\n const closedAt = run.closedMessages.get(id)\n emit(\"AGUI101\", { messageId: id }, {\n pointer: \"/messageId\",\n ...(closedAt !== undefined ? { relatedEventIndex: closedAt } : {}),\n })\n return\n }\n if (event.delta === \"\") {\n emit(\"AGUI105\", { messageId: id }, { pointer: \"/delta\", relatedEventIndex: open.startIndex })\n }\n return\n }\n\n case \"TEXT_MESSAGE_END\": {\n const id = str(event, \"messageId\")\n if (id === undefined) return\n if (!run.openMessages.has(id)) {\n emit(\"AGUI102\", { messageId: id }, { pointer: \"/messageId\" })\n return\n }\n run.openMessages.delete(id)\n run.closedMessages.set(id, index)\n return\n }\n\n case \"TEXT_MESSAGE_CHUNK\": {\n const id = str(event, \"messageId\")\n if (id === undefined) {\n // Continuation chunks may omit messageId; the first chunk must not\n // (docs: \"First chunk for a message must include messageId\").\n if (run.textChunk === null) {\n emit(\"AGUI504\", { type, detail: \"first TEXT_MESSAGE_CHUNK for a message must include messageId\" }, {\n pointer: \"/messageId\",\n })\n }\n return\n }\n // Mixing chunk and explicit forms on one id is undefined behaviour\n // (SQ-9): tolerated, treated as content for the open message.\n if (run.openMessages.has(id)) return\n if (run.textChunk !== null && run.textChunk.messageId === id) return\n closeTextChunk(run, index)\n if (run.closedMessages.has(id)) {\n emit(\"AGUI104\", { messageId: id }, {\n pointer: \"/messageId\",\n relatedEventIndex: run.closedMessages.get(id)!,\n })\n return\n }\n run.textChunk = { messageId: id, startIndex: index }\n run.knownMessageIds.add(id)\n return\n }\n }\n}\n\n/** Chunk streams close implicitly on the next non-chunk event. */\nexport function closeTextChunk(run: RunState, atIndex: number): void {\n if (run.textChunk === null) return\n run.closedMessages.set(run.textChunk.messageId, atIndex)\n run.textChunk = null\n}\n\n/** AGUI103 — open messages when the run reaches a clean end. */\nexport function endOfRunText(run: RunState, emit: EmitFn, atIndex: number): void {\n for (const [id, open] of run.openMessages) {\n emit(\"AGUI103\", { messageId: id }, {\n eventIndex: atIndex,\n relatedEventIndex: open.startIndex,\n })\n }\n}\n","// Tool call rules: AGUI201–AGUI208, plus TOOL_CALL_CHUNK stream handling.\n\nimport type { CheckApi, RunState, EmitFn } from \"./context.js\"\nimport { str } from \"./context.js\"\n\nexport function handleToolCallEvent(api: CheckApi): void {\n const { type, event, run, emit, index } = api\n api.feature(\"backend-tool-rendering\")\n\n switch (type) {\n case \"TOOL_CALL_START\": {\n const id = str(event, \"toolCallId\")\n if (id === undefined) return\n if (run.openToolCalls.has(id) || run.closedToolCalls.has(id)) {\n const related = run.openToolCalls.get(id)?.startIndex ?? run.closedToolCalls.get(id)!\n emit(\"AGUI205\", { toolCallId: id }, { pointer: \"/toolCallId\", relatedEventIndex: related })\n return\n }\n run.openToolCalls.set(id, { startIndex: index, args: \"\", sawArgs: false })\n const parent = str(event, \"parentMessageId\")\n if (parent !== undefined && !run.knownMessageIds.has(parent)) {\n emit(\"AGUI208\", { parentMessageId: parent }, { pointer: \"/parentMessageId\" })\n }\n return\n }\n\n case \"TOOL_CALL_ARGS\": {\n const id = str(event, \"toolCallId\")\n if (id === undefined) return\n const open = run.openToolCalls.get(id)\n if (open === undefined) {\n emit(\"AGUI201\", { toolCallId: id }, { pointer: \"/toolCallId\" })\n return\n }\n const delta = str(event, \"delta\")\n if (delta !== undefined) {\n open.args += delta\n open.sawArgs = true\n }\n return\n }\n\n case \"TOOL_CALL_END\": {\n const id = str(event, \"toolCallId\")\n if (id === undefined) return\n const open = run.openToolCalls.get(id)\n if (open === undefined) {\n emit(\"AGUI202\", { toolCallId: id }, { pointer: \"/toolCallId\" })\n return\n }\n run.openToolCalls.delete(id)\n run.closedToolCalls.set(id, index)\n checkArgsJson(id, open, emit, index)\n return\n }\n\n case \"TOOL_CALL_RESULT\": {\n const id = str(event, \"toolCallId\")\n if (id !== undefined) {\n const open = run.openToolCalls.get(id)\n if (open !== undefined) {\n emit(\"AGUI206\", { toolCallId: id }, {\n pointer: \"/toolCallId\",\n relatedEventIndex: open.startIndex,\n })\n } else if (!run.closedToolCalls.has(id) && !run.knownToolCallIds.has(id)) {\n emit(\"AGUI207\", { toolCallId: id }, { pointer: \"/toolCallId\" })\n }\n }\n // The result is itself a tool message in the conversation.\n const messageId = str(event, \"messageId\")\n if (messageId !== undefined) run.knownMessageIds.add(messageId)\n return\n }\n\n case \"TOOL_CALL_CHUNK\": {\n const id = str(event, \"toolCallId\")\n const delta = str(event, \"delta\")\n if (id === undefined) {\n if (run.toolChunk === null) {\n emit(\"AGUI504\", { type, detail: \"first TOOL_CALL_CHUNK for a tool call must include toolCallId and toolCallName\" }, {\n pointer: \"/toolCallId\",\n })\n return\n }\n if (delta !== undefined) {\n run.toolChunk.args += delta\n run.toolChunk.sawArgs = true\n }\n return\n }\n // SQ-9: chunk continuing an explicitly-opened call — treat as args.\n const openExplicit = run.openToolCalls.get(id)\n if (openExplicit !== undefined) {\n if (delta !== undefined) {\n openExplicit.args += delta\n openExplicit.sawArgs = true\n }\n return\n }\n if (run.toolChunk !== null && run.toolChunk.toolCallId === id) {\n if (delta !== undefined) {\n run.toolChunk.args += delta\n run.toolChunk.sawArgs = true\n }\n return\n }\n closeToolChunk(run, emit, index)\n if (run.closedToolCalls.has(id)) {\n emit(\"AGUI205\", { toolCallId: id }, {\n pointer: \"/toolCallId\",\n relatedEventIndex: run.closedToolCalls.get(id)!,\n })\n return\n }\n if (str(event, \"toolCallName\") === undefined) {\n emit(\"AGUI504\", { type, detail: \"first TOOL_CALL_CHUNK for a tool call must include toolCallName\" }, {\n pointer: \"/toolCallName\",\n })\n }\n run.toolChunk = {\n toolCallId: id,\n startIndex: index,\n args: delta ?? \"\",\n sawArgs: delta !== undefined && delta.length > 0,\n }\n return\n }\n }\n}\n\nfunction checkArgsJson(\n id: string,\n call: { startIndex: number; args: string; sawArgs: boolean },\n emit: EmitFn,\n atIndex: number,\n): void {\n // A call that streamed no args at all is fine (a no-argument tool).\n if (!call.sawArgs || call.args.length === 0) return\n try {\n JSON.parse(call.args)\n } catch (e) {\n emit(\"AGUI204\", { toolCallId: id, error: e instanceof Error ? e.message : String(e) }, {\n eventIndex: atIndex,\n relatedEventIndex: call.startIndex,\n })\n }\n}\n\n/** Chunk streams close implicitly on the next non-chunk event. */\nexport function closeToolChunk(run: RunState, emit: EmitFn, atIndex: number): void {\n if (run.toolChunk === null) return\n const { toolCallId, startIndex, args, sawArgs } = run.toolChunk\n run.toolChunk = null\n run.closedToolCalls.set(toolCallId, atIndex)\n checkArgsJson(toolCallId, { startIndex, args, sawArgs }, emit, atIndex)\n}\n\n/** AGUI203 — open tool calls when the run reaches a clean end. */\nexport function endOfRunToolCalls(run: RunState, emit: EmitFn, atIndex: number): void {\n for (const [id, open] of run.openToolCalls) {\n emit(\"AGUI203\", { toolCallId: id }, {\n eventIndex: atIndex,\n relatedEventIndex: open.startIndex,\n })\n }\n}\n","// Transport rules (AGUI501, AGUI505–AGUI508) are only checkable against a\n// live connection: SSE framing, Content-Type, keepalive timing, flush\n// behaviour, abnormal EOF. The core cannot observe any of that from a parsed\n// event sequence, so it reports these rules as skipped — never silently —\n// and the transport layer (ag-ui-validate/transport, M5) evaluates them.\n//\n// AGUI502/503/504 are transport-adjacent but *are* checkable here (the core\n// accepts raw JSON strings), so they live in the engine, not this list.\n\nimport { CATALOG } from \"../catalog.js\"\n\nexport const TRANSPORT_SKIP_REASON =\n \"transport-layer rule; only checkable against a live connection (validated by ag-ui-validate/transport)\"\n\nexport const TRANSPORT_RULE_IDS: readonly string[] = CATALOG.rules\n .filter((r) => r.checkedIn === \"transport\")\n .map((r) => r.id)\n","import type { Severity, SeverityOrOff } from \"./rules/catalog.js\"\n\nexport type { Severity, SeverityOrOff }\n\n/** A single conformance finding. */\nexport interface Diagnostic {\n /** Rule ID, e.g. \"AGUI203\". */\n rule: string\n severity: Severity\n /** Human-readable, includes the offending id/value. */\n message: string\n /**\n * 0-based position in the stream of the event this diagnostic is about.\n * Stream-level diagnostics (e.g. AGUI902) use -1.\n */\n eventIndex: number\n /** The event's declared type, if parseable. */\n eventType?: string\n /** RFC 6901 JSON pointer into the event, e.g. \"/toolCallId\". */\n pointer?: string\n /** e.g. the unterminated TOOL_CALL_START this refers back to. */\n relatedEventIndex?: number\n /** Link to the governing spec section. Always populated. */\n specUrl: string\n}\n\n/** The seven canonical AG-UI features (from the AG-UI Dojo). */\nexport type CanonicalFeature =\n | \"agentic-chat\"\n | \"backend-tool-rendering\"\n | \"human-in-the-loop\"\n | \"agentic-generative-ui\"\n | \"tool-based-generative-ui\"\n | \"shared-state\"\n | \"predictive-state-updates\"\n\nexport const CANONICAL_FEATURES: readonly CanonicalFeature[] = [\n \"agentic-chat\",\n \"backend-tool-rendering\",\n \"human-in-the-loop\",\n \"agentic-generative-ui\",\n \"tool-based-generative-ui\",\n \"shared-state\",\n \"predictive-state-updates\",\n]\n\n/**\n * Feature-matrix status. Capability discovery (getCapabilities()) is\n * out-of-band and invisible to a passive stream observer, so this matrix is\n * inferred from observed events; features whose exercise cannot be\n * distinguished passively are \"not-inferable\". See docs/spec-questions.md SQ-13.\n */\nexport type FeatureStatus = \"exercised\" | \"not-exercised\" | \"not-inferable\"\n\nexport type FeatureMatrix = Record<CanonicalFeature, FeatureStatus>\n\nexport interface Summary {\n errors: number\n warnings: number\n info: number\n}\n\nexport interface SkippedRule {\n rule: string\n reason: string\n}\n\nexport interface Report {\n diagnostics: Diagnostic[]\n summary: Summary\n features: FeatureMatrix\n /**\n * Rules that were not evaluated in this mode and why — e.g. transport rules\n * when validating recorded input. Skips are reported, never silent.\n */\n skipped: SkippedRule[]\n eventCount: number\n /**\n * Unexpected internal validator errors. The validator never throws on any\n * input; if a check itself crashes, the message lands here instead.\n */\n internalErrors: string[]\n}\n\nexport type ValidationLayer = \"core\" | \"transport\"\n\nexport interface ValidatorOptions {\n /** Pins the rule set to a spec version. Only \"0.x\" exists today. */\n spec?: \"0.x\"\n /**\n * Declared features. Enables feature-conditional rules (e.g. AGUI305 fires\n * only when \"shared-state\" is declared).\n */\n features?: string[]\n /** Per-rule severity overrides; \"off\" disables a rule. */\n severityOverrides?: Record<string, SeverityOrOff>\n /**\n * Which rule layers are being evaluated. \"core\" is always on. Wrapping\n * layers that check transport rules (via emitExternal) declare \"transport\"\n * so those rules stop being reported as skipped. Default: [\"core\"].\n */\n layers?: ValidationLayer[]\n}\n\nexport interface Validator {\n /**\n * Feed one event — a parsed object, or a raw JSON string (malformed JSON is\n * a diagnostic, not an exception). Returns diagnostics detectable at this\n * event, in stream order. Never throws.\n */\n feed(event: unknown): Diagnostic[]\n /**\n * End-of-stream checks (unterminated tool calls, missing RUN_FINISHED, …).\n * Idempotent: second and later calls return []. Never throws.\n */\n finalize(): Diagnostic[]\n /** Cumulative report over everything fed so far. Never throws. */\n report(): Report\n /**\n * For wrapping layers (transport, CLI): report a layer-checked rule through\n * the same catalog formatting, severity overrides, and summary as core\n * diagnostics. Returns the diagnostic, or null when the rule is unknown\n * (recorded in internalErrors) or overridden off. Never throws.\n */\n emitExternal(\n rule: string,\n params?: Record<string, unknown>,\n extra?: { eventIndex?: number; pointer?: string; relatedEventIndex?: number },\n ): Diagnostic | null\n /**\n * For wrapping layers: declare that a rule was NOT evaluated and why (e.g.\n * timing rules on recorded input). The entry appears in report().skipped,\n * replacing any layer-computed entry for the same rule. Never throws.\n */\n markSkipped(rule: string, reason: string): void\n}\n","// ag-ui-validate core: a pure function over an AG-UI event sequence.\n// Zero I/O, zero runtime dependencies, isomorphic. Transports, the CLI, and\n// the Vitest matcher are thin wrappers over this module.\n//\n// Two invariants hold everywhere here:\n// - the validator NEVER throws on input: broken input is its input;\n// - every diagnostic cites the spec section that governs it (specUrl).\n\nimport { DRAFT_EVENT_TYPES, EVENT_TABLE, EVENT_TYPES, SDK_VERSION } from \"./protocol/event-table.js\"\nimport type { EventSpec } from \"./protocol/event-table.js\"\nimport { RULES, formatMessage } from \"./rules/catalog.js\"\nimport type { CheckApi, EmitFn, RunState, StreamState } from \"./rules/checks/context.js\"\nimport { newRunState, str } from \"./rules/checks/context.js\"\nimport { checkRunIdStability, endOfRunSteps, handleStepEvent } from \"./rules/checks/lifecycle.js\"\nimport { closeReasoningChunk, endOfRunReasoning, handleReasoningEvent } from \"./rules/checks/reasoning.js\"\nimport { handleStateEvent } from \"./rules/checks/state.js\"\nimport { closeTextChunk, endOfRunText, handleTextEvent } from \"./rules/checks/text.js\"\nimport { closeToolChunk, endOfRunToolCalls, handleToolCallEvent } from \"./rules/checks/toolcalls.js\"\nimport { TRANSPORT_RULE_IDS, TRANSPORT_SKIP_REASON } from \"./rules/checks/transport.js\"\nimport type {\n CanonicalFeature,\n Diagnostic,\n FeatureMatrix,\n Report,\n Severity,\n Validator,\n ValidatorOptions,\n} from \"./types.js\"\nimport { CANONICAL_FEATURES } from \"./types.js\"\n\nexport * from \"./types.js\"\nexport { CATALOG, RULES, formatMessage, validateCatalog } from \"./rules/catalog.js\"\nexport type { Catalog, RuleDefinition, Severity as RuleSeverity, SeverityOrOff } from \"./rules/catalog.js\"\nexport { EVENT_TABLE, EVENT_TYPES, SDK_VERSION } from \"./protocol/event-table.js\"\nexport type { EventCategory, EventSpec, FieldKind, FieldSpec } from \"./protocol/event-table.js\"\nexport { applyPatch, validatePatchShape } from \"./protocol/jsonpatch.js\"\n\nconst DRAFTS_META_URL = \"https://docs.ag-ui.com/drafts/meta-events\"\n\n// Features whose exercise cannot be distinguished on a passive stream: both\n// generative-UI features need knowledge of the frontend's tool/component\n// registry, which is out-of-band (see SQ-13).\nconst NOT_INFERABLE: readonly CanonicalFeature[] = [\n \"agentic-generative-ui\",\n \"tool-based-generative-ui\",\n]\n\n/** \"runStarted\" → \"RUN_STARTED\": case-insensitive match against wire types. */\nconst CANONICAL_BY_SQUASHED: ReadonlyMap<string, string> = new Map(\n EVENT_TYPES.map((t) => [t.replace(/_/g, \"\").toLowerCase(), t]),\n)\n\nfunction describeValue(v: unknown): string {\n if (v === null) return \"null\"\n if (Array.isArray(v)) return \"array\"\n return typeof v\n}\n\nexport function createValidator(opts: ValidatorOptions = {}): Validator {\n const overrides = opts.severityOverrides ?? {}\n const declaredFeatures = new Set(opts.features ?? [])\n const layers = new Set([\"core\", ...(opts.layers ?? [])])\n\n const diagnostics: Diagnostic[] = []\n const internalErrors: string[] = []\n const explicitSkips = new Map<string, string>()\n const stream: StreamState = {\n eventCount: 0,\n sawTimestamp: false,\n anySnapshot: false,\n agui001Fired: false,\n features: new Set(),\n }\n let run: RunState | null = null\n let finalized = false\n\n function mkEmit(batch: Diagnostic[], current: { index: number; type: string } | null): EmitFn {\n return (ruleId, params, extra = {}) => {\n const rule = RULES.get(ruleId)\n if (rule === undefined) {\n internalErrors.push(`emit() for unknown rule ${ruleId}`)\n return\n }\n const override = overrides[ruleId]\n if (override === \"off\") return\n const severity: Severity = override ?? extra.severity ?? rule.severity\n const aboutCurrentEvent = extra.eventIndex === undefined && current !== null\n const diag: Diagnostic = {\n rule: ruleId,\n severity,\n message: formatMessage(rule, params) + (extra.messageSuffix ?? \"\"),\n eventIndex: extra.eventIndex ?? current?.index ?? -1,\n specUrl: extra.specUrl ?? rule.specUrl,\n }\n if (aboutCurrentEvent) diag.eventType = current.type\n if (extra.pointer !== undefined) diag.pointer = extra.pointer\n if (extra.relatedEventIndex !== undefined) diag.relatedEventIndex = extra.relatedEventIndex\n diagnostics.push(diag)\n batch.push(diag)\n }\n }\n\n function validateSchema(type: string, spec: EventSpec, ev: Record<string, unknown>, emit: EmitFn): void {\n for (const [field, fs] of Object.entries(spec.fields)) {\n const v = ev[field]\n if (v === undefined) {\n if (fs.required) {\n emit(\"AGUI504\", { type, detail: `missing required field '${field}' (${fs.kind})` }, {\n pointer: `/${field}`,\n })\n }\n continue\n }\n let kindOk = true\n switch (fs.kind) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n kindOk = typeof v === fs.kind\n break\n case \"array\":\n kindOk = Array.isArray(v)\n break\n case \"object\":\n kindOk = typeof v === \"object\" && v !== null && !Array.isArray(v)\n break\n case \"any\":\n break\n }\n if (!kindOk) {\n emit(\"AGUI504\", { type, detail: `field '${field}' must be ${fs.kind === \"array\" ? \"an\" : \"a\"} ${fs.kind}, got ${describeValue(v)}` }, {\n pointer: `/${field}`,\n })\n continue\n }\n if (fs.enum !== undefined && typeof v === \"string\" && !fs.enum.includes(v)) {\n emit(\"AGUI504\", { type, detail: `field '${field}' must be one of ${fs.enum.join(\"|\")}, got '${v}'` }, {\n pointer: `/${field}`,\n })\n }\n }\n }\n\n /** Chunk streams close implicitly on any event of a different type. */\n function closeChunks(r: RunState, emit: EmitFn, atIndex: number, except?: string): void {\n if (except !== \"TEXT_MESSAGE_CHUNK\") closeTextChunk(r, atIndex)\n if (except !== \"TOOL_CALL_CHUNK\") closeToolChunk(r, emit, atIndex)\n if (except !== \"REASONING_MESSAGE_CHUNK\") closeReasoningChunk(r)\n }\n\n /** Unterminated-at-run-end rules. Only on a *clean* end (RUN_FINISHED or a\n * stream that just stops): after RUN_ERROR, open streams are expected\n * debris of the failure, and flagging them would manufacture noise. */\n function endOfRunChecks(r: RunState, emit: EmitFn, atIndex: number): void {\n endOfRunText(r, emit, atIndex)\n endOfRunToolCalls(r, emit, atIndex)\n endOfRunSteps(r, emit, atIndex)\n endOfRunReasoning(r, emit, atIndex)\n }\n\n /** Opens the implicit run scope for streams that never announced one. */\n function ensureRun(index: number, type: string, emit: EmitFn): RunState {\n if (run === null) {\n if (!stream.agui001Fired) {\n emit(\"AGUI001\", { type }, {})\n stream.agui001Fired = true\n }\n run = newRunState({ runId: null, threadId: null, startIndex: index, implicit: true })\n }\n return run\n }\n\n function processEvent(input: unknown, batch: Diagnostic[]): void {\n const index = stream.eventCount\n stream.eventCount += 1\n\n // 1. Parse. Malformed input is a diagnostic, never an exception.\n let parsed: unknown = input\n if (typeof input === \"string\") {\n try {\n parsed = JSON.parse(input)\n } catch (e) {\n mkEmit(batch, { index, type: \"\" })(\"AGUI502\", {\n error: e instanceof Error ? e.message : String(e),\n })\n return\n }\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n mkEmit(batch, { index, type: \"\" })(\"AGUI502\", {\n error: `payload is ${describeValue(parsed)}, expected a JSON object`,\n })\n return\n }\n const ev = parsed as Record<string, unknown>\n\n // 2. The declared type is the key to everything else.\n if (typeof ev.type !== \"string\") {\n mkEmit(batch, { index, type: \"\" })(\"AGUI504\", {\n type: \"(untyped)\",\n detail: \"event has no string 'type' property\",\n }, { pointer: \"/type\" })\n return\n }\n const type = ev.type\n const emit = mkEmit(batch, { index, type })\n\n // 3. Base-event fields.\n if (\"timestamp\" in ev && ev.timestamp !== undefined) {\n if (typeof ev.timestamp === \"number\") stream.sawTimestamp = true\n else emit(\"AGUI504\", { type, detail: `field 'timestamp' must be a number, got ${describeValue(ev.timestamp)}` }, { pointer: \"/timestamp\" })\n }\n\n // 4. Unknown types: AGUI503 (documented drafts at info; casing hints for\n // near-misses — SQ-7).\n const spec = EVENT_TABLE[type]\n if (spec === undefined) {\n if (DRAFT_EVENT_TYPES.includes(type)) {\n emit(\"AGUI503\", { type, sdkVersion: SDK_VERSION }, {\n severity: \"info\",\n specUrl: DRAFTS_META_URL,\n messageSuffix: \" — documented draft event type, not yet in @ag-ui/core\",\n })\n } else {\n const canonical = CANONICAL_BY_SQUASHED.get(type.replace(/[_\\-\\s]/g, \"\").toLowerCase())\n emit(\"AGUI503\", { type, sdkVersion: SDK_VERSION }, {\n ...(canonical !== undefined\n ? { messageSuffix: ` — did you mean '${canonical}'? AG-UI wire types use SCREAMING_SNAKE_CASE` }\n : {}),\n })\n }\n return\n }\n\n // 5. Schema validation for the declared type (AGUI504).\n validateSchema(type, spec, ev, emit)\n\n // 6. Lifecycle position.\n if (type === \"RUN_STARTED\") {\n if (run === null) {\n run = newRunState({\n runId: str(ev, \"runId\") ?? null,\n threadId: str(ev, \"threadId\") ?? null,\n startIndex: index,\n implicit: false,\n })\n } else if (run.terminal !== null) {\n // A new run after a clean terminal: multi-run streams are legal\n // (serialized logs branch via parentRunId — SQ-6). Fresh scope.\n run = newRunState({\n runId: str(ev, \"runId\") ?? null,\n threadId: str(ev, \"threadId\") ?? null,\n startIndex: index,\n implicit: false,\n })\n } else if (run.implicit) {\n // The stream opened without RUN_STARTED (AGUI001 already fired); the\n // late start legitimizes the implicit scope rather than double-firing.\n closeChunks(run, emit, index)\n run.implicit = false\n run.runId = str(ev, \"runId\") ?? null\n run.threadId = str(ev, \"threadId\") ?? null\n } else {\n closeChunks(run, emit, index)\n emit(\"AGUI002\", { runId: str(ev, \"runId\") ?? \"(missing)\" }, {\n relatedEventIndex: run.startIndex,\n })\n }\n return\n }\n\n const r = ensureRun(index, type, emit)\n\n // 7. Nothing may follow a terminal event (AGUI004/AGUI005).\n if (r.terminal !== null) {\n const terminalType = r.terminal.type\n if ((type === \"RUN_FINISHED\" || type === \"RUN_ERROR\") && type !== terminalType) {\n emit(\"AGUI005\", { type, terminalType }, { relatedEventIndex: r.terminal.index })\n } else {\n emit(\"AGUI004\", { type, terminalType }, { relatedEventIndex: r.terminal.index })\n }\n return\n }\n\n closeChunks(r, emit, index, type)\n\n // 8. Terminal events.\n if (type === \"RUN_FINISHED\" || type === \"RUN_ERROR\") {\n if (type === \"RUN_FINISHED\") {\n checkRunIdStability(api(index, type, ev, r, emit))\n endOfRunChecks(r, emit, index)\n const outcome = ev.outcome\n if (typeof outcome === \"object\" && outcome !== null &&\n (outcome as Record<string, unknown>).type === \"interrupt\") {\n stream.features.add(\"human-in-the-loop\")\n }\n }\n r.terminal = { type, index }\n return\n }\n\n // 9. Per-category checks.\n const a = api(index, type, ev, r, emit)\n switch (spec.category) {\n case \"lifecycle\":\n handleStepEvent(a) // STEP_STARTED / STEP_FINISHED\n break\n case \"text\":\n handleTextEvent(a)\n break\n case \"toolcall\":\n handleToolCallEvent(a)\n break\n case \"state\":\n handleStateEvent(a)\n break\n case \"reasoning\":\n handleReasoningEvent(a)\n break\n case \"thinking\":\n // Deprecated but valid (SQ-8): schema-checked above, no ordering rules\n // in the catalog yet — a \"deprecated event used\" rule is proposed\n // upstream rather than invented here.\n break\n case \"activity\":\n // No activity rules in the catalog yet.\n break\n case \"special\":\n if (type === \"RAW\") {\n const wrapped = ev.event\n if (typeof wrapped === \"object\" && wrapped !== null) {\n const wrappedType = (wrapped as Record<string, unknown>).type\n if (typeof wrappedType === \"string\" && EVENT_TABLE[wrappedType] !== undefined) {\n emit(\"AGUI901\", { wrappedType }, { pointer: \"/event/type\" })\n }\n }\n } else if (type === \"CUSTOM\") {\n const name = str(ev, \"name\")\n if (name !== undefined) {\n if (name === \"PredictState\") stream.features.add(\"predictive-state-updates\")\n if (!/[.:/]/.test(name)) emit(\"AGUI903\", { name }, { pointer: \"/name\" })\n }\n }\n break\n }\n }\n\n function api(\n index: number,\n type: string,\n event: Record<string, unknown>,\n r: RunState,\n emit: EmitFn,\n ): CheckApi {\n return {\n index,\n type,\n event,\n run: r,\n stream,\n emit,\n feature: (f) => stream.features.add(f),\n }\n }\n\n return {\n feed(event: unknown): Diagnostic[] {\n const batch: Diagnostic[] = []\n try {\n processEvent(event, batch)\n } catch (e) {\n internalErrors.push(`feed(event ${stream.eventCount - 1}): ${e instanceof Error ? (e.stack ?? e.message) : String(e)}`)\n }\n return batch\n },\n\n finalize(): Diagnostic[] {\n if (finalized) return []\n finalized = true\n const batch: Diagnostic[] = []\n const emit = mkEmit(batch, null)\n try {\n if (run !== null && run.terminal === null) {\n closeChunks(run, emit, -1)\n emit(\"AGUI003\", { runId: run.runId ?? \"(unknown)\" }, {\n eventIndex: -1,\n relatedEventIndex: run.startIndex,\n })\n endOfRunChecks(run, emit, -1)\n }\n if (stream.eventCount > 0 && !stream.sawTimestamp) {\n emit(\"AGUI902\", { eventCount: stream.eventCount }, { eventIndex: -1 })\n }\n if (declaredFeatures.has(\"shared-state\") && !stream.anySnapshot) {\n emit(\"AGUI305\", {}, { eventIndex: -1 })\n }\n } catch (e) {\n internalErrors.push(`finalize(): ${e instanceof Error ? (e.stack ?? e.message) : String(e)}`)\n }\n return batch\n },\n\n emitExternal(rule, params = {}, extra = {}): Diagnostic | null {\n const batch: Diagnostic[] = []\n try {\n mkEmit(batch, null)(rule, params, extra)\n } catch (e) {\n internalErrors.push(`emitExternal(${rule}): ${e instanceof Error ? e.message : String(e)}`)\n }\n return batch[0] ?? null\n },\n\n markSkipped(rule, reason): void {\n explicitSkips.set(String(rule), String(reason))\n },\n\n report(): Report {\n const summary = { errors: 0, warnings: 0, info: 0 }\n for (const d of diagnostics) {\n if (d.severity === \"error\") summary.errors += 1\n else if (d.severity === \"warning\") summary.warnings += 1\n else summary.info += 1\n }\n\n const features = {} as FeatureMatrix\n for (const f of CANONICAL_FEATURES) {\n features[f] = NOT_INFERABLE.includes(f)\n ? \"not-inferable\"\n : stream.features.has(f)\n ? \"exercised\"\n : \"not-exercised\"\n }\n\n let skipped = layers.has(\"transport\")\n ? []\n : TRANSPORT_RULE_IDS\n .filter((id) => overrides[id] !== \"off\")\n .map((rule) => ({ rule, reason: TRANSPORT_SKIP_REASON }))\n if (!declaredFeatures.has(\"shared-state\") && overrides.AGUI305 !== \"off\") {\n skipped.push({\n rule: \"AGUI305\",\n reason: \"only evaluated when the 'shared-state' feature is declared via options.features\",\n })\n }\n for (const [rule, severity] of Object.entries(overrides)) {\n if (severity === \"off\" && RULES.has(rule)) {\n skipped.push({ rule, reason: \"disabled by severityOverrides\" })\n }\n }\n if (explicitSkips.size > 0) {\n skipped = skipped.filter((s) => !explicitSkips.has(s.rule))\n for (const [rule, reason] of explicitSkips) skipped.push({ rule, reason })\n }\n\n return {\n diagnostics: [...diagnostics],\n summary,\n features,\n skipped,\n eventCount: stream.eventCount,\n internalErrors: [...internalErrors],\n }\n },\n }\n}\n","// Human-readable output. Pure string formatting — the CLI decides where it\n// goes and whether a TTY wants color.\nimport type { Diagnostic, Report, Severity } from \"../types.js\"\n\nexport interface PrettyOptions {\n color: boolean\n}\n\nconst SYMBOL: Record<Severity, string> = { error: \"✖\", warning: \"⚠\", info: \"ℹ\" }\nconst SGR: Record<Severity, string> = { error: \"31\", warning: \"33\", info: \"36\" }\n\nfunction paint(code: string, s: string, on: boolean): string {\n return on ? `\\x1b[${code}m${s}\\x1b[0m` : s\n}\n\nexport function formatDiagnosticLine(d: Diagnostic, opts: PrettyOptions): string {\n const where = d.eventIndex >= 0 ? `event ${d.eventIndex}` : \"—\"\n const head = paint(SGR[d.severity], `${SYMBOL[d.severity]} ${d.rule}`, opts.color)\n const meta = paint(\"2\", `${d.severity.padEnd(7)} ${where.padEnd(10)}`, opts.color)\n const cite = paint(\"2\", ` ↳ ${d.specUrl}`, opts.color)\n return `${head} ${meta} ${d.message}\\n${cite}`\n}\n\nfunction count(n: number, noun: string): string {\n return `${n} ${noun}${n === 1 ? \"\" : \"s\"}`\n}\n\nexport function formatReportSummary(report: Report, opts: PrettyOptions): string {\n const { errors, warnings, info } = report.summary\n const lines: string[] = []\n\n if (errors + warnings + info === 0) {\n lines.push(\n paint(\"32\", `✔ no conformance violations across ${count(report.eventCount, \"event\")}`, opts.color),\n )\n } else {\n lines.push(\n `${count(errors, \"error\")}, ${count(warnings, \"warning\")}, ${info} info across ${count(report.eventCount, \"event\")}`,\n )\n }\n\n const features = Object.entries(report.features)\n const exercised = features.filter(([, s]) => s === \"exercised\").map(([f]) => f)\n const suffix = exercised.length > 0 ? `: ${exercised.join(\", \")}` : \"\"\n lines.push(`${exercised.length} of ${features.length} AG-UI features exercised${suffix}`)\n\n if (report.skipped.length > 0) {\n lines.push(`${count(report.skipped.length, \"rule\")} not evaluated:`)\n for (const s of report.skipped) {\n lines.push(paint(\"2\", ` – ${s.rule}: ${s.reason}`, opts.color))\n }\n }\n\n for (const e of report.internalErrors) {\n lines.push(paint(\"31\", `! internal validator error: ${e}`, opts.color))\n }\n\n return lines.join(\"\\n\")\n}\n","// The matcher itself is framework-agnostic and pure: it takes the received\n// value and options, runs the core validator, and returns {pass, message}.\n// vitest/index.ts registers it with expect.extend; Jest users can do the same.\nimport { decideExitCode } from \"../cli-args.js\"\nimport { createValidator } from \"../index.js\"\nimport { formatDiagnosticLine } from \"../report/pretty.js\"\nimport type { SeverityOrOff, ValidatorOptions } from \"../types.js\"\n\nexport interface ToBeValidAGUIOptions {\n /** Declared features (enables feature-conditional rules, e.g. AGUI305). */\n features?: string[]\n /** Per-rule severity overrides; \"off\" disables a rule. */\n severityOverrides?: Record<string, SeverityOrOff>\n /** Fail when warning-severity findings exceed this budget. */\n maxWarnings?: number\n}\n\nexport interface MatcherResult {\n pass: boolean\n message: () => string\n}\n\nexport function toBeValidAGUI(\n received: unknown,\n options: ToBeValidAGUIOptions = {},\n): MatcherResult {\n let events: unknown[]\n if (typeof received === \"string\") {\n // A JSONL/NDJSON capture: one event per non-empty line.\n events = received.split(/\\r?\\n/).filter((line) => line.trim() !== \"\")\n } else if (Array.isArray(received)) {\n events = received\n } else {\n throw new TypeError(\n `toBeValidAGUI expects an array of events (objects or JSON strings) or a JSONL string; ` +\n `received ${received === null ? \"null\" : typeof received}. Wrap a single event in an array.`,\n )\n }\n\n const validatorOptions: ValidatorOptions = {}\n if (options.features !== undefined) validatorOptions.features = options.features\n if (options.severityOverrides !== undefined) {\n validatorOptions.severityOverrides = options.severityOverrides\n }\n\n const v = createValidator(validatorOptions)\n for (const e of events) v.feed(e)\n v.finalize()\n const report = v.report()\n const { errors, warnings, info } = report.summary\n const pass = decideExitCode(report.summary, options.maxWarnings) === 0\n\n return {\n pass,\n message: (): string => {\n if (pass) {\n return (\n `expected the stream to violate AG-UI conformance, but it is valid: ` +\n `${report.eventCount} events, ${errors} errors, ${warnings} warnings, ${info} info`\n )\n }\n const lines: string[] = []\n if (errors > 0) {\n lines.push(`expected a valid AG-UI stream, but found ${errors} error-severity finding${errors === 1 ? \"\" : \"s\"}:`)\n } else {\n lines.push(\n `expected a valid AG-UI stream, but ${warnings} warning${warnings === 1 ? \"\" : \"s\"} exceed maxWarnings: ${options.maxWarnings}:`,\n )\n }\n for (const d of report.diagnostics) {\n if (d.severity === \"info\") continue\n lines.push(formatDiagnosticLine(d, { color: false }))\n }\n return lines.join(\"\\n\")\n },\n }\n}\n","import { expect } from \"vitest\"\nimport { toBeValidAGUI } from \"./matcher.js\"\nimport type { ToBeValidAGUIOptions } from \"./matcher.js\"\n\nexport { toBeValidAGUI } from \"./matcher.js\"\nexport type { MatcherResult, ToBeValidAGUIOptions } from \"./matcher.js\"\n\ndeclare module \"vitest\" {\n // The type parameter must match vitest's own `interface Matchers<T = any>`.\n interface Matchers<T = any> {\n toBeValidAGUI(options?: ToBeValidAGUIOptions): T\n }\n}\n\nexpect.extend({\n toBeValidAGUI(received: unknown, options?: ToBeValidAGUIOptions) {\n return toBeValidAGUI(received, options)\n },\n})\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ag-ui-validate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Conformance validator for the AG-UI protocol. Feed it an event stream, get every violation with a rule ID, a severity, and a link to the governing spec section.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ag-ui",
|
|
7
|
+
"agui",
|
|
8
|
+
"agent-user-interaction",
|
|
9
|
+
"conformance",
|
|
10
|
+
"validator",
|
|
11
|
+
"protocol",
|
|
12
|
+
"sse",
|
|
13
|
+
"agents"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Faraz (https://langport.dev)",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/langport-dev/ag-ui-validate.git"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/langport-dev/ag-ui-validate#readme",
|
|
22
|
+
"bugs": "https://github.com/langport-dev/ag-ui-validate/issues",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"./dist/vitest.js",
|
|
26
|
+
"./src/vitest/index.ts"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"bin": {
|
|
32
|
+
"ag-ui-validate": "./dist/cli.js"
|
|
33
|
+
},
|
|
34
|
+
"main": "./dist/index.cjs",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"typesVersions": {
|
|
38
|
+
"*": {
|
|
39
|
+
"transport": [
|
|
40
|
+
"./dist/transport.d.ts"
|
|
41
|
+
],
|
|
42
|
+
"report": [
|
|
43
|
+
"./dist/report.d.ts"
|
|
44
|
+
],
|
|
45
|
+
"vitest": [
|
|
46
|
+
"./dist/vitest.d.ts"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"exports": {
|
|
51
|
+
".": {
|
|
52
|
+
"import": {
|
|
53
|
+
"types": "./dist/index.d.ts",
|
|
54
|
+
"default": "./dist/index.js"
|
|
55
|
+
},
|
|
56
|
+
"require": {
|
|
57
|
+
"types": "./dist/index.d.cts",
|
|
58
|
+
"default": "./dist/index.cjs"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"./transport": {
|
|
62
|
+
"import": {
|
|
63
|
+
"types": "./dist/transport.d.ts",
|
|
64
|
+
"default": "./dist/transport.js"
|
|
65
|
+
},
|
|
66
|
+
"require": {
|
|
67
|
+
"types": "./dist/transport.d.cts",
|
|
68
|
+
"default": "./dist/transport.cjs"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"./report": {
|
|
72
|
+
"import": {
|
|
73
|
+
"types": "./dist/report.d.ts",
|
|
74
|
+
"default": "./dist/report.js"
|
|
75
|
+
},
|
|
76
|
+
"require": {
|
|
77
|
+
"types": "./dist/report.d.cts",
|
|
78
|
+
"default": "./dist/report.cjs"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"./vitest": {
|
|
82
|
+
"import": {
|
|
83
|
+
"types": "./dist/vitest.d.ts",
|
|
84
|
+
"default": "./dist/vitest.js"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"./package.json": "./package.json"
|
|
88
|
+
},
|
|
89
|
+
"files": [
|
|
90
|
+
"dist",
|
|
91
|
+
"src"
|
|
92
|
+
],
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "tsdown",
|
|
95
|
+
"typecheck": "tsc --noEmit -p tsconfig.src.json && tsc --noEmit",
|
|
96
|
+
"test": "vitest run",
|
|
97
|
+
"test:watch": "vitest",
|
|
98
|
+
"fixtures:build": "npm run build && node scripts/build-fixtures.mjs",
|
|
99
|
+
"protocol:derive": "node scripts/generate-event-table.mjs",
|
|
100
|
+
"docs:generate": "node scripts/generate-rule-docs.mjs",
|
|
101
|
+
"docs:check": "node scripts/generate-rule-docs.mjs --check",
|
|
102
|
+
"demo": "node scripts/demo.mjs",
|
|
103
|
+
"fuzz": "node scripts/fuzz.mjs",
|
|
104
|
+
"e2e": "node scripts/e2e-live-server.mjs",
|
|
105
|
+
"links:check": "node scripts/check-spec-links.mjs",
|
|
106
|
+
"changeset": "changeset",
|
|
107
|
+
"version": "changeset version",
|
|
108
|
+
"prepublishOnly": "npm run build"
|
|
109
|
+
},
|
|
110
|
+
"peerDependencies": {
|
|
111
|
+
"vitest": ">=2.1.0"
|
|
112
|
+
},
|
|
113
|
+
"peerDependenciesMeta": {
|
|
114
|
+
"vitest": {
|
|
115
|
+
"optional": true
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"devDependencies": {
|
|
119
|
+
"@ag-ui/core": "^0.0.58",
|
|
120
|
+
"@changesets/cli": "^3.0.0",
|
|
121
|
+
"@types/node": "^26.2.0",
|
|
122
|
+
"tsdown": "^0.22.14",
|
|
123
|
+
"typescript": "^7.0.2",
|
|
124
|
+
"unrun": "^0.3.1",
|
|
125
|
+
"vitest": "^4.1.10"
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/cli-args.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Pure CLI argument parsing — no Node APIs, so it obeys the core purity rules
|
|
2
|
+
// and tests without spawning processes. The Node-only entry lives in cli.ts.
|
|
3
|
+
import type { Severity } from "./types.js"
|
|
4
|
+
|
|
5
|
+
export type CliFormat = "pretty" | "json" | "sarif" | "junit"
|
|
6
|
+
|
|
7
|
+
export interface CliConfig {
|
|
8
|
+
/** URL, file path, or "-" for stdin. Empty only with --help/--version. */
|
|
9
|
+
target: string
|
|
10
|
+
format: CliFormat
|
|
11
|
+
/** true/false forced; null = auto-detect from TTY. */
|
|
12
|
+
color: boolean | null
|
|
13
|
+
maxWarnings?: number
|
|
14
|
+
timeoutMs?: number
|
|
15
|
+
/** Header names lowercased. */
|
|
16
|
+
headers: Record<string, string>
|
|
17
|
+
features?: string[]
|
|
18
|
+
severityOverrides: Record<string, Severity | "off">
|
|
19
|
+
/** Write these formats to files in the same run, whatever stdout shows. */
|
|
20
|
+
sarifFile?: string
|
|
21
|
+
junitFile?: string
|
|
22
|
+
jsonFile?: string
|
|
23
|
+
help: boolean
|
|
24
|
+
version: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type ParseResult = { ok: true; config: CliConfig } | { ok: false; error: string }
|
|
28
|
+
|
|
29
|
+
export const USAGE = `ag-ui-validate — conformance validator for the AG-UI protocol
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
ag-ui-validate <url> connect to a live endpoint and validate the stream
|
|
33
|
+
ag-ui-validate <file> validate a recorded stream (SSE capture or NDJSON/JSONL)
|
|
34
|
+
ag-ui-validate - read a recorded stream from stdin
|
|
35
|
+
|
|
36
|
+
Output (default: human-readable):
|
|
37
|
+
--json machine-readable report on stdout
|
|
38
|
+
--sarif SARIF 2.1.0 log on stdout (code scanning)
|
|
39
|
+
--junit JUnit XML on stdout (CI test reports)
|
|
40
|
+
--json-file <path> additionally write the JSON report to a file
|
|
41
|
+
--sarif-file <path> additionally write a SARIF log to a file
|
|
42
|
+
--junit-file <path> additionally write JUnit XML to a file
|
|
43
|
+
--no-color disable ANSI colors
|
|
44
|
+
|
|
45
|
+
Rules:
|
|
46
|
+
--rule AGUI###=<severity> override a rule's severity (error|warning|info|off)
|
|
47
|
+
--off AGUI### shorthand for --rule AGUI###=off
|
|
48
|
+
--features <a,b,...> declare exercised features (enables e.g. AGUI305)
|
|
49
|
+
--max-warnings <n> exit 1 when warnings exceed n
|
|
50
|
+
|
|
51
|
+
Endpoint options:
|
|
52
|
+
--header "Name: value" extra request header (repeatable)
|
|
53
|
+
--timeout <seconds> abort the request after this long
|
|
54
|
+
|
|
55
|
+
Exit codes: 0 clean, 1 findings at error level (or warnings over --max-warnings), 2 tool failure.
|
|
56
|
+
`
|
|
57
|
+
|
|
58
|
+
const SEVERITIES = new Set(["error", "warning", "info", "off"])
|
|
59
|
+
const RULE_ID = /^AGUI\d{3}$/
|
|
60
|
+
|
|
61
|
+
interface Flag {
|
|
62
|
+
takesValue: boolean
|
|
63
|
+
apply(config: CliConfig, value: string): string | null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const FLAGS: Record<string, Flag> = {
|
|
67
|
+
"--help": { takesValue: false, apply: (c) => ((c.help = true), null) },
|
|
68
|
+
"--version": { takesValue: false, apply: (c) => ((c.version = true), null) },
|
|
69
|
+
"--no-color": { takesValue: false, apply: (c) => ((c.color = false), null) },
|
|
70
|
+
"--json": { takesValue: false, apply: (c) => setFormat(c, "json") },
|
|
71
|
+
"--sarif": { takesValue: false, apply: (c) => setFormat(c, "sarif") },
|
|
72
|
+
"--junit": { takesValue: false, apply: (c) => setFormat(c, "junit") },
|
|
73
|
+
"--off": {
|
|
74
|
+
takesValue: true,
|
|
75
|
+
apply: (c, v) => {
|
|
76
|
+
if (!RULE_ID.test(v)) return `--off expects a rule ID like AGUI203, got '${v}'`
|
|
77
|
+
c.severityOverrides[v] = "off"
|
|
78
|
+
return null
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
"--rule": {
|
|
82
|
+
takesValue: true,
|
|
83
|
+
apply: (c, v) => {
|
|
84
|
+
const eq = v.indexOf("=")
|
|
85
|
+
if (eq === -1) return `--rule expects ID=severity (e.g. AGUI105=warning), got '${v}'`
|
|
86
|
+
const id = v.slice(0, eq)
|
|
87
|
+
const severity = v.slice(eq + 1)
|
|
88
|
+
if (!RULE_ID.test(id)) return `--rule expects a rule ID like AGUI105, got '${id}'`
|
|
89
|
+
if (!SEVERITIES.has(severity)) {
|
|
90
|
+
return `'${severity}' is not a severity; use error, warning, info, or off`
|
|
91
|
+
}
|
|
92
|
+
c.severityOverrides[id] = severity as Severity | "off"
|
|
93
|
+
return null
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
"--max-warnings": {
|
|
97
|
+
takesValue: true,
|
|
98
|
+
apply: (c, v) => {
|
|
99
|
+
const n = Number(v)
|
|
100
|
+
if (!Number.isInteger(n) || n < 0) return `--max-warnings expects a non-negative integer, got '${v}'`
|
|
101
|
+
c.maxWarnings = n
|
|
102
|
+
return null
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
"--timeout": {
|
|
106
|
+
takesValue: true,
|
|
107
|
+
apply: (c, v) => {
|
|
108
|
+
const n = Number(v)
|
|
109
|
+
if (!Number.isFinite(n) || n <= 0) return `--timeout expects a positive number of seconds, got '${v}'`
|
|
110
|
+
c.timeoutMs = Math.round(n * 1000)
|
|
111
|
+
return null
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
"--header": {
|
|
115
|
+
takesValue: true,
|
|
116
|
+
apply: (c, v) => {
|
|
117
|
+
const colon = v.indexOf(":")
|
|
118
|
+
if (colon <= 0) return `--header expects "Name: value", got '${v}'`
|
|
119
|
+
c.headers[v.slice(0, colon).trim().toLowerCase()] = v.slice(colon + 1).trim()
|
|
120
|
+
return null
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
"--sarif-file": { takesValue: true, apply: (c, v) => ((c.sarifFile = v), null) },
|
|
124
|
+
"--junit-file": { takesValue: true, apply: (c, v) => ((c.junitFile = v), null) },
|
|
125
|
+
"--json-file": { takesValue: true, apply: (c, v) => ((c.jsonFile = v), null) },
|
|
126
|
+
"--features": {
|
|
127
|
+
takesValue: true,
|
|
128
|
+
apply: (c, v) => {
|
|
129
|
+
c.features = v
|
|
130
|
+
.split(",")
|
|
131
|
+
.map((f) => f.trim())
|
|
132
|
+
.filter((f) => f !== "")
|
|
133
|
+
return null
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function setFormat(c: CliConfig, format: CliFormat): string | null {
|
|
139
|
+
if (c.format !== "pretty" && c.format !== format) {
|
|
140
|
+
return `pick at most one of --json, --sarif, --junit`
|
|
141
|
+
}
|
|
142
|
+
c.format = format
|
|
143
|
+
return null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function parseCliArgs(argv: string[]): ParseResult {
|
|
147
|
+
const config: CliConfig = {
|
|
148
|
+
target: "",
|
|
149
|
+
format: "pretty",
|
|
150
|
+
color: null,
|
|
151
|
+
headers: {},
|
|
152
|
+
severityOverrides: {},
|
|
153
|
+
help: false,
|
|
154
|
+
version: false,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const targets: string[] = []
|
|
158
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
159
|
+
const arg = argv[i]!
|
|
160
|
+
if (arg === "-" || !arg.startsWith("-")) {
|
|
161
|
+
targets.push(arg)
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
let name = arg
|
|
165
|
+
let inlineValue: string | null = null
|
|
166
|
+
const eq = arg.indexOf("=")
|
|
167
|
+
if (eq !== -1) {
|
|
168
|
+
name = arg.slice(0, eq)
|
|
169
|
+
inlineValue = arg.slice(eq + 1)
|
|
170
|
+
}
|
|
171
|
+
const flag = FLAGS[name]
|
|
172
|
+
if (flag === undefined) return { ok: false, error: `unknown flag '${name}'` }
|
|
173
|
+
let value = ""
|
|
174
|
+
if (flag.takesValue) {
|
|
175
|
+
if (inlineValue !== null) value = inlineValue
|
|
176
|
+
else if (i + 1 < argv.length) value = argv[(i += 1)]!
|
|
177
|
+
else return { ok: false, error: `${name} requires a value` }
|
|
178
|
+
} else if (inlineValue !== null) {
|
|
179
|
+
return { ok: false, error: `${name} does not take a value` }
|
|
180
|
+
}
|
|
181
|
+
const error = flag.apply(config, value)
|
|
182
|
+
if (error !== null) return { ok: false, error }
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (targets.length > 1) {
|
|
186
|
+
return { ok: false, error: `expected exactly one target, got ${targets.length}` }
|
|
187
|
+
}
|
|
188
|
+
if (targets.length === 1) config.target = targets[0]!
|
|
189
|
+
else if (!config.help && !config.version) {
|
|
190
|
+
return { ok: false, error: "missing target: a URL, a file path, or - for stdin" }
|
|
191
|
+
}
|
|
192
|
+
return { ok: true, config }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function decideExitCode(
|
|
196
|
+
summary: { errors: number; warnings: number; info: number },
|
|
197
|
+
maxWarnings?: number,
|
|
198
|
+
): 0 | 1 {
|
|
199
|
+
if (summary.errors > 0) return 1
|
|
200
|
+
if (maxWarnings !== undefined && summary.warnings > maxWarnings) return 1
|
|
201
|
+
return 0
|
|
202
|
+
}
|