seer-mcp 0.1.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 (371) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/LICENSE +176 -0
  3. package/README.md +272 -0
  4. package/README_dev.md +199 -0
  5. package/dist/bundle/ci.d.ts +47 -0
  6. package/dist/bundle/ci.d.ts.map +1 -0
  7. package/dist/bundle/ci.js +113 -0
  8. package/dist/bundle/ci.js.map +1 -0
  9. package/dist/bundle/contract.d.ts +111 -0
  10. package/dist/bundle/contract.d.ts.map +1 -0
  11. package/dist/bundle/contract.js +352 -0
  12. package/dist/bundle/contract.js.map +1 -0
  13. package/dist/bundle/export.d.ts +36 -0
  14. package/dist/bundle/export.d.ts.map +1 -0
  15. package/dist/bundle/export.js +152 -0
  16. package/dist/bundle/export.js.map +1 -0
  17. package/dist/bundle/external.d.ts +66 -0
  18. package/dist/bundle/external.d.ts.map +1 -0
  19. package/dist/bundle/external.js +238 -0
  20. package/dist/bundle/external.js.map +1 -0
  21. package/dist/bundle/format.d.ts +94 -0
  22. package/dist/bundle/format.d.ts.map +1 -0
  23. package/dist/bundle/format.js +42 -0
  24. package/dist/bundle/format.js.map +1 -0
  25. package/dist/bundle/import.d.ts +49 -0
  26. package/dist/bundle/import.d.ts.map +1 -0
  27. package/dist/bundle/import.js +116 -0
  28. package/dist/bundle/import.js.map +1 -0
  29. package/dist/cli/index.d.ts +3 -0
  30. package/dist/cli/index.d.ts.map +1 -0
  31. package/dist/cli/index.js +1402 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/cli/init.d.ts +48 -0
  34. package/dist/cli/init.d.ts.map +1 -0
  35. package/dist/cli/init.js +284 -0
  36. package/dist/cli/init.js.map +1 -0
  37. package/dist/db/schema.d.ts +3 -0
  38. package/dist/db/schema.d.ts.map +1 -0
  39. package/dist/db/schema.js +616 -0
  40. package/dist/db/schema.js.map +1 -0
  41. package/dist/db/store.d.ts +1011 -0
  42. package/dist/db/store.d.ts.map +1 -0
  43. package/dist/db/store.js +3888 -0
  44. package/dist/db/store.js.map +1 -0
  45. package/dist/graph/pagerank.d.ts +9 -0
  46. package/dist/graph/pagerank.d.ts.map +1 -0
  47. package/dist/graph/pagerank.js +47 -0
  48. package/dist/graph/pagerank.js.map +1 -0
  49. package/dist/indexer/architecture.d.ts +72 -0
  50. package/dist/indexer/architecture.d.ts.map +1 -0
  51. package/dist/indexer/architecture.js +112 -0
  52. package/dist/indexer/architecture.js.map +1 -0
  53. package/dist/indexer/behavior.d.ts +75 -0
  54. package/dist/indexer/behavior.d.ts.map +1 -0
  55. package/dist/indexer/behavior.js +395 -0
  56. package/dist/indexer/behavior.js.map +1 -0
  57. package/dist/indexer/boundaries.d.ts +60 -0
  58. package/dist/indexer/boundaries.d.ts.map +1 -0
  59. package/dist/indexer/boundaries.js +366 -0
  60. package/dist/indexer/boundaries.js.map +1 -0
  61. package/dist/indexer/churn.d.ts +15 -0
  62. package/dist/indexer/churn.d.ts.map +1 -0
  63. package/dist/indexer/churn.js +49 -0
  64. package/dist/indexer/churn.js.map +1 -0
  65. package/dist/indexer/classify.d.ts +9 -0
  66. package/dist/indexer/classify.d.ts.map +1 -0
  67. package/dist/indexer/classify.js +90 -0
  68. package/dist/indexer/classify.js.map +1 -0
  69. package/dist/indexer/context.d.ts +176 -0
  70. package/dist/indexer/context.d.ts.map +1 -0
  71. package/dist/indexer/context.js +193 -0
  72. package/dist/indexer/context.js.map +1 -0
  73. package/dist/indexer/continuity.d.ts +67 -0
  74. package/dist/indexer/continuity.d.ts.map +1 -0
  75. package/dist/indexer/continuity.js +288 -0
  76. package/dist/indexer/continuity.js.map +1 -0
  77. package/dist/indexer/detectchanges.d.ts +32 -0
  78. package/dist/indexer/detectchanges.d.ts.map +1 -0
  79. package/dist/indexer/detectchanges.js +74 -0
  80. package/dist/indexer/detectchanges.js.map +1 -0
  81. package/dist/indexer/discovery.d.ts +37 -0
  82. package/dist/indexer/discovery.d.ts.map +1 -0
  83. package/dist/indexer/discovery.js +136 -0
  84. package/dist/indexer/discovery.js.map +1 -0
  85. package/dist/indexer/externaldeps.d.ts +18 -0
  86. package/dist/indexer/externaldeps.d.ts.map +1 -0
  87. package/dist/indexer/externaldeps.js +288 -0
  88. package/dist/indexer/externaldeps.js.map +1 -0
  89. package/dist/indexer/freshness.d.ts +48 -0
  90. package/dist/indexer/freshness.d.ts.map +1 -0
  91. package/dist/indexer/freshness.js +128 -0
  92. package/dist/indexer/freshness.js.map +1 -0
  93. package/dist/indexer/git.d.ts +144 -0
  94. package/dist/indexer/git.d.ts.map +1 -0
  95. package/dist/indexer/git.js +444 -0
  96. package/dist/indexer/git.js.map +1 -0
  97. package/dist/indexer/index.d.ts +145 -0
  98. package/dist/indexer/index.d.ts.map +1 -0
  99. package/dist/indexer/index.js +930 -0
  100. package/dist/indexer/index.js.map +1 -0
  101. package/dist/indexer/modules.d.ts +62 -0
  102. package/dist/indexer/modules.d.ts.map +1 -0
  103. package/dist/indexer/modules.js +293 -0
  104. package/dist/indexer/modules.js.map +1 -0
  105. package/dist/indexer/preflight.d.ts +154 -0
  106. package/dist/indexer/preflight.d.ts.map +1 -0
  107. package/dist/indexer/preflight.js +399 -0
  108. package/dist/indexer/preflight.js.map +1 -0
  109. package/dist/indexer/protoScanner.d.ts +34 -0
  110. package/dist/indexer/protoScanner.d.ts.map +1 -0
  111. package/dist/indexer/protoScanner.js +133 -0
  112. package/dist/indexer/protoScanner.js.map +1 -0
  113. package/dist/indexer/risk.d.ts +115 -0
  114. package/dist/indexer/risk.d.ts.map +1 -0
  115. package/dist/indexer/risk.js +194 -0
  116. package/dist/indexer/risk.js.map +1 -0
  117. package/dist/indexer/serviceHostScanner.d.ts +25 -0
  118. package/dist/indexer/serviceHostScanner.d.ts.map +1 -0
  119. package/dist/indexer/serviceHostScanner.js +95 -0
  120. package/dist/indexer/serviceHostScanner.js.map +1 -0
  121. package/dist/indexer/serviceLinks.d.ts +105 -0
  122. package/dist/indexer/serviceLinks.d.ts.map +1 -0
  123. package/dist/indexer/serviceLinks.js +509 -0
  124. package/dist/indexer/serviceLinks.js.map +1 -0
  125. package/dist/indexer/shapehash.d.ts +98 -0
  126. package/dist/indexer/shapehash.d.ts.map +1 -0
  127. package/dist/indexer/shapehash.js +354 -0
  128. package/dist/indexer/shapehash.js.map +1 -0
  129. package/dist/indexer/skeleton.d.ts +15 -0
  130. package/dist/indexer/skeleton.d.ts.map +1 -0
  131. package/dist/indexer/skeleton.js +136 -0
  132. package/dist/indexer/skeleton.js.map +1 -0
  133. package/dist/indexer/symbolhistory.d.ts +41 -0
  134. package/dist/indexer/symbolhistory.d.ts.map +1 -0
  135. package/dist/indexer/symbolhistory.js +124 -0
  136. package/dist/indexer/symbolhistory.js.map +1 -0
  137. package/dist/indexer/watcher.d.ts +68 -0
  138. package/dist/indexer/watcher.d.ts.map +1 -0
  139. package/dist/indexer/watcher.js +179 -0
  140. package/dist/indexer/watcher.js.map +1 -0
  141. package/dist/mcp/server.d.ts +80 -0
  142. package/dist/mcp/server.d.ts.map +1 -0
  143. package/dist/mcp/server.js +1610 -0
  144. package/dist/mcp/server.js.map +1 -0
  145. package/dist/parser/index.d.ts +8 -0
  146. package/dist/parser/index.d.ts.map +1 -0
  147. package/dist/parser/index.js +33 -0
  148. package/dist/parser/index.js.map +1 -0
  149. package/dist/parser/languages/cpp.d.ts +3 -0
  150. package/dist/parser/languages/cpp.d.ts.map +1 -0
  151. package/dist/parser/languages/cpp.js +350 -0
  152. package/dist/parser/languages/cpp.js.map +1 -0
  153. package/dist/parser/languages/csharp.d.ts +3 -0
  154. package/dist/parser/languages/csharp.d.ts.map +1 -0
  155. package/dist/parser/languages/csharp.js +239 -0
  156. package/dist/parser/languages/csharp.js.map +1 -0
  157. package/dist/parser/languages/go.d.ts +3 -0
  158. package/dist/parser/languages/go.d.ts.map +1 -0
  159. package/dist/parser/languages/go.js +259 -0
  160. package/dist/parser/languages/go.js.map +1 -0
  161. package/dist/parser/languages/java.d.ts +3 -0
  162. package/dist/parser/languages/java.d.ts.map +1 -0
  163. package/dist/parser/languages/java.js +391 -0
  164. package/dist/parser/languages/java.js.map +1 -0
  165. package/dist/parser/languages/python.d.ts +3 -0
  166. package/dist/parser/languages/python.d.ts.map +1 -0
  167. package/dist/parser/languages/python.js +396 -0
  168. package/dist/parser/languages/python.js.map +1 -0
  169. package/dist/parser/languages/rust.d.ts +3 -0
  170. package/dist/parser/languages/rust.d.ts.map +1 -0
  171. package/dist/parser/languages/rust.js +159 -0
  172. package/dist/parser/languages/rust.js.map +1 -0
  173. package/dist/parser/languages/typescript.d.ts +3 -0
  174. package/dist/parser/languages/typescript.d.ts.map +1 -0
  175. package/dist/parser/languages/typescript.js +1442 -0
  176. package/dist/parser/languages/typescript.js.map +1 -0
  177. package/dist/parser/parserContext.d.ts +77 -0
  178. package/dist/parser/parserContext.d.ts.map +1 -0
  179. package/dist/parser/parserContext.js +354 -0
  180. package/dist/parser/parserContext.js.map +1 -0
  181. package/dist/parser/walker.d.ts +81 -0
  182. package/dist/parser/walker.d.ts.map +1 -0
  183. package/dist/parser/walker.js +217 -0
  184. package/dist/parser/walker.js.map +1 -0
  185. package/dist/parser/worker.d.ts +66 -0
  186. package/dist/parser/worker.d.ts.map +1 -0
  187. package/dist/parser/worker.js +129 -0
  188. package/dist/parser/worker.js.map +1 -0
  189. package/dist/parser/workerpool.d.ts +107 -0
  190. package/dist/parser/workerpool.d.ts.map +1 -0
  191. package/dist/parser/workerpool.js +383 -0
  192. package/dist/parser/workerpool.js.map +1 -0
  193. package/dist/scip/format.d.ts +87 -0
  194. package/dist/scip/format.d.ts.map +1 -0
  195. package/dist/scip/format.js +31 -0
  196. package/dist/scip/format.js.map +1 -0
  197. package/dist/scip/import.d.ts +37 -0
  198. package/dist/scip/import.d.ts.map +1 -0
  199. package/dist/scip/import.js +180 -0
  200. package/dist/scip/import.js.map +1 -0
  201. package/dist/types.d.ts +392 -0
  202. package/dist/types.d.ts.map +1 -0
  203. package/dist/types.js +4 -0
  204. package/dist/types.js.map +1 -0
  205. package/docs/architecture.md +105 -0
  206. package/docs/benchmarks/methodology.md +134 -0
  207. package/docs/benchmarks/raw-results.md +71 -0
  208. package/docs/benchmarks.md +74 -0
  209. package/docs/cli.md +148 -0
  210. package/docs/examples/behavior-tests.md +70 -0
  211. package/docs/examples/change-history.md +85 -0
  212. package/docs/examples/pre-edit-context.md +81 -0
  213. package/docs/examples/service-links.md +88 -0
  214. package/docs/examples.md +80 -0
  215. package/docs/faq.md +70 -0
  216. package/docs/internals.md +104 -0
  217. package/docs/languages.md +70 -0
  218. package/docs/limits.md +52 -0
  219. package/docs/mcp.md +199 -0
  220. package/docs/quickstart.md +119 -0
  221. package/docs/testing.md +123 -0
  222. package/docs/tools.md +115 -0
  223. package/package.json +52 -0
  224. package/research-codebase.md +578 -0
  225. package/seer-cli-docs.md +326 -0
  226. package/seer-master-guide.md +246 -0
  227. package/src/bundle/ci.ts +141 -0
  228. package/src/bundle/contract.ts +387 -0
  229. package/src/bundle/export.ts +175 -0
  230. package/src/bundle/external.ts +285 -0
  231. package/src/bundle/format.ts +92 -0
  232. package/src/bundle/import.ts +157 -0
  233. package/src/cli/index.ts +1249 -0
  234. package/src/cli/init.ts +389 -0
  235. package/src/db/schema.ts +614 -0
  236. package/src/db/store.ts +4306 -0
  237. package/src/graph/pagerank.ts +53 -0
  238. package/src/indexer/architecture.ts +148 -0
  239. package/src/indexer/behavior.ts +466 -0
  240. package/src/indexer/boundaries.ts +374 -0
  241. package/src/indexer/churn.ts +58 -0
  242. package/src/indexer/classify.ts +96 -0
  243. package/src/indexer/context.ts +340 -0
  244. package/src/indexer/continuity.ts +322 -0
  245. package/src/indexer/detectchanges.ts +94 -0
  246. package/src/indexer/discovery.ts +176 -0
  247. package/src/indexer/externaldeps.ts +243 -0
  248. package/src/indexer/freshness.ts +166 -0
  249. package/src/indexer/git.ts +453 -0
  250. package/src/indexer/index.ts +1092 -0
  251. package/src/indexer/modules.ts +358 -0
  252. package/src/indexer/preflight.ts +548 -0
  253. package/src/indexer/protoScanner.ts +147 -0
  254. package/src/indexer/risk.ts +304 -0
  255. package/src/indexer/serviceHostScanner.ts +92 -0
  256. package/src/indexer/serviceLinks.ts +543 -0
  257. package/src/indexer/shapehash.ts +370 -0
  258. package/src/indexer/skeleton.ts +169 -0
  259. package/src/indexer/symbolhistory.ts +172 -0
  260. package/src/indexer/watcher.ts +206 -0
  261. package/src/mcp/server.ts +1659 -0
  262. package/src/parser/index.ts +37 -0
  263. package/src/parser/languages/cpp.ts +361 -0
  264. package/src/parser/languages/csharp.ts +235 -0
  265. package/src/parser/languages/go.ts +259 -0
  266. package/src/parser/languages/java.ts +382 -0
  267. package/src/parser/languages/python.ts +370 -0
  268. package/src/parser/languages/rust.ts +164 -0
  269. package/src/parser/languages/typescript.ts +1435 -0
  270. package/src/parser/parserContext.ts +392 -0
  271. package/src/parser/walker.ts +306 -0
  272. package/src/parser/worker.ts +181 -0
  273. package/src/parser/workerpool.ts +448 -0
  274. package/src/scip/format.ts +83 -0
  275. package/src/scip/import.ts +216 -0
  276. package/src/types.ts +457 -0
  277. package/tests/benchmark-service-links.ts +244 -0
  278. package/tests/bug-regressions.ts +626 -0
  279. package/tests/filters.ts +264 -0
  280. package/tests/fixtures/Counter.tsx +38 -0
  281. package/tests/fixtures/caller.ts +7 -0
  282. package/tests/fixtures/collisions.ts +23 -0
  283. package/tests/fixtures/local_helper.ts +5 -0
  284. package/tests/fixtures/overloads.java +17 -0
  285. package/tests/fixtures/remote_helper.ts +4 -0
  286. package/tests/fixtures/sample.c +15 -0
  287. package/tests/fixtures/sample.cpp +47 -0
  288. package/tests/fixtures/sample.cs +62 -0
  289. package/tests/fixtures/sample.go +68 -0
  290. package/tests/fixtures/sample.h +30 -0
  291. package/tests/fixtures/sample.java +85 -0
  292. package/tests/fixtures/sample.py +46 -0
  293. package/tests/fixtures/sample.rs +78 -0
  294. package/tests/fixtures/sample.ts +76 -0
  295. package/tests/fixtures-service/HttpClients.cs +30 -0
  296. package/tests/fixtures-service/HttpClients.java +24 -0
  297. package/tests/fixtures-service/billing.ts +15 -0
  298. package/tests/fixtures-service/docker-compose.yml +15 -0
  299. package/tests/fixtures-service/gateway.ts +10 -0
  300. package/tests/fixtures-service/get_user.ts +11 -0
  301. package/tests/fixtures-service/graphql_client.ts +63 -0
  302. package/tests/fixtures-service/graphql_server.ts +30 -0
  303. package/tests/fixtures-service/grpc_client.go +30 -0
  304. package/tests/fixtures-service/http_clients.go +23 -0
  305. package/tests/fixtures-service/http_clients.py +38 -0
  306. package/tests/fixtures-service/http_clients.ts +49 -0
  307. package/tests/fixtures-service/k8s/payment-service.yaml +22 -0
  308. package/tests/fixtures-service/k8s_calls.ts +20 -0
  309. package/tests/fixtures-service/messaging.ts +87 -0
  310. package/tests/fixtures-service/trpc_client.ts +39 -0
  311. package/tests/fixtures-service/trpc_server.ts +39 -0
  312. package/tests/fixtures-service/user_service.proto +33 -0
  313. package/tests/fixtures-trackcd/Cargo.toml +11 -0
  314. package/tests/fixtures-trackcd/SpringController.java +36 -0
  315. package/tests/fixtures-trackcd/auth_service.ts +19 -0
  316. package/tests/fixtures-trackcd/complex_module.py +50 -0
  317. package/tests/fixtures-trackcd/express_app.js +30 -0
  318. package/tests/fixtures-trackcd/fastapi_app.py +49 -0
  319. package/tests/fixtures-trackcd/fastify_object_routes.js +32 -0
  320. package/tests/fixtures-trackcd/go.mod +8 -0
  321. package/tests/fixtures-trackcd/package.json +15 -0
  322. package/tests/fixtures-trackcd/requirements.txt +4 -0
  323. package/tests/fixtures-trackcd/tests/auth_service.test.ts +13 -0
  324. package/tests/fixtures-tracke/auth/AuthService.ts +23 -0
  325. package/tests/fixtures-tracke/auth/crypto.ts +7 -0
  326. package/tests/fixtures-tracke/billing/Billing.ts +20 -0
  327. package/tests/fixtures-tracke/billing/Invoice.ts +10 -0
  328. package/tests/fixtures-tracke/billing/server.ts +17 -0
  329. package/tests/fixtures-tracke/package.json +7 -0
  330. package/tests/fixtures-tracke/tests/auth.test.ts +23 -0
  331. package/tests/fixtures-tracke/tests/billing.test.ts +14 -0
  332. package/tests/fixtures-trackf/package.json +5 -0
  333. package/tests/fixtures-trackf/src/auth.ts +26 -0
  334. package/tests/fixtures-trackf/src/handlers.ts +35 -0
  335. package/tests/fixtures-tracki/billing/routes.ts +12 -0
  336. package/tests/fixtures-tracki/gateway/client.ts +13 -0
  337. package/tests/git-features.ts +267 -0
  338. package/tests/init.ts +141 -0
  339. package/tests/mcp-jit.ts +130 -0
  340. package/tests/mcp-smoke.ts +191 -0
  341. package/tests/mcp-trackcd.ts +169 -0
  342. package/tests/mcp-tracke.ts +229 -0
  343. package/tests/mcp-trackf.ts +330 -0
  344. package/tests/mcp-trackg.ts +219 -0
  345. package/tests/mcp-tracki.ts +174 -0
  346. package/tests/mcp-watcher.ts +126 -0
  347. package/tests/optspec.ts +194 -0
  348. package/tests/parallel-index.ts +333 -0
  349. package/tests/parallel-read.ts +125 -0
  350. package/tests/parallel-recovery.ts +241 -0
  351. package/tests/perf-callers.ts +145 -0
  352. package/tests/query-parity.ts +184 -0
  353. package/tests/query-perf.ts +55 -0
  354. package/tests/scale-parallel-parity.ts +225 -0
  355. package/tests/scale-test.ts +523 -0
  356. package/tests/smoke.ts +396 -0
  357. package/tests/trackcd.ts +325 -0
  358. package/tests/tracke-collisions.ts +255 -0
  359. package/tests/tracke.ts +314 -0
  360. package/tests/trackf-bugs.ts +406 -0
  361. package/tests/trackf.ts +390 -0
  362. package/tests/trackg.ts +1372 -0
  363. package/tests/tracki-boundaries.ts +202 -0
  364. package/tests/tracki-continuity.ts +253 -0
  365. package/tests/tracki-contract-diff.ts +249 -0
  366. package/tests/tracki-external-bundles.ts +341 -0
  367. package/tests/tracki-preflight.ts +251 -0
  368. package/tests/verify-roles.ts +51 -0
  369. package/tests/worker-parity.ts +286 -0
  370. package/tests/worker-pool.ts +262 -0
  371. package/tsconfig.json +20 -0
@@ -0,0 +1,389 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import os from 'os';
4
+
5
+ /**
6
+ * `seer init` — one command that wires Seer into whatever AI coding agents a
7
+ * developer is running. The hard part of "install an MCP server" is never the
8
+ * server; it is that every client invented its own config file, root key, and
9
+ * location. This module knows them all and writes the right snippet to the
10
+ * right place, idempotently.
11
+ *
12
+ * It also drops an AGENTS.md block so the agent actually knows Seer exists and
13
+ * how to use it well, rather than ignoring a tool it was never told about.
14
+ *
15
+ * Everything here is deterministic and local. No network, no telemetry.
16
+ */
17
+
18
+ export type ClientId =
19
+ | 'claude'
20
+ | 'cursor'
21
+ | 'vscode'
22
+ | 'codex'
23
+ | 'gemini'
24
+ | 'antigravity';
25
+
26
+ export interface InitOptions {
27
+ workspace: string;
28
+ clients?: ClientId[]; // explicit subset; default = the project-local set
29
+ global?: boolean; // write user-level config instead of project-local
30
+ command?: string; // override the launch command line entirely
31
+ npx?: boolean; // emit the portable `npx -y <pkg> mcp` launcher
32
+ pkg?: string; // npm package name for the npx launcher
33
+ agents?: boolean; // write the AGENTS.md guidance block (default true)
34
+ print?: boolean; // dry run: report the plan, write nothing
35
+ force?: boolean; // overwrite an existing seer entry / agents block
36
+ db?: string; // custom db path passed through to the launcher
37
+ }
38
+
39
+ interface LaunchSpec {
40
+ command: string;
41
+ args: string[];
42
+ }
43
+
44
+ /** All clients we know how to configure, in display order. */
45
+ const ALL_CLIENTS: ClientId[] = ['claude', 'cursor', 'vscode', 'codex', 'gemini', 'antigravity'];
46
+
47
+ /** The default set when the user does not name clients: everything that has a
48
+ * clean project-local config. Antigravity is user-level only, so it is opt-in. */
49
+ const DEFAULT_CLIENTS: ClientId[] = ['claude', 'cursor', 'vscode', 'codex', 'gemini'];
50
+
51
+ const DEFAULT_PKG = 'seer-mcp';
52
+ const AGENTS_BEGIN = '<!-- seer:begin -->';
53
+ const AGENTS_END = '<!-- seer:end -->';
54
+
55
+ interface PlanEntry {
56
+ client: ClientId;
57
+ label: string;
58
+ file: string;
59
+ action: 'wrote' | 'updated' | 'skipped' | 'manual';
60
+ note?: string;
61
+ snippet?: string;
62
+ }
63
+
64
+ export interface InitResult {
65
+ launch: LaunchSpec;
66
+ entries: PlanEntry[];
67
+ agents?: { file: string; action: 'wrote' | 'updated' | 'skipped' };
68
+ }
69
+
70
+ // ── Launcher resolution ─────────────────────────────────────────────────────
71
+
72
+ /**
73
+ * Figure out how an agent should start the Seer MCP server. Two shapes:
74
+ * - npx form: fully portable, no machine paths. Relies on the client
75
+ * launching the server with cwd = project root.
76
+ * - node form: an absolute path to the built CLI. Works today, before the
77
+ * package is published, but is machine-specific.
78
+ */
79
+ function resolveLaunch(workspace: string, opts: InitOptions): LaunchSpec {
80
+ if (opts.command && opts.command.trim()) {
81
+ const parts = opts.command.trim().split(/\s+/);
82
+ return { command: parts[0], args: parts.slice(1) };
83
+ }
84
+
85
+ if (opts.npx) {
86
+ const args = ['-y', opts.pkg || DEFAULT_PKG, 'mcp'];
87
+ if (opts.db) args.push('--db', opts.db);
88
+ return { command: 'npx', args };
89
+ }
90
+
91
+ // Default: an absolute path to the compiled CLI entry. __dirname is
92
+ // dist/cli when built; map a src/.ts path back to dist/.js so the snippet we
93
+ // emit always points at the thing agents can actually run.
94
+ let entry = path.join(__dirname, 'index.js');
95
+ if (entry.includes(`${path.sep}src${path.sep}`) || entry.endsWith('.ts')) {
96
+ entry = entry
97
+ .replace(`${path.sep}src${path.sep}`, `${path.sep}dist${path.sep}`)
98
+ .replace(/\.ts$/, '.js');
99
+ }
100
+ const args = [entry, 'mcp', '--workspace', workspace];
101
+ if (opts.db) args.push('--db', opts.db);
102
+ return { command: 'node', args };
103
+ }
104
+
105
+ // ── Small file helpers ──────────────────────────────────────────────────────
106
+
107
+ function readJsonTolerant(file: string): { ok: true; data: any } | { ok: false } {
108
+ try {
109
+ const raw = fs.readFileSync(file, 'utf8');
110
+ if (!raw.trim()) return { ok: true, data: {} };
111
+ // Tolerate JSONC (// and /* */ comments, trailing commas) so we do not
112
+ // choke on a hand-edited VS Code mcp.json.
113
+ const stripped = raw
114
+ .replace(/\/\*[\s\S]*?\*\//g, '')
115
+ .replace(/(^|[^:])\/\/.*$/gm, '$1')
116
+ .replace(/,(\s*[}\]])/g, '$1');
117
+ return { ok: true, data: JSON.parse(stripped) };
118
+ } catch {
119
+ return { ok: false };
120
+ }
121
+ }
122
+
123
+ function ensureDir(file: string): void {
124
+ const dir = path.dirname(file);
125
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
126
+ }
127
+
128
+ // ── Per-client writers ──────────────────────────────────────────────────────
129
+
130
+ interface ClientSpec {
131
+ label: string;
132
+ /** Project-local config path, relative to workspace. Null = user-level only. */
133
+ projectPath: string | null;
134
+ /** User-level (global) config path. Null = project-only. */
135
+ globalPath: string | null;
136
+ rootKey: 'mcpServers' | 'servers';
137
+ /** VS Code wants an explicit `type: "stdio"` on each entry. */
138
+ stdioType?: boolean;
139
+ /** Codex is TOML, not JSON. */
140
+ toml?: boolean;
141
+ }
142
+
143
+ function home(...p: string[]): string {
144
+ return path.join(os.homedir(), ...p);
145
+ }
146
+
147
+ const CLIENTS: Record<ClientId, ClientSpec> = {
148
+ claude: {
149
+ label: 'Claude Code',
150
+ projectPath: '.mcp.json',
151
+ globalPath: home('.claude.json'),
152
+ rootKey: 'mcpServers',
153
+ },
154
+ cursor: {
155
+ label: 'Cursor',
156
+ projectPath: path.join('.cursor', 'mcp.json'),
157
+ globalPath: home('.cursor', 'mcp.json'),
158
+ rootKey: 'mcpServers',
159
+ },
160
+ vscode: {
161
+ label: 'VS Code (Copilot / native MCP)',
162
+ projectPath: path.join('.vscode', 'mcp.json'),
163
+ globalPath: null,
164
+ rootKey: 'servers',
165
+ stdioType: true,
166
+ },
167
+ codex: {
168
+ label: 'OpenAI Codex',
169
+ projectPath: path.join('.codex', 'config.toml'),
170
+ globalPath: home('.codex', 'config.toml'),
171
+ rootKey: 'mcpServers',
172
+ toml: true,
173
+ },
174
+ gemini: {
175
+ label: 'Gemini CLI',
176
+ projectPath: path.join('.gemini', 'settings.json'),
177
+ globalPath: home('.gemini', 'settings.json'),
178
+ rootKey: 'mcpServers',
179
+ },
180
+ antigravity: {
181
+ label: 'Google Antigravity',
182
+ projectPath: null,
183
+ globalPath: home('.gemini', 'config', 'mcp_config.json'),
184
+ rootKey: 'mcpServers',
185
+ },
186
+ };
187
+
188
+ function jsonEntry(launch: LaunchSpec, stdioType: boolean): Record<string, any> {
189
+ const entry: Record<string, any> = {};
190
+ if (stdioType) entry.type = 'stdio';
191
+ entry.command = launch.command;
192
+ entry.args = launch.args;
193
+ return entry;
194
+ }
195
+
196
+ function tomlBlock(launch: LaunchSpec): string {
197
+ const argList = launch.args.map((a) => JSON.stringify(a)).join(', ');
198
+ return [
199
+ '[mcp_servers.seer]',
200
+ `command = ${JSON.stringify(launch.command)}`,
201
+ `args = [${argList}]`,
202
+ '',
203
+ ].join('\n');
204
+ }
205
+
206
+ function writeJsonClient(
207
+ spec: ClientSpec,
208
+ file: string,
209
+ launch: LaunchSpec,
210
+ opts: InitOptions,
211
+ ): PlanEntry {
212
+ const base: PlanEntry = { client: 'claude', label: spec.label, file, action: 'wrote' };
213
+ const entry = jsonEntry(launch, !!spec.stdioType);
214
+ const snippet = JSON.stringify({ [spec.rootKey]: { seer: entry } }, null, 2);
215
+
216
+ if (opts.print) {
217
+ return { ...base, action: fs.existsSync(file) ? 'updated' : 'wrote', snippet, note: 'dry run' };
218
+ }
219
+
220
+ let data: any = {};
221
+ let existed = false;
222
+ if (fs.existsSync(file)) {
223
+ existed = true;
224
+ const parsed = readJsonTolerant(file);
225
+ if (!parsed.ok) {
226
+ return {
227
+ ...base,
228
+ action: 'manual',
229
+ note: `could not parse existing ${path.basename(file)}; add the snippet by hand`,
230
+ snippet,
231
+ };
232
+ }
233
+ data = parsed.data || {};
234
+ }
235
+
236
+ if (!data[spec.rootKey] || typeof data[spec.rootKey] !== 'object') data[spec.rootKey] = {};
237
+ if (data[spec.rootKey].seer && !opts.force) {
238
+ return { ...base, action: 'skipped', note: 'seer entry already present (use --force to overwrite)' };
239
+ }
240
+ data[spec.rootKey].seer = entry;
241
+
242
+ ensureDir(file);
243
+ fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n', 'utf8');
244
+ return { ...base, action: existed ? 'updated' : 'wrote' };
245
+ }
246
+
247
+ function writeTomlClient(
248
+ spec: ClientSpec,
249
+ file: string,
250
+ launch: LaunchSpec,
251
+ opts: InitOptions,
252
+ ): PlanEntry {
253
+ const base: PlanEntry = { client: 'codex', label: spec.label, file, action: 'wrote' };
254
+ const block = tomlBlock(launch);
255
+
256
+ if (opts.print) {
257
+ return { ...base, action: fs.existsSync(file) ? 'updated' : 'wrote', snippet: block, note: 'dry run' };
258
+ }
259
+
260
+ if (fs.existsSync(file)) {
261
+ const raw = fs.readFileSync(file, 'utf8');
262
+ if (/^[ \t]*\[mcp_servers\.seer\]/m.test(raw)) {
263
+ if (!opts.force) {
264
+ return { ...base, action: 'skipped', note: 'mcp_servers.seer already present (use --force to overwrite)' };
265
+ }
266
+ // Replace the existing block: splice out from its header line to the
267
+ // next TOML table header (or end of file), then drop the fresh block in.
268
+ const lines = raw.split('\n');
269
+ const start = lines.findIndex((l) => /^[ \t]*\[mcp_servers\.seer\]/.test(l));
270
+ let end = lines.length;
271
+ for (let i = start + 1; i < lines.length; i++) {
272
+ if (/^[ \t]*\[/.test(lines[i])) { end = i; break; }
273
+ }
274
+ const next = [...lines.slice(0, start), ...block.split('\n'), ...lines.slice(end)].join('\n');
275
+ fs.writeFileSync(file, next, 'utf8');
276
+ return { ...base, action: 'updated' };
277
+ }
278
+ const sep = raw.endsWith('\n') ? '\n' : '\n\n';
279
+ fs.writeFileSync(file, raw + sep + block, 'utf8');
280
+ return { ...base, action: 'updated' };
281
+ }
282
+
283
+ ensureDir(file);
284
+ fs.writeFileSync(file, block, 'utf8');
285
+ return { ...base, action: 'wrote' };
286
+ }
287
+
288
+ function configureClient(
289
+ client: ClientId,
290
+ launch: LaunchSpec,
291
+ opts: InitOptions,
292
+ ): PlanEntry {
293
+ const spec = CLIENTS[client];
294
+ const useGlobal = opts.global || spec.projectPath === null;
295
+ const rel = useGlobal ? spec.globalPath : spec.projectPath;
296
+
297
+ if (!rel) {
298
+ // e.g. asked for project-local antigravity, which does not exist.
299
+ return {
300
+ client,
301
+ label: spec.label,
302
+ file: '(n/a)',
303
+ action: 'manual',
304
+ note: `${spec.label} has no ${useGlobal ? 'user-level' : 'project-local'} config; try the other scope`,
305
+ };
306
+ }
307
+
308
+ const file = path.isAbsolute(rel) ? rel : path.join(opts.workspace, rel);
309
+ const result = spec.toml
310
+ ? writeTomlClient(spec, file, launch, opts)
311
+ : writeJsonClient(spec, file, launch, opts);
312
+ return { ...result, client };
313
+ }
314
+
315
+ // ── AGENTS.md ───────────────────────────────────────────────────────────────
316
+
317
+ function agentsBlock(): string {
318
+ return [
319
+ AGENTS_BEGIN,
320
+ '## Seer — read this before navigating or editing code',
321
+ '',
322
+ 'This repo is indexed by **Seer**, a local MCP server that gives you',
323
+ 'structural facts about the codebase: definitions, call graphs, routes,',
324
+ 'tests, edit-risk, monorepo boundaries, and per-symbol git history. It is',
325
+ 'deterministic and local. Prefer it over grep/file-reading for anything',
326
+ 'structural — it is faster and uses far fewer tokens.',
327
+ '',
328
+ '**Before you edit an unfamiliar symbol**, call `seer_preflight` with the',
329
+ 'symbol name. One call returns the definition, who calls it, the tests that',
330
+ 'cover it, its risk profile, and recent history — the context you would',
331
+ 'otherwise gather with ten searches.',
332
+ '',
333
+ 'A good default workflow:',
334
+ '',
335
+ '1. `seer_health` — confirm the index is live.',
336
+ '2. `seer_architecture` or `seer_boundaries` — orient in an unfamiliar repo.',
337
+ '3. `seer_preflight { symbol }` — pull the full pre-edit packet for a target.',
338
+ '4. `seer_preflight { fromRef: "main", toRef: "HEAD" }` — blast radius of a diff.',
339
+ '5. `seer_behavior` / `seer_history` — tests and blame for a symbol.',
340
+ '6. `seer_skeleton { file }` — read a large file as signatures only, cheaply.',
341
+ '',
342
+ 'Use `seer_batch` to run several read-only lookups in one round-trip. Fall',
343
+ 'back to grep only for comments, string literals, and config values.',
344
+ AGENTS_END,
345
+ ].join('\n');
346
+ }
347
+
348
+ function writeAgents(opts: InitOptions): InitResult['agents'] {
349
+ const file = path.join(opts.workspace, 'AGENTS.md');
350
+ const block = agentsBlock();
351
+
352
+ if (opts.print) {
353
+ return { file, action: fs.existsSync(file) ? 'updated' : 'wrote' };
354
+ }
355
+
356
+ if (fs.existsSync(file)) {
357
+ const raw = fs.readFileSync(file, 'utf8');
358
+ if (raw.includes(AGENTS_BEGIN) && raw.includes(AGENTS_END)) {
359
+ if (!opts.force) return { file, action: 'skipped' };
360
+ const replaced = raw.replace(
361
+ new RegExp(`${AGENTS_BEGIN}[\\s\\S]*?${AGENTS_END}`),
362
+ block,
363
+ );
364
+ fs.writeFileSync(file, replaced, 'utf8');
365
+ return { file, action: 'updated' };
366
+ }
367
+ const sep = raw.endsWith('\n') ? '\n' : '\n\n';
368
+ fs.writeFileSync(file, raw + sep + block + '\n', 'utf8');
369
+ return { file, action: 'updated' };
370
+ }
371
+
372
+ fs.writeFileSync(file, block + '\n', 'utf8');
373
+ return { file, action: 'wrote' };
374
+ }
375
+
376
+ // ── Entry point ─────────────────────────────────────────────────────────────
377
+
378
+ export function runInit(opts: InitOptions): InitResult {
379
+ const workspace = path.resolve(opts.workspace);
380
+ const clients = (opts.clients && opts.clients.length ? opts.clients : DEFAULT_CLIENTS)
381
+ .filter((c) => ALL_CLIENTS.includes(c));
382
+
383
+ const launch = resolveLaunch(workspace, { ...opts, workspace });
384
+
385
+ const entries = clients.map((c) => configureClient(c, launch, { ...opts, workspace }));
386
+ const agents = opts.agents === false ? undefined : writeAgents({ ...opts, workspace });
387
+
388
+ return { launch, entries, agents };
389
+ }