@glubean/sdk 0.2.0 → 0.2.2

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 (104) hide show
  1. package/dist/configure/http.d.ts +25 -0
  2. package/dist/configure/http.d.ts.map +1 -0
  3. package/dist/configure/http.js +88 -0
  4. package/dist/configure/http.js.map +1 -0
  5. package/dist/configure/index.d.ts +78 -0
  6. package/dist/configure/index.d.ts.map +1 -0
  7. package/dist/configure/index.js +78 -0
  8. package/dist/configure/index.js.map +1 -0
  9. package/dist/configure/plugin.d.ts +23 -0
  10. package/dist/configure/plugin.d.ts.map +1 -0
  11. package/dist/configure/plugin.js +81 -0
  12. package/dist/configure/plugin.js.map +1 -0
  13. package/dist/configure/runtime.d.ts +24 -0
  14. package/dist/configure/runtime.d.ts.map +1 -0
  15. package/dist/configure/runtime.js +45 -0
  16. package/dist/configure/runtime.js.map +1 -0
  17. package/dist/configure/template.d.ts +22 -0
  18. package/dist/configure/template.d.ts.map +1 -0
  19. package/dist/configure/template.js +34 -0
  20. package/dist/configure/template.js.map +1 -0
  21. package/dist/configure/vars.d.ts +20 -0
  22. package/dist/configure/vars.d.ts.map +1 -0
  23. package/dist/configure/vars.js +48 -0
  24. package/dist/configure/vars.js.map +1 -0
  25. package/dist/configure.d.ts +2 -150
  26. package/dist/configure.d.ts.map +1 -1
  27. package/dist/configure.js +2 -562
  28. package/dist/configure.js.map +1 -1
  29. package/dist/contract-artifacts.d.ts +268 -0
  30. package/dist/contract-artifacts.d.ts.map +1 -0
  31. package/dist/contract-artifacts.js +402 -0
  32. package/dist/contract-artifacts.js.map +1 -0
  33. package/dist/contract-core.d.ts +33 -1
  34. package/dist/contract-core.d.ts.map +1 -1
  35. package/dist/contract-core.js +51 -2
  36. package/dist/contract-core.js.map +1 -1
  37. package/dist/contract-http/adapter.d.ts.map +1 -1
  38. package/dist/contract-http/adapter.js +22 -7
  39. package/dist/contract-http/adapter.js.map +1 -1
  40. package/dist/contract-http/factory.d.ts.map +1 -1
  41. package/dist/contract-http/factory.js +13 -14
  42. package/dist/contract-http/factory.js.map +1 -1
  43. package/dist/contract-http/index.d.ts +4 -3
  44. package/dist/contract-http/index.d.ts.map +1 -1
  45. package/dist/contract-http/index.js +4 -3
  46. package/dist/contract-http/index.js.map +1 -1
  47. package/dist/contract-http/openapi.d.ts +56 -7
  48. package/dist/contract-http/openapi.d.ts.map +1 -1
  49. package/dist/contract-http/openapi.js +371 -21
  50. package/dist/contract-http/openapi.js.map +1 -1
  51. package/dist/contract-http/types.d.ts +2 -13
  52. package/dist/contract-http/types.d.ts.map +1 -1
  53. package/dist/contract-types.d.ts +59 -10
  54. package/dist/contract-types.d.ts.map +1 -1
  55. package/dist/expect.d.ts +13 -0
  56. package/dist/expect.d.ts.map +1 -1
  57. package/dist/expect.js +18 -0
  58. package/dist/expect.js.map +1 -1
  59. package/dist/index.d.ts +61 -518
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +26 -835
  62. package/dist/index.js.map +1 -1
  63. package/dist/install-plugin.d.ts +94 -0
  64. package/dist/install-plugin.d.ts.map +1 -0
  65. package/dist/install-plugin.js +222 -0
  66. package/dist/install-plugin.js.map +1 -0
  67. package/dist/internal.d.ts +2 -0
  68. package/dist/internal.d.ts.map +1 -1
  69. package/dist/internal.js +6 -0
  70. package/dist/internal.js.map +1 -1
  71. package/dist/plugin.d.ts +45 -34
  72. package/dist/plugin.d.ts.map +1 -1
  73. package/dist/plugin.js +47 -34
  74. package/dist/plugin.js.map +1 -1
  75. package/dist/runtime-carrier.d.ts +142 -0
  76. package/dist/runtime-carrier.d.ts.map +1 -0
  77. package/dist/runtime-carrier.js +148 -0
  78. package/dist/runtime-carrier.js.map +1 -0
  79. package/dist/session.d.ts.map +1 -1
  80. package/dist/session.js +2 -1
  81. package/dist/session.js.map +1 -1
  82. package/dist/test/builder.d.ts +249 -0
  83. package/dist/test/builder.d.ts.map +1 -0
  84. package/dist/test/builder.js +265 -0
  85. package/dist/test/builder.js.map +1 -0
  86. package/dist/test/each-builder.d.ts +244 -0
  87. package/dist/test/each-builder.d.ts.map +1 -0
  88. package/dist/test/each-builder.js +268 -0
  89. package/dist/test/each-builder.js.map +1 -0
  90. package/dist/test/extend.d.ts +59 -0
  91. package/dist/test/extend.d.ts.map +1 -0
  92. package/dist/test/extend.js +111 -0
  93. package/dist/test/extend.js.map +1 -0
  94. package/dist/test/utils.d.ts +39 -0
  95. package/dist/test/utils.d.ts.map +1 -0
  96. package/dist/test/utils.js +91 -0
  97. package/dist/test/utils.js.map +1 -0
  98. package/dist/types.d.ts +89 -111
  99. package/dist/types.d.ts.map +1 -1
  100. package/package.json +1 -1
  101. package/dist/contract-http/markdown.d.ts +0 -10
  102. package/dist/contract-http/markdown.d.ts.map +0 -1
  103. package/dist/contract-http/markdown.js +0 -21
  104. package/dist/contract-http/markdown.js.map +0 -1
@@ -0,0 +1,268 @@
1
+ /**
2
+ * @module contract-artifacts
3
+ *
4
+ * Contract artifact registry — declarative extension point for
5
+ * "contracts → X" rendering (markdown / openapi / future proto / sdl /
6
+ * asyncapi / ...).
7
+ *
8
+ * Replaces the v0.1 per-adapter `toMarkdown?` / `toOpenApi?` hooks which
9
+ * (a) polluted the generic `ContractProtocolAdapter` interface with
10
+ * protocol-specific artifacts (OpenAPI is HTTP-only), (b) had dead
11
+ * declarations that nothing called, and (c) gave consumers no way to
12
+ * enumerate "which artifact kinds does this project support".
13
+ *
14
+ * See `internal/40-discovery/proposals/contract-artifact-registry.md` (v6).
15
+ *
16
+ * ## Concepts
17
+ *
18
+ * **ArtifactKind**: first-class description of an output format (name +
19
+ * merge strategy + empty skeleton + optional defaultRender). Per-contract
20
+ * Part and final merged Final are independently typed (markdown renders
21
+ * structured parts that the merge assembles into a document; openapi
22
+ * renders per-contract partial documents that the merge stitches together).
23
+ *
24
+ * **ContractProtocolAdapter.artifacts**: each adapter declares which
25
+ * kinds it produces. Mapping from kind name to per-contract renderer.
26
+ *
27
+ * **Consumers**: `renderArtifact(kind, contracts, options?, control?)`
28
+ * dispatches across all registered adapters; fallback to kind.defaultRender
29
+ * where the adapter doesn't implement the kind; ultimate fallback to
30
+ * kind.empty when no contract contributes a part.
31
+ *
32
+ * ## Types
33
+ *
34
+ * `KnownArtifacts` / `KnownArtifactParts` / `KnownArtifactOptions` are
35
+ * declared at the package root (`packages/sdk/src/index.ts`) so third-
36
+ * party plugins can augment via `declare module "@glubean/sdk"`. This file
37
+ * imports them as types from the root so declaration merging hits the
38
+ * same node.
39
+ */
40
+ import type { ExtractedContractProjection } from "./contract-types.js";
41
+ import type { OpenApiDocument, OpenApiOptions } from "./contract-http/openapi.js";
42
+ /**
43
+ * Declarative description of an artifact format.
44
+ *
45
+ * @template Final Final merged value type (what consumers receive).
46
+ * @template Part Per-contract partial type (what producer / defaultRender
47
+ * emit). Defaults to Final; distinct when per-contract
48
+ * rendering is structured (e.g. markdown produces
49
+ * `{ body, feature, caseCount }` parts and the merge
50
+ * assembles a feature-grouped doc string).
51
+ * @template Options Per-render options type. Threaded through the entire
52
+ * pipeline (producer / defaultRender / merge) so kinds
53
+ * whose options affect per-contract rendering (e.g. proto
54
+ * `package` per message) are as well-served as kinds whose
55
+ * options only affect the final merge (e.g. openapi
56
+ * `title`).
57
+ */
58
+ export interface ArtifactKind<Final, Part = Final, Options = void> {
59
+ /** Kind identifier (snake-case or kebab-case). Unique across the registry. */
60
+ readonly name: string;
61
+ /**
62
+ * Combine per-contract parts into the final artifact. Called once per
63
+ * render; receives the collected parts and the same options that were
64
+ * passed to producers / defaultRender.
65
+ */
66
+ readonly merge: (parts: Part[], options?: Options) => Final;
67
+ /**
68
+ * Optional fallback: when an adapter has not declared a producer for this
69
+ * kind, use this function to render a per-contract Part from the generic
70
+ * `ExtractedContractProjection`. Omitted for kinds that only make sense
71
+ * for specific protocols (e.g. openapi has no defaultRender — non-HTTP
72
+ * contracts are skipped).
73
+ */
74
+ readonly defaultRender?: (projection: ExtractedContractProjection<unknown, unknown>, options?: Options) => Part;
75
+ /**
76
+ * Required: the value returned by `renderArtifact` when no contract
77
+ * contributes a part. Must be a valid Final. Lets `renderArtifact` promise
78
+ * `Final` (not `Final | undefined`) and forces kind authors to think
79
+ * about the zero-contribution scenario explicitly.
80
+ */
81
+ readonly empty: Final;
82
+ }
83
+ /**
84
+ * Register an artifact kind by name. Idempotent when re-registering the same
85
+ * kind object; throws when a different object tries to take the same name
86
+ * (protects against typo-level collisions across plugins).
87
+ *
88
+ * `defineArtifactKind` is the ergonomic entry; this is exported for advanced
89
+ * scenarios where a kind is built separately from its registration.
90
+ */
91
+ export declare function registerArtifactKind<Final, Part, Options>(kind: ArtifactKind<Final, Part, Options>): void;
92
+ /**
93
+ * Look up a registered kind by name. Used by `renderArtifactByName` and any
94
+ * other string-driven consumer (CLI --format, MCP tool inputs, etc.).
95
+ */
96
+ export declare function getArtifactKind(name: string): ArtifactKind<unknown, unknown, unknown> | undefined;
97
+ /** List all registered kind names (insertion order). */
98
+ export declare function listArtifactKinds(): string[];
99
+ /**
100
+ * Define and register an artifact kind in one call. Preferred entry point
101
+ * for kind authors (SDK built-ins + first-party plugins).
102
+ */
103
+ export declare function defineArtifactKind<Final, Part = Final, Options = void>(spec: ArtifactKind<Final, Part, Options>): ArtifactKind<Final, Part, Options>;
104
+ /**
105
+ * Test-only: clear the kind registry. Not exposed publicly; imported by
106
+ * `contract-artifacts.test.ts` via relative path.
107
+ *
108
+ * @internal
109
+ */
110
+ export declare function __resetArtifactKindsForTesting(): void;
111
+ /**
112
+ * Control knobs for a single render invocation (orthogonal to kind-specific
113
+ * options). Kept separate from `options` so adding new flags here doesn't
114
+ * require each kind author to know about them.
115
+ */
116
+ export interface RenderArtifactControl {
117
+ /**
118
+ * Skip each adapter's `artifacts[kind]` producer even when defined; force
119
+ * all contracts through `kind.defaultRender`. For kinds without a
120
+ * defaultRender, contracts are skipped entirely.
121
+ *
122
+ * Used by CLI `--generic` for reproducible output across installed
123
+ * plugin versions, and by tests that assert default-render behavior.
124
+ */
125
+ preferDefaultRender?: boolean;
126
+ }
127
+ /**
128
+ * Summary of a render invocation — per-contract classification of how each
129
+ * contract contributed (or was skipped) + a `usedEmptyFallback` boolean.
130
+ */
131
+ export interface ArtifactContribution {
132
+ contractId: string;
133
+ protocol: string;
134
+ /** Whether the part came from the adapter's producer or kind.defaultRender. */
135
+ source: "explicit-producer" | "default-render";
136
+ }
137
+ export interface ArtifactSkip {
138
+ contractId: string;
139
+ protocol: string;
140
+ reason: "no-producer-no-default-render" | "prefer-default-render-no-default";
141
+ }
142
+ export interface ArtifactRenderSummary<Final> {
143
+ /** Same value `renderArtifact` would have returned. */
144
+ value: Final;
145
+ /** Contracts that produced a part. */
146
+ contributions: ArtifactContribution[];
147
+ /** Contracts that did not produce a part (with reason). */
148
+ skipped: ArtifactSkip[];
149
+ /**
150
+ * True iff `value === kind.empty` was returned because zero parts were
151
+ * collected. False when `kind.merge(parts, options)` was called. Callers
152
+ * should use this instead of comparing `value === kind.empty`
153
+ * themselves — merge typically returns a fresh object for object-typed
154
+ * Final, so identity / structural equality are not reliable.
155
+ */
156
+ usedEmptyFallback: boolean;
157
+ }
158
+ /**
159
+ * Render an artifact of the given kind from a list of contracts. Threads
160
+ * `options` through the producer / defaultRender / merge pipeline. When no
161
+ * contract contributes a part, returns `kind.empty` (guaranteed valid
162
+ * `Final`).
163
+ *
164
+ * Strong-typed entry point: kind argument is a concrete `ArtifactKind<...>`
165
+ * object, so `options` type and return type are inferred at compile time.
166
+ */
167
+ export declare function renderArtifact<Final, Part, Options>(kind: ArtifactKind<Final, Part, Options>, contracts: ReadonlyArray<ExtractedContractProjection<unknown, unknown>>, options?: Options, control?: RenderArtifactControl): Final;
168
+ /**
169
+ * Render an artifact and return the full summary (value + contributions +
170
+ * skipped + usedEmptyFallback). Use this when you need to distinguish
171
+ * "zero contribution" from "merged to kind.empty-shaped value" — the
172
+ * `usedEmptyFallback` field is the authoritative signal (do not compare
173
+ * `value === kind.empty` yourself for object-typed Final).
174
+ */
175
+ export declare function renderArtifactWithSummary<Final, Part, Options>(kind: ArtifactKind<Final, Part, Options>, contracts: ReadonlyArray<ExtractedContractProjection<unknown, unknown>>, options?: Options, control?: RenderArtifactControl): ArtifactRenderSummary<Final>;
176
+ /**
177
+ * Look up a kind by name and render. Used by string-driven consumers
178
+ * (CLI --format <name>, MCP tools, agent introspection). Throws when the
179
+ * name is not registered — the error message includes the list of
180
+ * registered kinds so callers can surface it without extra lookups.
181
+ *
182
+ * Returns `unknown` since we don't know the Final type statically;
183
+ * callers that need a typed return should use `renderArtifact` directly
184
+ * with the kind object they import.
185
+ */
186
+ export declare function renderArtifactByName(kindName: string, contracts: ReadonlyArray<ExtractedContractProjection<unknown, unknown>>, options?: unknown, control?: RenderArtifactControl): unknown;
187
+ /**
188
+ * List the protocols whose adapter **explicitly declares a producer** for
189
+ * the given kind. Does NOT include protocols that would fall back to
190
+ * `kind.defaultRender`. Use `listArtifactCapability` for the three-way split.
191
+ */
192
+ export declare function listArtifactProducers(kindName: string): string[];
193
+ /**
194
+ * Static capability view — **based on installed adapters**, not on any
195
+ * particular project's contracts. Partitions protocols into:
196
+ *
197
+ * - `explicit` : adapter declares a producer for this kind
198
+ * - `fallback` : adapter has no producer but kind.defaultRender exists
199
+ * - `unsupported` : adapter has no producer and kind has no defaultRender
200
+ *
201
+ * To answer "does **this project** produce the artifact?", use
202
+ * `renderArtifactWithSummary` and inspect `contributions` + `usedEmptyFallback`.
203
+ * The capability view cannot know how many contracts of each protocol exist
204
+ * in the caller's project.
205
+ */
206
+ export declare function listArtifactCapability(kindName: string): {
207
+ explicit: string[];
208
+ fallback: string[];
209
+ unsupported: string[];
210
+ };
211
+ /**
212
+ * OpenAPI 3.1 artifact kind. Per-contract partials are produced by HTTP
213
+ * adapter's `artifacts.openapi` (see `contract-http/openapi.ts`); merge
214
+ * combines them into a full spec. No `defaultRender` — non-HTTP protocols
215
+ * don't map to OpenAPI and are skipped.
216
+ *
217
+ * Ported from MCP's former `contractsToOpenApi` — CAR-1 Phase 2.
218
+ */
219
+ export declare const openapiArtifact: ArtifactKind<OpenApiDocument, OpenApiDocument, OpenApiOptions>;
220
+ /**
221
+ * Per-contract structured data consumed by `assembleMarkdownDocument`.
222
+ * Carries raw fields; the merge step handles feature grouping,
223
+ * instanceName-aware labeling, doc header, and summary counts.
224
+ */
225
+ export interface MarkdownPart {
226
+ contractId: string;
227
+ /** Display target — equivalent to `projection.target`. */
228
+ endpoint: string;
229
+ protocol: string;
230
+ description?: string;
231
+ feature?: string;
232
+ instanceName?: string;
233
+ deprecated?: string;
234
+ cases: Array<{
235
+ key: string;
236
+ description?: string;
237
+ /** "active" | "deferred" | "deprecated". */
238
+ lifecycle: "active" | "deferred" | "deprecated";
239
+ severity: "critical" | "warning" | "info";
240
+ defaultRun?: "always" | "opt-in";
241
+ requires?: "headless" | "browser" | "out-of-band";
242
+ deferredReason?: string;
243
+ deprecatedReason?: string;
244
+ }>;
245
+ }
246
+ /**
247
+ * Protocol-agnostic default renderer. Reads raw fields off the
248
+ * projection; every protocol gets a valid Part even if its adapter
249
+ * doesn't declare `artifacts.markdown`.
250
+ */
251
+ export declare function genericMarkdownPart(projection: ExtractedContractProjection<unknown, unknown>): MarkdownPart;
252
+ /**
253
+ * Feature-grouped, doc-level markdown assembly. Byte-for-byte output
254
+ * compatible with `formatMdOutline` from `packages/cli/src/commands/
255
+ * contracts.ts` (the legacy CLI markdown path).
256
+ *
257
+ * Structure:
258
+ * # Contract Specification
259
+ * Generated: YYYY-MM-DD | N cases | N active | ...
260
+ *
261
+ * ## <feature>
262
+ * 🚫 **Deprecated:** ... (if contract-level deprecated)
263
+ * <description or endpoint intro>
264
+ * - **case** — ...
265
+ */
266
+ export declare function assembleMarkdownDocument(parts: MarkdownPart[]): string;
267
+ export declare const markdownArtifact: ArtifactKind<string, MarkdownPart, void>;
268
+ //# sourceMappingURL=contract-artifacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-artifacts.d.ts","sourceRoot":"","sources":["../src/contract-artifacts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,402 @@
1
+ /**
2
+ * @module contract-artifacts
3
+ *
4
+ * Contract artifact registry — declarative extension point for
5
+ * "contracts → X" rendering (markdown / openapi / future proto / sdl /
6
+ * asyncapi / ...).
7
+ *
8
+ * Replaces the v0.1 per-adapter `toMarkdown?` / `toOpenApi?` hooks which
9
+ * (a) polluted the generic `ContractProtocolAdapter` interface with
10
+ * protocol-specific artifacts (OpenAPI is HTTP-only), (b) had dead
11
+ * declarations that nothing called, and (c) gave consumers no way to
12
+ * enumerate "which artifact kinds does this project support".
13
+ *
14
+ * See `internal/40-discovery/proposals/contract-artifact-registry.md` (v6).
15
+ *
16
+ * ## Concepts
17
+ *
18
+ * **ArtifactKind**: first-class description of an output format (name +
19
+ * merge strategy + empty skeleton + optional defaultRender). Per-contract
20
+ * Part and final merged Final are independently typed (markdown renders
21
+ * structured parts that the merge assembles into a document; openapi
22
+ * renders per-contract partial documents that the merge stitches together).
23
+ *
24
+ * **ContractProtocolAdapter.artifacts**: each adapter declares which
25
+ * kinds it produces. Mapping from kind name to per-contract renderer.
26
+ *
27
+ * **Consumers**: `renderArtifact(kind, contracts, options?, control?)`
28
+ * dispatches across all registered adapters; fallback to kind.defaultRender
29
+ * where the adapter doesn't implement the kind; ultimate fallback to
30
+ * kind.empty when no contract contributes a part.
31
+ *
32
+ * ## Types
33
+ *
34
+ * `KnownArtifacts` / `KnownArtifactParts` / `KnownArtifactOptions` are
35
+ * declared at the package root (`packages/sdk/src/index.ts`) so third-
36
+ * party plugins can augment via `declare module "@glubean/sdk"`. This file
37
+ * imports them as types from the root so declaration merging hits the
38
+ * same node.
39
+ */
40
+ import { getAdapter, listRegisteredProtocols, } from "./contract-core.js";
41
+ import { emptyOpenApiDocument, mergeOpenApiParts, } from "./contract-http/openapi.js";
42
+ // =============================================================================
43
+ // Kind registry
44
+ // =============================================================================
45
+ const _kinds = new Map();
46
+ /**
47
+ * Register an artifact kind by name. Idempotent when re-registering the same
48
+ * kind object; throws when a different object tries to take the same name
49
+ * (protects against typo-level collisions across plugins).
50
+ *
51
+ * `defineArtifactKind` is the ergonomic entry; this is exported for advanced
52
+ * scenarios where a kind is built separately from its registration.
53
+ */
54
+ export function registerArtifactKind(kind) {
55
+ const existing = _kinds.get(kind.name);
56
+ if (existing) {
57
+ if (existing !== kind) {
58
+ throw new Error(`Artifact kind "${kind.name}" already registered with a different instance. ` +
59
+ `Ensure each kind is defined exactly once per process.`);
60
+ }
61
+ return;
62
+ }
63
+ _kinds.set(kind.name, kind);
64
+ }
65
+ /**
66
+ * Look up a registered kind by name. Used by `renderArtifactByName` and any
67
+ * other string-driven consumer (CLI --format, MCP tool inputs, etc.).
68
+ */
69
+ export function getArtifactKind(name) {
70
+ return _kinds.get(name);
71
+ }
72
+ /** List all registered kind names (insertion order). */
73
+ export function listArtifactKinds() {
74
+ return [..._kinds.keys()];
75
+ }
76
+ /**
77
+ * Define and register an artifact kind in one call. Preferred entry point
78
+ * for kind authors (SDK built-ins + first-party plugins).
79
+ */
80
+ export function defineArtifactKind(spec) {
81
+ registerArtifactKind(spec);
82
+ return spec;
83
+ }
84
+ /**
85
+ * Test-only: clear the kind registry. Not exposed publicly; imported by
86
+ * `contract-artifacts.test.ts` via relative path.
87
+ *
88
+ * @internal
89
+ */
90
+ export function __resetArtifactKindsForTesting() {
91
+ _kinds.clear();
92
+ }
93
+ /**
94
+ * Core render pipeline implementation — produces both a value and a
95
+ * detailed summary. `renderArtifact` is a thin wrapper returning just the
96
+ * value; `renderArtifactWithSummary` returns the full summary.
97
+ *
98
+ * Generic type `Final` / `Part` / `Options` instead of referring to the
99
+ * kind's generics directly so runtime-typed callers (renderArtifactByName)
100
+ * can pass `unknown`.
101
+ */
102
+ function runRender(kind, contracts, options, control) {
103
+ const parts = [];
104
+ const contributions = [];
105
+ const skipped = [];
106
+ for (const c of contracts) {
107
+ const adapter = getAdapter(c.protocol);
108
+ const explicitProducer = !control?.preferDefaultRender
109
+ ? adapter?.artifacts?.[kind.name]
110
+ : undefined;
111
+ if (explicitProducer) {
112
+ parts.push(explicitProducer(c, options));
113
+ contributions.push({
114
+ contractId: c.id,
115
+ protocol: c.protocol,
116
+ source: "explicit-producer",
117
+ });
118
+ continue;
119
+ }
120
+ if (kind.defaultRender) {
121
+ parts.push(kind.defaultRender(c, options));
122
+ contributions.push({
123
+ contractId: c.id,
124
+ protocol: c.protocol,
125
+ source: "default-render",
126
+ });
127
+ continue;
128
+ }
129
+ skipped.push({
130
+ contractId: c.id,
131
+ protocol: c.protocol,
132
+ reason: control?.preferDefaultRender
133
+ ? "prefer-default-render-no-default"
134
+ : "no-producer-no-default-render",
135
+ });
136
+ }
137
+ if (parts.length === 0) {
138
+ return {
139
+ value: kind.empty,
140
+ contributions,
141
+ skipped,
142
+ usedEmptyFallback: true,
143
+ };
144
+ }
145
+ return {
146
+ value: kind.merge(parts, options),
147
+ contributions,
148
+ skipped,
149
+ usedEmptyFallback: false,
150
+ };
151
+ }
152
+ /**
153
+ * Render an artifact of the given kind from a list of contracts. Threads
154
+ * `options` through the producer / defaultRender / merge pipeline. When no
155
+ * contract contributes a part, returns `kind.empty` (guaranteed valid
156
+ * `Final`).
157
+ *
158
+ * Strong-typed entry point: kind argument is a concrete `ArtifactKind<...>`
159
+ * object, so `options` type and return type are inferred at compile time.
160
+ */
161
+ export function renderArtifact(kind, contracts, options, control) {
162
+ return runRender(kind, contracts, options, control).value;
163
+ }
164
+ /**
165
+ * Render an artifact and return the full summary (value + contributions +
166
+ * skipped + usedEmptyFallback). Use this when you need to distinguish
167
+ * "zero contribution" from "merged to kind.empty-shaped value" — the
168
+ * `usedEmptyFallback` field is the authoritative signal (do not compare
169
+ * `value === kind.empty` yourself for object-typed Final).
170
+ */
171
+ export function renderArtifactWithSummary(kind, contracts, options, control) {
172
+ return runRender(kind, contracts, options, control);
173
+ }
174
+ /**
175
+ * Look up a kind by name and render. Used by string-driven consumers
176
+ * (CLI --format <name>, MCP tools, agent introspection). Throws when the
177
+ * name is not registered — the error message includes the list of
178
+ * registered kinds so callers can surface it without extra lookups.
179
+ *
180
+ * Returns `unknown` since we don't know the Final type statically;
181
+ * callers that need a typed return should use `renderArtifact` directly
182
+ * with the kind object they import.
183
+ */
184
+ export function renderArtifactByName(kindName, contracts, options, control) {
185
+ const kind = getArtifactKind(kindName);
186
+ if (!kind) {
187
+ const known = listArtifactKinds();
188
+ const hint = known.length > 0 ? known.join(", ") : "(none)";
189
+ throw new Error(`Unknown artifact kind "${kindName}". Registered kinds: ${hint}`);
190
+ }
191
+ return renderArtifact(kind, contracts, options, control);
192
+ }
193
+ // =============================================================================
194
+ // Introspection
195
+ // =============================================================================
196
+ /**
197
+ * List the protocols whose adapter **explicitly declares a producer** for
198
+ * the given kind. Does NOT include protocols that would fall back to
199
+ * `kind.defaultRender`. Use `listArtifactCapability` for the three-way split.
200
+ */
201
+ export function listArtifactProducers(kindName) {
202
+ return listRegisteredProtocols().filter((p) => {
203
+ const adapter = getAdapter(p);
204
+ return (adapter !== undefined &&
205
+ adapter.artifacts?.[kindName] !==
206
+ undefined);
207
+ });
208
+ }
209
+ /**
210
+ * Static capability view — **based on installed adapters**, not on any
211
+ * particular project's contracts. Partitions protocols into:
212
+ *
213
+ * - `explicit` : adapter declares a producer for this kind
214
+ * - `fallback` : adapter has no producer but kind.defaultRender exists
215
+ * - `unsupported` : adapter has no producer and kind has no defaultRender
216
+ *
217
+ * To answer "does **this project** produce the artifact?", use
218
+ * `renderArtifactWithSummary` and inspect `contributions` + `usedEmptyFallback`.
219
+ * The capability view cannot know how many contracts of each protocol exist
220
+ * in the caller's project.
221
+ */
222
+ export function listArtifactCapability(kindName) {
223
+ const kind = getArtifactKind(kindName);
224
+ const allProtocols = listRegisteredProtocols();
225
+ const explicit = listArtifactProducers(kindName);
226
+ const explicitSet = new Set(explicit);
227
+ const rest = allProtocols.filter((p) => !explicitSet.has(p));
228
+ if (kind?.defaultRender) {
229
+ return { explicit, fallback: rest, unsupported: [] };
230
+ }
231
+ return { explicit, fallback: [], unsupported: rest };
232
+ }
233
+ // =============================================================================
234
+ // Built-in kinds
235
+ // =============================================================================
236
+ /**
237
+ * OpenAPI 3.1 artifact kind. Per-contract partials are produced by HTTP
238
+ * adapter's `artifacts.openapi` (see `contract-http/openapi.ts`); merge
239
+ * combines them into a full spec. No `defaultRender` — non-HTTP protocols
240
+ * don't map to OpenAPI and are skipped.
241
+ *
242
+ * Ported from MCP's former `contractsToOpenApi` — CAR-1 Phase 2.
243
+ */
244
+ export const openapiArtifact = defineArtifactKind({
245
+ name: "openapi",
246
+ merge: (parts, options) => mergeOpenApiParts(parts, options),
247
+ empty: emptyOpenApiDocument,
248
+ });
249
+ /**
250
+ * Protocol-agnostic default renderer. Reads raw fields off the
251
+ * projection; every protocol gets a valid Part even if its adapter
252
+ * doesn't declare `artifacts.markdown`.
253
+ */
254
+ export function genericMarkdownPart(projection) {
255
+ return {
256
+ contractId: projection.id,
257
+ endpoint: projection.target,
258
+ protocol: projection.protocol,
259
+ description: projection.description,
260
+ feature: projection.feature,
261
+ instanceName: projection.instanceName,
262
+ deprecated: projection.deprecated,
263
+ cases: projection.cases.map((c) => ({
264
+ key: c.key,
265
+ description: c.description,
266
+ lifecycle: c.lifecycle ??
267
+ (c.deprecatedReason
268
+ ? "deprecated"
269
+ : c.deferredReason
270
+ ? "deferred"
271
+ : "active"),
272
+ severity: c.severity ?? "warning",
273
+ defaultRun: c.defaultRun,
274
+ requires: c.requires,
275
+ deferredReason: c.deferredReason,
276
+ deprecatedReason: c.deprecatedReason,
277
+ })),
278
+ };
279
+ }
280
+ function computeMarkdownSummary(parts) {
281
+ let total = 0;
282
+ let deferred = 0;
283
+ let deprecated = 0;
284
+ let gated = 0;
285
+ for (const p of parts) {
286
+ for (const c of p.cases) {
287
+ total++;
288
+ if (c.lifecycle === "deprecated")
289
+ deprecated++;
290
+ else if (c.lifecycle === "deferred")
291
+ deferred++;
292
+ else if (c.requires === "browser" || c.requires === "out-of-band")
293
+ gated++;
294
+ }
295
+ }
296
+ return {
297
+ total,
298
+ active: total - deferred - deprecated - gated,
299
+ deferred,
300
+ deprecated,
301
+ gated,
302
+ };
303
+ }
304
+ function formatMarkdownCase(c) {
305
+ const desc = c.description ? ` — ${c.description}` : "";
306
+ if (c.lifecycle === "deprecated") {
307
+ const reason = c.deprecatedReason ?? "deprecated";
308
+ return `- ⊘ **${c.key}** — deprecated: ${reason}`;
309
+ }
310
+ if (c.lifecycle === "deferred") {
311
+ const reason = c.deferredReason ?? "deferred";
312
+ return `- ⊘ **${c.key}** — deferred: ${reason}`;
313
+ }
314
+ if (c.requires === "browser" || c.requires === "out-of-band") {
315
+ return `- ⊘ **${c.key}** — requires: ${c.requires}`;
316
+ }
317
+ const severityTag = c.severity === "critical" ? " 🔴" : c.severity === "info" ? " ℹ️" : "";
318
+ const suffix = c.defaultRun === "opt-in" ? " *(opt-in)*" : "";
319
+ return `- **${c.key}**${desc}${suffix}${severityTag}`;
320
+ }
321
+ /**
322
+ * Compute the effective feature key for a part — applies the
323
+ * instanceName-aware transform when the project has any instanced
324
+ * contract (matches CLI `hasInstances` pre-pass behavior).
325
+ */
326
+ function displayFeature(part, hasInstances) {
327
+ if (hasInstances && part.instanceName) {
328
+ return `${part.instanceName}: ${part.feature ?? part.endpoint}`;
329
+ }
330
+ return part.feature ?? part.endpoint;
331
+ }
332
+ /**
333
+ * Feature-grouped, doc-level markdown assembly. Byte-for-byte output
334
+ * compatible with `formatMdOutline` from `packages/cli/src/commands/
335
+ * contracts.ts` (the legacy CLI markdown path).
336
+ *
337
+ * Structure:
338
+ * # Contract Specification
339
+ * Generated: YYYY-MM-DD | N cases | N active | ...
340
+ *
341
+ * ## <feature>
342
+ * 🚫 **Deprecated:** ... (if contract-level deprecated)
343
+ * <description or endpoint intro>
344
+ * - **case** — ...
345
+ */
346
+ export function assembleMarkdownDocument(parts) {
347
+ if (parts.length === 0)
348
+ return "";
349
+ const hasInstances = parts.some((p) => !!p.instanceName);
350
+ // Group preserving insertion order
351
+ const groups = new Map();
352
+ for (const part of parts) {
353
+ const key = displayFeature(part, hasInstances);
354
+ const list = groups.get(key) ?? [];
355
+ list.push(part);
356
+ groups.set(key, list);
357
+ }
358
+ const summary = computeMarkdownSummary(parts);
359
+ const lines = [];
360
+ lines.push("# Contract Specification");
361
+ lines.push("");
362
+ const date = new Date().toISOString().slice(0, 10);
363
+ const summaryParts = [`Generated: ${date}`, `${summary.total} cases`];
364
+ if (summary.active > 0)
365
+ summaryParts.push(`${summary.active} active`);
366
+ if (summary.deferred > 0)
367
+ summaryParts.push(`${summary.deferred} deferred`);
368
+ if (summary.deprecated > 0)
369
+ summaryParts.push(`${summary.deprecated} deprecated`);
370
+ if (summary.gated > 0)
371
+ summaryParts.push(`${summary.gated} gated`);
372
+ lines.push(summaryParts.join(" | "));
373
+ lines.push("");
374
+ for (const [featureName, featureParts] of groups.entries()) {
375
+ lines.push(`## ${featureName}`);
376
+ lines.push("");
377
+ for (const contract of featureParts) {
378
+ const intro = contract.description ??
379
+ (featureName !== contract.endpoint ? contract.endpoint : undefined);
380
+ if (contract.deprecated) {
381
+ lines.push(`🚫 **Deprecated:** ${contract.deprecated}`);
382
+ lines.push("");
383
+ }
384
+ if (intro) {
385
+ lines.push(intro);
386
+ lines.push("");
387
+ }
388
+ for (const c of contract.cases) {
389
+ lines.push(formatMarkdownCase(c));
390
+ }
391
+ lines.push("");
392
+ }
393
+ }
394
+ return lines.join("\n").trimEnd() + "\n";
395
+ }
396
+ export const markdownArtifact = defineArtifactKind({
397
+ name: "markdown",
398
+ defaultRender: (projection) => genericMarkdownPart(projection),
399
+ merge: (parts) => assembleMarkdownDocument(parts),
400
+ empty: "",
401
+ });
402
+ //# sourceMappingURL=contract-artifacts.js.map