@vibecheckai/cli 3.2.6 → 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.
Files changed (84) hide show
  1. package/bin/registry.js +192 -5
  2. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  3. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  4. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  5. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  6. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  7. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  8. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  11. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  12. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  13. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  14. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  15. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  16. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  17. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  18. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  19. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  20. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  21. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  22. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  23. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  24. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  25. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  26. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  27. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  28. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  29. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  30. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  31. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  32. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  35. package/bin/runners/lib/analyzers.js +81 -18
  36. package/bin/runners/lib/authority-badge.js +425 -0
  37. package/bin/runners/lib/cli-output.js +7 -1
  38. package/bin/runners/lib/error-handler.js +16 -9
  39. package/bin/runners/lib/exit-codes.js +275 -0
  40. package/bin/runners/lib/global-flags.js +37 -0
  41. package/bin/runners/lib/help-formatter.js +413 -0
  42. package/bin/runners/lib/logger.js +38 -0
  43. package/bin/runners/lib/unified-cli-output.js +604 -0
  44. package/bin/runners/lib/upsell.js +148 -0
  45. package/bin/runners/runApprove.js +1200 -0
  46. package/bin/runners/runAuth.js +324 -95
  47. package/bin/runners/runCheckpoint.js +39 -21
  48. package/bin/runners/runClassify.js +859 -0
  49. package/bin/runners/runContext.js +136 -24
  50. package/bin/runners/runDoctor.js +108 -68
  51. package/bin/runners/runFix.js +6 -5
  52. package/bin/runners/runGuard.js +212 -118
  53. package/bin/runners/runInit.js +3 -2
  54. package/bin/runners/runMcp.js +130 -52
  55. package/bin/runners/runPolish.js +43 -20
  56. package/bin/runners/runProve.js +1 -2
  57. package/bin/runners/runReport.js +3 -2
  58. package/bin/runners/runScan.js +63 -44
  59. package/bin/runners/runShip.js +3 -4
  60. package/bin/runners/runValidate.js +19 -2
  61. package/bin/runners/runWatch.js +104 -53
  62. package/bin/vibecheck.js +106 -19
  63. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  64. package/mcp-server/agent-firewall-interceptor.js +367 -31
  65. package/mcp-server/authority-tools.js +569 -0
  66. package/mcp-server/conductor/conflict-resolver.js +588 -0
  67. package/mcp-server/conductor/execution-planner.js +544 -0
  68. package/mcp-server/conductor/index.js +377 -0
  69. package/mcp-server/conductor/lock-manager.js +615 -0
  70. package/mcp-server/conductor/request-queue.js +550 -0
  71. package/mcp-server/conductor/session-manager.js +500 -0
  72. package/mcp-server/conductor/tools.js +510 -0
  73. package/mcp-server/index.js +1149 -243
  74. package/mcp-server/lib/{api-client.js → api-client.cjs} +40 -4
  75. package/mcp-server/lib/logger.cjs +30 -0
  76. package/mcp-server/logger.js +173 -0
  77. package/mcp-server/package.json +2 -2
  78. package/mcp-server/premium-tools.js +2 -2
  79. package/mcp-server/tier-auth.js +245 -35
  80. package/mcp-server/truth-firewall-tools.js +145 -15
  81. package/mcp-server/vibecheck-tools.js +2 -2
  82. package/package.json +2 -3
  83. package/mcp-server/index.old.js +0 -4137
  84. package/mcp-server/package-lock.json +0 -165
@@ -0,0 +1,394 @@
1
+ /**
2
+ * Assumption Extractor
3
+ *
4
+ * Auto-extracts assumptions from code content.
5
+ * Used when proposals don't explicitly declare their assumptions.
6
+ */
7
+
8
+ "use strict";
9
+
10
+ /**
11
+ * Extract environment variable assumptions
12
+ * @param {string} content - File content
13
+ * @returns {Array} Env var assumptions
14
+ */
15
+ function extractEnvAssumptions(content) {
16
+ const assumptions = [];
17
+ const seen = new Set();
18
+
19
+ // process.env.VAR_NAME
20
+ const processEnvRegex = /process\.env\.([A-Z][A-Z0-9_]+)/g;
21
+ let match;
22
+
23
+ while ((match = processEnvRegex.exec(content)) !== null) {
24
+ const key = match[1];
25
+ if (!seen.has(key)) {
26
+ seen.add(key);
27
+ assumptions.push({
28
+ type: "env",
29
+ key,
30
+ reason: `Used in code: process.env.${key}`,
31
+ line: content.substring(0, match.index).split("\n").length,
32
+ });
33
+ }
34
+ }
35
+
36
+ // import.meta.env.VAR_NAME (Vite)
37
+ const viteEnvRegex = /import\.meta\.env\.([A-Z][A-Z0-9_]+)/g;
38
+
39
+ while ((match = viteEnvRegex.exec(content)) !== null) {
40
+ const key = match[1];
41
+ if (!seen.has(key)) {
42
+ seen.add(key);
43
+ assumptions.push({
44
+ type: "env",
45
+ key,
46
+ reason: `Used in code: import.meta.env.${key}`,
47
+ line: content.substring(0, match.index).split("\n").length,
48
+ });
49
+ }
50
+ }
51
+
52
+ // Destructured: const { VAR } = process.env
53
+ const destructuredRegex = /const\s*\{\s*([^}]+)\s*\}\s*=\s*process\.env/g;
54
+
55
+ while ((match = destructuredRegex.exec(content)) !== null) {
56
+ const vars = match[1].split(",").map(s => s.trim().split(/\s+as\s+/)[0].trim());
57
+ for (const varName of vars) {
58
+ if (varName && /^[A-Z][A-Z0-9_]*$/.test(varName) && !seen.has(varName)) {
59
+ seen.add(varName);
60
+ assumptions.push({
61
+ type: "env",
62
+ key: varName,
63
+ reason: "Destructured from process.env",
64
+ line: content.substring(0, match.index).split("\n").length,
65
+ });
66
+ }
67
+ }
68
+ }
69
+
70
+ return assumptions;
71
+ }
72
+
73
+ /**
74
+ * Extract route assumptions
75
+ * @param {string} content - File content
76
+ * @returns {Array} Route assumptions
77
+ */
78
+ function extractRouteAssumptions(content) {
79
+ const assumptions = [];
80
+ const seen = new Set();
81
+
82
+ // fetch('/api/...')
83
+ const fetchRegex = /fetch\s*\(\s*['"`]([^'"`]+)['"`]/g;
84
+ let match;
85
+
86
+ while ((match = fetchRegex.exec(content)) !== null) {
87
+ const path = match[1];
88
+ if (path.startsWith("/api/") || path.startsWith("/")) {
89
+ const key = path.split("?")[0]; // Remove query params
90
+ if (!seen.has(key)) {
91
+ seen.add(key);
92
+ assumptions.push({
93
+ type: "route",
94
+ path: key,
95
+ method: detectHttpMethod(content, match.index),
96
+ reason: `Fetch call to ${key}`,
97
+ line: content.substring(0, match.index).split("\n").length,
98
+ });
99
+ }
100
+ }
101
+ }
102
+
103
+ // axios.get('/api/...')
104
+ const axiosRegex = /axios\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]/gi;
105
+
106
+ while ((match = axiosRegex.exec(content)) !== null) {
107
+ const method = match[1].toUpperCase();
108
+ const path = match[2];
109
+ if (path.startsWith("/api/") || path.startsWith("/")) {
110
+ const key = `${method}:${path.split("?")[0]}`;
111
+ if (!seen.has(key)) {
112
+ seen.add(key);
113
+ assumptions.push({
114
+ type: "route",
115
+ path: path.split("?")[0],
116
+ method,
117
+ reason: `Axios ${method} call`,
118
+ line: content.substring(0, match.index).split("\n").length,
119
+ });
120
+ }
121
+ }
122
+ }
123
+
124
+ return assumptions;
125
+ }
126
+
127
+ /**
128
+ * Detect HTTP method from context
129
+ */
130
+ function detectHttpMethod(content, index) {
131
+ // Look back for method specification
132
+ const context = content.substring(Math.max(0, index - 200), index);
133
+
134
+ if (context.includes("method: 'POST'") || context.includes('method: "POST"')) return "POST";
135
+ if (context.includes("method: 'PUT'") || context.includes('method: "PUT"')) return "PUT";
136
+ if (context.includes("method: 'DELETE'") || context.includes('method: "DELETE"')) return "DELETE";
137
+ if (context.includes("method: 'PATCH'") || context.includes('method: "PATCH"')) return "PATCH";
138
+
139
+ return "GET"; // Default
140
+ }
141
+
142
+ /**
143
+ * Extract import/dependency assumptions
144
+ * @param {string} content - File content
145
+ * @returns {Array} Dependency assumptions
146
+ */
147
+ function extractDependencyAssumptions(content) {
148
+ const assumptions = [];
149
+ const seen = new Set();
150
+
151
+ // External imports
152
+ const importRegex = /import\s+.*?\s+from\s+['"]([^'"./][^'"]*)['"]/g;
153
+ let match;
154
+
155
+ while ((match = importRegex.exec(content)) !== null) {
156
+ const pkg = match[1].split("/")[0]; // Get package name
157
+ if (!seen.has(pkg) && !isBuiltinModule(pkg)) {
158
+ seen.add(pkg);
159
+ assumptions.push({
160
+ type: "dependency",
161
+ key: pkg,
162
+ reason: `Import statement: ${match[0].slice(0, 50)}...`,
163
+ line: content.substring(0, match.index).split("\n").length,
164
+ });
165
+ }
166
+ }
167
+
168
+ // require() calls
169
+ const requireRegex = /require\s*\(\s*['"]([^'"./][^'"]*)['"]\s*\)/g;
170
+
171
+ while ((match = requireRegex.exec(content)) !== null) {
172
+ const pkg = match[1].split("/")[0];
173
+ if (!seen.has(pkg) && !isBuiltinModule(pkg)) {
174
+ seen.add(pkg);
175
+ assumptions.push({
176
+ type: "dependency",
177
+ key: pkg,
178
+ reason: "Required module",
179
+ line: content.substring(0, match.index).split("\n").length,
180
+ });
181
+ }
182
+ }
183
+
184
+ return assumptions;
185
+ }
186
+
187
+ /**
188
+ * Check if module is Node.js builtin
189
+ */
190
+ function isBuiltinModule(name) {
191
+ const builtins = [
192
+ "fs", "path", "os", "http", "https", "crypto", "util", "events",
193
+ "stream", "buffer", "url", "querystring", "child_process", "net",
194
+ "assert", "zlib", "readline", "cluster", "dns", "tls", "dgram",
195
+ "process", "module", "vm", "worker_threads",
196
+ ];
197
+ return builtins.includes(name) || name.startsWith("node:");
198
+ }
199
+
200
+ /**
201
+ * Extract service/class assumptions
202
+ * @param {string} content - File content
203
+ * @returns {Array} Service assumptions
204
+ */
205
+ function extractServiceAssumptions(content) {
206
+ const assumptions = [];
207
+ const seen = new Set();
208
+
209
+ // new ServiceName() or ServiceName.method()
210
+ const serviceRegex = /(?:new\s+|(?:await\s+)?)((?:[A-Z][a-z]+)+(?:Service|Client|Provider|Manager|Controller|Repository))(?:\s*\(|\.)/g;
211
+ let match;
212
+
213
+ while ((match = serviceRegex.exec(content)) !== null) {
214
+ const service = match[1];
215
+ if (!seen.has(service)) {
216
+ seen.add(service);
217
+ assumptions.push({
218
+ type: "service",
219
+ key: service,
220
+ reason: `Service usage: ${service}`,
221
+ line: content.substring(0, match.index).split("\n").length,
222
+ });
223
+ }
224
+ }
225
+
226
+ // Prisma client
227
+ if (content.includes("prisma.")) {
228
+ const prismaRegex = /prisma\.(\w+)\./g;
229
+ while ((match = prismaRegex.exec(content)) !== null) {
230
+ const model = match[1];
231
+ const key = `prisma.${model}`;
232
+ if (!seen.has(key)) {
233
+ seen.add(key);
234
+ assumptions.push({
235
+ type: "service",
236
+ key: `PrismaModel:${model}`,
237
+ reason: `Prisma model access: ${model}`,
238
+ line: content.substring(0, match.index).split("\n").length,
239
+ });
240
+ }
241
+ }
242
+ }
243
+
244
+ return assumptions;
245
+ }
246
+
247
+ /**
248
+ * Extract file reference assumptions
249
+ * @param {string} content - File content
250
+ * @param {string} currentFile - Current file path
251
+ * @returns {Array} File assumptions
252
+ */
253
+ function extractFileAssumptions(content, currentFile = "") {
254
+ const assumptions = [];
255
+ const seen = new Set();
256
+
257
+ // Relative imports
258
+ const relativeImportRegex = /(?:import|require)\s*\(?['"](\.[^'"]+)['"]/g;
259
+ let match;
260
+
261
+ while ((match = relativeImportRegex.exec(content)) !== null) {
262
+ const importPath = match[1];
263
+ if (!seen.has(importPath)) {
264
+ seen.add(importPath);
265
+ assumptions.push({
266
+ type: "file",
267
+ path: importPath,
268
+ reason: `Relative import: ${importPath}`,
269
+ line: content.substring(0, match.index).split("\n").length,
270
+ });
271
+ }
272
+ }
273
+
274
+ // fs.readFileSync, fs.writeFileSync, etc.
275
+ const fsOpRegex = /fs(?:Promises)?\.(?:read|write|unlink|mkdir|rmdir|access)(?:File)?(?:Sync)?\s*\(\s*['"`]([^'"`]+)['"`]/g;
276
+
277
+ while ((match = fsOpRegex.exec(content)) !== null) {
278
+ const filePath = match[1];
279
+ if (!seen.has(filePath) && !filePath.includes("${")) { // Skip template literals
280
+ seen.add(filePath);
281
+ assumptions.push({
282
+ type: "file",
283
+ path: filePath,
284
+ reason: `File system operation on: ${filePath}`,
285
+ line: content.substring(0, match.index).split("\n").length,
286
+ });
287
+ }
288
+ }
289
+
290
+ return assumptions;
291
+ }
292
+
293
+ /**
294
+ * Extract all assumptions from content
295
+ * @param {string} content - File content
296
+ * @param {Object} options - Extraction options
297
+ * @returns {Array} All extracted assumptions
298
+ */
299
+ function extractAssumptions(content, options = {}) {
300
+ const { filePath = "", includeTypes = ["env", "route", "dependency", "service", "file"] } = options;
301
+
302
+ const assumptions = [];
303
+
304
+ if (includeTypes.includes("env")) {
305
+ assumptions.push(...extractEnvAssumptions(content));
306
+ }
307
+
308
+ if (includeTypes.includes("route")) {
309
+ assumptions.push(...extractRouteAssumptions(content));
310
+ }
311
+
312
+ if (includeTypes.includes("dependency")) {
313
+ assumptions.push(...extractDependencyAssumptions(content));
314
+ }
315
+
316
+ if (includeTypes.includes("service")) {
317
+ assumptions.push(...extractServiceAssumptions(content));
318
+ }
319
+
320
+ if (includeTypes.includes("file")) {
321
+ assumptions.push(...extractFileAssumptions(content, filePath));
322
+ }
323
+
324
+ // Sort by line number
325
+ assumptions.sort((a, b) => (a.line || 0) - (b.line || 0));
326
+
327
+ return assumptions;
328
+ }
329
+
330
+ /**
331
+ * Extract assumptions from all operations in a proposal
332
+ * @param {Array} operations - Proposal operations
333
+ * @returns {Array} All assumptions
334
+ */
335
+ function extractFromOperations(operations) {
336
+ const allAssumptions = [];
337
+ const seen = new Set();
338
+
339
+ for (const op of operations) {
340
+ if (op.content) {
341
+ const assumptions = extractAssumptions(op.content, { filePath: op.path });
342
+
343
+ for (const assumption of assumptions) {
344
+ // Deduplicate
345
+ const key = `${assumption.type}:${assumption.key || assumption.path}`;
346
+ if (!seen.has(key)) {
347
+ seen.add(key);
348
+ allAssumptions.push({
349
+ ...assumption,
350
+ sourceFile: op.path,
351
+ });
352
+ }
353
+ }
354
+ }
355
+ }
356
+
357
+ return allAssumptions;
358
+ }
359
+
360
+ /**
361
+ * Merge extracted assumptions with declared assumptions
362
+ * @param {Array} declared - Declared assumptions
363
+ * @param {Array} extracted - Extracted assumptions
364
+ * @returns {Array} Merged assumptions
365
+ */
366
+ function mergeAssumptions(declared, extracted) {
367
+ const merged = [...declared];
368
+ const declaredKeys = new Set(
369
+ declared.map(a => `${a.type}:${a.key || a.path}`)
370
+ );
371
+
372
+ for (const assumption of extracted) {
373
+ const key = `${assumption.type}:${assumption.key || assumption.path}`;
374
+ if (!declaredKeys.has(key)) {
375
+ merged.push({
376
+ ...assumption,
377
+ autoExtracted: true,
378
+ });
379
+ }
380
+ }
381
+
382
+ return merged;
383
+ }
384
+
385
+ module.exports = {
386
+ extractAssumptions,
387
+ extractEnvAssumptions,
388
+ extractRouteAssumptions,
389
+ extractDependencyAssumptions,
390
+ extractServiceAssumptions,
391
+ extractFileAssumptions,
392
+ extractFromOperations,
393
+ mergeAssumptions,
394
+ };
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Proposal Module
3
+ *
4
+ * Entry point for structured change proposal handling.
5
+ * Provides schema, validation, and assumption extraction.
6
+ *
7
+ * Usage:
8
+ * const { proposal } = require('./proposal');
9
+ *
10
+ * // Validate a proposal
11
+ * const result = proposal.validate(rawProposal);
12
+ * if (!result.valid) {
13
+ * console.log('Invalid proposal:', result.errors);
14
+ * }
15
+ *
16
+ * // Use normalized proposal
17
+ * const normalized = result.normalized;
18
+ */
19
+
20
+ "use strict";
21
+
22
+ const {
23
+ PROPOSAL_SCHEMA,
24
+ MINIMAL_PROPOSAL_SCHEMA,
25
+ DEFAULT_PROPOSAL_VALUES,
26
+ createProposalTemplate,
27
+ normalizeIntent,
28
+ } = require("./schema");
29
+
30
+ const {
31
+ validate,
32
+ validateStructure,
33
+ validateSemantics,
34
+ validateCompleteness,
35
+ normalizeProposal,
36
+ isValid,
37
+ } = require("./validator");
38
+
39
+ const {
40
+ extractAssumptions,
41
+ extractEnvAssumptions,
42
+ extractRouteAssumptions,
43
+ extractDependencyAssumptions,
44
+ extractServiceAssumptions,
45
+ extractFileAssumptions,
46
+ extractFromOperations,
47
+ mergeAssumptions,
48
+ } = require("./extractor");
49
+
50
+ /**
51
+ * Proposal handling singleton
52
+ */
53
+ const proposal = {
54
+ /**
55
+ * Validate a proposal
56
+ * @param {Object} rawProposal - Raw proposal object
57
+ * @param {Object} options - Validation options
58
+ * @returns {Object} Validation result
59
+ */
60
+ validate(rawProposal, options = {}) {
61
+ return validate(rawProposal, options);
62
+ },
63
+
64
+ /**
65
+ * Quick validity check
66
+ * @param {Object} rawProposal - Proposal to check
67
+ * @returns {boolean} Is valid
68
+ */
69
+ isValid(rawProposal) {
70
+ return isValid(rawProposal);
71
+ },
72
+
73
+ /**
74
+ * Normalize a proposal
75
+ * @param {Object} rawProposal - Raw proposal
76
+ * @returns {Object} Normalized proposal
77
+ */
78
+ normalize(rawProposal) {
79
+ return normalizeProposal(rawProposal);
80
+ },
81
+
82
+ /**
83
+ * Create a proposal template
84
+ * @param {string} intent - Intent identifier
85
+ * @param {Array} operations - Operations
86
+ * @returns {Object} Proposal template
87
+ */
88
+ create(intent, operations) {
89
+ return createProposalTemplate(intent, operations);
90
+ },
91
+
92
+ /**
93
+ * Extract assumptions from content
94
+ * @param {string} content - File content
95
+ * @param {Object} options - Extraction options
96
+ * @returns {Array} Extracted assumptions
97
+ */
98
+ extractAssumptions(content, options = {}) {
99
+ return extractAssumptions(content, options);
100
+ },
101
+
102
+ /**
103
+ * Extract assumptions from operations
104
+ * @param {Array} operations - Proposal operations
105
+ * @returns {Array} Extracted assumptions
106
+ */
107
+ extractFromOperations(operations) {
108
+ return extractFromOperations(operations);
109
+ },
110
+
111
+ /**
112
+ * Merge declared and extracted assumptions
113
+ * @param {Array} declared - Declared assumptions
114
+ * @param {Array} extracted - Extracted assumptions
115
+ * @returns {Array} Merged assumptions
116
+ */
117
+ mergeAssumptions(declared, extracted) {
118
+ return mergeAssumptions(declared, extracted);
119
+ },
120
+
121
+ /**
122
+ * Enrich proposal with auto-extracted assumptions
123
+ * @param {Object} rawProposal - Raw proposal
124
+ * @returns {Object} Enriched proposal
125
+ */
126
+ enrich(rawProposal) {
127
+ const normalized = normalizeProposal(rawProposal);
128
+ const extracted = extractFromOperations(normalized.operations);
129
+ const merged = mergeAssumptions(normalized.assumptions || [], extracted);
130
+
131
+ return {
132
+ ...normalized,
133
+ assumptions: merged,
134
+ };
135
+ },
136
+
137
+ /**
138
+ * Get the proposal schema
139
+ * @returns {Object} JSON Schema
140
+ */
141
+ getSchema() {
142
+ return PROPOSAL_SCHEMA;
143
+ },
144
+
145
+ /**
146
+ * Get default values
147
+ * @returns {Object} Default values
148
+ */
149
+ getDefaults() {
150
+ return DEFAULT_PROPOSAL_VALUES;
151
+ },
152
+
153
+ /**
154
+ * Normalize an intent string
155
+ * @param {string} intent - Raw intent
156
+ * @returns {string} Normalized intent
157
+ */
158
+ normalizeIntent(intent) {
159
+ return normalizeIntent(intent);
160
+ },
161
+
162
+ /**
163
+ * Convert legacy format to proposal format
164
+ * @param {Object} legacy - Legacy change object
165
+ * @returns {Object} Proposal format
166
+ */
167
+ fromLegacy(legacy) {
168
+ // Handle old formats that just have filePath + content
169
+ if (legacy.filePath && !legacy.operations) {
170
+ return {
171
+ intent: legacy.intent || "unknown_change",
172
+ summary: legacy.summary || legacy.intent || "",
173
+ operations: [{
174
+ type: legacy.type || (legacy.oldContent ? "modify" : "create"),
175
+ path: legacy.filePath,
176
+ content: legacy.content || legacy.newContent,
177
+ }],
178
+ assumptions: legacy.assumptions || [],
179
+ confidence: legacy.confidence || 0.5,
180
+ };
181
+ }
182
+
183
+ // Already in proposal format
184
+ return legacy;
185
+ },
186
+ };
187
+
188
+ module.exports = {
189
+ proposal,
190
+ // Schema exports
191
+ PROPOSAL_SCHEMA,
192
+ MINIMAL_PROPOSAL_SCHEMA,
193
+ DEFAULT_PROPOSAL_VALUES,
194
+ createProposalTemplate,
195
+ normalizeIntent,
196
+ // Validator exports
197
+ validate,
198
+ validateStructure,
199
+ validateSemantics,
200
+ validateCompleteness,
201
+ normalizeProposal,
202
+ isValid,
203
+ // Extractor exports
204
+ extractAssumptions,
205
+ extractEnvAssumptions,
206
+ extractRouteAssumptions,
207
+ extractDependencyAssumptions,
208
+ extractServiceAssumptions,
209
+ extractFileAssumptions,
210
+ extractFromOperations,
211
+ mergeAssumptions,
212
+ };