@contractspec/bundle.workspace 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,8 +9,218 @@ var __export = (target, all) => {
9
9
  set: (newValue) => all[name] = () => newValue
10
10
  });
11
11
  };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
13
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
13
14
 
15
+ // src/services/config.ts
16
+ import {
17
+ ContractsrcSchema,
18
+ DEFAULT_CONTRACTSRC as DEFAULT_CONTRACTSRC2
19
+ } from "@contractspec/lib.contracts-spec/workspace-config";
20
+ async function loadWorkspaceConfig(fs5, cwd) {
21
+ const configPath = fs5.join(cwd ?? ".", ".contractsrc.json");
22
+ const exists = await fs5.exists(configPath);
23
+ if (!exists) {
24
+ return DEFAULT_CONTRACTSRC2;
25
+ }
26
+ try {
27
+ const content = await fs5.readFile(configPath);
28
+ const parsed = JSON.parse(content);
29
+ const resolved = ContractsrcSchema.safeParse(parsed);
30
+ return {
31
+ ...DEFAULT_CONTRACTSRC2,
32
+ ...resolved.data,
33
+ conventions: {
34
+ ...DEFAULT_CONTRACTSRC2.conventions,
35
+ ...resolved.data?.conventions || {}
36
+ }
37
+ };
38
+ } catch {
39
+ return DEFAULT_CONTRACTSRC2;
40
+ }
41
+ }
42
+ function getApiKey(provider) {
43
+ switch (provider) {
44
+ case "claude":
45
+ return process.env["ANTHROPIC_API_KEY"];
46
+ case "openai":
47
+ return process.env["OPENAI_API_KEY"];
48
+ case "custom":
49
+ return process.env["CONTRACTSPEC_LLM_API_KEY"];
50
+ case "ollama":
51
+ return;
52
+ default:
53
+ return;
54
+ }
55
+ }
56
+ var init_config = () => {};
57
+
58
+ // src/services/create/ai-generator.ts
59
+ var exports_ai_generator = {};
60
+ __export(exports_ai_generator, {
61
+ AIGenerator: () => AIGenerator
62
+ });
63
+ import { generateObject as generateObject2, generateText as generateText6, streamText as streamText2 } from "ai";
64
+ import * as z2 from "zod";
65
+ import {
66
+ createProvider
67
+ } from "@contractspec/lib.ai-providers";
68
+ import {
69
+ buildComponentPrompt as buildComponentPrompt2,
70
+ buildEventSpecPrompt,
71
+ buildFormPrompt as buildFormPrompt2,
72
+ buildHandlerPrompt as buildHandlerPrompt2,
73
+ buildOperationSpecPrompt,
74
+ buildPresentationSpecPrompt,
75
+ buildTestPrompt as buildTestPrompt2,
76
+ getCodeGenSystemPrompt as getCodeGenSystemPrompt2,
77
+ getSystemPrompt
78
+ } from "@contractspec/module.workspace";
79
+
80
+ class AIGenerator {
81
+ config;
82
+ constructor(config) {
83
+ this.config = config;
84
+ }
85
+ getModel() {
86
+ const providerName = this.config.aiProvider;
87
+ const apiKey = this.config.customApiKey || getApiKey(this.config.aiProvider);
88
+ const providerConfig = {
89
+ provider: providerName === "custom" ? "openai" : providerName,
90
+ model: this.config.aiModel,
91
+ apiKey,
92
+ baseUrl: this.config.customEndpoint || undefined
93
+ };
94
+ const provider = createProvider(providerConfig);
95
+ return provider.getModel();
96
+ }
97
+ async generateOperationSpec(description, kind) {
98
+ const model = this.getModel();
99
+ const schema = z2.object({
100
+ name: z2.string().describe('Dot notation name like "domain.operation"'),
101
+ version: z2.number().int().positive().default(1),
102
+ description: z2.string().describe("Clear, concise summary"),
103
+ goal: z2.string().describe("Business purpose"),
104
+ context: z2.string().describe("Background and constraints"),
105
+ stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
106
+ owners: z2.array(z2.string()).describe("Team/person owners with @ prefix"),
107
+ tags: z2.array(z2.string()).describe("Categorization tags"),
108
+ auth: z2.enum(["anonymous", "user", "admin"]).describe("Required auth level"),
109
+ inputShape: z2.string().describe("Description of input structure"),
110
+ outputShape: z2.string().describe("Description of output structure"),
111
+ flags: z2.array(z2.string()).describe("Feature flags").default([]),
112
+ possibleEvents: z2.array(z2.string()).describe("Events this may emit").default([]),
113
+ analytics: z2.array(z2.string()).describe("Analytics events to track").default([])
114
+ });
115
+ const prompt = buildOperationSpecPrompt(description, kind);
116
+ const result = await generateObject2({
117
+ model,
118
+ schema,
119
+ prompt,
120
+ system: getSystemPrompt()
121
+ });
122
+ return result.object;
123
+ }
124
+ async generateEventSpec(description) {
125
+ const model = this.getModel();
126
+ const schema = z2.object({
127
+ name: z2.string().describe('Dot notation name like "domain.event_name"'),
128
+ version: z2.number().int().positive().default(1),
129
+ description: z2.string().describe("When this event is emitted"),
130
+ stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
131
+ owners: z2.array(z2.string()).default([]),
132
+ tags: z2.array(z2.string()).default([]),
133
+ payloadShape: z2.string().describe("Description of event payload"),
134
+ piiFields: z2.array(z2.string()).describe("PII field paths").default([])
135
+ });
136
+ const prompt = buildEventSpecPrompt(description);
137
+ const result = await generateObject2({
138
+ model,
139
+ schema,
140
+ prompt,
141
+ system: getSystemPrompt()
142
+ });
143
+ return result.object;
144
+ }
145
+ async generatePresentationSpec(description, kind) {
146
+ const model = this.getModel();
147
+ const schema = z2.object({
148
+ name: z2.string(),
149
+ version: z2.number().int().positive().default(1),
150
+ description: z2.string(),
151
+ stability: z2.enum(["experimental", "beta", "stable", "deprecated"]).default("beta"),
152
+ owners: z2.array(z2.string()).default([]),
153
+ tags: z2.array(z2.string()).default([]),
154
+ componentKey: z2.string().optional(),
155
+ propsShape: z2.string().optional(),
156
+ content: z2.string().optional(),
157
+ mimeType: z2.string().optional(),
158
+ dataShape: z2.string().optional()
159
+ });
160
+ const prompt = buildPresentationSpecPrompt(description, kind);
161
+ const result = await generateObject2({
162
+ model,
163
+ schema,
164
+ prompt,
165
+ system: getSystemPrompt()
166
+ });
167
+ return result.object;
168
+ }
169
+ async generateHandler(specCode) {
170
+ const model = this.getModel();
171
+ const result = await generateText6({
172
+ model,
173
+ prompt: buildHandlerPrompt2(specCode),
174
+ system: getCodeGenSystemPrompt2()
175
+ });
176
+ return result.text;
177
+ }
178
+ async generateComponent(specCode) {
179
+ const model = this.getModel();
180
+ const result = await generateText6({
181
+ model,
182
+ prompt: buildComponentPrompt2(specCode),
183
+ system: getCodeGenSystemPrompt2()
184
+ });
185
+ return result.text;
186
+ }
187
+ async generateForm(specCode) {
188
+ const model = this.getModel();
189
+ const result = await generateText6({
190
+ model,
191
+ prompt: buildFormPrompt2(specCode),
192
+ system: getCodeGenSystemPrompt2()
193
+ });
194
+ return result.text;
195
+ }
196
+ async generateTests(specCode, implementationCode, testType) {
197
+ const model = this.getModel();
198
+ const result = await generateText6({
199
+ model,
200
+ prompt: buildTestPrompt2(specCode, implementationCode, testType),
201
+ system: getCodeGenSystemPrompt2()
202
+ });
203
+ return result.text;
204
+ }
205
+ async streamCodeGeneration(prompt, onChunk) {
206
+ const model = this.getModel();
207
+ const result = await streamText2({
208
+ model,
209
+ prompt,
210
+ system: getCodeGenSystemPrompt2()
211
+ });
212
+ let fullText = "";
213
+ for await (const chunk of result.textStream) {
214
+ fullText += chunk;
215
+ onChunk(chunk);
216
+ }
217
+ return fullText;
218
+ }
219
+ }
220
+ var init_ai_generator = __esm(() => {
221
+ init_config();
222
+ });
223
+
14
224
  // src/index.ts
15
225
  import * as module from "@contractspec/module.workspace";
16
226
  // src/adapters/fs.node.ts
@@ -2900,47 +3110,10 @@ function getGraphStats(graph) {
2900
3110
  unused: unused.length
2901
3111
  };
2902
3112
  }
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
- }
3113
+
3114
+ // src/services/index.ts
3115
+ init_config();
3116
+
2944
3117
  // src/services/build.ts
2945
3118
  import {
2946
3119
  generateComponentTemplate,
@@ -7473,6 +7646,7 @@ async function runDoctorChecks(adapters, options) {
7473
7646
  return issues;
7474
7647
  }
7475
7648
  // src/services/ci-check/checks/handlers.ts
7649
+ init_config();
7476
7650
  async function runHandlerChecks(adapters, specFiles) {
7477
7651
  const { fs: fs5 } = adapters;
7478
7652
  const issues = [];
@@ -7506,6 +7680,7 @@ async function runHandlerChecks(adapters, specFiles) {
7506
7680
  return issues;
7507
7681
  }
7508
7682
  // src/services/ci-check/checks/tests.ts
7683
+ init_config();
7509
7684
  async function runTestChecks(adapters, specFiles) {
7510
7685
  const { fs: fs5 } = adapters;
7511
7686
  const issues = [];
@@ -7834,6 +8009,9 @@ async function runCoverageChecks(adapters, specFiles, options) {
7834
8009
  }
7835
8010
  return issues;
7836
8011
  }
8012
+ // src/services/ci-check/checks/implementation.ts
8013
+ init_config();
8014
+
7837
8015
  // src/services/implementation/resolver/index.ts
7838
8016
  import { createHash } from "crypto";
7839
8017
 
@@ -8392,6 +8570,9 @@ async function runLayerChecks2(adapters, _options) {
8392
8570
  }
8393
8571
  return issues;
8394
8572
  }
8573
+ // src/services/ci-check/checks/drift.ts
8574
+ init_config();
8575
+
8395
8576
  // src/services/drift.ts
8396
8577
  import path4 from "path";
8397
8578
  import { mkdtemp, rm as rm3 } from "node:fs/promises";
@@ -9709,163 +9890,8 @@ function exportSpecForLLM(spec, format, agent = "generic-mcp") {
9709
9890
  return specToMarkdown(spec, "full");
9710
9891
  }
9711
9892
  }
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
- }
9893
+ // src/services/create/index.ts
9894
+ init_ai_generator();
9869
9895
 
9870
9896
  // src/services/create/templates.ts
9871
9897
  var exports_templates2 = {};
@@ -11171,6 +11197,8 @@ ${formatRefs(params.experiments) || " // Add experiments here"}
11171
11197
  `;
11172
11198
  }
11173
11199
  // src/services/create/index.ts
11200
+ init_ai_generator();
11201
+
11174
11202
  class SpecCreatorService {
11175
11203
  ai;
11176
11204
  templates = exports_templates2;
@@ -13109,6 +13137,7 @@ import {
13109
13137
  } from "@contractspec/lib.contracts-spec";
13110
13138
 
13111
13139
  // src/services/versioning/changelog-formatter.ts
13140
+ import { dirname as dirname10, basename as basename5 } from "node:path";
13112
13141
  function formatKeepAChangelog(entries) {
13113
13142
  const lines = [
13114
13143
  "# Changelog",
@@ -13231,9 +13260,55 @@ function formatChangelogJson(analysis, baseline) {
13231
13260
  }
13232
13261
  ]
13233
13262
  })),
13234
- libraries: []
13263
+ libraries: groupSpecsByLibrary(specsNeedingBump, isoDate)
13235
13264
  };
13236
13265
  }
13266
+ function extractLibraryPath(specPath) {
13267
+ const parts = specPath.split("/");
13268
+ const packagesIdx = parts.lastIndexOf("packages");
13269
+ if (packagesIdx >= 0 && packagesIdx + 2 < parts.length) {
13270
+ return parts.slice(0, packagesIdx + 3).join("/");
13271
+ }
13272
+ return dirname10(specPath);
13273
+ }
13274
+ var BUMP_RANK = { major: 3, minor: 2, patch: 1 };
13275
+ function groupSpecsByLibrary(specs, isoDate) {
13276
+ const groups = new Map;
13277
+ for (const spec of specs) {
13278
+ const libPath = extractLibraryPath(spec.specPath);
13279
+ const existing = groups.get(libPath);
13280
+ if (existing) {
13281
+ existing.push(spec);
13282
+ } else {
13283
+ groups.set(libPath, [spec]);
13284
+ }
13285
+ }
13286
+ return Array.from(groups.entries()).flatMap(([libPath, libSpecs]) => {
13287
+ const first = libSpecs[0];
13288
+ if (!first)
13289
+ return [];
13290
+ const highestBump = libSpecs.reduce((max, s) => {
13291
+ const rank = BUMP_RANK[s.bumpType] ?? 0;
13292
+ return rank > (BUMP_RANK[max.bumpType] ?? 0) ? s : max;
13293
+ }, first);
13294
+ return [
13295
+ {
13296
+ name: basename5(libPath),
13297
+ path: libPath,
13298
+ version: highestBump.suggestedVersion,
13299
+ entries: [
13300
+ {
13301
+ version: highestBump.suggestedVersion,
13302
+ date: isoDate,
13303
+ bumpType: highestBump.bumpType,
13304
+ changes: libSpecs.flatMap((s) => s.changes),
13305
+ breakingChanges: libSpecs.flatMap((s) => s.changes).filter((c) => c.type === "breaking")
13306
+ }
13307
+ ]
13308
+ }
13309
+ ];
13310
+ });
13311
+ }
13237
13312
  function compareVersionsDescending(a, b) {
13238
13313
  const parseVer = (v) => {
13239
13314
  const parts = v.split(".").map((p) => parseInt(p, 10) || 0);
@@ -14838,11 +14913,50 @@ async function implementAiStrategy(issue, options, adapters2) {
14838
14913
  };
14839
14914
  }
14840
14915
  }
14841
- async function enrichWithAI(ctx, _options, logger3) {
14916
+ async function enrichWithAI(ctx, options, logger3) {
14842
14917
  logger3.info("Generating AI content for spec", {
14843
14918
  key: ctx.key,
14844
14919
  type: ctx.specType
14845
14920
  });
14921
+ if (options.aiConfig) {
14922
+ try {
14923
+ const { AIGenerator: AIGenerator2 } = await Promise.resolve().then(() => (init_ai_generator(), exports_ai_generator));
14924
+ const config = buildResolvedConfig(options);
14925
+ const generator = new AIGenerator2(config);
14926
+ const kind = ctx.specType === "operation" ? "command" : ctx.specType;
14927
+ const description = `${capitalize2(ctx.specType)} for ${ctx.key}`;
14928
+ if (ctx.specType === "operation") {
14929
+ const result = await generator.generateOperationSpec(description, kind);
14930
+ return {
14931
+ ...ctx,
14932
+ description: result.description,
14933
+ enrichment: {
14934
+ goal: result.goal,
14935
+ context: result.context,
14936
+ owners: result.owners,
14937
+ tags: result.tags
14938
+ }
14939
+ };
14940
+ }
14941
+ if (ctx.specType === "event") {
14942
+ const result = await generator.generateEventSpec(description);
14943
+ return {
14944
+ ...ctx,
14945
+ description: result.description,
14946
+ enrichment: {
14947
+ goal: `Emit ${ctx.key} event`,
14948
+ context: result.description,
14949
+ owners: ["@team"],
14950
+ tags: result.tags
14951
+ }
14952
+ };
14953
+ }
14954
+ } catch (aiError) {
14955
+ logger3.warn("AIGenerator call failed, falling back to heuristics", {
14956
+ error: aiError instanceof Error ? aiError.message : String(aiError)
14957
+ });
14958
+ }
14959
+ }
14846
14960
  const enrichment = inferEnrichmentFromKey(ctx.key, ctx.specType);
14847
14961
  return {
14848
14962
  ...ctx,
@@ -14855,6 +14969,21 @@ async function enrichWithAI(ctx, _options, logger3) {
14855
14969
  }
14856
14970
  };
14857
14971
  }
14972
+ function buildResolvedConfig(options) {
14973
+ const ai3 = options.aiConfig;
14974
+ const providerMap = {
14975
+ claude: "anthropic",
14976
+ openai: "openai",
14977
+ ollama: "ollama",
14978
+ custom: "custom"
14979
+ };
14980
+ return {
14981
+ aiProvider: providerMap[ai3?.provider ?? "openai"] ?? "openai",
14982
+ aiModel: ai3?.model ?? "gpt-4-turbo",
14983
+ customApiKey: ai3?.apiKey ?? "",
14984
+ customEndpoint: ai3?.endpoint ?? ""
14985
+ };
14986
+ }
14858
14987
  function inferEnrichmentFromKey(key, specType) {
14859
14988
  const parts = key.split(".");
14860
14989
  const domain = parts[0] || "unknown";
@@ -15376,6 +15505,7 @@ async function analyzeGap(adapters2, cwd) {
15376
15505
  };
15377
15506
  }
15378
15507
  // src/services/extract.ts
15508
+ init_config();
15379
15509
  async function extractContracts(adapters2, options, cwd) {
15380
15510
  const { fs: fs5, logger: logger3 } = adapters2;
15381
15511
  const { source, outputDir } = options;
@@ -15766,7 +15896,7 @@ async function getWorkflow(id, cwd) {
15766
15896
  // src/services/vibe/context.ts
15767
15897
  import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile3, copyFile } from "node:fs/promises";
15768
15898
  import { existsSync as existsSync6 } from "node:fs";
15769
- import { join as join11, dirname as dirname10 } from "node:path";
15899
+ import { join as join11, dirname as dirname11 } from "node:path";
15770
15900
  import { glob } from "glob";
15771
15901
  var DEFAULT_IGNORES2 = [
15772
15902
  "**/node_modules/**",
@@ -15817,7 +15947,7 @@ async function exportContext(cwd) {
15817
15947
  for (const file of uniqueFiles) {
15818
15948
  const absSource = join11(root, file);
15819
15949
  const absDest = join11(contextFilesDir, file);
15820
- await mkdir4(dirname10(absDest), { recursive: true });
15950
+ await mkdir4(dirname11(absDest), { recursive: true });
15821
15951
  await copyFile(absSource, absDest);
15822
15952
  exportedFiles.push({ path: file, size: 0 });
15823
15953
  }
@@ -15909,7 +16039,7 @@ import {
15909
16039
  generateRegistry,
15910
16040
  generateSchemas
15911
16041
  } from "@contractspec/lib.source-extractors/codegen";
15912
- import { dirname as dirname11, join as join13 } from "path";
16042
+ import { dirname as dirname12, join as join13 } from "path";
15913
16043
  async function importFromSourceService(config, options, adapters2, cwd) {
15914
16044
  const { fs: fs5, logger: logger3 } = adapters2;
15915
16045
  const rootPath = cwd ?? process.cwd();
@@ -15972,7 +16102,7 @@ async function importFromSourceService(config, options, adapters2, cwd) {
15972
16102
  if (!options.dryRun) {
15973
16103
  for (const file of allFiles) {
15974
16104
  const fullPath = join13(outputDir, file.path);
15975
- const dir = dirname11(fullPath);
16105
+ const dir = dirname12(fullPath);
15976
16106
  if (!await fs5.exists(dir)) {
15977
16107
  await fs5.mkdir(dir);
15978
16108
  }
@@ -16697,7 +16827,7 @@ function sarifToJson(sarif) {
16697
16827
  }
16698
16828
  // src/formatters/json.ts
16699
16829
  function formatAsJson(result, options = {}) {
16700
- const { pretty = true } = options;
16830
+ const { pretty = true, driftResult } = options;
16701
16831
  const checks = result.issues.map((issue) => ({
16702
16832
  name: issue.ruleId,
16703
16833
  status: issue.severity === "error" ? "fail" : issue.severity === "warning" ? "warn" : "pass",
@@ -16713,8 +16843,8 @@ function formatAsJson(result, options = {}) {
16713
16843
  schemaVersion: "1.0",
16714
16844
  checks,
16715
16845
  drift: {
16716
- status: "none",
16717
- files: []
16846
+ status: driftResult?.hasDrift ? "detected" : "none",
16847
+ files: driftResult?.files ?? []
16718
16848
  },
16719
16849
  summary: {
16720
16850
  pass: 0,