@vibecheck-ai/mcp 24.6.8 → 24.6.11

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 (41) hide show
  1. package/README.md +1 -1
  2. package/dist/APITruthEngine-IZRR3NT5-LPFUOMLD.js +9 -0
  3. package/dist/CredentialsEngine-B66ANCBB-HY5ZQTSX.js +9 -0
  4. package/dist/EnvVarEngine-ZFNW2XKP-6HRTZULP.js +9 -0
  5. package/dist/ErrorHandlingEngine-VAHVDVFG-3GDGRN3U.js +11 -0
  6. package/dist/FrameworkPackEngine-RRBJW4MC-KH7WRXXS.js +12 -0
  7. package/dist/GhostRouteEngine-UMYBCOCL-MSZOPVZY.js +9 -0
  8. package/dist/LogicGapEngine-OK5UKZQ5-YGXZDERB.js +11 -0
  9. package/dist/PhantomDepEngine-HQEXAS25-TRVEXBMF.js +10 -0
  10. package/dist/SecurityEngine-MVMRPKLH-BNP7IC46.js +9 -0
  11. package/dist/VersionHallucinationEngine-673DJ26J-BD4SK6JX.js +9 -0
  12. package/dist/chokidar-CI5VJY5M.js +2414 -0
  13. package/dist/chunk-43XAAYST.js +863 -0
  14. package/dist/chunk-5DADZJ3D.js +650 -0
  15. package/dist/chunk-DDTUTWRY.js +605 -0
  16. package/dist/chunk-DGNNNAVK.js +304 -0
  17. package/dist/chunk-F34MHA6A.js +772 -0
  18. package/dist/chunk-FGMVY5QW.js +42 -0
  19. package/dist/chunk-G3FQJC2H.js +1968 -0
  20. package/dist/chunk-J52EUKKW.js +196 -0
  21. package/dist/chunk-JZSHXEYP.js +915 -0
  22. package/dist/chunk-LQSBUKYZ.js +551 -0
  23. package/dist/chunk-MUP4JXOF.js +219 -0
  24. package/dist/chunk-NR36RTVO.js +152 -0
  25. package/dist/chunk-QFDZMUGO.js +213300 -0
  26. package/dist/chunk-QGPX6H6L.js +3044 -0
  27. package/dist/chunk-QYXENOVK.js +499 -0
  28. package/dist/chunk-RNFMO5GH.js +8861 -0
  29. package/dist/chunk-RR5ETBSV.js +66 -0
  30. package/dist/chunk-YWUMPN4Z.js +53 -0
  31. package/dist/dist-HFMJ3GIR.js +1091 -0
  32. package/dist/dist-JUOVMQEA.js +9 -0
  33. package/dist/dist-NXITTS32-O3XLWR6T.js +386 -0
  34. package/dist/dist-OUJKMVTB.js +22 -0
  35. package/dist/fingerprint-NOJ7TDB6-K6SB7LCZ.js +9 -0
  36. package/dist/index.js +4735 -3577
  37. package/dist/semantic-WW6XVII4.js +8544 -0
  38. package/dist/transformers.node-K4WKH4PR.js +45809 -0
  39. package/dist/tree-sitter-AGICL65I.js +1412 -0
  40. package/dist/tree-sitter-H5E7LKR4-MKO3NNLJ.js +9 -0
  41. package/package.json +7 -6
@@ -0,0 +1,772 @@
1
+ import { createRequire } from 'module';
2
+ import { fileURLToPath } from 'url';
3
+ import * as path from 'path';
4
+ import { dirname } from 'path';
5
+ import { existsSync, readFileSync } from 'fs';
6
+
7
+ createRequire(import.meta.url);
8
+ const __filename$1 = fileURLToPath(import.meta.url);
9
+ dirname(__filename$1);
10
+ function deterministicId(uri, line, ruleId, library, apiName) {
11
+ const input = `vhal:${uri}::${line}::${ruleId}::${library}::${apiName}`;
12
+ let hash = 2166136261;
13
+ for (let i = 0; i < input.length; i++) {
14
+ hash ^= input.charCodeAt(i);
15
+ hash = hash * 16777619 >>> 0;
16
+ }
17
+ return `vhal-${hash.toString(16).padStart(8, "0")}`;
18
+ }
19
+ var VERSION_CHANGES = {
20
+ // ── Next.js ──────────────────────────────────────────────────────────────
21
+ next: [
22
+ { removed: "getServerSideProps", since: "13.0.0", replacement: "server components or route handlers" },
23
+ { removed: "getStaticProps", since: "13.0.0", replacement: "fetch in server components" },
24
+ { removed: "getStaticPaths", since: "13.0.0", replacement: "generateStaticParams" },
25
+ { removed: "getInitialProps", since: "13.0.0", replacement: "server components (app router)" },
26
+ { oldImport: "next/router", newImport: "next/navigation", since: "13.0.0" },
27
+ { oldImport: "next/image", newImport: "next/image (new component)", since: "13.0.0" },
28
+ { removed: "next/head", since: "13.0.0", replacement: "export const metadata or generateMetadata()" },
29
+ { hallucinated: "getServerProps", realMethod: "getServerSideProps (pages) or server components (app)" },
30
+ { hallucinated: "getProps", realMethod: "getServerSideProps or getStaticProps" },
31
+ { hallucinated: "useRouter().query", realMethod: "useSearchParams() in app router" },
32
+ { added: "useSearchParams", addedIn: "13.0.0" },
33
+ { added: "usePathname", addedIn: "13.0.0" },
34
+ { added: "generateMetadata", addedIn: "13.2.0" },
35
+ { added: "unstable_cache", addedIn: "14.0.0" }
36
+ ],
37
+ // ── React ────────────────────────────────────────────────────────────────
38
+ react: [
39
+ { removed: "componentWillMount", since: "17.0.0", replacement: "useEffect or constructor" },
40
+ { removed: "componentWillReceiveProps", since: "17.0.0", replacement: "getDerivedStateFromProps or useEffect" },
41
+ { removed: "componentWillUpdate", since: "17.0.0", replacement: "getSnapshotBeforeUpdate or useEffect" },
42
+ { removed: "createClass", since: "16.0.0", replacement: "class extends React.Component or function components" },
43
+ { removed: "PropTypes", since: "15.5.0", replacement: 'import PropTypes from "prop-types" or TypeScript' },
44
+ { added: "useId", addedIn: "18.0.0" },
45
+ { added: "useDeferredValue", addedIn: "18.0.0" },
46
+ { added: "useTransition", addedIn: "18.0.0" },
47
+ { added: "useSyncExternalStore", addedIn: "18.0.0" },
48
+ { added: "useOptimistic", addedIn: "19.0.0" },
49
+ { added: "useActionState", addedIn: "19.0.0" },
50
+ { added: "use", addedIn: "19.0.0" },
51
+ { hallucinated: "useFormState", realMethod: "useActionState (React 19) \u2014 useFormState was renamed" },
52
+ { hallucinated: "React.render", realMethod: "ReactDOM.createRoot(el).render(<App />)" },
53
+ { hallucinated: "React.createContext().useContext", realMethod: "useContext(MyContext)" }
54
+ ],
55
+ // ── React DOM ────────────────────────────────────────────────────────────
56
+ "react-dom": [
57
+ { removed: "render", since: "18.0.0", replacement: "createRoot().render()" },
58
+ { removed: "hydrate", since: "18.0.0", replacement: "hydrateRoot()" },
59
+ { removed: "unmountComponentAtNode", since: "18.0.0", replacement: "root.unmount()" },
60
+ { removed: "findDOMNode", since: "18.0.0", replacement: "useRef" },
61
+ { added: "createRoot", addedIn: "18.0.0" },
62
+ { added: "hydrateRoot", addedIn: "18.0.0" },
63
+ { added: "preload", addedIn: "19.0.0" },
64
+ { added: "prefetchDNS", addedIn: "19.0.0" },
65
+ { added: "preconnect", addedIn: "19.0.0" }
66
+ ],
67
+ // ── React Router ─────────────────────────────────────────────────────────
68
+ "react-router-dom": [
69
+ { removed: "Switch", since: "6.0.0", replacement: "Routes" },
70
+ { removed: "Redirect", since: "6.0.0", replacement: "Navigate" },
71
+ { removed: "useHistory", since: "6.0.0", replacement: "useNavigate" },
72
+ { removed: "useRouteMatch", since: "6.0.0", replacement: "useMatch" },
73
+ { removed: "withRouter", since: "6.0.0", replacement: "useNavigate, useParams, useLocation hooks" },
74
+ { oldImport: "react-router-dom", newImport: "react-router", since: "7.0.0" },
75
+ { added: "createBrowserRouter", addedIn: "6.4.0" },
76
+ { added: "RouterProvider", addedIn: "6.4.0" },
77
+ { added: "useLoaderData", addedIn: "6.4.0" },
78
+ { hallucinated: "useRouter", realMethod: "useNavigate (React Router) or useRouter (Next.js)" }
79
+ ],
80
+ // ── Prisma ───────────────────────────────────────────────────────────────
81
+ prisma: [
82
+ { hallucinated: "findOne", realMethod: "findUnique or findFirst" },
83
+ { hallucinated: "getAll", realMethod: "findMany" },
84
+ { hallucinated: "getById", realMethod: "findUnique" },
85
+ { hallucinated: "fetchAll", realMethod: "findMany" },
86
+ { hallucinated: "fetchOne", realMethod: "findUnique or findFirst" },
87
+ { hallucinated: "insert", realMethod: "create" },
88
+ { hallucinated: "save", realMethod: "create or update" },
89
+ { hallucinated: "remove", realMethod: "delete" },
90
+ { hallucinated: "destroy", realMethod: "delete" },
91
+ { hallucinated: "updateAll", realMethod: "updateMany" },
92
+ { hallucinated: "removeAll", realMethod: "deleteMany" },
93
+ { hallucinated: "search", realMethod: "findMany({ where: { ... } })" },
94
+ { hallucinated: "query", realMethod: "$queryRaw or $queryRawUnsafe" },
95
+ { hallucinated: "raw", realMethod: "$queryRaw" },
96
+ { hallucinated: "bulkCreate", realMethod: "createMany" },
97
+ { hallucinated: "bulkUpdate", realMethod: "updateMany" }
98
+ ],
99
+ // ── Mongoose ─────────────────────────────────────────────────────────────
100
+ mongoose: [
101
+ { removed: "remove", since: "7.0.0", replacement: "deleteOne or deleteMany" },
102
+ { removed: "update", since: "7.0.0", replacement: "updateOne or updateMany" },
103
+ { removed: "count", since: "7.0.0", replacement: "countDocuments" },
104
+ { removed: "findAndModify", since: "7.0.0", replacement: "findOneAndUpdate" },
105
+ { hallucinated: "getById", realMethod: "findById" },
106
+ { hallucinated: "findAll", realMethod: "find" },
107
+ { hallucinated: "insert", realMethod: "create or insertMany" },
108
+ { hallucinated: "destroy", realMethod: "deleteOne or deleteMany" },
109
+ { hallucinated: "save", realMethod: "doc.save() (instance method) or create (static)" }
110
+ ],
111
+ // ── Axios ────────────────────────────────────────────────────────────────
112
+ axios: [
113
+ { hallucinated: "axios.fetch", realMethod: "axios.get or axios.request" },
114
+ { hallucinated: "axios.send", realMethod: "axios.post or axios.request" },
115
+ { hallucinated: "axios.call", realMethod: "axios.request" },
116
+ { hallucinated: "axios.query", realMethod: "axios.get with params" },
117
+ { hallucinated: "axios.setHeader", realMethod: 'axios.defaults.headers.common["X-Header"] = val' },
118
+ { hallucinated: "axios.setBaseURL", realMethod: "axios.defaults.baseURL = url" },
119
+ { hallucinated: "axios.abort", realMethod: "AbortController with signal option" }
120
+ ],
121
+ // ── Lodash ───────────────────────────────────────────────────────────────
122
+ lodash: [
123
+ { hallucinated: "lodash.contains", realMethod: "lodash.includes" },
124
+ { hallucinated: "lodash.pluck", realMethod: "lodash.map with iteratee shorthand" },
125
+ { hallucinated: "lodash.first", realMethod: "lodash.head" },
126
+ { hallucinated: "lodash.last", realMethod: "lodash.last (this one exists!)" },
127
+ { hallucinated: "lodash.where", realMethod: "lodash.filter" },
128
+ { hallucinated: "lodash.any", realMethod: "lodash.some" },
129
+ { hallucinated: "lodash.all", realMethod: "lodash.every" },
130
+ { hallucinated: "lodash.collect", realMethod: "lodash.map" },
131
+ { hallucinated: "lodash.detect", realMethod: "lodash.find" },
132
+ { hallucinated: "lodash.select", realMethod: "lodash.filter" }
133
+ ],
134
+ // ── Zod ──────────────────────────────────────────────────────────────────
135
+ zod: [
136
+ { hallucinated: "z.validate", realMethod: "z.parse or z.safeParse" },
137
+ { hallucinated: "z.check", realMethod: "z.refine or z.superRefine" },
138
+ { hallucinated: "z.assert", realMethod: "z.parse (throws) or z.safeParse (returns result)" },
139
+ { hallucinated: "z.isValid", realMethod: "schema.safeParse(data).success" },
140
+ { hallucinated: "z.create", realMethod: "z.object, z.string, z.number, etc." },
141
+ { hallucinated: "z.define", realMethod: "z.object({...})" },
142
+ { hallucinated: "z.schema", realMethod: "z.object({...})" },
143
+ { hallucinated: "z.required", realMethod: "field is required by default; use .optional() to make optional" }
144
+ ],
145
+ // ── TanStack Query ───────────────────────────────────────────────────────
146
+ "@tanstack/react-query": [
147
+ { removed: "useQuery(key, fn)", since: "5.0.0", replacement: "useQuery({ queryKey, queryFn })" },
148
+ { removed: "useMutation(fn)", since: "5.0.0", replacement: "useMutation({ mutationFn })" },
149
+ { removed: "useInfiniteQuery(key, fn)", since: "5.0.0", replacement: "useInfiniteQuery({ queryKey, queryFn, ... })" },
150
+ { removed: "onSuccess", since: "5.0.0", replacement: "use the returned data in useEffect or handle in mutate callbacks" },
151
+ { removed: "onError", since: "5.0.0", replacement: "use the returned error in useEffect or handle in mutate callbacks" },
152
+ { removed: "onSettled", since: "5.0.0", replacement: "handle in mutate callbacks" },
153
+ { hallucinated: "useQueryClient().fetch", realMethod: "queryClient.fetchQuery or queryClient.prefetchQuery" },
154
+ { hallucinated: "useQuery().refetch()", realMethod: "const { refetch } = useQuery(...); refetch()" }
155
+ ],
156
+ // ── Express ──────────────────────────────────────────────────────────────
157
+ express: [
158
+ { removed: "app.del", since: "4.0.0", replacement: "app.delete" },
159
+ { removed: "app.configure", since: "4.0.0", replacement: "use if/else with process.env.NODE_ENV" },
160
+ { removed: "express.createServer", since: "4.0.0", replacement: "express()" },
161
+ { removed: "express.bodyParser", since: "4.0.0", replacement: "express.json() and express.urlencoded()" },
162
+ { removed: "express.cookieParser", since: "4.0.0", replacement: "npm install cookie-parser" },
163
+ { removed: "express.session", since: "4.0.0", replacement: "npm install express-session" },
164
+ { hallucinated: "app.handle", realMethod: "app.use or app.get/post/put/delete" },
165
+ { hallucinated: "app.serve", realMethod: "app.use(express.static(path))" },
166
+ { hallucinated: "app.mount", realMethod: "app.use(path, router)" },
167
+ { hallucinated: "app.register", realMethod: "app.use(middleware) or app.get/post(path, handler)" },
168
+ { hallucinated: "app.start", realMethod: "app.listen(port, callback)" },
169
+ { hallucinated: "res.json()", realMethod: "res.json(data) \u2014 requires an argument" },
170
+ { hallucinated: "res.sendJSON", realMethod: "res.json(data)" },
171
+ { hallucinated: "res.render()", realMethod: "res.render(view, locals) \u2014 requires view name" }
172
+ ],
173
+ // ── Fastify ──────────────────────────────────────────────────────────────
174
+ fastify: [
175
+ { removed: "fastify.use", since: "4.0.0", replacement: "@fastify/middie or @fastify/express for middleware compat" },
176
+ { hallucinated: "fastify.listen(port)", realMethod: "fastify.listen({ port, host })" },
177
+ { hallucinated: "fastify.start", realMethod: "fastify.listen({ port })" },
178
+ { hallucinated: "fastify.handle", realMethod: "fastify.route or fastify.get/post/put/delete" },
179
+ { hallucinated: "reply.json", realMethod: "reply.send(data) \u2014 Fastify auto-serializes objects" },
180
+ { hallucinated: "reply.render", realMethod: "reply.view(template, data) with @fastify/view" }
181
+ ],
182
+ // ── tRPC ─────────────────────────────────────────────────────────────────
183
+ "@trpc/server": [
184
+ { removed: "createRouter", since: "10.0.0", replacement: "router (from initTRPC.create())" },
185
+ { removed: ".query(resolver)", since: "10.0.0", replacement: ".query(({ input, ctx }) => ...)" },
186
+ { removed: ".mutation(resolver)", since: "10.0.0", replacement: ".mutation(({ input, ctx }) => ...)" },
187
+ { removed: "createSSGHelpers", since: "10.0.0", replacement: "createServerSideHelpers" },
188
+ { hallucinated: "trpc.procedure", realMethod: "publicProcedure or protectedProcedure (from your trpc setup)" },
189
+ { hallucinated: "trpc.route", realMethod: "router({ routeName: procedure.query/mutation })" }
190
+ ],
191
+ // ── Zustand ──────────────────────────────────────────────────────────────
192
+ zustand: [
193
+ { removed: "create(set => ...)", since: "5.0.0", replacement: "createStore (Zustand 5) or create()((set) => ...)" },
194
+ { hallucinated: "useStore.getState", realMethod: "useStore.getState() \u2014 works, but called as a function" },
195
+ { hallucinated: "zustand.createStore", realMethod: 'import { create } from "zustand"' },
196
+ { hallucinated: "useStore.dispatch", realMethod: "actions defined in the store, e.g. useStore(s => s.increment)" },
197
+ { hallucinated: "useStore.subscribe", realMethod: "useStore.subscribe(listener) \u2014 returns unsubscribe" }
198
+ ],
199
+ // ── SWR ──────────────────────────────────────────────────────────────────
200
+ swr: [
201
+ { removed: "useSWR(key, fetcher, config)", since: "2.0.0", replacement: "useSWR(key, fetcher, config) \u2014 API unchanged but options renamed" },
202
+ { hallucinated: "useSWR().revalidate", realMethod: "useSWR().mutate() \u2014 revalidate was renamed to mutate" },
203
+ { hallucinated: "swr.fetch", realMethod: "useSWR(key, fetcher)" },
204
+ { hallucinated: "swr.cache", realMethod: 'import { cache } from "swr" or useSWRConfig().cache' },
205
+ { hallucinated: "useSWR().loading", realMethod: "useSWR().isLoading or useSWR().isValidating" }
206
+ ],
207
+ // ── NextAuth / Auth.js ───────────────────────────────────────────────────
208
+ "next-auth": [
209
+ { removed: "getSession", since: "5.0.0", replacement: "auth() from next-auth" },
210
+ { removed: "getServerSession", since: "5.0.0", replacement: "auth() from next-auth" },
211
+ { removed: "useSession().loading", since: "4.0.0", replacement: 'useSession().status === "loading"' },
212
+ { oldImport: "next-auth/react", newImport: "next-auth/react", since: "5.0.0" },
213
+ { oldImport: "next-auth/jwt", newImport: "next-auth", since: "5.0.0" },
214
+ { hallucinated: "NextAuth.configure", realMethod: "NextAuth({ providers: [...], ... })" },
215
+ { hallucinated: "signIn(provider, redirect)", realMethod: "signIn(provider, { redirectTo })" }
216
+ ],
217
+ // ── Drizzle ORM ──────────────────────────────────────────────────────────
218
+ "drizzle-orm": [
219
+ { hallucinated: "db.findMany", realMethod: "db.select().from(table)" },
220
+ { hallucinated: "db.findOne", realMethod: "db.select().from(table).where(...).limit(1)" },
221
+ { hallucinated: "db.findUnique", realMethod: "db.select().from(table).where(eq(table.id, id))" },
222
+ { hallucinated: "db.create", realMethod: "db.insert(table).values(data)" },
223
+ { hallucinated: "db.update(table, data)", realMethod: "db.update(table).set(data).where(...)" },
224
+ { hallucinated: "db.remove", realMethod: "db.delete(table).where(...)" },
225
+ { hallucinated: "db.destroy", realMethod: "db.delete(table).where(...)" },
226
+ { hallucinated: "db.query", realMethod: "db.select().from(table) or db.execute(sql`...`)" },
227
+ { hallucinated: "db.raw", realMethod: "db.execute(sql`...`)" }
228
+ ],
229
+ // ── TypeORM ──────────────────────────────────────────────────────────────
230
+ typeorm: [
231
+ { hallucinated: "repository.findAll", realMethod: "repository.find()" },
232
+ { hallucinated: "repository.findById", realMethod: "repository.findOneBy({ id })" },
233
+ { hallucinated: "repository.get", realMethod: "repository.findOneBy or repository.findOne" },
234
+ { hallucinated: "repository.insert", realMethod: "repository.save(entity) or repository.insert(data)" },
235
+ { hallucinated: "repository.destroy", realMethod: "repository.remove(entity) or repository.delete(id)" },
236
+ { hallucinated: "repository.updateById", realMethod: "repository.update(id, data)" },
237
+ { removed: "findOne(id)", since: "0.3.0", replacement: "findOneBy({ id }) \u2014 findOne no longer accepts a plain ID" },
238
+ { removed: "find({ where: string })", since: "0.3.0", replacement: "find({ where: { column: value } })" }
239
+ ],
240
+ // ── Sequelize ────────────────────────────────────────────────────────────
241
+ sequelize: [
242
+ { hallucinated: "Model.get", realMethod: "Model.findOne or Model.findByPk" },
243
+ { hallucinated: "Model.insert", realMethod: "Model.create" },
244
+ { hallucinated: "Model.remove", realMethod: "Model.destroy or instance.destroy()" },
245
+ { hallucinated: "Model.delete", realMethod: "Model.destroy({ where: { ... } })" },
246
+ { hallucinated: "Model.updateAll", realMethod: "Model.update(values, { where: { ... } })" },
247
+ { hallucinated: "Model.fetch", realMethod: "Model.findAll or Model.findOne" },
248
+ { hallucinated: "Model.search", realMethod: "Model.findAll({ where: { ... } })" }
249
+ ],
250
+ // ── Socket.io ────────────────────────────────────────────────────────────
251
+ "socket.io": [
252
+ { removed: "io.set", since: "1.0.0", replacement: "pass options to Server constructor" },
253
+ { removed: "io.sockets.on", since: "3.0.0", replacement: 'io.on("connection", ...)' },
254
+ { hallucinated: "socket.send", realMethod: "socket.emit(event, data)" },
255
+ { hallucinated: "socket.broadcast", realMethod: "socket.broadcast.emit(event, data)" },
256
+ { hallucinated: "io.listen", realMethod: "new Server(httpServer) or io.attach(httpServer)" }
257
+ ],
258
+ // ── date-fns ─────────────────────────────────────────────────────────────
259
+ "date-fns": [
260
+ { hallucinated: "dateFns.format", realMethod: 'import { format } from "date-fns" \u2014 named imports only' },
261
+ { hallucinated: "dateFns.parse", realMethod: 'import { parse } from "date-fns"' },
262
+ { hallucinated: 'format(date, "YYYY-MM-DD")', realMethod: 'format(date, "yyyy-MM-dd") \u2014 lowercase year tokens' },
263
+ { hallucinated: 'format(date, "DD/MM/YYYY")', realMethod: 'format(date, "dd/MM/yyyy") \u2014 lowercase day/year' }
264
+ ],
265
+ // ── dayjs ────────────────────────────────────────────────────────────────
266
+ dayjs: [
267
+ { hallucinated: "dayjs.now", realMethod: "dayjs() \u2014 no .now() method" },
268
+ { hallucinated: "dayjs.parse", realMethod: "dayjs(dateString) or dayjs(dateString, format) with customParseFormat plugin" },
269
+ { hallucinated: "dayjs().toDate()", realMethod: "dayjs().toDate() \u2014 this one actually exists!" },
270
+ { hallucinated: "dayjs.duration", realMethod: "dayjs.duration() requires the duration plugin" },
271
+ { hallucinated: "dayjs().diff().humanize", realMethod: "dayjs().fromNow() with relativeTime plugin" }
272
+ ],
273
+ // ── Hono ─────────────────────────────────────────────────────────────────
274
+ hono: [
275
+ { hallucinated: "app.listen", realMethod: "serve(app) from @hono/node-server, or export default app for edge" },
276
+ { hallucinated: "app.start", realMethod: "serve({ fetch: app.fetch, port }) from @hono/node-server" },
277
+ { hallucinated: "c.json()", realMethod: "c.json(data) \u2014 requires data argument" },
278
+ { hallucinated: "c.sendJSON", realMethod: "c.json(data)" },
279
+ { hallucinated: "c.render", realMethod: "c.html(content) or use JSX middleware" },
280
+ { hallucinated: "app.register", realMethod: "app.route(path, subApp) or app.use(middleware)" }
281
+ ],
282
+ // ── Supabase ────────────────────────────────────────────────────────────
283
+ "@supabase/supabase-js": [
284
+ { hallucinated: "supabase.query", realMethod: "supabase.from(table).select()" },
285
+ { hallucinated: "supabase.insert", realMethod: "supabase.from(table).insert(data)" },
286
+ { hallucinated: "supabase.update", realMethod: "supabase.from(table).update(data).eq(col, val)" },
287
+ { hallucinated: "supabase.delete", realMethod: "supabase.from(table).delete().eq(col, val)" },
288
+ { hallucinated: "supabase.find", realMethod: "supabase.from(table).select().eq(col, val)" },
289
+ { hallucinated: "supabase.findOne", realMethod: "supabase.from(table).select().eq(col, val).single()" },
290
+ { hallucinated: "supabase.getUser", realMethod: "supabase.auth.getUser()" },
291
+ { hallucinated: "supabase.signIn", realMethod: "supabase.auth.signInWithPassword({ email, password })" },
292
+ { hallucinated: "supabase.signUp", realMethod: "supabase.auth.signUp({ email, password })" },
293
+ { hallucinated: "supabase.signOut", realMethod: "supabase.auth.signOut()" },
294
+ { hallucinated: "supabase.onAuthStateChange", realMethod: "supabase.auth.onAuthStateChange(callback)" },
295
+ { hallucinated: "supabase.storage.upload", realMethod: "supabase.storage.from(bucket).upload(path, file)" },
296
+ { hallucinated: "supabase.rpc", realMethod: "supabase.rpc(fnName, params) \u2014 this one exists! verify your fn name." }
297
+ ],
298
+ // ── Firebase ────────────────────────────────────────────────────────────
299
+ firebase: [
300
+ { hallucinated: "firebase.auth().signIn", realMethod: "signInWithEmailAndPassword(auth, email, password) \u2014 modular v9+ API" },
301
+ { hallucinated: "firebase.auth().createUser", realMethod: "createUserWithEmailAndPassword(auth, email, password)" },
302
+ { hallucinated: "firebase.auth().signOut", realMethod: "signOut(auth)" },
303
+ { hallucinated: "firebase.firestore().get", realMethod: "getDoc(docRef) or getDocs(query)" },
304
+ { hallucinated: "firebase.firestore().add", realMethod: "addDoc(collectionRef, data)" },
305
+ { hallucinated: "firebase.firestore().set", realMethod: "setDoc(docRef, data)" },
306
+ { hallucinated: "firebase.firestore().update", realMethod: "updateDoc(docRef, data)" },
307
+ { hallucinated: "firebase.firestore().delete", realMethod: "deleteDoc(docRef)" },
308
+ { removed: "firebase.initializeApp", since: "9.0.0", replacement: 'import { initializeApp } from "firebase/app" \u2014 modular SDK' },
309
+ { removed: "firebase.auth()", since: "9.0.0", replacement: 'import { getAuth } from "firebase/auth"' },
310
+ { removed: "firebase.firestore()", since: "9.0.0", replacement: 'import { getFirestore } from "firebase/firestore"' },
311
+ { removed: "firebase.storage()", since: "9.0.0", replacement: 'import { getStorage } from "firebase/storage"' },
312
+ { oldImport: "firebase/app", newImport: "firebase/app", since: "9.0.0" }
313
+ ],
314
+ // ── Stripe (Node SDK) ──────────────────────────────────────────────────
315
+ stripe: [
316
+ { hallucinated: "stripe.createPayment", realMethod: "stripe.paymentIntents.create({ amount, currency })" },
317
+ { hallucinated: "stripe.charge", realMethod: "stripe.charges.create or stripe.paymentIntents.create" },
318
+ { hallucinated: "stripe.createCustomer", realMethod: "stripe.customers.create({ email })" },
319
+ { hallucinated: "stripe.getCustomer", realMethod: "stripe.customers.retrieve(id)" },
320
+ { hallucinated: "stripe.createSubscription", realMethod: "stripe.subscriptions.create({ customer, items })" },
321
+ { hallucinated: "stripe.createCheckout", realMethod: "stripe.checkout.sessions.create({ ... })" },
322
+ { hallucinated: "stripe.verifyWebhook", realMethod: "stripe.webhooks.constructEvent(body, sig, secret)" },
323
+ { hallucinated: "stripe.createProduct", realMethod: "stripe.products.create({ name })" },
324
+ { hallucinated: "stripe.createPrice", realMethod: "stripe.prices.create({ unit_amount, currency, product })" },
325
+ { hallucinated: "stripe.getInvoice", realMethod: "stripe.invoices.retrieve(id)" },
326
+ { hallucinated: "stripe.createPortal", realMethod: "stripe.billingPortal.sessions.create({ customer })" }
327
+ ],
328
+ // ── Clerk ──────────────────────────────────────────────────────────────
329
+ "@clerk/nextjs": [
330
+ { hallucinated: "useAuth().user", realMethod: "useUser() for user data; useAuth() for session/token" },
331
+ { hallucinated: "useAuth().signIn", realMethod: "useSignIn() hook" },
332
+ { hallucinated: "useAuth().signUp", realMethod: "useSignUp() hook" },
333
+ { hallucinated: "getAuth(req).user", realMethod: "currentUser() for user data; auth() for session claims" },
334
+ { hallucinated: "auth().user", realMethod: "currentUser() in server components" },
335
+ { removed: "withClerkMiddleware", since: "4.0.0", replacement: "clerkMiddleware()" },
336
+ { removed: "authMiddleware", since: "5.0.0", replacement: "clerkMiddleware()" }
337
+ ],
338
+ // ── Tailwind CSS ───────────────────────────────────────────────────────
339
+ tailwindcss: [
340
+ { removed: "purge", since: "3.0.0", replacement: "content (in tailwind.config.js)" },
341
+ { removed: 'mode: "jit"', since: "3.0.0", replacement: "JIT is default in v3+" },
342
+ { removed: 'darkMode: "media"', since: "4.0.0", replacement: "dark: variant selector (v4 uses CSS-first config)" },
343
+ { removed: "tailwind.config.js", since: "4.0.0", replacement: "@theme directive in CSS (v4 is CSS-first)" }
344
+ ],
345
+ // ── Vite ───────────────────────────────────────────────────────────────
346
+ vite: [
347
+ { removed: "defineConfig", since: "6.0.0", replacement: "export default { ... } \u2014 defineConfig still works but Environment API changed" },
348
+ { hallucinated: "vite.createServer", realMethod: 'createServer from "vite" \u2014 import { createServer } from "vite"' },
349
+ { hallucinated: "vite.build", realMethod: 'import { build } from "vite"' }
350
+ ],
351
+ // ── OpenAI (Node SDK) ───────────────────────────────────────────────────
352
+ openai: [
353
+ { removed: "createChatCompletion", since: "4.0.0", replacement: "chat.completions.create()" },
354
+ { removed: "createCompletion", since: "4.0.0", replacement: "completions.create()" },
355
+ { removed: "createTranscription", since: "4.0.0", replacement: "audio.transcriptions.create()" },
356
+ { removed: "OpenAIApi", since: "4.0.0", replacement: "new OpenAI({ apiKey })" },
357
+ { removed: "Configuration", since: "4.0.0", replacement: "pass options to OpenAI constructor" },
358
+ { hallucinated: "openai.chat", realMethod: "openai.chat.completions.create({ model, messages })" },
359
+ { hallucinated: "openai.complete", realMethod: "openai.completions.create or openai.chat.completions.create" },
360
+ { hallucinated: "openai.generate", realMethod: "openai.chat.completions.create or openai.completions.create" },
361
+ { hallucinated: "openai.create", realMethod: "openai.chat.completions.create, openai.completions.create, etc." },
362
+ { hallucinated: "openai.embed", realMethod: "openai.embeddings.create" },
363
+ { hallucinated: "openai.transcribe", realMethod: "openai.audio.transcriptions.create" }
364
+ ],
365
+ // ── Vercel AI SDK ──────────────────────────────────────────────────────
366
+ ai: [
367
+ { hallucinated: "ai.generate", realMethod: 'generateText() or streamText() from "ai" package' },
368
+ { hallucinated: "ai.chat", realMethod: "useChat() hook or streamText()" },
369
+ { hallucinated: "ai.complete", realMethod: "generateText() or streamText()" },
370
+ { hallucinated: "ai.stream", realMethod: "streamText()" },
371
+ { hallucinated: "ai.embed", realMethod: "embed() from @ai-sdk/openai or similar provider" },
372
+ { hallucinated: "useAI", realMethod: "useChat() for chat UI; useCompletion() for single completion" }
373
+ ],
374
+ // ── Resend (email API) ───────────────────────────────────────────────────
375
+ resend: [
376
+ { hallucinated: "resend.send", realMethod: "resend.emails.send({ from, to, subject, html })" },
377
+ { hallucinated: "resend.sendEmail", realMethod: "resend.emails.send()" },
378
+ { hallucinated: "resend.create", realMethod: "resend.emails.send()" },
379
+ { hallucinated: "resend.email", realMethod: "resend.emails.send()" },
380
+ { hallucinated: "resend.deliver", realMethod: "resend.emails.send()" }
381
+ ],
382
+ // ── Playwright ─────────────────────────────────────────────────────────
383
+ "@playwright/test": [
384
+ { hallucinated: "page.click", realMethod: "page.locator(selector).click() \u2014 locator API preferred since v1.14" },
385
+ { hallucinated: "page.fill", realMethod: "page.locator(selector).fill(value)" },
386
+ { hallucinated: "page.type", realMethod: "page.locator(selector).pressSequentially(text) \u2014 type() is deprecated" },
387
+ { hallucinated: "page.$(selector)", realMethod: "page.locator(selector) \u2014 $ API is discouraged" },
388
+ { hallucinated: "page.$$(selector)", realMethod: "page.locator(selector) \u2014 use locator.all()" },
389
+ { hallucinated: "page.waitForSelector", realMethod: "page.locator(selector).waitFor() or expect(locator).toBeVisible()" },
390
+ { hallucinated: "page.waitForNavigation", realMethod: "page.waitForURL(url) or await Promise.all([page.waitForURL(), click])" }
391
+ ]
392
+ };
393
+ function escapeRegex(str) {
394
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
395
+ }
396
+ function buildPatterns() {
397
+ const patterns = [];
398
+ for (const [lib, changes] of Object.entries(VERSION_CHANGES)) {
399
+ for (const change of changes) {
400
+ if (change.hallucinated) {
401
+ let patternPart = change.hallucinated;
402
+ if (lib === "lodash" && patternPart.startsWith("lodash.")) {
403
+ patternPart = patternPart.slice(7);
404
+ } else if (lib === "zod" && patternPart.startsWith("z.")) {
405
+ patternPart = patternPart.slice(2);
406
+ }
407
+ const escaped = escapeRegex(patternPart);
408
+ let regex;
409
+ if (lib === "prisma") {
410
+ regex = new RegExp(`(?:prisma|db|client)\\.\\w+\\.${escaped}\\s*\\(`);
411
+ } else if (lib === "axios") {
412
+ regex = new RegExp(`${escaped}\\s*\\(`);
413
+ } else if (lib === "lodash") {
414
+ regex = new RegExp(`(?:_|lodash)\\.${escaped}\\s*\\(`);
415
+ } else if (lib === "zod") {
416
+ regex = new RegExp(`z\\.${escaped}\\s*[(<]`);
417
+ } else if (lib === "drizzle-orm") {
418
+ regex = new RegExp(`(?:db|drizzle)\\.${escaped}\\s*[(<]`);
419
+ } else if (lib === "typeorm") {
420
+ regex = new RegExp(`(?:repository|repo|manager)\\.${escaped}\\s*\\(`);
421
+ } else if (lib === "sequelize") {
422
+ regex = new RegExp(`(?:Model|\\w+Model|\\w+)\\.${escaped}\\s*\\(`);
423
+ } else if (lib === "swr") {
424
+ regex = new RegExp(`${escaped}\\s*[(<]`);
425
+ } else if (lib === "hono") {
426
+ regex = new RegExp(`(?:app|c)\\.${escaped}\\s*\\(`);
427
+ } else if (lib === "fastify") {
428
+ regex = new RegExp(`(?:fastify|server|app|reply)\\.${escaped}\\s*\\(`);
429
+ } else if (lib === "dayjs") {
430
+ regex = new RegExp(`dayjs(?:\\([^)]*\\))?\\.${escaped}\\s*[(<]`);
431
+ } else if (lib === "date-fns") {
432
+ regex = new RegExp(`dateFns\\.${escaped}\\s*\\(`);
433
+ } else if (lib === "socket.io") {
434
+ regex = new RegExp(`(?:io|socket)\\.${escaped}\\s*\\(`);
435
+ } else if (lib === "express") {
436
+ regex = new RegExp(`(?:app|router|express|res)\\.${escaped}\\s*\\(`);
437
+ } else if (lib === "zustand") {
438
+ regex = new RegExp(`(?:useStore|store|zustand)\\.${escaped}\\b`);
439
+ } else if (lib === "@supabase/supabase-js") {
440
+ regex = new RegExp(`(?:supabase|client|sb)\\.${escaped}\\s*\\(`);
441
+ } else if (lib === "firebase") {
442
+ regex = new RegExp(`(?:firebase|app|auth|db|firestore|storage)\\.${escaped}\\s*\\(`);
443
+ } else if (lib === "stripe") {
444
+ regex = new RegExp(`(?:stripe|stripeClient)\\.${escaped}\\s*\\(`);
445
+ } else if (lib === "@clerk/nextjs") {
446
+ regex = new RegExp(`(?:useAuth|auth|clerk|getAuth)(?:\\([^)]*\\))?\\.${escaped}\\b`);
447
+ } else if (lib === "@playwright/test") {
448
+ regex = new RegExp(`(?:page|browser|context)\\.${escaped}\\s*\\(`);
449
+ } else if (lib === "openai") {
450
+ const methodPart = patternPart.includes(".") ? patternPart.split(".").pop() : patternPart;
451
+ regex = new RegExp(`(?:openai|client|api)\\.${escapeRegex(methodPart)}\\s*\\(`);
452
+ } else if (lib === "ai") {
453
+ if (patternPart.startsWith("use")) {
454
+ regex = new RegExp(`(?:^|[^a-zA-Z0-9_])${escaped}\\s*\\(`);
455
+ } else {
456
+ const methodPart = patternPart.includes(".") ? patternPart.split(".").pop() : patternPart;
457
+ regex = new RegExp(`(?:ai|client)\\.${escapeRegex(methodPart)}\\s*\\(`);
458
+ }
459
+ } else if (lib === "resend") {
460
+ const methodPart = patternPart.includes(".") ? patternPart.split(".").pop() : patternPart;
461
+ regex = new RegExp(`(?:resend|client)\\.${escapeRegex(methodPart)}\\s*\\(`);
462
+ } else {
463
+ regex = new RegExp(`\\.${escaped}\\s*\\(`);
464
+ }
465
+ patterns.push({
466
+ ruleId: "VHAL004",
467
+ library: lib,
468
+ regex,
469
+ change,
470
+ severity: "critical",
471
+ confidence: 0.92
472
+ });
473
+ }
474
+ if (change.removed && change.since) {
475
+ const escaped = escapeRegex(change.removed);
476
+ patterns.push({
477
+ ruleId: "VHAL001",
478
+ library: lib,
479
+ regex: new RegExp(`(?:^|[^a-zA-Z0-9_])${escaped}(?:\\s*\\(|\\s*=|[^a-zA-Z0-9_])`),
480
+ change,
481
+ severity: "high",
482
+ confidence: 0.75
483
+ });
484
+ }
485
+ if (change.oldImport && change.newImport && change.since) {
486
+ const escaped = escapeRegex(change.oldImport);
487
+ patterns.push({
488
+ ruleId: "VHAL003",
489
+ library: lib,
490
+ regex: new RegExp(`(?:from|import)\\s+['"]${escaped}['"]`),
491
+ change,
492
+ severity: "medium",
493
+ confidence: 0.85
494
+ });
495
+ }
496
+ if (change.added && change.addedIn) {
497
+ const escaped = escapeRegex(change.added);
498
+ patterns.push({
499
+ ruleId: "VHAL002",
500
+ library: lib,
501
+ regex: new RegExp(`(?:^|[^a-zA-Z0-9_])${escaped}\\s*\\(`),
502
+ change: { ...change, since: change.addedIn },
503
+ severity: "high",
504
+ confidence: 0.7
505
+ });
506
+ }
507
+ }
508
+ }
509
+ return patterns;
510
+ }
511
+ var COMPILED_PATTERNS = buildPatterns();
512
+ function parseSemver(version) {
513
+ const cleaned = version.replace(/^[~^>=<\s]+/, "");
514
+ const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)/);
515
+ if (!match) return null;
516
+ return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)];
517
+ }
518
+ function semverGte(installed, threshold) {
519
+ const inst = parseSemver(installed);
520
+ const thresh = parseSemver(threshold);
521
+ if (!inst || !thresh) return false;
522
+ if (inst[0] !== thresh[0]) return inst[0] > thresh[0];
523
+ if (inst[1] !== thresh[1]) return inst[1] > thresh[1];
524
+ return inst[2] >= thresh[2];
525
+ }
526
+ function semverLt(installed, threshold) {
527
+ return !semverGte(installed, threshold);
528
+ }
529
+ var _projectRootCache = /* @__PURE__ */ new Map();
530
+ function findProjectRoot(filePath) {
531
+ const startDir = path.dirname(filePath);
532
+ const cached = _projectRootCache.get(startDir);
533
+ if (cached !== void 0) return cached;
534
+ let dir = startDir;
535
+ for (let i = 0; i < 20; i++) {
536
+ const pkgPath = path.join(dir, "package.json");
537
+ if (existsSync(pkgPath)) {
538
+ _projectRootCache.set(startDir, dir);
539
+ return dir;
540
+ }
541
+ const parent = path.dirname(dir);
542
+ if (parent === dir) break;
543
+ dir = parent;
544
+ }
545
+ _projectRootCache.set(startDir, null);
546
+ return null;
547
+ }
548
+ var _versionCache = /* @__PURE__ */ new Map();
549
+ function readInstalledVersions(projectRoot) {
550
+ const cached = _versionCache.get(projectRoot);
551
+ if (cached) return cached;
552
+ const versions = {};
553
+ const pkgPath = path.join(projectRoot, "package.json");
554
+ if (!existsSync(pkgPath)) return versions;
555
+ try {
556
+ const raw = readFileSync(pkgPath, "utf-8");
557
+ const pkg = JSON.parse(raw);
558
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies };
559
+ for (const [name, ver] of Object.entries(allDeps)) {
560
+ if (typeof ver === "string") versions[name] = ver;
561
+ }
562
+ _versionCache.set(projectRoot, versions);
563
+ } catch {
564
+ }
565
+ return versions;
566
+ }
567
+ var _importRegexCache = /* @__PURE__ */ new Map();
568
+ function isLibraryImportedInFile(content, library) {
569
+ let re = _importRegexCache.get(library);
570
+ if (!re) {
571
+ const escaped = escapeRegex(library);
572
+ re = new RegExp(`(?:from|require\\s*\\()\\s*['"]${escaped}(?:/[^'"]*)?['"]`);
573
+ _importRegexCache.set(library, re);
574
+ }
575
+ return re.test(content);
576
+ }
577
+ var LIBRARY_ALIASES = {
578
+ prisma: ["@prisma/client", "prisma"],
579
+ mongoose: ["mongoose"],
580
+ next: ["next", "next/navigation", "next/router", "next/image", "next/head", "next/link"],
581
+ react: ["react", "react/jsx-runtime"],
582
+ "react-dom": ["react-dom", "react-dom/client", "react-dom/server"],
583
+ "react-router-dom": ["react-router-dom", "react-router"],
584
+ axios: ["axios"],
585
+ lodash: ["lodash", "lodash-es", "lodash/fp"],
586
+ zod: ["zod"],
587
+ "@tanstack/react-query": ["@tanstack/react-query"],
588
+ express: ["express"],
589
+ fastify: ["fastify"],
590
+ "@trpc/server": ["@trpc/server", "@trpc/client", "@trpc/react-query"],
591
+ zustand: ["zustand"],
592
+ swr: ["swr"],
593
+ "next-auth": ["next-auth", "@auth/core"],
594
+ "drizzle-orm": ["drizzle-orm"],
595
+ typeorm: ["typeorm"],
596
+ sequelize: ["sequelize"],
597
+ "socket.io": ["socket.io", "socket.io-client"],
598
+ "date-fns": ["date-fns"],
599
+ dayjs: ["dayjs"],
600
+ hono: ["hono"],
601
+ "@supabase/supabase-js": ["@supabase/supabase-js", "@supabase/ssr", "@supabase/auth-helpers-nextjs"],
602
+ firebase: ["firebase", "firebase/app", "firebase/auth", "firebase/firestore", "firebase/storage"],
603
+ stripe: ["stripe"],
604
+ "@clerk/nextjs": ["@clerk/nextjs", "@clerk/clerk-react", "@clerk/backend"],
605
+ tailwindcss: ["tailwindcss"],
606
+ vite: ["vite"],
607
+ "@playwright/test": ["@playwright/test", "playwright"],
608
+ openai: ["openai"],
609
+ ai: ["ai", "@ai-sdk/openai", "@ai-sdk/anthropic"],
610
+ resend: ["resend"]
611
+ };
612
+ function isLibraryOrAliasImported(content, library) {
613
+ if (isLibraryImportedInFile(content, library)) return true;
614
+ const aliases = LIBRARY_ALIASES[library];
615
+ if (aliases) {
616
+ for (const alias of aliases) {
617
+ if (alias !== library && isLibraryImportedInFile(content, alias)) return true;
618
+ }
619
+ }
620
+ return false;
621
+ }
622
+ function isLibraryInProject(versions, library) {
623
+ if (versions[library] !== void 0) return true;
624
+ const aliases = LIBRARY_ALIASES[library];
625
+ if (aliases) {
626
+ for (const alias of aliases) {
627
+ if (versions[alias] !== void 0) return true;
628
+ }
629
+ }
630
+ return false;
631
+ }
632
+ function getInstalledVersion(versions, library) {
633
+ if (versions[library] !== void 0) return versions[library];
634
+ const aliases = LIBRARY_ALIASES[library];
635
+ if (aliases) {
636
+ for (const alias of aliases) {
637
+ if (versions[alias] !== void 0) return versions[alias];
638
+ }
639
+ }
640
+ return void 0;
641
+ }
642
+ function isTestFile(uri) {
643
+ return /\.(test|spec)\.(ts|tsx|js|jsx)$/i.test(uri) || /(?:^|\/)(?:__tests__|__mocks__|tests?|fixtures?|e2e|spec|cypress|playwright)\//i.test(uri);
644
+ }
645
+ function buildCommentMask(lines) {
646
+ const mask = new Array(lines.length).fill(false);
647
+ let inBlockComment = false;
648
+ for (let i = 0; i < lines.length; i++) {
649
+ const trimmed = lines[i].trim();
650
+ if (inBlockComment) {
651
+ mask[i] = true;
652
+ if (trimmed.includes("*/")) inBlockComment = false;
653
+ continue;
654
+ }
655
+ if (trimmed.startsWith("//") || trimmed.startsWith("*")) {
656
+ mask[i] = true;
657
+ continue;
658
+ }
659
+ if (trimmed.startsWith("/*")) {
660
+ mask[i] = true;
661
+ if (!trimmed.includes("*/")) inBlockComment = true;
662
+ continue;
663
+ }
664
+ }
665
+ return mask;
666
+ }
667
+ var VersionHallucinationEngine = class {
668
+ id = "version_hallucination";
669
+ async scan(delta, signal) {
670
+ const findings = [];
671
+ const filePath = delta.documentUri;
672
+ const content = delta.fullText;
673
+ if (isTestFile(filePath)) return findings;
674
+ const lang = delta.documentLanguage.toLowerCase();
675
+ if (!lang.includes("typescript") && !lang.includes("javascript") && !lang.includes("typescriptreact") && !lang.includes("javascriptreact")) {
676
+ return findings;
677
+ }
678
+ if (!content.includes("import") && !content.includes("require")) return findings;
679
+ const lines = delta.lines ?? content.split("\n");
680
+ const commentMask = buildCommentMask(lines);
681
+ const projectRoot = findProjectRoot(filePath);
682
+ const versions = projectRoot ? readInstalledVersions(projectRoot) : {};
683
+ const relevantPatterns = COMPILED_PATTERNS.filter(
684
+ (p) => isLibraryOrAliasImported(content, p.library) || isLibraryInProject(versions, p.library)
685
+ );
686
+ if (relevantPatterns.length === 0) return findings;
687
+ const seen = /* @__PURE__ */ new Set();
688
+ for (let i = 0; i < lines.length; i++) {
689
+ if (signal.aborted) break;
690
+ if (commentMask[i]) continue;
691
+ const line = lines[i];
692
+ const trimmed = line.trim();
693
+ if (!trimmed) continue;
694
+ for (const pattern of relevantPatterns) {
695
+ const match = line.match(pattern.regex);
696
+ if (!match) continue;
697
+ const matchIdx = match.index ?? 0;
698
+ const beforeMatch = line.slice(0, matchIdx);
699
+ if (/\/\//.test(beforeMatch)) continue;
700
+ const installedVersion = getInstalledVersion(versions, pattern.library);
701
+ const libraryInProject = isLibraryInProject(versions, pattern.library);
702
+ const libraryImported = isLibraryOrAliasImported(content, pattern.library);
703
+ const change = pattern.change;
704
+ let shouldReport = false;
705
+ let message = "";
706
+ let fix = "";
707
+ let confidence = pattern.confidence;
708
+ let severity = pattern.severity;
709
+ if (change.hallucinated) {
710
+ shouldReport = libraryInProject || libraryImported;
711
+ message = `Hallucinated method '${change.hallucinated}' does not exist on ${pattern.library}`;
712
+ fix = `Use ${change.realMethod} instead. Check the ${pattern.library} documentation.`;
713
+ confidence = libraryImported ? 0.92 : libraryInProject ? 0.85 : 0;
714
+ } else if (change.removed && change.since) {
715
+ if (installedVersion && change.since !== "never" && semverGte(installedVersion, change.since) && (libraryImported || libraryInProject)) {
716
+ shouldReport = true;
717
+ message = `'${change.removed}' was removed in ${pattern.library}@${change.since} (you have ${installedVersion})`;
718
+ fix = change.replacement ? `Use ${change.replacement} instead.` : `Check ${pattern.library} migration guide for ${change.since}.`;
719
+ confidence = libraryImported ? 0.88 : 0.72;
720
+ } else if (!installedVersion && libraryImported) {
721
+ shouldReport = true;
722
+ message = `'${change.removed}' may be deprecated/removed in ${pattern.library} (version unknown)`;
723
+ fix = change.replacement ? `If using ${pattern.library} >= ${change.since}, use ${change.replacement} instead.` : `Check ${pattern.library} migration guide.`;
724
+ confidence = Math.max(0.5, confidence - 0.2);
725
+ severity = "medium";
726
+ }
727
+ } else if (change.oldImport && change.newImport && change.since) {
728
+ if (installedVersion && semverGte(installedVersion, change.since)) {
729
+ shouldReport = true;
730
+ message = `Import path '${change.oldImport}' changed in ${pattern.library}@${change.since} (you have ${installedVersion})`;
731
+ fix = `Use '${change.newImport}' instead.`;
732
+ }
733
+ } else if (change.added && change.since) {
734
+ if (installedVersion && semverLt(installedVersion, change.since)) {
735
+ shouldReport = libraryImported;
736
+ message = `'${change.added}' was added in ${pattern.library}@${change.since} but you have ${installedVersion}`;
737
+ fix = `Upgrade ${pattern.library} to >= ${change.since}, or use the equivalent API for your version.`;
738
+ }
739
+ }
740
+ if (!shouldReport) continue;
741
+ const dedupeKey = `${pattern.ruleId}:${pattern.library}:${i + 1}:${change.hallucinated ?? change.removed ?? change.added ?? change.oldImport}`;
742
+ if (seen.has(dedupeKey)) continue;
743
+ seen.add(dedupeKey);
744
+ const col = match.index ?? 0;
745
+ findings.push({
746
+ id: deterministicId(filePath, i + 1, pattern.ruleId, pattern.library, change.hallucinated ?? change.removed ?? change.added ?? change.oldImport ?? ""),
747
+ engine: "version_hallucination",
748
+ severity,
749
+ category: "hallucinations",
750
+ file: filePath,
751
+ line: i + 1,
752
+ column: col,
753
+ endLine: i + 1,
754
+ endColumn: col + match[0].length,
755
+ message,
756
+ evidence: trimmed.length > 120 ? trimmed.slice(0, 117) + "..." : trimmed,
757
+ suggestion: fix,
758
+ confidence,
759
+ autoFixable: false,
760
+ ruleId: pattern.ruleId
761
+ });
762
+ }
763
+ }
764
+ return findings;
765
+ }
766
+ /** Clear the version cache (e.g. after npm install). */
767
+ clearCache() {
768
+ _versionCache.clear();
769
+ }
770
+ };
771
+
772
+ export { VersionHallucinationEngine };