ag-ui-validate 0.2.0 → 0.3.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.
Files changed (144) hide show
  1. package/README.md +70 -10
  2. package/dist/{catalog-Ci9dqc1a.cjs → catalog-AB5vuZ8j.cjs} +3 -3
  3. package/dist/catalog-AB5vuZ8j.cjs.map +1 -0
  4. package/dist/{catalog-BglXBNbL.js → catalog-DqTI4VLt.js} +3 -3
  5. package/dist/catalog-DqTI4VLt.js.map +1 -0
  6. package/dist/cli.js +2 -2
  7. package/dist/cli.js.map +1 -1
  8. package/dist/index.cjs +2 -2
  9. package/dist/index.js +2 -2
  10. package/dist/report.cjs +1 -1
  11. package/dist/report.cjs.map +1 -1
  12. package/dist/report.js +1 -1
  13. package/dist/report.js.map +1 -1
  14. package/dist/{src-HmI-kxef.cjs → src-D04i3Vso.cjs} +2 -2
  15. package/dist/src-D04i3Vso.cjs.map +1 -0
  16. package/dist/{src-rGZ2G4qA.js → src-Dcuqz2QC.js} +2 -2
  17. package/dist/src-Dcuqz2QC.js.map +1 -0
  18. package/dist/transport.cjs +1 -1
  19. package/dist/transport.cjs.map +1 -1
  20. package/dist/transport.js +1 -1
  21. package/dist/transport.js.map +1 -1
  22. package/dist/vitest.js +2 -2
  23. package/dist/vitest.js.map +1 -1
  24. package/{src → js/src}/rules/catalog.ts +1 -1
  25. package/{src → js/src}/transport/index.ts +1 -1
  26. package/package.json +14 -13
  27. package/{src/rules → spec}/catalog.json +1 -1
  28. package/spec/event-categories.json +56 -0
  29. package/spec/fixtures/README.md +91 -0
  30. package/spec/fixtures/invalid/AGUI001-first-event-not-run-started/expected.json +10 -0
  31. package/spec/fixtures/invalid/AGUI001-first-event-not-run-started/stream.jsonl +4 -0
  32. package/spec/fixtures/invalid/AGUI002-duplicate-run-started/expected.json +11 -0
  33. package/spec/fixtures/invalid/AGUI002-duplicate-run-started/stream.jsonl +3 -0
  34. package/spec/fixtures/invalid/AGUI003-run-never-terminated/expected.json +10 -0
  35. package/spec/fixtures/invalid/AGUI003-run-never-terminated/stream.jsonl +4 -0
  36. package/spec/fixtures/invalid/AGUI004-event-after-terminal/expected.json +11 -0
  37. package/spec/fixtures/invalid/AGUI004-event-after-terminal/stream.jsonl +3 -0
  38. package/spec/fixtures/invalid/AGUI005-finished-and-error/expected.json +11 -0
  39. package/spec/fixtures/invalid/AGUI005-finished-and-error/stream.jsonl +3 -0
  40. package/spec/fixtures/invalid/AGUI006-step-finished-unmatched/expected.json +11 -0
  41. package/spec/fixtures/invalid/AGUI006-step-finished-unmatched/stream.jsonl +3 -0
  42. package/spec/fixtures/invalid/AGUI007-step-unterminated/expected.json +10 -0
  43. package/spec/fixtures/invalid/AGUI007-step-unterminated/stream.jsonl +3 -0
  44. package/spec/fixtures/invalid/AGUI008-unstable-run-ids/expected.json +12 -0
  45. package/spec/fixtures/invalid/AGUI008-unstable-run-ids/stream.jsonl +2 -0
  46. package/spec/fixtures/invalid/AGUI101-content-without-start/expected.json +11 -0
  47. package/spec/fixtures/invalid/AGUI101-content-without-start/stream.jsonl +3 -0
  48. package/spec/fixtures/invalid/AGUI102-end-without-start/expected.json +11 -0
  49. package/spec/fixtures/invalid/AGUI102-end-without-start/stream.jsonl +3 -0
  50. package/spec/fixtures/invalid/AGUI103-message-unterminated/expected.json +10 -0
  51. package/spec/fixtures/invalid/AGUI103-message-unterminated/stream.jsonl +4 -0
  52. package/spec/fixtures/invalid/AGUI104-duplicate-message-id/expected.json +12 -0
  53. package/spec/fixtures/invalid/AGUI104-duplicate-message-id/stream.jsonl +6 -0
  54. package/spec/fixtures/invalid/AGUI105-empty-content-delta/expected.json +12 -0
  55. package/spec/fixtures/invalid/AGUI105-empty-content-delta/stream.jsonl +5 -0
  56. package/spec/fixtures/invalid/AGUI106-interleaved-same-message-id/expected.json +12 -0
  57. package/spec/fixtures/invalid/AGUI106-interleaved-same-message-id/stream.jsonl +5 -0
  58. package/spec/fixtures/invalid/AGUI201-args-without-start/expected.json +11 -0
  59. package/spec/fixtures/invalid/AGUI201-args-without-start/stream.jsonl +3 -0
  60. package/spec/fixtures/invalid/AGUI202-end-without-start/expected.json +11 -0
  61. package/spec/fixtures/invalid/AGUI202-end-without-start/stream.jsonl +3 -0
  62. package/spec/fixtures/invalid/AGUI203-unterminated-tool-call/expected.json +10 -0
  63. package/spec/fixtures/invalid/AGUI203-unterminated-tool-call/stream.jsonl +4 -0
  64. package/spec/fixtures/invalid/AGUI204-args-not-json/expected.json +10 -0
  65. package/spec/fixtures/invalid/AGUI204-args-not-json/stream.jsonl +6 -0
  66. package/spec/fixtures/invalid/AGUI205-duplicate-tool-call-id/expected.json +12 -0
  67. package/spec/fixtures/invalid/AGUI205-duplicate-tool-call-id/stream.jsonl +5 -0
  68. package/spec/fixtures/invalid/AGUI206-result-before-end/expected.json +12 -0
  69. package/spec/fixtures/invalid/AGUI206-result-before-end/stream.jsonl +5 -0
  70. package/spec/fixtures/invalid/AGUI207-result-unknown-id/expected.json +11 -0
  71. package/spec/fixtures/invalid/AGUI207-result-unknown-id/stream.jsonl +3 -0
  72. package/spec/fixtures/invalid/AGUI208-unknown-parent-message-id/expected.json +11 -0
  73. package/spec/fixtures/invalid/AGUI208-unknown-parent-message-id/stream.jsonl +4 -0
  74. package/spec/fixtures/invalid/AGUI301-delta-before-snapshot/expected.json +10 -0
  75. package/spec/fixtures/invalid/AGUI301-delta-before-snapshot/stream.jsonl +3 -0
  76. package/spec/fixtures/invalid/AGUI302-delta-failed-to-apply/expected.json +11 -0
  77. package/spec/fixtures/invalid/AGUI302-delta-failed-to-apply/stream.jsonl +4 -0
  78. package/spec/fixtures/invalid/AGUI303-invalid-patch-document/expected.json +11 -0
  79. package/spec/fixtures/invalid/AGUI303-invalid-patch-document/stream.jsonl +4 -0
  80. package/spec/fixtures/invalid/AGUI304-midrun-snapshot-discards-deltas/expected.json +10 -0
  81. package/spec/fixtures/invalid/AGUI304-midrun-snapshot-discards-deltas/stream.jsonl +5 -0
  82. package/spec/fixtures/invalid/AGUI305-shared-state-never-established/expected.json +9 -0
  83. package/spec/fixtures/invalid/AGUI305-shared-state-never-established/options.json +5 -0
  84. package/spec/fixtures/invalid/AGUI305-shared-state-never-established/stream.jsonl +5 -0
  85. package/spec/fixtures/invalid/AGUI401-reasoning-content-without-start/expected.json +11 -0
  86. package/spec/fixtures/invalid/AGUI401-reasoning-content-without-start/stream.jsonl +3 -0
  87. package/spec/fixtures/invalid/AGUI402-reasoning-unterminated/expected.json +10 -0
  88. package/spec/fixtures/invalid/AGUI402-reasoning-unterminated/stream.jsonl +3 -0
  89. package/spec/fixtures/invalid/AGUI501-missing-data-prefix/expected.json +9 -0
  90. package/spec/fixtures/invalid/AGUI501-missing-data-prefix/scenario.json +17 -0
  91. package/spec/fixtures/invalid/AGUI502-payload-not-json/expected.json +10 -0
  92. package/spec/fixtures/invalid/AGUI502-payload-not-json/stream.jsonl +3 -0
  93. package/spec/fixtures/invalid/AGUI503-unknown-event-type/expected.json +10 -0
  94. package/spec/fixtures/invalid/AGUI503-unknown-event-type/stream.jsonl +3 -0
  95. package/spec/fixtures/invalid/AGUI504-schema-violation/expected.json +11 -0
  96. package/spec/fixtures/invalid/AGUI504-schema-violation/stream.jsonl +4 -0
  97. package/spec/fixtures/invalid/AGUI505-unexpected-content-type/expected.json +9 -0
  98. package/spec/fixtures/invalid/AGUI505-unexpected-content-type/scenario.json +25 -0
  99. package/spec/fixtures/invalid/AGUI506-keepalive-gap/expected.json +9 -0
  100. package/spec/fixtures/invalid/AGUI506-keepalive-gap/scenario.json +25 -0
  101. package/spec/fixtures/invalid/AGUI507-buffered-response/expected.json +9 -0
  102. package/spec/fixtures/invalid/AGUI507-buffered-response/scenario.json +9 -0
  103. package/spec/fixtures/invalid/AGUI508-connection-dropped/expected.json +17 -0
  104. package/spec/fixtures/invalid/AGUI508-connection-dropped/scenario.json +10 -0
  105. package/spec/fixtures/invalid/AGUI901-raw-wraps-typed-event/expected.json +11 -0
  106. package/spec/fixtures/invalid/AGUI901-raw-wraps-typed-event/stream.jsonl +3 -0
  107. package/spec/fixtures/invalid/AGUI902-no-timestamps/expected.json +9 -0
  108. package/spec/fixtures/invalid/AGUI902-no-timestamps/stream.jsonl +2 -0
  109. package/spec/fixtures/invalid/AGUI903-custom-name-not-namespaced/expected.json +11 -0
  110. package/spec/fixtures/invalid/AGUI903-custom-name-not-namespaced/stream.jsonl +3 -0
  111. package/spec/fixtures/valid/agentic-chat.jsonl +14 -0
  112. package/spec/fixtures/valid/agentic-generative-ui.jsonl +13 -0
  113. package/spec/fixtures/valid/backend-tool-rendering.jsonl +14 -0
  114. package/spec/fixtures/valid/human-in-the-loop.jsonl +13 -0
  115. package/spec/fixtures/valid/predictive-state-updates.expected.json +11 -0
  116. package/spec/fixtures/valid/predictive-state-updates.jsonl +11 -0
  117. package/spec/fixtures/valid/shared-state.jsonl +8 -0
  118. package/spec/fixtures/valid/tool-based-generative-ui.jsonl +5 -0
  119. package/dist/catalog-BglXBNbL.js.map +0 -1
  120. package/dist/catalog-Ci9dqc1a.cjs.map +0 -1
  121. package/dist/src-HmI-kxef.cjs.map +0 -1
  122. package/dist/src-rGZ2G4qA.js.map +0 -1
  123. /package/{src → js/src}/cli-args.ts +0 -0
  124. /package/{src → js/src}/cli.ts +0 -0
  125. /package/{src → js/src}/index.ts +0 -0
  126. /package/{src → js/src}/protocol/event-table.ts +0 -0
  127. /package/{src → js/src}/protocol/jsonpatch.ts +0 -0
  128. /package/{src → js/src}/report/index.ts +0 -0
  129. /package/{src → js/src}/report/json.ts +0 -0
  130. /package/{src → js/src}/report/junit.ts +0 -0
  131. /package/{src → js/src}/report/pretty.ts +0 -0
  132. /package/{src → js/src}/report/sarif.ts +0 -0
  133. /package/{src → js/src}/rules/checks/context.ts +0 -0
  134. /package/{src → js/src}/rules/checks/lifecycle.ts +0 -0
  135. /package/{src → js/src}/rules/checks/reasoning.ts +0 -0
  136. /package/{src → js/src}/rules/checks/state.ts +0 -0
  137. /package/{src → js/src}/rules/checks/text.ts +0 -0
  138. /package/{src → js/src}/rules/checks/toolcalls.ts +0 -0
  139. /package/{src → js/src}/rules/checks/transport.ts +0 -0
  140. /package/{src → js/src}/transport/ndjson.ts +0 -0
  141. /package/{src → js/src}/transport/sse.ts +0 -0
  142. /package/{src → js/src}/types.ts +0 -0
  143. /package/{src → js/src}/vitest/index.ts +0 -0
  144. /package/{src → js/src}/vitest/matcher.ts +0 -0
package/README.md CHANGED
@@ -15,10 +15,11 @@ spec section.
15
15
  2 errors, 0 warnings, 1 info — 3 of 7 AG-UI features exercised
16
16
  ```
17
17
 
18
- > **Status: pre-release.** The core validator, the language-neutral fixture
19
- > corpus, and the transport layer are implemented and tested. The CLI
20
- > (`npx ag-ui-validate <url|->`), the Vitest matcher, and SARIF/JUnit
21
- > reporters are in progress.
18
+ > **Status:** the TypeScript implementation is released to npm
19
+ > (`npm install ag-ui-validate`). A native Python port same rule catalog,
20
+ > same fixture corpus, byte-identical CLI is fully implemented and tested
21
+ > but not yet published to PyPI as a functional release; see
22
+ > [Python](#python) below.
22
23
 
23
24
  ## Why
24
25
 
@@ -124,7 +125,7 @@ const { diagnostics, summary, features, skipped } = v.report()
124
125
  ```
125
126
 
126
127
  The core is a pure function over an event sequence: zero I/O, zero runtime
127
- dependencies, isomorphic across Node 20+, browsers, Deno, and Workers.
128
+ dependencies, isomorphic across Node 22+, browsers, Deno, and Workers.
128
129
 
129
130
  ### Validate a live endpoint
130
131
 
@@ -170,12 +171,71 @@ import { formatReportSummary, toSarif, toJUnit } from "ag-ui-validate/report"
170
171
  }
171
172
  ```
172
173
 
174
+ ## Python
175
+
176
+ A native Python port ships in [py/](py/) — the same rule catalog, the same
177
+ fixture corpus, and a CLI with byte-identical flags, error messages, and
178
+ JSON/SARIF/JUnit output to the TypeScript one above. It's fully implemented
179
+ and tested, and checked against the TypeScript implementation on every PR
180
+ by Parity CI (see [docs/TESTING.md](docs/TESTING.md) for how, and
181
+ [docs/PYTHON-PORT-PLAN.md](docs/PYTHON-PORT-PLAN.md) for the port's full
182
+ milestone history). **Not yet published to PyPI as a functional release**
183
+ — only a name-reservation placeholder (`0.0.1`) is live today.
184
+ Install from source until a real release ships:
185
+
186
+ ```bash
187
+ git clone https://github.com/langport-dev/ag-ui-validate
188
+ cd ag-ui-validate/py
189
+ pip install -e ".[dev]" # or ".[transport]" for just the endpoint-validating extras
190
+ ```
191
+
192
+ ### CLI
193
+
194
+ ```bash
195
+ ag-ui-validate http://localhost:8000/agui # live endpoint (POSTs a RunAgentInput)
196
+ ag-ui-validate run.jsonl # recorded stream (NDJSON/JSONL or SSE capture)
197
+ cat run.jsonl | ag-ui-validate - # stdin
198
+ ```
199
+
200
+ Same exit codes and the same flags as the [CLI](#cli) above (see
201
+ `ag-ui-validate --help`) — the Python argument parser is a direct,
202
+ hand-rolled port of the TypeScript one rather than `argparse`/`click`,
203
+ specifically to keep both CLIs' invocation and error messages
204
+ byte-for-byte identical.
205
+
206
+ ### Test your agent in pytest
207
+
208
+ ```python
209
+ from ag_ui_validate.pytest_plugin import assert_valid_agui
210
+
211
+ def test_my_agent_stream(captured_events):
212
+ assert_valid_agui(captured_events, features=["shared-state"], max_warnings=0)
213
+ ```
214
+
215
+ `assert_valid_agui` accepts a list of events (dicts or JSON strings) or a
216
+ whole JSONL capture as one string, and raises `AssertionError` with every
217
+ finding's rule ID and spec link on failure. It registers automatically as a
218
+ pytest plugin on install — no `conftest.py` setup needed. An async
219
+ counterpart validates a live endpoint directly from a test:
220
+
221
+ ```python
222
+ from ag_ui_validate.pytest_plugin import assert_valid_agui_endpoint
223
+
224
+ async def test_my_live_agent():
225
+ await assert_valid_agui_endpoint("http://localhost:8000/agui", max_warnings=0)
226
+ ```
227
+
228
+ `assert_valid_agui` has zero runtime dependencies; only the
229
+ endpoint-validating helpers (`assert_valid_agui_endpoint`,
230
+ `validate_agui_endpoint`) pull in `httpx`
231
+ (`pip install ag-ui-validate[transport]`).
232
+
173
233
  ## The rule catalog
174
234
 
175
235
  40 rules, maintained as **data** in
176
- [src/rules/catalog.json](src/rules/catalog.json) so other implementations
177
- (Python, Go, ) can share them. Every rule has its own page — spec grounding,
178
- severity, and a violating example from the corpus in the
236
+ [spec/catalog.json](spec/catalog.json), shared by both implementations in
237
+ this repo ([TypeScript](.) and [Python](py/)) rather than duplicated.
238
+ Every rule has its own pagespec grounding,
179
239
  **[rule index](docs/rules/README.md)** (generated from the catalog,
180
240
  drift-checked in CI):
181
241
 
@@ -195,7 +255,7 @@ drift-tested against the installed SDK on every run.
195
255
 
196
256
  ## The fixture corpus
197
257
 
198
- [fixtures/](fixtures/README.md) is a language-neutral conformance corpus:
258
+ [spec/fixtures/](spec/fixtures/README.md) is a language-neutral conformance corpus:
199
259
  7 valid streams (one per canonical AG-UI feature — the false-positive guards)
200
260
  and 40 invalid fixtures (one per rule) with exact expected diagnostics. Any
201
261
  validator implementation that consumes the shared catalog can be tested
@@ -219,7 +279,7 @@ Component-by-component instructions live in
219
279
  rules are tracked in [docs/spec-questions.md](docs/spec-questions.md).
220
280
 
221
281
  Adding a rule: add the catalog entry (with its `specUrl`), add the fixture
222
- stream + intended findings to `scripts/build-fixtures.mjs`, and run
282
+ stream + intended findings to `js/scripts/build-fixtures.mjs`, and run
223
283
  `npm run fixtures:build` — the meta-tests fail until both exist. Rule
224
284
  *proposals* belong upstream as issues on
225
285
  [`ag-ui-protocol/ag-ui`](https://github.com/ag-ui-protocol/ag-ui) first; this
@@ -1,4 +1,4 @@
1
- //#region src/rules/catalog.json
1
+ //#region ../spec/catalog.json
2
2
  var catalog_default = {
3
3
  $comment: "AG-UI conformance rule catalog. Data, not code: a Python/Go implementation shares these rules. Severities follow the working agreement that behaviour the spec does not clearly govern is at most 'info' — entries with 'specQuestion' were downgraded accordingly; see docs/spec-questions.md.",
4
4
  catalogVersion: "0.1.0",
@@ -342,7 +342,7 @@ var catalog_default = {
342
342
  "id": "AGUI503",
343
343
  "severity": "error",
344
344
  "title": "Unknown event type",
345
- "messageTemplate": "Unknown event type '{type}' (not in @ag-ui/core v{sdkVersion}, and not RAW or CUSTOM)",
345
+ "messageTemplate": "Unknown event type '{type}' (not in the installed AG-UI SDK v{sdkVersion}, and not RAW or CUSTOM)",
346
346
  "specUrl": "https://docs.ag-ui.com/concepts/events#event-types-overview",
347
347
  "specQuote": "Events in the protocol are categorized by their purpose.",
348
348
  "since": "0.x",
@@ -492,4 +492,4 @@ Object.defineProperty(exports, "validateCatalog", {
492
492
  }
493
493
  });
494
494
 
495
- //# sourceMappingURL=catalog-Ci9dqc1a.cjs.map
495
+ //# sourceMappingURL=catalog-AB5vuZ8j.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-AB5vuZ8j.cjs","names":["catalogJson"],"sources":["../spec/catalog.json","../js/src/rules/catalog.ts"],"sourcesContent":["","// 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 \"../../../spec/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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACaA,MAAM,aAAgC;CAAC;CAAS;CAAW;AAAM;AACjE,MAAM,SAA4B,CAAC,QAAQ,WAAW;;AAgCtD,SAAgB,gBAAgB,MAAwB;CACtD,MAAM,WAAqB,CAAC;CAC5B,MAAM,MAAM;CACZ,IAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAAK,GACrE,MAAM,IAAI,MAAM,qDAAqD;CAEvE,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,QAAQ,IAAI,OAAO;EAC5B,MAAM,QAAQ,MAAM,MAAM;EAC1B,IAAI,CAAC,cAAc,KAAK,KAAK,MAAM,EAAE,GAAG,SAAS,KAAK,GAAG,MAAM,wBAAwB;EACvF,IAAI,KAAK,IAAI,KAAK,EAAE,GAAG,SAAS,KAAK,GAAG,MAAM,eAAe;EAC7D,KAAK,IAAI,KAAK,EAAE;EAChB,IAAI,CAAC,WAAW,SAAS,KAAK,QAAQ,GAAG,SAAS,KAAK,GAAG,MAAM,kBAAkB,KAAK,SAAS,EAAE;EAClG,IAAI,CAAC,KAAK,OAAO,SAAS,KAAK,GAAG,MAAM,gBAAgB;EACxD,IAAI,CAAC,KAAK,iBAAiB,SAAS,KAAK,GAAG,MAAM,0BAA0B;EAC5E,IAAI,CAAC,KAAK,SAAS,WAAW,UAAU,GAAG,SAAS,KAAK,GAAG,MAAM,+BAA+B;EACjG,IAAI,CAAC,KAAK,OAAO,SAAS,KAAK,GAAG,MAAM,gBAAgB;EACxD,IAAI,CAAC,OAAO,SAAS,KAAK,SAAS,GAAG,SAAS,KAAK,GAAG,MAAM,mBAAmB,KAAK,UAAU,EAAE;EACjG,IAAI,KAAK,mBAAmB,CAAC,KAAK,SAAS,SAAS,KAAK,GAAG,MAAM,kCAAkC;CACtG;CACA,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,MAAM,+BAA+B,SAAS,KAAK,MAAM,GAAG;CAExE,OAAO;AACT;AAEA,MAAa,UAAmB,gBAAgBA,eAAW;AAE3D,MAAa,QAA6C,IAAI,IAC5D,QAAQ,MAAM,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CACpC;;AAGA,SAAgB,cAAc,MAAsB,QAAyC;CAC3F,OAAO,KAAK,gBAAgB,QAAQ,eAAe,OAAO,QACxD,OAAO,SAAS,OAAO,OAAO,IAAI,IAAI,KACxC;AACF"}
@@ -1,4 +1,4 @@
1
- //#region src/rules/catalog.json
1
+ //#region ../spec/catalog.json
2
2
  var catalog_default = {
3
3
  $comment: "AG-UI conformance rule catalog. Data, not code: a Python/Go implementation shares these rules. Severities follow the working agreement that behaviour the spec does not clearly govern is at most 'info' — entries with 'specQuestion' were downgraded accordingly; see docs/spec-questions.md.",
4
4
  catalogVersion: "0.1.0",
@@ -342,7 +342,7 @@ var catalog_default = {
342
342
  "id": "AGUI503",
343
343
  "severity": "error",
344
344
  "title": "Unknown event type",
345
- "messageTemplate": "Unknown event type '{type}' (not in @ag-ui/core v{sdkVersion}, and not RAW or CUSTOM)",
345
+ "messageTemplate": "Unknown event type '{type}' (not in the installed AG-UI SDK v{sdkVersion}, and not RAW or CUSTOM)",
346
346
  "specUrl": "https://docs.ag-ui.com/concepts/events#event-types-overview",
347
347
  "specQuote": "Events in the protocol are categorized by their purpose.",
348
348
  "since": "0.x",
@@ -469,4 +469,4 @@ function formatMessage(rule, params) {
469
469
  //#endregion
470
470
  export { validateCatalog as i, RULES as n, formatMessage as r, CATALOG as t };
471
471
 
472
- //# sourceMappingURL=catalog-BglXBNbL.js.map
472
+ //# sourceMappingURL=catalog-DqTI4VLt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-DqTI4VLt.js","names":["catalogJson"],"sources":["../spec/catalog.json","../js/src/rules/catalog.ts"],"sourcesContent":["","// 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 \"../../../spec/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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACaA,MAAM,aAAgC;CAAC;CAAS;CAAW;AAAM;AACjE,MAAM,SAA4B,CAAC,QAAQ,WAAW;;AAgCtD,SAAgB,gBAAgB,MAAwB;CACtD,MAAM,WAAqB,CAAC;CAC5B,MAAM,MAAM;CACZ,IAAI,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAAK,GACrE,MAAM,IAAI,MAAM,qDAAqD;CAEvE,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,QAAQ,IAAI,OAAO;EAC5B,MAAM,QAAQ,MAAM,MAAM;EAC1B,IAAI,CAAC,cAAc,KAAK,KAAK,MAAM,EAAE,GAAG,SAAS,KAAK,GAAG,MAAM,wBAAwB;EACvF,IAAI,KAAK,IAAI,KAAK,EAAE,GAAG,SAAS,KAAK,GAAG,MAAM,eAAe;EAC7D,KAAK,IAAI,KAAK,EAAE;EAChB,IAAI,CAAC,WAAW,SAAS,KAAK,QAAQ,GAAG,SAAS,KAAK,GAAG,MAAM,kBAAkB,KAAK,SAAS,EAAE;EAClG,IAAI,CAAC,KAAK,OAAO,SAAS,KAAK,GAAG,MAAM,gBAAgB;EACxD,IAAI,CAAC,KAAK,iBAAiB,SAAS,KAAK,GAAG,MAAM,0BAA0B;EAC5E,IAAI,CAAC,KAAK,SAAS,WAAW,UAAU,GAAG,SAAS,KAAK,GAAG,MAAM,+BAA+B;EACjG,IAAI,CAAC,KAAK,OAAO,SAAS,KAAK,GAAG,MAAM,gBAAgB;EACxD,IAAI,CAAC,OAAO,SAAS,KAAK,SAAS,GAAG,SAAS,KAAK,GAAG,MAAM,mBAAmB,KAAK,UAAU,EAAE;EACjG,IAAI,KAAK,mBAAmB,CAAC,KAAK,SAAS,SAAS,KAAK,GAAG,MAAM,kCAAkC;CACtG;CACA,IAAI,SAAS,SAAS,GACpB,MAAM,IAAI,MAAM,+BAA+B,SAAS,KAAK,MAAM,GAAG;CAExE,OAAO;AACT;AAEA,MAAa,UAAmB,gBAAgBA,eAAW;AAE3D,MAAa,QAA6C,IAAI,IAC5D,QAAQ,MAAM,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CACpC;;AAGA,SAAgB,cAAc,MAAsB,QAAyC;CAC3F,OAAO,KAAK,gBAAgB,QAAQ,eAAe,OAAO,QACxD,OAAO,SAAS,OAAO,OAAO,IAAI,IAAI,KACxC;AACF"}
package/dist/cli.js CHANGED
@@ -212,7 +212,7 @@ function decideExitCode(summary, maxWarnings) {
212
212
  return 0;
213
213
  }
214
214
  //#endregion
215
- //#region src/rules/catalog.json
215
+ //#region ../spec/catalog.json
216
216
  var catalog_default = {
217
217
  $comment: "AG-UI conformance rule catalog. Data, not code: a Python/Go implementation shares these rules. Severities follow the working agreement that behaviour the spec does not clearly govern is at most 'info' — entries with 'specQuestion' were downgraded accordingly; see docs/spec-questions.md.",
218
218
  catalogVersion: "0.1.0",
@@ -556,7 +556,7 @@ var catalog_default = {
556
556
  "id": "AGUI503",
557
557
  "severity": "error",
558
558
  "title": "Unknown event type",
559
- "messageTemplate": "Unknown event type '{type}' (not in @ag-ui/core v{sdkVersion}, and not RAW or CUSTOM)",
559
+ "messageTemplate": "Unknown event type '{type}' (not in the installed AG-UI SDK v{sdkVersion}, and not RAW or CUSTOM)",
560
560
  "specUrl": "https://docs.ag-ui.com/concepts/events#event-types-overview",
561
561
  "specQuote": "Events in the protocol are categorized by their purpose.",
562
562
  "since": "0.x",