@vibecheckai/cli 3.2.5 → 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 (197) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/registry.js +192 -5
  4. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  5. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  6. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  7. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  8. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  11. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  12. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  13. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  14. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  15. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  16. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  17. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  18. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  19. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  20. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  21. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  22. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  23. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  24. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  25. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  26. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  27. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  28. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  29. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  30. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  31. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  32. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  35. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  36. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  37. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  38. package/bin/runners/lib/analyzers.js +81 -18
  39. package/bin/runners/lib/api-client.js +269 -0
  40. package/bin/runners/lib/auth-truth.js +193 -193
  41. package/bin/runners/lib/authority-badge.js +425 -0
  42. package/bin/runners/lib/backup.js +62 -62
  43. package/bin/runners/lib/billing.js +107 -107
  44. package/bin/runners/lib/claims.js +118 -118
  45. package/bin/runners/lib/cli-output.js +7 -1
  46. package/bin/runners/lib/cli-ui.js +540 -540
  47. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  48. package/bin/runners/lib/contracts/env-contract.js +181 -181
  49. package/bin/runners/lib/contracts/external-contract.js +206 -206
  50. package/bin/runners/lib/contracts/guard.js +168 -168
  51. package/bin/runners/lib/contracts/index.js +89 -89
  52. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  53. package/bin/runners/lib/contracts/route-contract.js +199 -199
  54. package/bin/runners/lib/contracts.js +804 -804
  55. package/bin/runners/lib/detect.js +89 -89
  56. package/bin/runners/lib/doctor/autofix.js +254 -254
  57. package/bin/runners/lib/doctor/index.js +37 -37
  58. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  59. package/bin/runners/lib/doctor/modules/index.js +46 -46
  60. package/bin/runners/lib/doctor/modules/network.js +250 -250
  61. package/bin/runners/lib/doctor/modules/project.js +312 -312
  62. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  63. package/bin/runners/lib/doctor/modules/security.js +348 -348
  64. package/bin/runners/lib/doctor/modules/system.js +213 -213
  65. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  66. package/bin/runners/lib/doctor/reporter.js +262 -262
  67. package/bin/runners/lib/doctor/service.js +262 -262
  68. package/bin/runners/lib/doctor/types.js +113 -113
  69. package/bin/runners/lib/doctor/ui.js +263 -263
  70. package/bin/runners/lib/doctor-v2.js +608 -608
  71. package/bin/runners/lib/drift.js +425 -425
  72. package/bin/runners/lib/enforcement.js +72 -72
  73. package/bin/runners/lib/enterprise-detect.js +603 -603
  74. package/bin/runners/lib/enterprise-init.js +942 -942
  75. package/bin/runners/lib/env-resolver.js +417 -417
  76. package/bin/runners/lib/env-template.js +66 -66
  77. package/bin/runners/lib/env.js +189 -189
  78. package/bin/runners/lib/error-handler.js +16 -9
  79. package/bin/runners/lib/exit-codes.js +275 -0
  80. package/bin/runners/lib/extractors/client-calls.js +990 -990
  81. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  82. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  83. package/bin/runners/lib/extractors/index.js +363 -363
  84. package/bin/runners/lib/extractors/next-routes.js +524 -524
  85. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  86. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  87. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  88. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  89. package/bin/runners/lib/findings-schema.js +281 -281
  90. package/bin/runners/lib/firewall-prompt.js +50 -50
  91. package/bin/runners/lib/global-flags.js +37 -0
  92. package/bin/runners/lib/graph/graph-builder.js +265 -265
  93. package/bin/runners/lib/graph/html-renderer.js +413 -413
  94. package/bin/runners/lib/graph/index.js +32 -32
  95. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  96. package/bin/runners/lib/graph/static-extractor.js +518 -518
  97. package/bin/runners/lib/help-formatter.js +413 -0
  98. package/bin/runners/lib/html-report.js +650 -650
  99. package/bin/runners/lib/llm.js +75 -75
  100. package/bin/runners/lib/logger.js +38 -0
  101. package/bin/runners/lib/meter.js +61 -61
  102. package/bin/runners/lib/missions/evidence.js +126 -126
  103. package/bin/runners/lib/patch.js +40 -40
  104. package/bin/runners/lib/permissions/auth-model.js +213 -213
  105. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  106. package/bin/runners/lib/permissions/index.js +45 -45
  107. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  108. package/bin/runners/lib/pkgjson.js +28 -28
  109. package/bin/runners/lib/policy.js +295 -295
  110. package/bin/runners/lib/preflight.js +142 -142
  111. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  112. package/bin/runners/lib/reality/index.js +318 -318
  113. package/bin/runners/lib/reality/request-hashing.js +416 -416
  114. package/bin/runners/lib/reality/request-mapper.js +453 -453
  115. package/bin/runners/lib/reality/safety-rails.js +463 -463
  116. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  117. package/bin/runners/lib/reality/toast-detector.js +393 -393
  118. package/bin/runners/lib/reality-findings.js +84 -84
  119. package/bin/runners/lib/receipts.js +179 -179
  120. package/bin/runners/lib/redact.js +29 -29
  121. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  122. package/bin/runners/lib/replay/index.js +263 -263
  123. package/bin/runners/lib/replay/player.js +348 -348
  124. package/bin/runners/lib/replay/recorder.js +331 -331
  125. package/bin/runners/lib/report.js +135 -135
  126. package/bin/runners/lib/route-detection.js +1140 -1140
  127. package/bin/runners/lib/sandbox/index.js +59 -59
  128. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  129. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  130. package/bin/runners/lib/sandbox/worktree.js +174 -174
  131. package/bin/runners/lib/schema-validator.js +350 -350
  132. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  133. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  134. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  135. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  136. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  137. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  138. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  139. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  140. package/bin/runners/lib/schemas/validator.js +438 -438
  141. package/bin/runners/lib/score-history.js +282 -282
  142. package/bin/runners/lib/share-pack.js +239 -239
  143. package/bin/runners/lib/snippets.js +67 -67
  144. package/bin/runners/lib/unified-cli-output.js +604 -0
  145. package/bin/runners/lib/upsell.js +658 -510
  146. package/bin/runners/lib/usage.js +153 -153
  147. package/bin/runners/lib/validate-patch.js +156 -156
  148. package/bin/runners/lib/verdict-engine.js +628 -628
  149. package/bin/runners/reality/engine.js +917 -917
  150. package/bin/runners/reality/flows.js +122 -122
  151. package/bin/runners/reality/report.js +378 -378
  152. package/bin/runners/reality/session.js +193 -193
  153. package/bin/runners/runAgent.d.ts +5 -0
  154. package/bin/runners/runApprove.js +1200 -0
  155. package/bin/runners/runAuth.js +324 -95
  156. package/bin/runners/runCheckpoint.js +39 -21
  157. package/bin/runners/runClassify.js +859 -0
  158. package/bin/runners/runContext.js +136 -24
  159. package/bin/runners/runDoctor.js +108 -68
  160. package/bin/runners/runFirewall.d.ts +5 -0
  161. package/bin/runners/runFirewallHook.d.ts +5 -0
  162. package/bin/runners/runFix.js +6 -5
  163. package/bin/runners/runGuard.js +262 -168
  164. package/bin/runners/runInit.js +3 -2
  165. package/bin/runners/runMcp.js +130 -52
  166. package/bin/runners/runPolish.js +43 -20
  167. package/bin/runners/runProve.js +1 -2
  168. package/bin/runners/runReport.js +3 -2
  169. package/bin/runners/runScan.js +145 -44
  170. package/bin/runners/runShip.js +3 -4
  171. package/bin/runners/runTruth.d.ts +5 -0
  172. package/bin/runners/runValidate.js +19 -2
  173. package/bin/runners/runWatch.js +104 -53
  174. package/bin/vibecheck.js +106 -19
  175. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  176. package/mcp-server/agent-firewall-interceptor.js +367 -31
  177. package/mcp-server/authority-tools.js +569 -0
  178. package/mcp-server/conductor/conflict-resolver.js +588 -0
  179. package/mcp-server/conductor/execution-planner.js +544 -0
  180. package/mcp-server/conductor/index.js +377 -0
  181. package/mcp-server/conductor/lock-manager.js +615 -0
  182. package/mcp-server/conductor/request-queue.js +550 -0
  183. package/mcp-server/conductor/session-manager.js +500 -0
  184. package/mcp-server/conductor/tools.js +510 -0
  185. package/mcp-server/index.js +1199 -208
  186. package/mcp-server/lib/api-client.cjs +305 -0
  187. package/mcp-server/lib/logger.cjs +30 -0
  188. package/mcp-server/logger.js +173 -0
  189. package/mcp-server/package.json +2 -2
  190. package/mcp-server/premium-tools.js +2 -2
  191. package/mcp-server/tier-auth.js +351 -136
  192. package/mcp-server/tools/index.js +72 -72
  193. package/mcp-server/truth-firewall-tools.js +145 -15
  194. package/mcp-server/vibecheck-tools.js +2 -2
  195. package/package.json +2 -3
  196. package/mcp-server/index.old.js +0 -4137
  197. 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
+ };