@ggui-ai/protocol 0.1.0-rc.1

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 (222) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +46 -0
  3. package/dist/bridge/invoke-agent.d.ts +65 -0
  4. package/dist/bridge/invoke-agent.d.ts.map +1 -0
  5. package/dist/bridge/invoke-agent.js +113 -0
  6. package/dist/envelope-adapters.d.ts +24 -0
  7. package/dist/envelope-adapters.d.ts.map +1 -0
  8. package/dist/envelope-adapters.js +14 -0
  9. package/dist/envelopes/builders.d.ts +145 -0
  10. package/dist/envelopes/builders.d.ts.map +1 -0
  11. package/dist/envelopes/builders.js +113 -0
  12. package/dist/errors/unknown-permission-name.d.ts +12 -0
  13. package/dist/errors/unknown-permission-name.d.ts.map +1 -0
  14. package/dist/errors/unknown-permission-name.js +29 -0
  15. package/dist/errors/version-mismatch.d.ts +55 -0
  16. package/dist/errors/version-mismatch.d.ts.map +1 -0
  17. package/dist/errors/version-mismatch.js +52 -0
  18. package/dist/gadgets/resolve-contract-gadgets.d.ts +93 -0
  19. package/dist/gadgets/resolve-contract-gadgets.d.ts.map +1 -0
  20. package/dist/gadgets/resolve-contract-gadgets.js +119 -0
  21. package/dist/gadgets/stdlib-gadgets.d.ts +43 -0
  22. package/dist/gadgets/stdlib-gadgets.d.ts.map +1 -0
  23. package/dist/gadgets/stdlib-gadgets.js +161 -0
  24. package/dist/iframe-bridge.d.ts +63 -0
  25. package/dist/iframe-bridge.d.ts.map +1 -0
  26. package/dist/iframe-bridge.js +166 -0
  27. package/dist/index.d.ts +62 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +79 -0
  30. package/dist/integrations/mcp-apps.d.ts +1218 -0
  31. package/dist/integrations/mcp-apps.d.ts.map +1 -0
  32. package/dist/integrations/mcp-apps.js +427 -0
  33. package/dist/navigation/index.d.ts +3 -0
  34. package/dist/navigation/index.d.ts.map +1 -0
  35. package/dist/navigation/index.js +1 -0
  36. package/dist/navigation/stack-navigation.d.ts +55 -0
  37. package/dist/navigation/stack-navigation.d.ts.map +1 -0
  38. package/dist/navigation/stack-navigation.js +80 -0
  39. package/dist/recommended-prompts.d.ts +56 -0
  40. package/dist/recommended-prompts.d.ts.map +1 -0
  41. package/dist/recommended-prompts.js +55 -0
  42. package/dist/registry/blueprint-key.d.ts +9 -0
  43. package/dist/registry/blueprint-key.d.ts.map +1 -0
  44. package/dist/registry/blueprint-key.js +28 -0
  45. package/dist/registry/canonicalize-contract.d.ts +35 -0
  46. package/dist/registry/canonicalize-contract.d.ts.map +1 -0
  47. package/dist/registry/canonicalize-contract.js +166 -0
  48. package/dist/registry/summarize-contract.d.ts +46 -0
  49. package/dist/registry/summarize-contract.d.ts.map +1 -0
  50. package/dist/registry/summarize-contract.js +63 -0
  51. package/dist/schema-learning/derive-contract.d.ts +67 -0
  52. package/dist/schema-learning/derive-contract.d.ts.map +1 -0
  53. package/dist/schema-learning/derive-contract.js +117 -0
  54. package/dist/schema-learning/merge.d.ts +32 -0
  55. package/dist/schema-learning/merge.d.ts.map +1 -0
  56. package/dist/schema-learning/merge.js +146 -0
  57. package/dist/schemas/blueprint.d.ts +32 -0
  58. package/dist/schemas/blueprint.d.ts.map +1 -0
  59. package/dist/schemas/blueprint.js +92 -0
  60. package/dist/schemas/data-contract.d.ts +750 -0
  61. package/dist/schemas/data-contract.d.ts.map +1 -0
  62. package/dist/schemas/data-contract.js +663 -0
  63. package/dist/schemas/gadget-name-grammar.d.ts +29 -0
  64. package/dist/schemas/gadget-name-grammar.d.ts.map +1 -0
  65. package/dist/schemas/gadget-name-grammar.js +28 -0
  66. package/dist/schemas/handshake-suggestion.d.ts +46 -0
  67. package/dist/schemas/handshake-suggestion.d.ts.map +1 -0
  68. package/dist/schemas/handshake-suggestion.js +107 -0
  69. package/dist/schemas/invoke.d.ts +337 -0
  70. package/dist/schemas/invoke.d.ts.map +1 -0
  71. package/dist/schemas/invoke.js +169 -0
  72. package/dist/schemas/mcp.d.ts +301 -0
  73. package/dist/schemas/mcp.d.ts.map +1 -0
  74. package/dist/schemas/mcp.js +373 -0
  75. package/dist/schemas/ops-blueprint.d.ts +176 -0
  76. package/dist/schemas/ops-blueprint.d.ts.map +1 -0
  77. package/dist/schemas/ops-blueprint.js +259 -0
  78. package/dist/schemas/sync-check.d.ts +11 -0
  79. package/dist/schemas/sync-check.d.ts.map +1 -0
  80. package/dist/schemas/sync-check.js +60 -0
  81. package/dist/screen-blueprints/define.d.ts +22 -0
  82. package/dist/screen-blueprints/define.d.ts.map +1 -0
  83. package/dist/screen-blueprints/define.js +3 -0
  84. package/dist/screen-blueprints/index.d.ts +4 -0
  85. package/dist/screen-blueprints/index.d.ts.map +1 -0
  86. package/dist/screen-blueprints/index.js +3 -0
  87. package/dist/screen-blueprints/match.d.ts +35 -0
  88. package/dist/screen-blueprints/match.d.ts.map +1 -0
  89. package/dist/screen-blueprints/match.js +51 -0
  90. package/dist/screen-blueprints/types.d.ts +164 -0
  91. package/dist/screen-blueprints/types.d.ts.map +1 -0
  92. package/dist/screen-blueprints/types.js +1 -0
  93. package/dist/stream/stream-parser.d.ts +62 -0
  94. package/dist/stream/stream-parser.d.ts.map +1 -0
  95. package/dist/stream/stream-parser.js +199 -0
  96. package/dist/transport/websocket.d.ts +178 -0
  97. package/dist/transport/websocket.d.ts.map +1 -0
  98. package/dist/transport/websocket.js +1 -0
  99. package/dist/types/app-config.d.ts +61 -0
  100. package/dist/types/app-config.d.ts.map +1 -0
  101. package/dist/types/app-config.js +1 -0
  102. package/dist/types/auth.d.ts +61 -0
  103. package/dist/types/auth.d.ts.map +1 -0
  104. package/dist/types/auth.js +1 -0
  105. package/dist/types/blueprint.d.ts +206 -0
  106. package/dist/types/blueprint.d.ts.map +1 -0
  107. package/dist/types/blueprint.js +1 -0
  108. package/dist/types/canvas-lifecycle.d.ts +105 -0
  109. package/dist/types/canvas-lifecycle.d.ts.map +1 -0
  110. package/dist/types/canvas-lifecycle.js +38 -0
  111. package/dist/types/capabilities.d.ts +40 -0
  112. package/dist/types/capabilities.d.ts.map +1 -0
  113. package/dist/types/capabilities.js +19 -0
  114. package/dist/types/contract-inference.d.ts +401 -0
  115. package/dist/types/contract-inference.d.ts.map +1 -0
  116. package/dist/types/contract-inference.js +44 -0
  117. package/dist/types/credential.d.ts +41 -0
  118. package/dist/types/credential.d.ts.map +1 -0
  119. package/dist/types/credential.js +32 -0
  120. package/dist/types/data-bindings.d.ts +322 -0
  121. package/dist/types/data-bindings.d.ts.map +1 -0
  122. package/dist/types/data-bindings.js +29 -0
  123. package/dist/types/data-contract.d.ts +1296 -0
  124. package/dist/types/data-contract.d.ts.map +1 -0
  125. package/dist/types/data-contract.js +111 -0
  126. package/dist/types/events.d.ts +182 -0
  127. package/dist/types/events.d.ts.map +1 -0
  128. package/dist/types/events.js +8 -0
  129. package/dist/types/feedback.d.ts +24 -0
  130. package/dist/types/feedback.d.ts.map +1 -0
  131. package/dist/types/feedback.js +7 -0
  132. package/dist/types/gadget.d.ts +121 -0
  133. package/dist/types/gadget.d.ts.map +1 -0
  134. package/dist/types/gadget.js +24 -0
  135. package/dist/types/handshake-suggestion.d.ts +264 -0
  136. package/dist/types/handshake-suggestion.d.ts.map +1 -0
  137. package/dist/types/handshake-suggestion.js +70 -0
  138. package/dist/types/host-context.d.ts +163 -0
  139. package/dist/types/host-context.d.ts.map +1 -0
  140. package/dist/types/host-context.js +142 -0
  141. package/dist/types/interface-context.d.ts +105 -0
  142. package/dist/types/interface-context.d.ts.map +1 -0
  143. package/dist/types/interface-context.js +115 -0
  144. package/dist/types/invoke.d.ts +28 -0
  145. package/dist/types/invoke.d.ts.map +1 -0
  146. package/dist/types/invoke.js +7 -0
  147. package/dist/types/live-channel.d.ts +613 -0
  148. package/dist/types/live-channel.d.ts.map +1 -0
  149. package/dist/types/live-channel.js +1 -0
  150. package/dist/types/llm.d.ts +61 -0
  151. package/dist/types/llm.d.ts.map +1 -0
  152. package/dist/types/llm.js +186 -0
  153. package/dist/types/mcp-proxy.d.ts +67 -0
  154. package/dist/types/mcp-proxy.d.ts.map +1 -0
  155. package/dist/types/mcp-proxy.js +46 -0
  156. package/dist/types/mcp.d.ts +637 -0
  157. package/dist/types/mcp.d.ts.map +1 -0
  158. package/dist/types/mcp.js +30 -0
  159. package/dist/types/openrouter-models.d.ts +22 -0
  160. package/dist/types/openrouter-models.d.ts.map +1 -0
  161. package/dist/types/openrouter-models.js +4843 -0
  162. package/dist/types/region.d.ts +26 -0
  163. package/dist/types/region.d.ts.map +1 -0
  164. package/dist/types/region.js +36 -0
  165. package/dist/types/session.d.ts +419 -0
  166. package/dist/types/session.d.ts.map +1 -0
  167. package/dist/types/session.js +1 -0
  168. package/dist/types/thread.d.ts +207 -0
  169. package/dist/types/thread.d.ts.map +1 -0
  170. package/dist/types/thread.js +57 -0
  171. package/dist/types/ui-generator.d.ts +100 -0
  172. package/dist/types/ui-generator.d.ts.map +1 -0
  173. package/dist/types/ui-generator.js +53 -0
  174. package/dist/validation/ajv-runtime.d.ts +140 -0
  175. package/dist/validation/ajv-runtime.d.ts.map +1 -0
  176. package/dist/validation/ajv-runtime.js +452 -0
  177. package/dist/validation/content-hash.d.ts +3 -0
  178. package/dist/validation/content-hash.d.ts.map +1 -0
  179. package/dist/validation/content-hash.js +21 -0
  180. package/dist/validation/contract-validator.d.ts +244 -0
  181. package/dist/validation/contract-validator.d.ts.map +1 -0
  182. package/dist/validation/contract-validator.js +711 -0
  183. package/dist/validation/cross-references.d.ts +105 -0
  184. package/dist/validation/cross-references.d.ts.map +1 -0
  185. package/dist/validation/cross-references.js +164 -0
  186. package/dist/validation/hygiene-rules.d.ts +250 -0
  187. package/dist/validation/hygiene-rules.d.ts.map +1 -0
  188. package/dist/validation/hygiene-rules.js +564 -0
  189. package/dist/validation/lint-contract.d.ts +130 -0
  190. package/dist/validation/lint-contract.d.ts.map +1 -0
  191. package/dist/validation/lint-contract.js +225 -0
  192. package/dist/validation/name-invariants.d.ts +117 -0
  193. package/dist/validation/name-invariants.d.ts.map +1 -0
  194. package/dist/validation/name-invariants.js +172 -0
  195. package/dist/validation/reserved-channels.d.ts +156 -0
  196. package/dist/validation/reserved-channels.d.ts.map +1 -0
  197. package/dist/validation/reserved-channels.js +356 -0
  198. package/dist/validation/resolve-stream-channel.d.ts +78 -0
  199. package/dist/validation/resolve-stream-channel.d.ts.map +1 -0
  200. package/dist/validation/resolve-stream-channel.js +64 -0
  201. package/dist/validation/sanitize-error.d.ts +46 -0
  202. package/dist/validation/sanitize-error.d.ts.map +1 -0
  203. package/dist/validation/sanitize-error.js +88 -0
  204. package/dist/validation/schema-compat-invariants.d.ts +140 -0
  205. package/dist/validation/schema-compat-invariants.d.ts.map +1 -0
  206. package/dist/validation/schema-compat-invariants.js +220 -0
  207. package/dist/validation/schema-meta-validation.d.ts +60 -0
  208. package/dist/validation/schema-meta-validation.d.ts.map +1 -0
  209. package/dist/validation/schema-meta-validation.js +131 -0
  210. package/dist/validation/schema-subset.d.ts +165 -0
  211. package/dist/validation/schema-subset.d.ts.map +1 -0
  212. package/dist/validation/schema-subset.js +295 -0
  213. package/dist/validation/ui-security.d.ts +54 -0
  214. package/dist/validation/ui-security.d.ts.map +1 -0
  215. package/dist/validation/ui-security.js +138 -0
  216. package/dist/validation/zod-to-json-schema.d.ts +63 -0
  217. package/dist/validation/zod-to-json-schema.d.ts.map +1 -0
  218. package/dist/validation/zod-to-json-schema.js +126 -0
  219. package/dist/version.d.ts +1458 -0
  220. package/dist/version.d.ts.map +1 -0
  221. package/dist/version.js +1459 -0
  222. package/package.json +113 -0
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Unified protocol-linter entry points for `DataContract`.
3
+ *
4
+ * Two reporting modes share one rule registry:
5
+ *
6
+ * - {@link validateContract} — strict; runs phased validation and
7
+ * throws {@link ContractValidationError} on the FIRST phase that
8
+ * produces errors. Used at every protocol boundary (push handler,
9
+ * blueprint registration, future synth output gate).
10
+ *
11
+ * - {@link lintContract} — graded; runs ALL phases unconditionally
12
+ * and returns errors + warnings together. Used by authoring
13
+ * tools (synth's self-correction loop, blueprint registration's
14
+ * warning surfaces, future contract-author tooling).
15
+ *
16
+ * **Phased execution** (stop-at-first-error-class for `validateContract`):
17
+ *
18
+ * ```
19
+ * phase 1: shape (zod wire-shape validation)
20
+ * phase 2: references (CTR_REF_*, CTR_DUP_NAME, CTR_RESERVED_NAME)
21
+ * phase 3: schema compat (CTR_SCHEMA_INCOMPAT)
22
+ * phase 4: hygiene (LINT_* — graded, warnings only today)
23
+ * ```
24
+ *
25
+ * Errors are reported one phase at a time during strict validation so
26
+ * the LLM gets a clean signal during iterative authoring — fixing a
27
+ * shape bug first, then references, then schemas, then hygiene. The
28
+ * graded mode emits every issue at once so authoring tools can
29
+ * present a complete checklist.
30
+ */
31
+ import type { DataContract } from '../types/data-contract';
32
+ /**
33
+ * Severity classification for a {@link ContractIssue}. Strict
34
+ * `validateContract` throws on `'error'`; graded `lintContract`
35
+ * surfaces both, partitioned by severity.
36
+ */
37
+ export type ContractIssueSeverity = 'error' | 'warn';
38
+ /**
39
+ * Phase classification for a {@link ContractIssue}. Surfaced so
40
+ * authoring tools can render issues grouped by phase + drive the
41
+ * "fix one phase at a time" UX.
42
+ */
43
+ export type ContractLintPhase = 'shape' | 'references' | 'schema-compat' | 'hygiene';
44
+ /**
45
+ * One observation about a contract from the linter's perspective.
46
+ *
47
+ * Stable-code-keyed (vs. the existing per-module `ContractViolation`
48
+ * shape) so authoring tools can pattern-match on `code` and drive
49
+ * fix workflows. The pre-existing per-module violation types
50
+ * (`CrossReferenceViolation`, `NameInvariantViolation`,
51
+ * `SchemaCompatViolation`) map into this shape via the internal
52
+ * conversion helpers in this file; consumers of `lintContract` /
53
+ * `validateContract` see only `ContractIssue`.
54
+ */
55
+ export interface ContractIssue {
56
+ /** Stable error code (e.g., 'CTR_REF_NEXT_STEP', 'CTR_DUP_NAME'). */
57
+ readonly code: string;
58
+ readonly severity: ContractIssueSeverity;
59
+ readonly phase: ContractLintPhase;
60
+ /**
61
+ * Field path into the contract identifying the offending entry.
62
+ * Uses dotted JS-style notation matching the per-module
63
+ * `ContractViolation.field` convention
64
+ * (`actionSpec.archive.nextStep`).
65
+ */
66
+ readonly path: string;
67
+ /** Human-readable violation prose. */
68
+ readonly message: string;
69
+ /**
70
+ * Optional remediation hint. Future hygiene-phase rules emit a
71
+ * fix recipe here ("declare `usage` on this entry"); invariant
72
+ * rules embed the recipe directly in `message` today.
73
+ */
74
+ readonly fixHint?: string;
75
+ }
76
+ /**
77
+ * Aggregate result of {@link lintContract}. Errors and warnings are
78
+ * partitioned at construction; consumers that want a flat list can
79
+ * concatenate.
80
+ */
81
+ export interface ContractLintResult {
82
+ readonly errors: readonly ContractIssue[];
83
+ readonly warnings: readonly ContractIssue[];
84
+ }
85
+ /**
86
+ * Strict-mode failure. Carries the offending phase + every issue
87
+ * the failing phase produced so error renderers can show every fix
88
+ * in one pass without re-running the linter.
89
+ *
90
+ * The `phase` field discriminates the error class: shape errors
91
+ * surface as a single rolled-up zod failure; reference / schema-compat
92
+ * errors carry one issue per violation.
93
+ */
94
+ export declare class ContractValidationError extends Error {
95
+ readonly code: "contract_validation_failed";
96
+ readonly phase: ContractLintPhase;
97
+ readonly issues: readonly ContractIssue[];
98
+ constructor(phase: ContractLintPhase, issues: readonly ContractIssue[]);
99
+ }
100
+ /**
101
+ * Strict-mode validator. Runs the four phases in order; throws
102
+ * {@link ContractValidationError} on the FIRST phase that produces
103
+ * errors. Used at every protocol boundary where a malformed
104
+ * contract is a fatal author bug.
105
+ *
106
+ * Phases run in dependency order:
107
+ *
108
+ * 1. shape — zod parse fails ⇒ nothing else makes sense
109
+ * 2. references — refs must resolve before schema-compat can read
110
+ * the referenced tool's schemas
111
+ * 3. schema-compat — checks rely on resolved references
112
+ * 4. hygiene — warnings only; never throws (handled by lintContract)
113
+ *
114
+ * Hygiene-only contracts (warnings without errors) pass the strict
115
+ * gate. Use {@link lintContract} when warnings matter.
116
+ */
117
+ export declare function validateContract(contract: DataContract): void;
118
+ /**
119
+ * Graded-mode linter. Runs ALL phases unconditionally and returns
120
+ * errors + warnings partitioned. Suitable for authoring tools that
121
+ * want a complete checklist of issues + suggestions rather than the
122
+ * fail-fast posture of {@link validateContract}.
123
+ *
124
+ * Phase ordering still matters for diagnostics (issues are returned
125
+ * in phase order); but graded mode never short-circuits, so an
126
+ * author seeing a phase-2 reference error also sees the phase-4
127
+ * hygiene warnings on the same contract.
128
+ */
129
+ export declare function lintContract(contract: DataContract): ContractLintResult;
130
+ //# sourceMappingURL=lint-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint-contract.d.ts","sourceRoot":"","sources":["../../src/validation/lint-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAgB3D;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,MAAM,CAAC;AAErD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GACzB,OAAO,GACP,YAAY,GACZ,eAAe,GACf,SAAS,CAAC;AAEd;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAG,4BAA4B,CAAU;IACtD,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;gBAE9B,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,aAAa,EAAE;CAOvE;AAwHD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAiB7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,kBAAkB,CAsBvE"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Unified protocol-linter entry points for `DataContract`.
3
+ *
4
+ * Two reporting modes share one rule registry:
5
+ *
6
+ * - {@link validateContract} — strict; runs phased validation and
7
+ * throws {@link ContractValidationError} on the FIRST phase that
8
+ * produces errors. Used at every protocol boundary (push handler,
9
+ * blueprint registration, future synth output gate).
10
+ *
11
+ * - {@link lintContract} — graded; runs ALL phases unconditionally
12
+ * and returns errors + warnings together. Used by authoring
13
+ * tools (synth's self-correction loop, blueprint registration's
14
+ * warning surfaces, future contract-author tooling).
15
+ *
16
+ * **Phased execution** (stop-at-first-error-class for `validateContract`):
17
+ *
18
+ * ```
19
+ * phase 1: shape (zod wire-shape validation)
20
+ * phase 2: references (CTR_REF_*, CTR_DUP_NAME, CTR_RESERVED_NAME)
21
+ * phase 3: schema compat (CTR_SCHEMA_INCOMPAT)
22
+ * phase 4: hygiene (LINT_* — graded, warnings only today)
23
+ * ```
24
+ *
25
+ * Errors are reported one phase at a time during strict validation so
26
+ * the LLM gets a clean signal during iterative authoring — fixing a
27
+ * shape bug first, then references, then schemas, then hygiene. The
28
+ * graded mode emits every issue at once so authoring tools can
29
+ * present a complete checklist.
30
+ */
31
+ import { dataContractSchema } from '../schemas/data-contract.js';
32
+ import { checkCrossReferences, } from './cross-references.js';
33
+ import { checkNameInvariants, } from './name-invariants.js';
34
+ import { checkSchemaCompat, } from './schema-compat-invariants.js';
35
+ import { checkHygiene } from './hygiene-rules.js';
36
+ /**
37
+ * Strict-mode failure. Carries the offending phase + every issue
38
+ * the failing phase produced so error renderers can show every fix
39
+ * in one pass without re-running the linter.
40
+ *
41
+ * The `phase` field discriminates the error class: shape errors
42
+ * surface as a single rolled-up zod failure; reference / schema-compat
43
+ * errors carry one issue per violation.
44
+ */
45
+ export class ContractValidationError extends Error {
46
+ code = 'contract_validation_failed';
47
+ phase;
48
+ issues;
49
+ constructor(phase, issues) {
50
+ const summary = issues.map((i) => `[${i.code}] ${i.message}`).join(' | ');
51
+ super(`Contract validation failed at phase '${phase}': ${summary}`);
52
+ this.name = 'ContractValidationError';
53
+ this.phase = phase;
54
+ this.issues = issues;
55
+ }
56
+ }
57
+ // =============================================================================
58
+ // Phase 1 — shape (zod wire-shape validation)
59
+ // =============================================================================
60
+ function phaseShape(contract) {
61
+ const parsed = dataContractSchema.safeParse(contract);
62
+ if (parsed.success)
63
+ return [];
64
+ return zodErrorToIssues(parsed.error);
65
+ }
66
+ function zodErrorToIssues(error) {
67
+ return error.issues.map((issue) => ({
68
+ code: zodIssueCode(issue.code),
69
+ severity: 'error',
70
+ phase: 'shape',
71
+ path: issue.path.join('.') || '<root>',
72
+ message: issue.message,
73
+ }));
74
+ }
75
+ /**
76
+ * Map a zod issue code to the linter's stable code namespace. The
77
+ * mapping is intentionally narrow — every unknown zod code rolls up
78
+ * to `CTR_SHAPE_INVALID`; consumers that want zod-level granularity
79
+ * can re-parse with `dataContractSchema.safeParse` themselves.
80
+ */
81
+ function zodIssueCode(zodCode) {
82
+ switch (zodCode) {
83
+ case 'invalid_type':
84
+ return 'CTR_SHAPE_INVALID_TYPE';
85
+ case 'unrecognized_keys':
86
+ return 'CTR_SHAPE_UNRECOGNIZED_KEYS';
87
+ default:
88
+ return 'CTR_SHAPE_INVALID';
89
+ }
90
+ }
91
+ // =============================================================================
92
+ // Phase 2 — references (CTR_REF_*, CTR_DUP_NAME, CTR_RESERVED_NAME)
93
+ // =============================================================================
94
+ function phaseReferences(contract) {
95
+ const issues = [];
96
+ for (const v of checkCrossReferences(contract)) {
97
+ issues.push(crossRefViolationToIssue(v));
98
+ }
99
+ for (const v of checkNameInvariants(contract)) {
100
+ issues.push(nameInvariantViolationToIssue(v));
101
+ }
102
+ return issues;
103
+ }
104
+ function crossRefViolationToIssue(v) {
105
+ return {
106
+ code: v.code,
107
+ severity: 'error',
108
+ phase: 'references',
109
+ path: v.field,
110
+ message: v.message,
111
+ };
112
+ }
113
+ function nameInvariantViolationToIssue(v) {
114
+ return {
115
+ code: v.code,
116
+ severity: 'error',
117
+ phase: 'references',
118
+ path: v.field,
119
+ message: v.message,
120
+ };
121
+ }
122
+ // =============================================================================
123
+ // Phase 3 — schema compat (CTR_SCHEMA_INCOMPAT)
124
+ // =============================================================================
125
+ function phaseSchemaCompat(contract) {
126
+ return checkSchemaCompat(contract).map(schemaCompatViolationToIssue);
127
+ }
128
+ function schemaCompatViolationToIssue(v) {
129
+ return {
130
+ code: v.code,
131
+ severity: 'error',
132
+ phase: 'schema-compat',
133
+ path: v.field,
134
+ message: v.message,
135
+ };
136
+ }
137
+ // =============================================================================
138
+ // Phase 4 — hygiene (LINT_*)
139
+ // =============================================================================
140
+ function phaseHygiene(contract) {
141
+ return checkHygiene(contract).map(hygieneWarningToIssue);
142
+ }
143
+ function hygieneWarningToIssue(w) {
144
+ return {
145
+ code: w.code,
146
+ severity: 'warn',
147
+ phase: 'hygiene',
148
+ path: w.path,
149
+ message: w.message,
150
+ ...(w.fixHint !== undefined ? { fixHint: w.fixHint } : {}),
151
+ };
152
+ }
153
+ // =============================================================================
154
+ // Public API
155
+ // =============================================================================
156
+ /**
157
+ * Strict-mode validator. Runs the four phases in order; throws
158
+ * {@link ContractValidationError} on the FIRST phase that produces
159
+ * errors. Used at every protocol boundary where a malformed
160
+ * contract is a fatal author bug.
161
+ *
162
+ * Phases run in dependency order:
163
+ *
164
+ * 1. shape — zod parse fails ⇒ nothing else makes sense
165
+ * 2. references — refs must resolve before schema-compat can read
166
+ * the referenced tool's schemas
167
+ * 3. schema-compat — checks rely on resolved references
168
+ * 4. hygiene — warnings only; never throws (handled by lintContract)
169
+ *
170
+ * Hygiene-only contracts (warnings without errors) pass the strict
171
+ * gate. Use {@link lintContract} when warnings matter.
172
+ */
173
+ export function validateContract(contract) {
174
+ const shapeIssues = phaseShape(contract);
175
+ if (shapeIssues.length > 0) {
176
+ throw new ContractValidationError('shape', shapeIssues);
177
+ }
178
+ // After phase 1 we know the contract structurally parses; safe to
179
+ // cast through into the phase-2 / phase-3 helpers (they accept
180
+ // `DataContract` directly).
181
+ const refIssues = phaseReferences(contract);
182
+ if (refIssues.length > 0) {
183
+ throw new ContractValidationError('references', refIssues);
184
+ }
185
+ const compatIssues = phaseSchemaCompat(contract);
186
+ if (compatIssues.length > 0) {
187
+ throw new ContractValidationError('schema-compat', compatIssues);
188
+ }
189
+ // Hygiene is graded-only; not thrown by strict validator.
190
+ }
191
+ /**
192
+ * Graded-mode linter. Runs ALL phases unconditionally and returns
193
+ * errors + warnings partitioned. Suitable for authoring tools that
194
+ * want a complete checklist of issues + suggestions rather than the
195
+ * fail-fast posture of {@link validateContract}.
196
+ *
197
+ * Phase ordering still matters for diagnostics (issues are returned
198
+ * in phase order); but graded mode never short-circuits, so an
199
+ * author seeing a phase-2 reference error also sees the phase-4
200
+ * hygiene warnings on the same contract.
201
+ */
202
+ export function lintContract(contract) {
203
+ const issues = [];
204
+ issues.push(...phaseShape(contract));
205
+ // Phase 2 + 3 produce shape-dependent errors. When the shape
206
+ // phase already failed, the contract may not match the type
207
+ // signatures these phases assume — skip downstream phases in that
208
+ // case to avoid throwing during the lint run. Authoring tools see
209
+ // "fix shape first" via the shape issues; once those are clean
210
+ // the next `lintContract` run reaches the deeper phases.
211
+ if (issues.length === 0) {
212
+ issues.push(...phaseReferences(contract));
213
+ issues.push(...phaseSchemaCompat(contract));
214
+ }
215
+ issues.push(...phaseHygiene(contract));
216
+ const errors = [];
217
+ const warnings = [];
218
+ for (const issue of issues) {
219
+ if (issue.severity === 'error')
220
+ errors.push(issue);
221
+ else
222
+ warnings.push(issue);
223
+ }
224
+ return { errors, warnings };
225
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Name-uniqueness and reserved-namespace invariants for `DataContract`.
3
+ *
4
+ * Two stable error codes:
5
+ *
6
+ * - `CTR_DUP_NAME` — the same key appears in two or more of
7
+ * `actionSpec`, `streamSpec`, `contextSpec`.
8
+ * Collisions are author bugs: the boilerplate
9
+ * generator emits identifiers from these keys
10
+ * (action handlers, channel subscribers, slot
11
+ * state hooks), and a collision either shadows
12
+ * or compiles to ambiguous source. The agent's
13
+ * downstream reasoning also fragments —
14
+ * "submit" can't be both a discrete event AND
15
+ * observable state without confusing the
16
+ * actions-vs-context placement rule.
17
+ *
18
+ * - `CTR_RESERVED_NAME` — a key on `actionSpec` or `contextSpec`
19
+ * starts with the `_ggui:` reserved prefix.
20
+ * `streamSpec` already enforces this in
21
+ * `validateContractStructure` (server-owned
22
+ * reserved channels can't be agent-declared);
23
+ * this invariant extends the rule to the other
24
+ * two inbound specs so the reserved namespace
25
+ * is uniformly off-limits to authors. Today no
26
+ * reserved actions or context slots exist, but
27
+ * the protocol reserves the namespace forward
28
+ * for runtime-owned signals.
29
+ *
30
+ * Pure checks; return violations rather than throwing. Callers that
31
+ * want fail-fast semantics use {@link assertNameInvariants}. Folded
32
+ * into `validateContractStructure` so the structural-validator surface
33
+ * picks up these rules without per-caller wiring.
34
+ *
35
+ * Companion to {@link CrossReferenceError} in `./cross-references` —
36
+ * the two modules ship the "phase 2: references" rule registry.
37
+ */
38
+ import type { DataContract } from '../types/data-contract';
39
+ import type { ContractViolation } from './contract-validator';
40
+ /**
41
+ * Stable error code for collisions across the three inbound spec maps
42
+ * (`actionSpec` / `streamSpec` / `contextSpec`). The boilerplate
43
+ * generator emits identifiers from these keys; a collision is an
44
+ * author bug that the protocol catches at push.
45
+ */
46
+ export declare const CTR_DUP_NAME = "CTR_DUP_NAME";
47
+ /**
48
+ * Stable error code for keys in the `_ggui:` reserved namespace on
49
+ * `actionSpec` or `contextSpec`. `streamSpec` already enforces the
50
+ * same rule in `validateContractStructure`.
51
+ */
52
+ export declare const CTR_RESERVED_NAME = "CTR_RESERVED_NAME";
53
+ /**
54
+ * Name-invariant violation. Adds a stable `code` field on top of
55
+ * `ContractViolation` so consumers can switch on the code rather than
56
+ * pattern-matching message strings.
57
+ */
58
+ export interface NameInvariantViolation extends ContractViolation {
59
+ code: typeof CTR_DUP_NAME | typeof CTR_RESERVED_NAME;
60
+ }
61
+ /**
62
+ * Validate that no name appears in more than one of `actionSpec`,
63
+ * `streamSpec`, `contextSpec`. Emits one violation per colliding name
64
+ * (not one per spec the name appears in) so the agent sees a single
65
+ * actionable line per collision.
66
+ *
67
+ * Order is stable: collisions are reported in the order names first
68
+ * appear when scanning `actionSpec` → `streamSpec` → `contextSpec`.
69
+ */
70
+ export declare function checkNameCollisions(contract: DataContract): NameInvariantViolation[];
71
+ /**
72
+ * Validate that no `actionSpec` or `contextSpec` key uses the
73
+ * `_ggui:` reserved namespace. `streamSpec` reserved-channel rejection
74
+ * lives in `validateContractStructure` (the reserved namespace there
75
+ * carries server-side semantics like the `_ggui:contract-error`
76
+ * channel); this invariant extends the rule uniformly across the
77
+ * other two inbound spec maps.
78
+ *
79
+ * Future runtime-owned action or context signals would carry the
80
+ * `_ggui:` prefix and would be emitted by the runtime, not declared
81
+ * by authors. Today no such signals exist, but the prefix is reserved
82
+ * forward.
83
+ */
84
+ export declare function checkReservedNames(contract: DataContract): NameInvariantViolation[];
85
+ /**
86
+ * Run every name-invariant check. Returns the aggregated violation
87
+ * list — order is stable: collisions first, reserved names second.
88
+ *
89
+ * Pure check; doesn't throw. Callers that want fail-fast semantics
90
+ * use {@link assertNameInvariants}.
91
+ */
92
+ export declare function checkNameInvariants(contract: DataContract): NameInvariantViolation[];
93
+ /**
94
+ * Throwable form of {@link checkNameInvariants}. Use at protocol
95
+ * boundaries where a name collision or reserved-namespace use is a
96
+ * contract bug the caller must fix (push handler, blueprint
97
+ * registration).
98
+ *
99
+ * Carries the full violation list so error renderers can show every
100
+ * offending name in one pass instead of fix-and-retry per-field.
101
+ */
102
+ export declare class NameInvariantError extends Error {
103
+ readonly code: "name_invariant_violation";
104
+ readonly violations: readonly NameInvariantViolation[];
105
+ constructor(violations: readonly NameInvariantViolation[]);
106
+ }
107
+ /**
108
+ * Throw-on-violation wrapper around {@link checkNameInvariants}.
109
+ * No-op when the contract's names are consistent.
110
+ *
111
+ * Designed to slot alongside `assertCrossReferences` at push time:
112
+ * cross-reference invariants catch dangling pointers between specs;
113
+ * name invariants catch malformed name spaces within specs. Both
114
+ * surface author-recoverable failures before any state mutation.
115
+ */
116
+ export declare function assertNameInvariants(contract: DataContract): void;
117
+ //# sourceMappingURL=name-invariants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-invariants.d.ts","sourceRoot":"","sources":["../../src/validation/name-invariants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAM9D;;;;;GAKG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,IAAI,EAAE,OAAO,YAAY,GAAG,OAAO,iBAAiB,CAAC;CACtD;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GACrB,sBAAsB,EAAE,CA6B1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,GACrB,sBAAsB,EAAE,CAmB1B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GACrB,sBAAsB,EAAE,CAE1B;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAG,0BAA0B,CAAU;IACpD,QAAQ,CAAC,UAAU,EAAE,SAAS,sBAAsB,EAAE,CAAC;gBAE3C,UAAU,EAAE,SAAS,sBAAsB,EAAE;CAQ1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAKjE"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Name-uniqueness and reserved-namespace invariants for `DataContract`.
3
+ *
4
+ * Two stable error codes:
5
+ *
6
+ * - `CTR_DUP_NAME` — the same key appears in two or more of
7
+ * `actionSpec`, `streamSpec`, `contextSpec`.
8
+ * Collisions are author bugs: the boilerplate
9
+ * generator emits identifiers from these keys
10
+ * (action handlers, channel subscribers, slot
11
+ * state hooks), and a collision either shadows
12
+ * or compiles to ambiguous source. The agent's
13
+ * downstream reasoning also fragments —
14
+ * "submit" can't be both a discrete event AND
15
+ * observable state without confusing the
16
+ * actions-vs-context placement rule.
17
+ *
18
+ * - `CTR_RESERVED_NAME` — a key on `actionSpec` or `contextSpec`
19
+ * starts with the `_ggui:` reserved prefix.
20
+ * `streamSpec` already enforces this in
21
+ * `validateContractStructure` (server-owned
22
+ * reserved channels can't be agent-declared);
23
+ * this invariant extends the rule to the other
24
+ * two inbound specs so the reserved namespace
25
+ * is uniformly off-limits to authors. Today no
26
+ * reserved actions or context slots exist, but
27
+ * the protocol reserves the namespace forward
28
+ * for runtime-owned signals.
29
+ *
30
+ * Pure checks; return violations rather than throwing. Callers that
31
+ * want fail-fast semantics use {@link assertNameInvariants}. Folded
32
+ * into `validateContractStructure` so the structural-validator surface
33
+ * picks up these rules without per-caller wiring.
34
+ *
35
+ * Companion to {@link CrossReferenceError} in `./cross-references` —
36
+ * the two modules ship the "phase 2: references" rule registry.
37
+ */
38
+ import { RESERVED_CHANNEL_PREFIX, isReservedChannelName, } from './reserved-channels.js';
39
+ /**
40
+ * Stable error code for collisions across the three inbound spec maps
41
+ * (`actionSpec` / `streamSpec` / `contextSpec`). The boilerplate
42
+ * generator emits identifiers from these keys; a collision is an
43
+ * author bug that the protocol catches at push.
44
+ */
45
+ export const CTR_DUP_NAME = 'CTR_DUP_NAME';
46
+ /**
47
+ * Stable error code for keys in the `_ggui:` reserved namespace on
48
+ * `actionSpec` or `contextSpec`. `streamSpec` already enforces the
49
+ * same rule in `validateContractStructure`.
50
+ */
51
+ export const CTR_RESERVED_NAME = 'CTR_RESERVED_NAME';
52
+ /** Spec maps that share the inbound name namespace. */
53
+ const SPEC_FIELDS = ['actionSpec', 'streamSpec', 'contextSpec'];
54
+ /**
55
+ * Validate that no name appears in more than one of `actionSpec`,
56
+ * `streamSpec`, `contextSpec`. Emits one violation per colliding name
57
+ * (not one per spec the name appears in) so the agent sees a single
58
+ * actionable line per collision.
59
+ *
60
+ * Order is stable: collisions are reported in the order names first
61
+ * appear when scanning `actionSpec` → `streamSpec` → `contextSpec`.
62
+ */
63
+ export function checkNameCollisions(contract) {
64
+ // Build name → list of spec fields where it appears
65
+ const byName = new Map();
66
+ for (const field of SPEC_FIELDS) {
67
+ const spec = contract[field];
68
+ if (!spec || typeof spec !== 'object')
69
+ continue;
70
+ for (const name of Object.keys(spec)) {
71
+ const existing = byName.get(name);
72
+ if (existing) {
73
+ existing.push(field);
74
+ }
75
+ else {
76
+ byName.set(name, [field]);
77
+ }
78
+ }
79
+ }
80
+ const violations = [];
81
+ for (const [name, fields] of byName) {
82
+ if (fields.length < 2)
83
+ continue;
84
+ violations.push({
85
+ code: CTR_DUP_NAME,
86
+ field: `${fields[0]}.${name}`,
87
+ message: `Name '${name}' is declared in multiple specs: ${fields.join(', ')}. Each name MUST appear in exactly one of actionSpec / streamSpec / contextSpec — the boilerplate generator emits identifiers from these keys and collisions produce shadowed or ambiguous source.`,
88
+ expected: 'unique name across inbound specs',
89
+ received: fields.join(' + '),
90
+ });
91
+ }
92
+ return violations;
93
+ }
94
+ /**
95
+ * Validate that no `actionSpec` or `contextSpec` key uses the
96
+ * `_ggui:` reserved namespace. `streamSpec` reserved-channel rejection
97
+ * lives in `validateContractStructure` (the reserved namespace there
98
+ * carries server-side semantics like the `_ggui:contract-error`
99
+ * channel); this invariant extends the rule uniformly across the
100
+ * other two inbound spec maps.
101
+ *
102
+ * Future runtime-owned action or context signals would carry the
103
+ * `_ggui:` prefix and would be emitted by the runtime, not declared
104
+ * by authors. Today no such signals exist, but the prefix is reserved
105
+ * forward.
106
+ */
107
+ export function checkReservedNames(contract) {
108
+ const violations = [];
109
+ for (const field of ['actionSpec', 'contextSpec']) {
110
+ const spec = contract[field];
111
+ if (!spec || typeof spec !== 'object')
112
+ continue;
113
+ for (const name of Object.keys(spec)) {
114
+ if (!isReservedChannelName(name))
115
+ continue;
116
+ violations.push({
117
+ code: CTR_RESERVED_NAME,
118
+ field: `${field}.${name}`,
119
+ message: `${field}.${name} is in the reserved '${RESERVED_CHANNEL_PREFIX}' namespace — names starting with that prefix are reserved for runtime-owned signals and cannot be agent-declared.`,
120
+ expected: `name not starting with '${RESERVED_CHANNEL_PREFIX}'`,
121
+ received: name,
122
+ });
123
+ }
124
+ }
125
+ return violations;
126
+ }
127
+ /**
128
+ * Run every name-invariant check. Returns the aggregated violation
129
+ * list — order is stable: collisions first, reserved names second.
130
+ *
131
+ * Pure check; doesn't throw. Callers that want fail-fast semantics
132
+ * use {@link assertNameInvariants}.
133
+ */
134
+ export function checkNameInvariants(contract) {
135
+ return [...checkNameCollisions(contract), ...checkReservedNames(contract)];
136
+ }
137
+ /**
138
+ * Throwable form of {@link checkNameInvariants}. Use at protocol
139
+ * boundaries where a name collision or reserved-namespace use is a
140
+ * contract bug the caller must fix (push handler, blueprint
141
+ * registration).
142
+ *
143
+ * Carries the full violation list so error renderers can show every
144
+ * offending name in one pass instead of fix-and-retry per-field.
145
+ */
146
+ export class NameInvariantError extends Error {
147
+ code = 'name_invariant_violation';
148
+ violations;
149
+ constructor(violations) {
150
+ const summary = violations
151
+ .map((v) => `[${v.code}] ${v.message}`)
152
+ .join(' | ');
153
+ super(`Contract name-invariant check failed: ${summary}`);
154
+ this.name = 'NameInvariantError';
155
+ this.violations = violations;
156
+ }
157
+ }
158
+ /**
159
+ * Throw-on-violation wrapper around {@link checkNameInvariants}.
160
+ * No-op when the contract's names are consistent.
161
+ *
162
+ * Designed to slot alongside `assertCrossReferences` at push time:
163
+ * cross-reference invariants catch dangling pointers between specs;
164
+ * name invariants catch malformed name spaces within specs. Both
165
+ * surface author-recoverable failures before any state mutation.
166
+ */
167
+ export function assertNameInvariants(contract) {
168
+ const violations = checkNameInvariants(contract);
169
+ if (violations.length > 0) {
170
+ throw new NameInvariantError(violations);
171
+ }
172
+ }