@contractspec/bundle.workspace 3.2.0 → 3.4.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.
@@ -5,6 +5,7 @@
5
5
  * for parsing in CI/CD scripts and integrations.
6
6
  */
7
7
  import type { CICheckResult } from '../services/ci-check/types';
8
+ import type { DriftResult } from '../services/drift';
8
9
  /**
9
10
  * Base interface for all standardized JSON outputs.
10
11
  */
@@ -18,6 +19,8 @@ export interface BaseJsonOutput {
18
19
  export interface JsonFormatOptions {
19
20
  /** Pretty print with indentation. */
20
21
  pretty?: boolean;
22
+ /** Drift detection result to include in the output. */
23
+ driftResult?: DriftResult;
21
24
  }
22
25
  /**
23
26
  * CI JSON output structure (v1.0).
package/dist/index.js CHANGED
@@ -1,16 +1,230 @@
1
1
  // @bun
2
2
  var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
3
7
  var __export = (target, all) => {
4
8
  for (var name in all)
5
9
  __defProp(target, name, {
6
10
  get: all[name],
7
11
  enumerable: true,
8
12
  configurable: true,
9
- set: (newValue) => all[name] = () => newValue
13
+ set: __exportSetter.bind(all, name)
10
14
  });
11
15
  };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
17
  var __require = import.meta.require;
13
18
 
19
+ // src/services/config.ts
20
+ import {
21
+ ContractsrcSchema,
22
+ DEFAULT_CONTRACTSRC as DEFAULT_CONTRACTSRC2
23
+ } from "@contractspec/lib.contracts-spec/workspace-config";
24
+ async function loadWorkspaceConfig(fs5, cwd) {
25
+ const configPath = fs5.join(cwd ?? ".", ".contractsrc.json");
26
+ const exists = await fs5.exists(configPath);
27
+ if (!exists) {
28
+ return DEFAULT_CONTRACTSRC2;
29
+ }
30
+ try {
31
+ const content = await fs5.readFile(configPath);
32
+ const parsed = JSON.parse(content);
33
+ const resolved = ContractsrcSchema.safeParse(parsed);
34
+ return {
35
+ ...DEFAULT_CONTRACTSRC2,
36
+ ...resolved.data,
37
+ conventions: {
38
+ ...DEFAULT_CONTRACTSRC2.conventions,
39
+ ...resolved.data?.conventions || {}
40
+ }
41
+ };
42
+ } catch {
43
+ return DEFAULT_CONTRACTSRC2;
44
+ }
45
+ }
46
+ function getApiKey(provider) {
47
+ switch (provider) {
48
+ case "claude":
49
+ return process.env["ANTHROPIC_API_KEY"];
50
+ case "openai":
51
+ return process.env["OPENAI_API_KEY"];
52
+ case "custom":
53
+ return process.env["CONTRACTSPEC_LLM_API_KEY"];
54
+ case "ollama":
55
+ return;
56
+ default:
57
+ return;
58
+ }
59
+ }
60
+ var init_config = () => {};
61
+
62
+ // src/services/create/ai-generator.ts
63
+ var exports_ai_generator = {};
64
+ __export(exports_ai_generator, {
65
+ AIGenerator: () => AIGenerator
66
+ });
67
+ import { generateObject as generateObject2, generateText as generateText6, streamText as streamText2 } from "ai";
68
+ import * as z2 from "zod";
69
+ import {
70
+ createProvider
71
+ } from "@contractspec/lib.ai-providers";
72
+ import {
73
+ buildComponentPrompt as buildComponentPrompt2,
74
+ buildEventSpecPrompt,
75
+ buildFormPrompt as buildFormPrompt2,
76
+ buildHandlerPrompt as buildHandlerPrompt2,
77
+ buildOperationSpecPrompt,
78
+ buildPresentationSpecPrompt,
79
+ buildTestPrompt as buildTestPrompt2,
80
+ getCodeGenSystemPrompt as getCodeGenSystemPrompt2,
81
+ getSystemPrompt
82
+ } from "@contractspec/module.workspace";
83
+
84
+ class AIGenerator {
85
+ config;
86
+ constructor(config) {
87
+ this.config = config;
88
+ }
89
+ getModel() {
90
+ const providerName = this.config.aiProvider;
91
+ const apiKey = this.config.customApiKey || getApiKey(this.config.aiProvider);
92
+ const providerConfig = {
93
+ provider: providerName === "custom" ? "openai" : providerName,
94
+ model: this.config.aiModel,
95
+ apiKey,
96
+ baseUrl: this.config.customEndpoint || undefined
97
+ };
98
+ const provider = createProvider(providerConfig);
99
+ return provider.getModel();
100
+ }
101
+ async generateOperationSpec(description, kind) {
102
+ const model = this.getModel();
103
+ const schema = z2.object({
104
+ name: z2.string().describe('Dot notation name like "domain.operation"'),
105
+ version: z2.number().int().positive().default(1),
106
+ description: z2.string().describe("Clear, concise summary"),
107
+ goal: z2.string().describe("Business purpose"),
108
+ context: z2.string().describe("Background and constraints"),
109
+ stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
110
+ owners: z2.array(z2.string()).describe("Team/person owners with @ prefix"),
111
+ tags: z2.array(z2.string()).describe("Categorization tags"),
112
+ auth: z2.enum(["anonymous", "user", "admin"]).describe("Required auth level"),
113
+ inputShape: z2.string().describe("Description of input structure"),
114
+ outputShape: z2.string().describe("Description of output structure"),
115
+ flags: z2.array(z2.string()).describe("Feature flags").default([]),
116
+ possibleEvents: z2.array(z2.string()).describe("Events this may emit").default([]),
117
+ analytics: z2.array(z2.string()).describe("Analytics events to track").default([])
118
+ });
119
+ const prompt = buildOperationSpecPrompt(description, kind);
120
+ const result = await generateObject2({
121
+ model,
122
+ schema,
123
+ prompt,
124
+ system: getSystemPrompt()
125
+ });
126
+ return result.object;
127
+ }
128
+ async generateEventSpec(description) {
129
+ const model = this.getModel();
130
+ const schema = z2.object({
131
+ name: z2.string().describe('Dot notation name like "domain.event_name"'),
132
+ version: z2.number().int().positive().default(1),
133
+ description: z2.string().describe("When this event is emitted"),
134
+ stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
135
+ owners: z2.array(z2.string()).default([]),
136
+ tags: z2.array(z2.string()).default([]),
137
+ payloadShape: z2.string().describe("Description of event payload"),
138
+ piiFields: z2.array(z2.string()).describe("PII field paths").default([])
139
+ });
140
+ const prompt = buildEventSpecPrompt(description);
141
+ const result = await generateObject2({
142
+ model,
143
+ schema,
144
+ prompt,
145
+ system: getSystemPrompt()
146
+ });
147
+ return result.object;
148
+ }
149
+ async generatePresentationSpec(description, kind) {
150
+ const model = this.getModel();
151
+ const schema = z2.object({
152
+ name: z2.string(),
153
+ version: z2.number().int().positive().default(1),
154
+ description: z2.string(),
155
+ stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
156
+ owners: z2.array(z2.string()).default([]),
157
+ tags: z2.array(z2.string()).default([]),
158
+ componentKey: z2.string().optional(),
159
+ propsShape: z2.string().optional(),
160
+ content: z2.string().optional(),
161
+ mimeType: z2.string().optional(),
162
+ dataShape: z2.string().optional()
163
+ });
164
+ const prompt = buildPresentationSpecPrompt(description, kind);
165
+ const result = await generateObject2({
166
+ model,
167
+ schema,
168
+ prompt,
169
+ system: getSystemPrompt()
170
+ });
171
+ return result.object;
172
+ }
173
+ async generateHandler(specCode) {
174
+ const model = this.getModel();
175
+ const result = await generateText6({
176
+ model,
177
+ prompt: buildHandlerPrompt2(specCode),
178
+ system: getCodeGenSystemPrompt2()
179
+ });
180
+ return result.text;
181
+ }
182
+ async generateComponent(specCode) {
183
+ const model = this.getModel();
184
+ const result = await generateText6({
185
+ model,
186
+ prompt: buildComponentPrompt2(specCode),
187
+ system: getCodeGenSystemPrompt2()
188
+ });
189
+ return result.text;
190
+ }
191
+ async generateForm(specCode) {
192
+ const model = this.getModel();
193
+ const result = await generateText6({
194
+ model,
195
+ prompt: buildFormPrompt2(specCode),
196
+ system: getCodeGenSystemPrompt2()
197
+ });
198
+ return result.text;
199
+ }
200
+ async generateTests(specCode, implementationCode, testType) {
201
+ const model = this.getModel();
202
+ const result = await generateText6({
203
+ model,
204
+ prompt: buildTestPrompt2(specCode, implementationCode, testType),
205
+ system: getCodeGenSystemPrompt2()
206
+ });
207
+ return result.text;
208
+ }
209
+ async streamCodeGeneration(prompt, onChunk) {
210
+ const model = this.getModel();
211
+ const result = await streamText2({
212
+ model,
213
+ prompt,
214
+ system: getCodeGenSystemPrompt2()
215
+ });
216
+ let fullText = "";
217
+ for await (const chunk of result.textStream) {
218
+ fullText += chunk;
219
+ onChunk(chunk);
220
+ }
221
+ return fullText;
222
+ }
223
+ }
224
+ var init_ai_generator = __esm(() => {
225
+ init_config();
226
+ });
227
+
14
228
  // src/index.ts
15
229
  import * as module from "@contractspec/module.workspace";
16
230
  // src/adapters/fs.node.ts
@@ -2900,47 +3114,10 @@ function getGraphStats(graph) {
2900
3114
  unused: unused.length
2901
3115
  };
2902
3116
  }
2903
- // src/services/config.ts
2904
- import {
2905
- ContractsrcSchema,
2906
- DEFAULT_CONTRACTSRC as DEFAULT_CONTRACTSRC2
2907
- } from "@contractspec/lib.contracts-spec/workspace-config";
2908
- async function loadWorkspaceConfig(fs5, cwd) {
2909
- const configPath = fs5.join(cwd ?? ".", ".contractsrc.json");
2910
- const exists = await fs5.exists(configPath);
2911
- if (!exists) {
2912
- return DEFAULT_CONTRACTSRC2;
2913
- }
2914
- try {
2915
- const content = await fs5.readFile(configPath);
2916
- const parsed = JSON.parse(content);
2917
- const resolved = ContractsrcSchema.safeParse(parsed);
2918
- return {
2919
- ...DEFAULT_CONTRACTSRC2,
2920
- ...resolved.data,
2921
- conventions: {
2922
- ...DEFAULT_CONTRACTSRC2.conventions,
2923
- ...resolved.data?.conventions || {}
2924
- }
2925
- };
2926
- } catch {
2927
- return DEFAULT_CONTRACTSRC2;
2928
- }
2929
- }
2930
- function getApiKey(provider) {
2931
- switch (provider) {
2932
- case "claude":
2933
- return process.env["ANTHROPIC_API_KEY"];
2934
- case "openai":
2935
- return process.env["OPENAI_API_KEY"];
2936
- case "custom":
2937
- return process.env["CONTRACTSPEC_LLM_API_KEY"];
2938
- case "ollama":
2939
- return;
2940
- default:
2941
- return;
2942
- }
2943
- }
3117
+
3118
+ // src/services/index.ts
3119
+ init_config();
3120
+
2944
3121
  // src/services/build.ts
2945
3122
  import {
2946
3123
  generateComponentTemplate,
@@ -7473,6 +7650,7 @@ async function runDoctorChecks(adapters, options) {
7473
7650
  return issues;
7474
7651
  }
7475
7652
  // src/services/ci-check/checks/handlers.ts
7653
+ init_config();
7476
7654
  async function runHandlerChecks(adapters, specFiles) {
7477
7655
  const { fs: fs5 } = adapters;
7478
7656
  const issues = [];
@@ -7506,6 +7684,7 @@ async function runHandlerChecks(adapters, specFiles) {
7506
7684
  return issues;
7507
7685
  }
7508
7686
  // src/services/ci-check/checks/tests.ts
7687
+ init_config();
7509
7688
  async function runTestChecks(adapters, specFiles) {
7510
7689
  const { fs: fs5 } = adapters;
7511
7690
  const issues = [];
@@ -7834,6 +8013,9 @@ async function runCoverageChecks(adapters, specFiles, options) {
7834
8013
  }
7835
8014
  return issues;
7836
8015
  }
8016
+ // src/services/ci-check/checks/implementation.ts
8017
+ init_config();
8018
+
7837
8019
  // src/services/implementation/resolver/index.ts
7838
8020
  import { createHash } from "crypto";
7839
8021
 
@@ -8392,6 +8574,9 @@ async function runLayerChecks2(adapters, _options) {
8392
8574
  }
8393
8575
  return issues;
8394
8576
  }
8577
+ // src/services/ci-check/checks/drift.ts
8578
+ init_config();
8579
+
8395
8580
  // src/services/drift.ts
8396
8581
  import path4 from "path";
8397
8582
  import { mkdtemp, rm as rm3 } from "fs/promises";
@@ -9709,163 +9894,8 @@ function exportSpecForLLM(spec, format, agent = "generic-mcp") {
9709
9894
  return specToMarkdown(spec, "full");
9710
9895
  }
9711
9896
  }
9712
- // src/services/create/ai-generator.ts
9713
- import { generateObject as generateObject2, generateText as generateText6, streamText as streamText2 } from "ai";
9714
- import * as z2 from "zod";
9715
- import {
9716
- createProvider
9717
- } from "@contractspec/lib.ai-providers";
9718
- import {
9719
- buildComponentPrompt as buildComponentPrompt2,
9720
- buildEventSpecPrompt,
9721
- buildFormPrompt as buildFormPrompt2,
9722
- buildHandlerPrompt as buildHandlerPrompt2,
9723
- buildOperationSpecPrompt,
9724
- buildPresentationSpecPrompt,
9725
- buildTestPrompt as buildTestPrompt2,
9726
- getCodeGenSystemPrompt as getCodeGenSystemPrompt2,
9727
- getSystemPrompt
9728
- } from "@contractspec/module.workspace";
9729
- class AIGenerator {
9730
- config;
9731
- constructor(config) {
9732
- this.config = config;
9733
- }
9734
- getModel() {
9735
- const providerName = this.config.aiProvider;
9736
- const apiKey = this.config.customApiKey || getApiKey(this.config.aiProvider);
9737
- const providerConfig = {
9738
- provider: providerName === "custom" ? "openai" : providerName,
9739
- model: this.config.aiModel,
9740
- apiKey,
9741
- baseUrl: this.config.customEndpoint || undefined
9742
- };
9743
- const provider = createProvider(providerConfig);
9744
- return provider.getModel();
9745
- }
9746
- async generateOperationSpec(description, kind) {
9747
- const model = this.getModel();
9748
- const schema = z2.object({
9749
- name: z2.string().describe('Dot notation name like "domain.operation"'),
9750
- version: z2.number().int().positive().default(1),
9751
- description: z2.string().describe("Clear, concise summary"),
9752
- goal: z2.string().describe("Business purpose"),
9753
- context: z2.string().describe("Background and constraints"),
9754
- stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
9755
- owners: z2.array(z2.string()).describe("Team/person owners with @ prefix"),
9756
- tags: z2.array(z2.string()).describe("Categorization tags"),
9757
- auth: z2.enum(["anonymous", "user", "admin"]).describe("Required auth level"),
9758
- inputShape: z2.string().describe("Description of input structure"),
9759
- outputShape: z2.string().describe("Description of output structure"),
9760
- flags: z2.array(z2.string()).describe("Feature flags").default([]),
9761
- possibleEvents: z2.array(z2.string()).describe("Events this may emit").default([]),
9762
- analytics: z2.array(z2.string()).describe("Analytics events to track").default([])
9763
- });
9764
- const prompt = buildOperationSpecPrompt(description, kind);
9765
- const result = await generateObject2({
9766
- model,
9767
- schema,
9768
- prompt,
9769
- system: getSystemPrompt()
9770
- });
9771
- return result.object;
9772
- }
9773
- async generateEventSpec(description) {
9774
- const model = this.getModel();
9775
- const schema = z2.object({
9776
- name: z2.string().describe('Dot notation name like "domain.event_name"'),
9777
- version: z2.number().int().positive().default(1),
9778
- description: z2.string().describe("When this event is emitted"),
9779
- stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
9780
- owners: z2.array(z2.string()).default([]),
9781
- tags: z2.array(z2.string()).default([]),
9782
- payloadShape: z2.string().describe("Description of event payload"),
9783
- piiFields: z2.array(z2.string()).describe("PII field paths").default([])
9784
- });
9785
- const prompt = buildEventSpecPrompt(description);
9786
- const result = await generateObject2({
9787
- model,
9788
- schema,
9789
- prompt,
9790
- system: getSystemPrompt()
9791
- });
9792
- return result.object;
9793
- }
9794
- async generatePresentationSpec(description, kind) {
9795
- const model = this.getModel();
9796
- const schema = z2.object({
9797
- name: z2.string(),
9798
- version: z2.number().int().positive().default(1),
9799
- description: z2.string(),
9800
- stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
9801
- owners: z2.array(z2.string()).default([]),
9802
- tags: z2.array(z2.string()).default([]),
9803
- componentKey: z2.string().optional(),
9804
- propsShape: z2.string().optional(),
9805
- content: z2.string().optional(),
9806
- mimeType: z2.string().optional(),
9807
- dataShape: z2.string().optional()
9808
- });
9809
- const prompt = buildPresentationSpecPrompt(description, kind);
9810
- const result = await generateObject2({
9811
- model,
9812
- schema,
9813
- prompt,
9814
- system: getSystemPrompt()
9815
- });
9816
- return result.object;
9817
- }
9818
- async generateHandler(specCode) {
9819
- const model = this.getModel();
9820
- const result = await generateText6({
9821
- model,
9822
- prompt: buildHandlerPrompt2(specCode),
9823
- system: getCodeGenSystemPrompt2()
9824
- });
9825
- return result.text;
9826
- }
9827
- async generateComponent(specCode) {
9828
- const model = this.getModel();
9829
- const result = await generateText6({
9830
- model,
9831
- prompt: buildComponentPrompt2(specCode),
9832
- system: getCodeGenSystemPrompt2()
9833
- });
9834
- return result.text;
9835
- }
9836
- async generateForm(specCode) {
9837
- const model = this.getModel();
9838
- const result = await generateText6({
9839
- model,
9840
- prompt: buildFormPrompt2(specCode),
9841
- system: getCodeGenSystemPrompt2()
9842
- });
9843
- return result.text;
9844
- }
9845
- async generateTests(specCode, implementationCode, testType) {
9846
- const model = this.getModel();
9847
- const result = await generateText6({
9848
- model,
9849
- prompt: buildTestPrompt2(specCode, implementationCode, testType),
9850
- system: getCodeGenSystemPrompt2()
9851
- });
9852
- return result.text;
9853
- }
9854
- async streamCodeGeneration(prompt, onChunk) {
9855
- const model = this.getModel();
9856
- const result = await streamText2({
9857
- model,
9858
- prompt,
9859
- system: getCodeGenSystemPrompt2()
9860
- });
9861
- let fullText = "";
9862
- for await (const chunk of result.textStream) {
9863
- fullText += chunk;
9864
- onChunk(chunk);
9865
- }
9866
- return fullText;
9867
- }
9868
- }
9897
+ // src/services/create/index.ts
9898
+ init_ai_generator();
9869
9899
 
9870
9900
  // src/services/create/templates.ts
9871
9901
  var exports_templates2 = {};
@@ -11171,6 +11201,8 @@ ${formatRefs(params.experiments) || " // Add experiments here"}
11171
11201
  `;
11172
11202
  }
11173
11203
  // src/services/create/index.ts
11204
+ init_ai_generator();
11205
+
11174
11206
  class SpecCreatorService {
11175
11207
  ai;
11176
11208
  templates = exports_templates2;
@@ -13109,6 +13141,7 @@ import {
13109
13141
  } from "@contractspec/lib.contracts-spec";
13110
13142
 
13111
13143
  // src/services/versioning/changelog-formatter.ts
13144
+ import { dirname as dirname10, basename as basename5 } from "path";
13112
13145
  function formatKeepAChangelog(entries) {
13113
13146
  const lines = [
13114
13147
  "# Changelog",
@@ -13231,9 +13264,55 @@ function formatChangelogJson(analysis, baseline) {
13231
13264
  }
13232
13265
  ]
13233
13266
  })),
13234
- libraries: []
13267
+ libraries: groupSpecsByLibrary(specsNeedingBump, isoDate)
13235
13268
  };
13236
13269
  }
13270
+ function extractLibraryPath(specPath) {
13271
+ const parts = specPath.split("/");
13272
+ const packagesIdx = parts.lastIndexOf("packages");
13273
+ if (packagesIdx >= 0 && packagesIdx + 2 < parts.length) {
13274
+ return parts.slice(0, packagesIdx + 3).join("/");
13275
+ }
13276
+ return dirname10(specPath);
13277
+ }
13278
+ var BUMP_RANK = { major: 3, minor: 2, patch: 1 };
13279
+ function groupSpecsByLibrary(specs, isoDate) {
13280
+ const groups = new Map;
13281
+ for (const spec of specs) {
13282
+ const libPath = extractLibraryPath(spec.specPath);
13283
+ const existing = groups.get(libPath);
13284
+ if (existing) {
13285
+ existing.push(spec);
13286
+ } else {
13287
+ groups.set(libPath, [spec]);
13288
+ }
13289
+ }
13290
+ return Array.from(groups.entries()).flatMap(([libPath, libSpecs]) => {
13291
+ const first = libSpecs[0];
13292
+ if (!first)
13293
+ return [];
13294
+ const highestBump = libSpecs.reduce((max, s) => {
13295
+ const rank = BUMP_RANK[s.bumpType] ?? 0;
13296
+ return rank > (BUMP_RANK[max.bumpType] ?? 0) ? s : max;
13297
+ }, first);
13298
+ return [
13299
+ {
13300
+ name: basename5(libPath),
13301
+ path: libPath,
13302
+ version: highestBump.suggestedVersion,
13303
+ entries: [
13304
+ {
13305
+ version: highestBump.suggestedVersion,
13306
+ date: isoDate,
13307
+ bumpType: highestBump.bumpType,
13308
+ changes: libSpecs.flatMap((s) => s.changes),
13309
+ breakingChanges: libSpecs.flatMap((s) => s.changes).filter((c) => c.type === "breaking")
13310
+ }
13311
+ ]
13312
+ }
13313
+ ];
13314
+ });
13315
+ }
13237
13316
  function compareVersionsDescending(a, b) {
13238
13317
  const parseVer = (v) => {
13239
13318
  const parts = v.split(".").map((p) => parseInt(p, 10) || 0);
@@ -14838,11 +14917,50 @@ async function implementAiStrategy(issue, options, adapters2) {
14838
14917
  };
14839
14918
  }
14840
14919
  }
14841
- async function enrichWithAI(ctx, _options, logger3) {
14920
+ async function enrichWithAI(ctx, options, logger3) {
14842
14921
  logger3.info("Generating AI content for spec", {
14843
14922
  key: ctx.key,
14844
14923
  type: ctx.specType
14845
14924
  });
14925
+ if (options.aiConfig) {
14926
+ try {
14927
+ const { AIGenerator: AIGenerator2 } = await Promise.resolve().then(() => (init_ai_generator(), exports_ai_generator));
14928
+ const config = buildResolvedConfig(options);
14929
+ const generator = new AIGenerator2(config);
14930
+ const kind = ctx.specType === "operation" ? "command" : ctx.specType;
14931
+ const description = `${capitalize2(ctx.specType)} for ${ctx.key}`;
14932
+ if (ctx.specType === "operation") {
14933
+ const result = await generator.generateOperationSpec(description, kind);
14934
+ return {
14935
+ ...ctx,
14936
+ description: result.description,
14937
+ enrichment: {
14938
+ goal: result.goal,
14939
+ context: result.context,
14940
+ owners: result.owners,
14941
+ tags: result.tags
14942
+ }
14943
+ };
14944
+ }
14945
+ if (ctx.specType === "event") {
14946
+ const result = await generator.generateEventSpec(description);
14947
+ return {
14948
+ ...ctx,
14949
+ description: result.description,
14950
+ enrichment: {
14951
+ goal: `Emit ${ctx.key} event`,
14952
+ context: result.description,
14953
+ owners: ["@team"],
14954
+ tags: result.tags
14955
+ }
14956
+ };
14957
+ }
14958
+ } catch (aiError) {
14959
+ logger3.warn("AIGenerator call failed, falling back to heuristics", {
14960
+ error: aiError instanceof Error ? aiError.message : String(aiError)
14961
+ });
14962
+ }
14963
+ }
14846
14964
  const enrichment = inferEnrichmentFromKey(ctx.key, ctx.specType);
14847
14965
  return {
14848
14966
  ...ctx,
@@ -14855,6 +14973,21 @@ async function enrichWithAI(ctx, _options, logger3) {
14855
14973
  }
14856
14974
  };
14857
14975
  }
14976
+ function buildResolvedConfig(options) {
14977
+ const ai3 = options.aiConfig;
14978
+ const providerMap = {
14979
+ claude: "anthropic",
14980
+ openai: "openai",
14981
+ ollama: "ollama",
14982
+ custom: "custom"
14983
+ };
14984
+ return {
14985
+ aiProvider: providerMap[ai3?.provider ?? "openai"] ?? "openai",
14986
+ aiModel: ai3?.model ?? "gpt-4-turbo",
14987
+ customApiKey: ai3?.apiKey ?? "",
14988
+ customEndpoint: ai3?.endpoint ?? ""
14989
+ };
14990
+ }
14858
14991
  function inferEnrichmentFromKey(key, specType) {
14859
14992
  const parts = key.split(".");
14860
14993
  const domain = parts[0] || "unknown";
@@ -15376,6 +15509,7 @@ async function analyzeGap(adapters2, cwd) {
15376
15509
  };
15377
15510
  }
15378
15511
  // src/services/extract.ts
15512
+ init_config();
15379
15513
  async function extractContracts(adapters2, options, cwd) {
15380
15514
  const { fs: fs5, logger: logger3 } = adapters2;
15381
15515
  const { source, outputDir } = options;
@@ -15766,7 +15900,7 @@ async function getWorkflow(id, cwd) {
15766
15900
  // src/services/vibe/context.ts
15767
15901
  import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile3, copyFile } from "fs/promises";
15768
15902
  import { existsSync as existsSync6 } from "fs";
15769
- import { join as join11, dirname as dirname10 } from "path";
15903
+ import { join as join11, dirname as dirname11 } from "path";
15770
15904
  import { glob } from "glob";
15771
15905
  var DEFAULT_IGNORES2 = [
15772
15906
  "**/node_modules/**",
@@ -15817,7 +15951,7 @@ async function exportContext(cwd) {
15817
15951
  for (const file of uniqueFiles) {
15818
15952
  const absSource = join11(root, file);
15819
15953
  const absDest = join11(contextFilesDir, file);
15820
- await mkdir4(dirname10(absDest), { recursive: true });
15954
+ await mkdir4(dirname11(absDest), { recursive: true });
15821
15955
  await copyFile(absSource, absDest);
15822
15956
  exportedFiles.push({ path: file, size: 0 });
15823
15957
  }
@@ -15909,7 +16043,7 @@ import {
15909
16043
  generateRegistry,
15910
16044
  generateSchemas
15911
16045
  } from "@contractspec/lib.source-extractors/codegen";
15912
- import { dirname as dirname11, join as join13 } from "path";
16046
+ import { dirname as dirname12, join as join13 } from "path";
15913
16047
  async function importFromSourceService(config, options, adapters2, cwd) {
15914
16048
  const { fs: fs5, logger: logger3 } = adapters2;
15915
16049
  const rootPath = cwd ?? process.cwd();
@@ -15972,7 +16106,7 @@ async function importFromSourceService(config, options, adapters2, cwd) {
15972
16106
  if (!options.dryRun) {
15973
16107
  for (const file of allFiles) {
15974
16108
  const fullPath = join13(outputDir, file.path);
15975
- const dir = dirname11(fullPath);
16109
+ const dir = dirname12(fullPath);
15976
16110
  if (!await fs5.exists(dir)) {
15977
16111
  await fs5.mkdir(dir);
15978
16112
  }
@@ -16697,7 +16831,7 @@ function sarifToJson(sarif) {
16697
16831
  }
16698
16832
  // src/formatters/json.ts
16699
16833
  function formatAsJson(result, options = {}) {
16700
- const { pretty = true } = options;
16834
+ const { pretty = true, driftResult } = options;
16701
16835
  const checks = result.issues.map((issue) => ({
16702
16836
  name: issue.ruleId,
16703
16837
  status: issue.severity === "error" ? "fail" : issue.severity === "warning" ? "warn" : "pass",
@@ -16713,8 +16847,8 @@ function formatAsJson(result, options = {}) {
16713
16847
  schemaVersion: "1.0",
16714
16848
  checks,
16715
16849
  drift: {
16716
- status: "none",
16717
- files: []
16850
+ status: driftResult?.hasDrift ? "detected" : "none",
16851
+ files: driftResult?.files ?? []
16718
16852
  },
16719
16853
  summary: {
16720
16854
  pass: 0,