weavatrix 0.3.13 → 1.0.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 (303) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +231 -199
  3. package/bin/native/darwin-arm64/weavatrix +0 -0
  4. package/bin/native/darwin-x64/weavatrix +0 -0
  5. package/bin/native/linux-arm64/weavatrix +0 -0
  6. package/bin/native/linux-x64/weavatrix +0 -0
  7. package/bin/native/win32-arm64/weavatrix.exe +0 -0
  8. package/bin/native/win32-x64/weavatrix.exe +0 -0
  9. package/bin/resolve-binary.mjs +73 -0
  10. package/bin/run-native.mjs +26 -0
  11. package/bin/weavatrix-mcp.mjs +7 -6
  12. package/bin/weavatrix.mjs +5 -0
  13. package/package.json +8 -65
  14. package/skill/SKILL.md +62 -374
  15. package/skill/agents/openai.yaml +4 -0
  16. package/skill/references/tool-routing.md +45 -0
  17. package/SECURITY.md +0 -101
  18. package/docs/adr/0001-v0.3-offline-online-split.md +0 -60
  19. package/docs/agent-task-benchmark.md +0 -58
  20. package/docs/releases/v0.2.19.md +0 -33
  21. package/docs/releases/v0.3.0.md +0 -43
  22. package/docs/releases/v0.3.1.md +0 -30
  23. package/docs/releases/v0.3.10.md +0 -76
  24. package/docs/releases/v0.3.11.md +0 -55
  25. package/docs/releases/v0.3.12.md +0 -44
  26. package/docs/releases/v0.3.13.md +0 -34
  27. package/docs/releases/v0.3.2.md +0 -15
  28. package/docs/releases/v0.3.3.md +0 -25
  29. package/docs/releases/v0.3.4.md +0 -40
  30. package/docs/releases/v0.3.5.md +0 -50
  31. package/docs/releases/v0.3.6.md +0 -44
  32. package/docs/releases/v0.3.7.md +0 -37
  33. package/docs/releases/v0.3.8.md +0 -21
  34. package/docs/releases/v0.3.9.md +0 -36
  35. package/scripts/run-agent-task-benchmark.mjs +0 -118
  36. package/src/analysis/allowed-test-runner.js +0 -70
  37. package/src/analysis/architecture/contract-graph.js +0 -119
  38. package/src/analysis/architecture/contract-schema.js +0 -110
  39. package/src/analysis/architecture/contract-storage.js +0 -35
  40. package/src/analysis/architecture/contract-verification.js +0 -168
  41. package/src/analysis/architecture-contract.js +0 -16
  42. package/src/analysis/audit-debt.js +0 -94
  43. package/src/analysis/audit-extensions.js +0 -60
  44. package/src/analysis/cargo-dependency-evidence.js +0 -108
  45. package/src/analysis/cargo-manifests.js +0 -81
  46. package/src/analysis/change-classification/diff-parser.js +0 -103
  47. package/src/analysis/change-classification/options.js +0 -40
  48. package/src/analysis/change-classification/symbol-classifier.js +0 -177
  49. package/src/analysis/change-classification.js +0 -188
  50. package/src/analysis/coverage-reports.js +0 -235
  51. package/src/analysis/cycle-route.js +0 -14
  52. package/src/analysis/data-flow-evidence.js +0 -114
  53. package/src/analysis/dead-check.js +0 -300
  54. package/src/analysis/dead-code-review/candidates.js +0 -194
  55. package/src/analysis/dead-code-review/policy.js +0 -23
  56. package/src/analysis/dead-code-review.js +0 -119
  57. package/src/analysis/dep-check-ecosystems.js +0 -205
  58. package/src/analysis/dep-check.js +0 -290
  59. package/src/analysis/dep-rules.js +0 -10
  60. package/src/analysis/dependency/conventions.js +0 -16
  61. package/src/analysis/dependency/scoped-dependencies.js +0 -51
  62. package/src/analysis/dependency/source-references.js +0 -21
  63. package/src/analysis/duplicate-groups.js +0 -104
  64. package/src/analysis/duplicates-worker.js +0 -11
  65. package/src/analysis/duplicates.compute.js +0 -269
  66. package/src/analysis/duplicates.js +0 -15
  67. package/src/analysis/duplicates.run.js +0 -52
  68. package/src/analysis/duplicates.tokenize.js +0 -199
  69. package/src/analysis/endpoints/common.js +0 -62
  70. package/src/analysis/endpoints/extract.js +0 -107
  71. package/src/analysis/endpoints/inventory.js +0 -84
  72. package/src/analysis/endpoints/mounts.js +0 -129
  73. package/src/analysis/endpoints-java.js +0 -260
  74. package/src/analysis/endpoints-rust.js +0 -124
  75. package/src/analysis/endpoints.js +0 -3
  76. package/src/analysis/findings.js +0 -70
  77. package/src/analysis/git-history/analytics.js +0 -177
  78. package/src/analysis/git-history/collector.js +0 -67
  79. package/src/analysis/git-history/options.js +0 -66
  80. package/src/analysis/git-history.js +0 -143
  81. package/src/analysis/git-ref-graph.js +0 -76
  82. package/src/analysis/go-dependency-evidence.js +0 -62
  83. package/src/analysis/graph-analysis.aggregate.js +0 -295
  84. package/src/analysis/graph-analysis.edges.js +0 -24
  85. package/src/analysis/graph-analysis.js +0 -7
  86. package/src/analysis/graph-analysis.refs.js +0 -154
  87. package/src/analysis/graph-analysis.summaries.js +0 -65
  88. package/src/analysis/health-capabilities.js +0 -83
  89. package/src/analysis/hot-path-review.js +0 -266
  90. package/src/analysis/http-contract-wrappers.js +0 -241
  91. package/src/analysis/http-contracts/analysis.js +0 -179
  92. package/src/analysis/http-contracts/client-call-detection.js +0 -82
  93. package/src/analysis/http-contracts/client-call-parser.js +0 -273
  94. package/src/analysis/http-contracts/graph-context.js +0 -143
  95. package/src/analysis/http-contracts/matching.js +0 -61
  96. package/src/analysis/http-contracts/shared.js +0 -85
  97. package/src/analysis/http-contracts.js +0 -6
  98. package/src/analysis/internal-audit/dependency-health.js +0 -113
  99. package/src/analysis/internal-audit/python-manifests.js +0 -78
  100. package/src/analysis/internal-audit/repo-files.js +0 -50
  101. package/src/analysis/internal-audit/supply-chain.js +0 -149
  102. package/src/analysis/internal-audit.collect.js +0 -213
  103. package/src/analysis/internal-audit.js +0 -9
  104. package/src/analysis/internal-audit.reach.js +0 -173
  105. package/src/analysis/internal-audit.run.js +0 -256
  106. package/src/analysis/java-source.js +0 -36
  107. package/src/analysis/jvm-artifact-index.js +0 -87
  108. package/src/analysis/jvm-dependency-evidence.js +0 -138
  109. package/src/analysis/jvm-manifests.js +0 -114
  110. package/src/analysis/manifests.js +0 -123
  111. package/src/analysis/package-reachability.js +0 -39
  112. package/src/analysis/source-complexity.ast.js +0 -97
  113. package/src/analysis/source-complexity.constants.js +0 -55
  114. package/src/analysis/source-complexity.js +0 -14
  115. package/src/analysis/source-complexity.report.js +0 -81
  116. package/src/analysis/source-complexity.walk.js +0 -228
  117. package/src/analysis/source-correctness/retry-patterns.js +0 -93
  118. package/src/analysis/source-correctness.js +0 -222
  119. package/src/analysis/static-test-reachability.js +0 -150
  120. package/src/analysis/structure/dependency-graph.js +0 -151
  121. package/src/analysis/structure/findings.js +0 -162
  122. package/src/analysis/task-retrieval.js +0 -107
  123. package/src/analysis/transport-contracts.js +0 -224
  124. package/src/analysis/transport-runtime-evidence.js +0 -155
  125. package/src/analysis-kit.mjs +0 -17
  126. package/src/bounds.js +0 -4
  127. package/src/build-graph.js +0 -209
  128. package/src/child-env.js +0 -7
  129. package/src/config.js +0 -5
  130. package/src/extension/local-services.mjs +0 -75
  131. package/src/git-exec.js +0 -67
  132. package/src/graph/build-worker.js +0 -49
  133. package/src/graph/builder/go-receiver-resolution.js +0 -112
  134. package/src/graph/builder/js/dynamic-import.js +0 -26
  135. package/src/graph/builder/js/queries.js +0 -48
  136. package/src/graph/builder/lang-csharp.js +0 -40
  137. package/src/graph/builder/lang-css.js +0 -29
  138. package/src/graph/builder/lang-go.js +0 -140
  139. package/src/graph/builder/lang-html.js +0 -29
  140. package/src/graph/builder/lang-java-calls.js +0 -142
  141. package/src/graph/builder/lang-java.js +0 -215
  142. package/src/graph/builder/lang-js.js +0 -291
  143. package/src/graph/builder/lang-python.js +0 -235
  144. package/src/graph/builder/lang-rust-calls.js +0 -63
  145. package/src/graph/builder/lang-rust.js +0 -299
  146. package/src/graph/builder/lang-solidity.js +0 -126
  147. package/src/graph/builder/lang-sql.js +0 -263
  148. package/src/graph/builder/pass2-resolution.js +0 -81
  149. package/src/graph/builder/spec-pkg.js +0 -87
  150. package/src/graph/community.js +0 -27
  151. package/src/graph/edge-provenance.js +0 -31
  152. package/src/graph/file-lock.js +0 -69
  153. package/src/graph/freshness-probe.js +0 -142
  154. package/src/graph/graph-filter.js +0 -63
  155. package/src/graph/incremental-refresh.js +0 -235
  156. package/src/graph/internal-builder.barrels.js +0 -235
  157. package/src/graph/internal-builder.build.js +0 -300
  158. package/src/graph/internal-builder.java.js +0 -33
  159. package/src/graph/internal-builder.js +0 -12
  160. package/src/graph/internal-builder.langs.js +0 -157
  161. package/src/graph/internal-builder.pass2.js +0 -163
  162. package/src/graph/internal-builder.resolvers.js +0 -286
  163. package/src/graph/layout.js +0 -51
  164. package/src/graph/node-id.js +0 -7
  165. package/src/graph/parser-artifact-boundary.js +0 -55
  166. package/src/graph/relations.js +0 -4
  167. package/src/graph/repo-registry.js +0 -124
  168. package/src/graph/resolvers/rust.js +0 -117
  169. package/src/infra/infra-items.js +0 -255
  170. package/src/infra/infra-registry.js +0 -184
  171. package/src/infra/infra.detect.js +0 -119
  172. package/src/infra/infra.js +0 -38
  173. package/src/infra/infra.match.js +0 -102
  174. package/src/infra/infra.scan.js +0 -93
  175. package/src/mcp/actions/graph-lifecycle.mjs +0 -148
  176. package/src/mcp/architecture-bootstrap.mjs +0 -168
  177. package/src/mcp/architecture-starter.mjs +0 -234
  178. package/src/mcp/catalog.mjs +0 -233
  179. package/src/mcp/company-contract-page.mjs +0 -142
  180. package/src/mcp/company-contract-reconcile.mjs +0 -87
  181. package/src/mcp/company-contract-verdict.mjs +0 -42
  182. package/src/mcp/evidence/bun-lock-graph.mjs +0 -209
  183. package/src/mcp/evidence/duplicate-member-order.mjs +0 -8
  184. package/src/mcp/evidence/package-graph-common.mjs +0 -115
  185. package/src/mcp/evidence/package-lock-graph.mjs +0 -92
  186. package/src/mcp/evidence-snapshot.architecture.mjs +0 -80
  187. package/src/mcp/evidence-snapshot.common.mjs +0 -158
  188. package/src/mcp/evidence-snapshot.duplicates.mjs +0 -213
  189. package/src/mcp/evidence-snapshot.health.mjs +0 -102
  190. package/src/mcp/evidence-snapshot.inventory.mjs +0 -148
  191. package/src/mcp/evidence-snapshot.mjs +0 -50
  192. package/src/mcp/evidence-snapshot.package-graph.mjs +0 -34
  193. package/src/mcp/evidence-snapshot.structure.mjs +0 -84
  194. package/src/mcp/extension-api.mjs +0 -77
  195. package/src/mcp/git-output.mjs +0 -7
  196. package/src/mcp/graph/context-core.mjs +0 -111
  197. package/src/mcp/graph/context-seeds.mjs +0 -207
  198. package/src/mcp/graph/context-state.mjs +0 -85
  199. package/src/mcp/graph/reverse-reach.mjs +0 -42
  200. package/src/mcp/graph/tools-core.mjs +0 -143
  201. package/src/mcp/graph/tools-query.mjs +0 -276
  202. package/src/mcp/graph-context.mjs +0 -5
  203. package/src/mcp/graph-diff.mjs +0 -218
  204. package/src/mcp/health/audit-format.mjs +0 -199
  205. package/src/mcp/health/audit.mjs +0 -174
  206. package/src/mcp/health/dead-code.mjs +0 -110
  207. package/src/mcp/health/duplicates.mjs +0 -85
  208. package/src/mcp/health/endpoints.mjs +0 -71
  209. package/src/mcp/health/structure.mjs +0 -219
  210. package/src/mcp/runtime-version.mjs +0 -31
  211. package/src/mcp/server/auto-refresh.mjs +0 -66
  212. package/src/mcp/server/runtime-config.mjs +0 -43
  213. package/src/mcp/server/shutdown.mjs +0 -40
  214. package/src/mcp/staleness-notice.mjs +0 -20
  215. package/src/mcp/sync/evidence-architecture.mjs +0 -54
  216. package/src/mcp/sync/evidence-common.mjs +0 -88
  217. package/src/mcp/sync/evidence-duplicates.mjs +0 -97
  218. package/src/mcp/sync/evidence-health.mjs +0 -56
  219. package/src/mcp/sync/evidence-packages.mjs +0 -95
  220. package/src/mcp/sync/payload-common.mjs +0 -97
  221. package/src/mcp/sync/payload-v2.mjs +0 -54
  222. package/src/mcp/sync/payload-v3.mjs +0 -79
  223. package/src/mcp/sync-evidence.mjs +0 -23
  224. package/src/mcp/sync-payload.mjs +0 -70
  225. package/src/mcp/tool-result.mjs +0 -54
  226. package/src/mcp/tools-actions.mjs +0 -11
  227. package/src/mcp/tools-architecture.mjs +0 -177
  228. package/src/mcp/tools-company.mjs +0 -251
  229. package/src/mcp/tools-context.mjs +0 -222
  230. package/src/mcp/tools-endpoints.mjs +0 -207
  231. package/src/mcp/tools-graph-hubs.mjs +0 -78
  232. package/src/mcp/tools-graph.mjs +0 -17
  233. package/src/mcp/tools-health.mjs +0 -24
  234. package/src/mcp/tools-history.mjs +0 -28
  235. package/src/mcp/tools-impact-change.mjs +0 -220
  236. package/src/mcp/tools-impact-precision.mjs +0 -89
  237. package/src/mcp/tools-impact.mjs +0 -169
  238. package/src/mcp/tools-source.mjs +0 -238
  239. package/src/mcp/tools-verified-change.mjs +0 -200
  240. package/src/mcp-rg.mjs +0 -50
  241. package/src/mcp-runtime.mjs +0 -2
  242. package/src/mcp-server.mjs +0 -298
  243. package/src/mcp-source-tools.mjs +0 -163
  244. package/src/path-classification.js +0 -220
  245. package/src/path-ignore.js +0 -69
  246. package/src/precision/lsp-client/constants.js +0 -12
  247. package/src/precision/lsp-client/environment.js +0 -20
  248. package/src/precision/lsp-client/errors.js +0 -15
  249. package/src/precision/lsp-client/lifecycle.js +0 -114
  250. package/src/precision/lsp-client/message-parser.js +0 -81
  251. package/src/precision/lsp-client/protocol.js +0 -212
  252. package/src/precision/lsp-client/registry.js +0 -59
  253. package/src/precision/lsp-client/repo-uri.js +0 -60
  254. package/src/precision/lsp-client/stdio-client.js +0 -140
  255. package/src/precision/lsp-client.js +0 -10
  256. package/src/precision/lsp-overlay/budget-policy.js +0 -78
  257. package/src/precision/lsp-overlay/build.js +0 -261
  258. package/src/precision/lsp-overlay/contract.js +0 -61
  259. package/src/precision/lsp-overlay/reference-results.js +0 -108
  260. package/src/precision/lsp-overlay/semantic-inputs.js +0 -62
  261. package/src/precision/lsp-overlay/source-session.js +0 -142
  262. package/src/precision/lsp-overlay/store.js +0 -150
  263. package/src/precision/lsp-overlay/target-index.js +0 -152
  264. package/src/precision/lsp-overlay/target-query.js +0 -55
  265. package/src/precision/lsp-overlay.js +0 -11
  266. package/src/precision/symbol-query.js +0 -224
  267. package/src/precision/typescript-lsp-provider.js +0 -12
  268. package/src/precision/typescript-provider/client.js +0 -89
  269. package/src/precision/typescript-provider/discovery.js +0 -124
  270. package/src/precision/typescript-provider/isolated-runtime.js +0 -39
  271. package/src/precision/typescript-provider/project-host.js +0 -254
  272. package/src/precision/typescript-provider/project-safety.js +0 -166
  273. package/src/precision/typescript-provider/reference-usage.js +0 -53
  274. package/src/process.js +0 -95
  275. package/src/repo-path.js +0 -53
  276. package/src/scan/discover.inventory.js +0 -78
  277. package/src/scan/discover.js +0 -5
  278. package/src/scan/discover.list.js +0 -79
  279. package/src/scan/discover.stack.js +0 -227
  280. package/src/scan/search.core.js +0 -24
  281. package/src/scan/search.git.js +0 -102
  282. package/src/scan/search.js +0 -9
  283. package/src/scan/search.node.js +0 -83
  284. package/src/scan/search.preview.js +0 -49
  285. package/src/scan/search.rg.js +0 -145
  286. package/src/security/advisory-store.js +0 -172
  287. package/src/security/installed-jvm-rust.js +0 -46
  288. package/src/security/installed.js +0 -280
  289. package/src/security/malware-file-heuristics.js +0 -121
  290. package/src/security/malware-heuristics.exclusions.js +0 -134
  291. package/src/security/malware-heuristics.js +0 -15
  292. package/src/security/malware-heuristics.roots.js +0 -145
  293. package/src/security/malware-heuristics.scan.js +0 -89
  294. package/src/security/malware-heuristics.sweep.js +0 -122
  295. package/src/security/malware-scoring.js +0 -105
  296. package/src/security/match.js +0 -85
  297. package/src/security/registry-sig.classify.js +0 -137
  298. package/src/security/registry-sig.js +0 -18
  299. package/src/security/registry-sig.rules.js +0 -192
  300. package/src/security/rust-advisory-report.js +0 -60
  301. package/src/security/typosquat.js +0 -81
  302. package/src/util.js +0 -40
  303. package/src/version.js +0 -7
@@ -1,89 +0,0 @@
1
- import {resolve} from 'node:path'
2
- import {startStdioLspClient} from '../lsp-client.js'
3
- import {WEAVATRIX_VERSION} from '../../version.js'
4
- import {
5
- discoverTypeScriptProvider,
6
- typeScriptLanguageId,
7
- typeScriptLspContract,
8
- } from './discovery.js'
9
- import {isolateTypeScriptRuntime} from './isolated-runtime.js'
10
-
11
- /** Starts Weavatrix's bundled TypeScript server without executing repository configuration. */
12
- export async function createTypeScriptLspClient({repoRoot, timeoutMs = 10_000} = {}) {
13
- const discovered = discoverTypeScriptProvider()
14
- const absoluteRepoRoot = resolve(repoRoot)
15
- const isolated = isolateTypeScriptRuntime(discovered.tsserverPath)
16
- let client
17
- let reportedTypeScript = null
18
- try {
19
- client = await startStdioLspClient({
20
- repoRoot: absoluteRepoRoot,
21
- executablePath: process.execPath,
22
- args: [discovered.cliPath, '--stdio'],
23
- requestTimeoutMs: timeoutMs,
24
- onNotification(method, params) {
25
- if (method === '$/typescriptVersion' && params && typeof params === 'object') {
26
- reportedTypeScript = {
27
- version: typeof params.version === 'string' ? params.version : null,
28
- source: typeof params.source === 'string' ? params.source : null,
29
- }
30
- }
31
- },
32
- })
33
- await client.initialize({
34
- clientInfo: {name: 'weavatrix', version: WEAVATRIX_VERSION},
35
- capabilities: {
36
- workspace: {configuration: true, workspaceFolders: true},
37
- textDocument: {
38
- definition: {linkSupport: true},
39
- references: {},
40
- rename: {},
41
- publishDiagnostics: {relatedInformation: false},
42
- },
43
- },
44
- initializationOptions: {
45
- hostInfo: 'weavatrix',
46
- disableAutomaticTypingAcquisition: true,
47
- tsserver: {path: isolated.tsserverPath},
48
- // An explicit empty list keeps the language-server plugin manager
49
- // from adding --globalPlugins or --pluginProbeLocations. tsserver's
50
- // local-plugin loading remains disabled by default as well.
51
- plugins: [],
52
- },
53
- })
54
- } catch (error) {
55
- client?.kill(error)
56
- isolated.cleanup()
57
- throw error
58
- }
59
- return Object.freeze({
60
- provider: discovered.provider,
61
- version: discovered.version,
62
- providerContract: typeScriptLspContract(),
63
- get typescriptVersion() { return reportedTypeScript?.version || discovered.typescriptVersion },
64
- get typescriptSource() { return reportedTypeScript?.source || 'configured-bundled-path' },
65
- async openDocument(relPath, text, languageId = typeScriptLanguageId(relPath)) {
66
- if (!languageId) throw new TypeError(`Unsupported TypeScript LSP document extension: ${relPath}`)
67
- return client.openDocument({filePath: relPath, text, languageId})
68
- },
69
- references(relPath, position, includeDeclaration = true, referenceTimeoutMs = timeoutMs) {
70
- return client.references({filePath: relPath, position, includeDeclaration, timeoutMs: referenceTimeoutMs})
71
- },
72
- // Generic read-only JSON-RPC passthrough plus URI normalization, so consumers outside
73
- // the core (weavatrix-refactor) can issue their own read-only LSP requests. The client
74
- // still refuses workspace/applyEdit, so nothing here can apply an edit.
75
- request(method, params, options) { return client.request(method, params, options) },
76
- toUri(relPath) { return client.normalizer.toUri(relPath) },
77
- fromUri(uri) { return client.normalizer.fromUri(uri) },
78
- definition(relPath, position) { return client.definition({filePath: relPath, position}) },
79
- closeDocument(relPath) { return client.closeDocument(relPath) },
80
- async close(shutdownTimeoutMs = timeoutMs) {
81
- try { return await client.shutdown({timeoutMs: shutdownTimeoutMs}) }
82
- finally { isolated.cleanup() }
83
- },
84
- kill() {
85
- try { client.kill() }
86
- finally { isolated.cleanup() }
87
- },
88
- })
89
- }
@@ -1,124 +0,0 @@
1
- import {existsSync, readFileSync, realpathSync} from 'node:fs'
2
- import {dirname, extname, isAbsolute, join} from 'node:path'
3
- import {createRequire} from 'node:module'
4
-
5
- const requireFromWeavatrix = createRequire(import.meta.url)
6
- const PROVIDER = 'typescript-language-server'
7
- export const TYPESCRIPT_LSP_CAPABILITY_CONTRACT = 'typescript-references-v4-plugin-suppression'
8
- let discoveredProvider = null
9
-
10
- function resolveOwn(specifier) {
11
- const resolved = requireFromWeavatrix.resolve(specifier)
12
- if (!isAbsolute(resolved)) throw new Error(`Resolved dependency path is not absolute: ${specifier}`)
13
- return realpathSync.native(resolved)
14
- }
15
-
16
- function packageInfoFrom(startPath, expectedName) {
17
- let directory = dirname(startPath)
18
- for (let depth = 0; depth < 10; depth++) {
19
- const packagePath = join(directory, 'package.json')
20
- if (existsSync(packagePath)) {
21
- try {
22
- const manifest = JSON.parse(readFileSync(packagePath, 'utf8'))
23
- if (manifest.name === expectedName) {
24
- return {directory, manifest, packagePath: realpathSync.native(packagePath)}
25
- }
26
- } catch { /* continue upward */ }
27
- }
28
- const parent = dirname(directory)
29
- if (parent === directory) break
30
- directory = parent
31
- }
32
- throw new Error(`Could not locate ${expectedName} package metadata`)
33
- }
34
-
35
- function resolveServerCli() {
36
- const candidates = [
37
- 'typescript-language-server',
38
- 'typescript-language-server/lib/cli.mjs',
39
- 'typescript-language-server/lib/cli.js',
40
- ]
41
- let lastError
42
- for (const candidate of candidates) {
43
- try {
44
- const path = resolveOwn(candidate)
45
- if (existsSync(path)) return path
46
- } catch (error) { lastError = error }
47
- }
48
- throw lastError || new Error('typescript-language-server CLI was not found')
49
- }
50
-
51
- function resolveTypeScriptServer() {
52
- const candidates = ['typescript/lib/tsserver.js', 'typescript/lib/_tsserver.js']
53
- let lastError
54
- for (const candidate of candidates) {
55
- try {
56
- const path = resolveOwn(candidate)
57
- if (existsSync(path)) return path
58
- } catch (error) { lastError = error }
59
- }
60
- try {
61
- const typescriptEntry = resolveOwn('typescript')
62
- for (const name of ['tsserver.js', '_tsserver.js']) {
63
- const candidate = join(dirname(typescriptEntry), name)
64
- if (existsSync(candidate)) return realpathSync.native(candidate)
65
- }
66
- } catch (error) { lastError = error }
67
- throw lastError || new Error('Bundled TypeScript tsserver was not found')
68
- }
69
-
70
- export function discoverTypeScriptProvider() {
71
- if (discoveredProvider) return discoveredProvider
72
- const cliPath = resolveServerCli()
73
- const tsserverPath = resolveTypeScriptServer()
74
- const serverPackage = packageInfoFrom(cliPath, PROVIDER)
75
- const typescriptPackage = packageInfoFrom(tsserverPath, 'typescript')
76
- discoveredProvider = Object.freeze({
77
- available: true,
78
- provider: PROVIDER,
79
- version: String(serverPackage.manifest.version || 'unknown'),
80
- typescriptVersion: String(typescriptPackage.manifest.version || 'unknown'),
81
- cliPath,
82
- tsserverPath,
83
- })
84
- return discoveredProvider
85
- }
86
-
87
- export function typeScriptLspAvailability() {
88
- try {
89
- const result = discoverTypeScriptProvider()
90
- return {
91
- available: true,
92
- provider: result.provider,
93
- version: result.version,
94
- typescriptVersion: result.typescriptVersion,
95
- }
96
- } catch (error) {
97
- return {
98
- available: false,
99
- provider: PROVIDER,
100
- version: null,
101
- typescriptVersion: null,
102
- reason: error?.code === 'MODULE_NOT_FOUND' ? 'DEPENDENCY_NOT_INSTALLED' : 'DISCOVERY_FAILED',
103
- }
104
- }
105
- }
106
-
107
- export function typeScriptLspContract() {
108
- const availability = typeScriptLspAvailability()
109
- return [
110
- TYPESCRIPT_LSP_CAPABILITY_CONTRACT,
111
- `${PROVIDER}@${availability.version || 'unavailable'}`,
112
- `typescript@${availability.typescriptVersion || 'unavailable'}`,
113
- `runtime@${process.platform}-${process.arch}-node${String(process.versions.node || '0').split('.')[0]}`,
114
- ].join('|')
115
- }
116
-
117
- export function typeScriptLanguageId(filePath) {
118
- const extension = extname(String(filePath)).toLowerCase()
119
- if (extension === '.ts' || extension === '.mts' || extension === '.cts') return 'typescript'
120
- if (extension === '.tsx') return 'typescriptreact'
121
- if (extension === '.js' || extension === '.mjs' || extension === '.cjs') return 'javascript'
122
- if (extension === '.jsx') return 'javascriptreact'
123
- return null
124
- }
@@ -1,39 +0,0 @@
1
- import {copyFileSync, linkSync, mkdirSync, mkdtempSync, readdirSync, rmSync} from 'node:fs'
2
- import {tmpdir} from 'node:os'
3
- import {basename, dirname, join} from 'node:path'
4
-
5
- const RUNTIME_FILES = new Set([
6
- 'tsserver.js', '_tsserver.js', 'typescript.js',
7
- 'typingsInstaller.js', '_typingsInstaller.js', 'typesMap.json', 'watchGuard.js',
8
- ])
9
-
10
- function materialize(source, target) {
11
- try { linkSync(source, target) }
12
- catch { copyFileSync(source, target) }
13
- }
14
-
15
- export function isolateTypeScriptRuntime(tsserverPath) {
16
- const sourceLib = dirname(tsserverPath)
17
- const sourceRoot = dirname(sourceLib)
18
- const root = mkdtempSync(join(tmpdir(), 'weavatrix-tsserver-'))
19
- const lib = join(root, 'lib')
20
- mkdirSync(lib, {recursive: true, mode: 0o700})
21
- try {
22
- materialize(join(sourceRoot, 'package.json'), join(root, 'package.json'))
23
- const files = readdirSync(sourceLib).filter((name) =>
24
- RUNTIME_FILES.has(name) || /^lib(?:\..+)?\.d\.ts$/i.test(name))
25
- for (const name of files) materialize(join(sourceLib, name), join(lib, basename(name)))
26
- let cleaned = false
27
- return {
28
- tsserverPath: join(lib, 'tsserver.js'),
29
- cleanup() {
30
- if (cleaned) return
31
- cleaned = true
32
- try { rmSync(root, {recursive: true, force: true}) } catch { /* process cleanup fallback */ }
33
- },
34
- }
35
- } catch (error) {
36
- try { rmSync(root, {recursive: true, force: true}) } catch { /* best effort */ }
37
- throw error
38
- }
39
- }
@@ -1,254 +0,0 @@
1
- import {createHash} from 'node:crypto'
2
- import {existsSync, opendirSync, readFileSync, realpathSync, statSync} from 'node:fs'
3
- import {dirname, isAbsolute, join, relative, resolve} from 'node:path'
4
- import {createRequire} from 'node:module'
5
- import {isPathInside} from '../../repo-path.js'
6
-
7
- const requireFromWeavatrix = createRequire(import.meta.url)
8
- const MAX_PROJECT_FILES = 8_192
9
- const MAX_CONFIG_FILES = 128
10
- const MAX_CONFIG_BYTES = 8 * 1024 * 1024
11
- const MAX_DIRECTORY_ENTRIES = 32_768
12
- const MAX_DIRECTORIES = 4_096
13
- const DEFAULT_SAFETY_TIMEOUT_MS = 5_000
14
- export const norm = (value) => String(value || '').replace(/\\/g, '/').replace(/^\.\//, '')
15
-
16
- export function canonicalKey(path, caseSensitive) {
17
- let canonical
18
- try { canonical = realpathSync.native(path) } catch { return null }
19
- return caseSensitive ? canonical : canonical.toLowerCase()
20
- }
21
-
22
- export function typeScriptRepoContext(repoRoot) {
23
- let root
24
- let ts
25
- try {
26
- root = realpathSync.native(repoRoot)
27
- ts = requireFromWeavatrix('typescript')
28
- } catch { return null }
29
- return {root, ts, caseSensitive: Boolean(ts.sys.useCaseSensitiveFileNames)}
30
- }
31
-
32
- export function guardedExistingPath(root, candidate, state = null) {
33
- const input = String(candidate || '')
34
- const lexical = isAbsolute(input) ? resolve(input) : resolve(root, input)
35
- if (!isPathInside(root, lexical)) {
36
- if (state) state.outsideAccess = true
37
- return null
38
- }
39
- try {
40
- const canonical = realpathSync.native(lexical)
41
- if (!isPathInside(root, canonical)) {
42
- if (state) state.outsideAccess = true
43
- return null
44
- }
45
- return canonical
46
- } catch { return null }
47
- }
48
-
49
- export function nearestTypeScriptConfig(context, absoluteFile) {
50
- const {root} = context
51
- let directory = dirname(absoluteFile)
52
- while (isPathInside(root, directory)) {
53
- for (const name of ['tsconfig.json', 'jsconfig.json']) {
54
- const candidate = join(directory, name)
55
- if (!existsSync(candidate)) continue
56
- const configPath = guardedExistingPath(root, candidate)
57
- return configPath ? {ok: true, configPath} : {ok: false, reason: 'CONFIG_OUTSIDE_REPOSITORY'}
58
- }
59
- if (directory === root) break
60
- const parent = dirname(directory)
61
- if (parent === directory) break
62
- directory = parent
63
- }
64
- return {ok: true, configPath: null}
65
- }
66
-
67
- export function safetyBudget(options = {}) {
68
- const requestedDeadline = Number(options.deadline)
69
- const requestedTimeout = Number(options.timeoutMs)
70
- const timeout = Number.isFinite(requestedTimeout)
71
- ? Math.max(100, Math.min(60_000, Math.floor(requestedTimeout)))
72
- : DEFAULT_SAFETY_TIMEOUT_MS
73
- return {
74
- deadline: Number.isFinite(requestedDeadline) ? requestedDeadline : Date.now() + timeout,
75
- maxEntries: Math.max(1, Math.min(MAX_DIRECTORY_ENTRIES,
76
- Number.isFinite(Number(options.maxDirectoryEntries))
77
- ? Math.floor(Number(options.maxDirectoryEntries)) : MAX_DIRECTORY_ENTRIES)),
78
- maxDirectories: Math.max(1, Math.min(MAX_DIRECTORIES,
79
- Number.isFinite(Number(options.maxDirectories))
80
- ? Math.floor(Number(options.maxDirectories)) : MAX_DIRECTORIES)),
81
- entries: 0,
82
- directories: 0,
83
- configBytes: 0,
84
- configFiles: new Set(),
85
- reason: null,
86
- }
87
- }
88
-
89
- function safetyLimitReached(budget, reason = 'PROJECT_INPUT_LIMIT') {
90
- if (!budget.reason && Date.now() >= budget.deadline) budget.reason = 'SAFETY_DEADLINE'
91
- if (!budget.reason && reason) budget.reason = reason
92
- return Boolean(budget.reason)
93
- }
94
-
95
- function boundedReadDirectory(context, state, budget, candidate, extensions, excludes, includes, depth) {
96
- const {root, ts, caseSensitive} = context
97
- const path = guardedExistingPath(root, candidate, state)
98
- if (!path || safetyLimitReached(budget, null)) return []
99
- const getFileSystemEntries = (directoryPath) => {
100
- if (safetyLimitReached(budget, null)) return {files: [], directories: []}
101
- const directory = guardedExistingPath(root, directoryPath, state)
102
- if (!directory) return {files: [], directories: []}
103
- budget.directories++
104
- if (budget.directories > budget.maxDirectories) {
105
- safetyLimitReached(budget)
106
- return {files: [], directories: []}
107
- }
108
- const files = []
109
- const directories = []
110
- let handle
111
- try {
112
- handle = opendirSync(directory)
113
- while (!safetyLimitReached(budget, null)) {
114
- const entry = handle.readSync()
115
- if (!entry) break
116
- budget.entries++
117
- if (budget.entries > budget.maxEntries) {
118
- safetyLimitReached(budget)
119
- break
120
- }
121
- if (entry.isFile()) files.push(entry.name)
122
- else if (entry.isDirectory()) directories.push(entry.name)
123
- else if (entry.isSymbolicLink()) {
124
- const linked = guardedExistingPath(root, join(directory, entry.name), state)
125
- if (!linked) continue
126
- let stats
127
- try { stats = statSync(linked) } catch { continue }
128
- if (stats.isFile()) files.push(entry.name)
129
- else if (stats.isDirectory()) directories.push(entry.name)
130
- }
131
- }
132
- } catch {
133
- return {files: [], directories: []}
134
- } finally {
135
- try { handle?.closeSync() } catch {}
136
- }
137
- return {files, directories}
138
- }
139
- const guardedRealpath = (entry) => guardedExistingPath(root, entry, state)
140
- || resolve(root, '.weavatrix-invalid-path')
141
- try {
142
- return ts.matchFiles(
143
- path, extensions, excludes, includes, caseSensitive, root, depth,
144
- getFileSystemEntries, guardedRealpath,
145
- )
146
- } catch {
147
- state.limitExceeded = true
148
- return []
149
- }
150
- }
151
-
152
- export function parseRepoConfig(context, configPath, budget) {
153
- const {root, ts, caseSensitive} = context
154
- const state = {
155
- outsideAccess: false,
156
- limitExceeded: false,
157
- configuredPlugins: new Set(),
158
- bytes: 0,
159
- records: new Map(),
160
- }
161
- const diagnostics = []
162
- const host = {
163
- useCaseSensitiveFileNames: caseSensitive,
164
- getCurrentDirectory: () => root,
165
- fileExists(candidate) {
166
- const path = guardedExistingPath(root, candidate, state)
167
- return Boolean(path && ts.sys.fileExists(path))
168
- },
169
- readFile(candidate) {
170
- if (safetyLimitReached(budget, null)) return undefined
171
- const path = guardedExistingPath(root, candidate, state)
172
- if (!path) return undefined
173
- let body
174
- try {
175
- const size = statSync(path).size
176
- if (size > MAX_CONFIG_BYTES || state.bytes + size > MAX_CONFIG_BYTES) {
177
- state.limitExceeded = true
178
- return undefined
179
- }
180
- body = readFileSync(path)
181
- } catch { return undefined }
182
- const rel = norm(relative(root, path))
183
- if (!state.records.has(rel)) {
184
- if (!budget.configFiles.has(rel)
185
- && (budget.configFiles.size >= MAX_CONFIG_FILES
186
- || budget.configBytes + body.byteLength > MAX_CONFIG_BYTES)) {
187
- state.limitExceeded = true
188
- safetyLimitReached(budget, 'CONFIG_INPUT_LIMIT')
189
- return undefined
190
- }
191
- if (!budget.configFiles.has(rel)) {
192
- budget.configFiles.add(rel)
193
- budget.configBytes += body.byteLength
194
- }
195
- state.records.set(rel, createHash('sha256').update(body).digest('hex'))
196
- state.bytes += body.byteLength
197
- }
198
- try {
199
- const raw = ts.parseConfigFileTextToJson(path, body.toString('utf8')).config
200
- for (const plugin of raw?.compilerOptions?.plugins || []) {
201
- const name = typeof plugin?.name === 'string' ? plugin.name.trim() : ''
202
- if (name) state.configuredPlugins.add(name.slice(0, 256))
203
- }
204
- } catch { /* parser diagnostics below decide safety */ }
205
- return body.toString('utf8')
206
- },
207
- readDirectory(candidate, extensions, excludes, includes, depth) {
208
- return boundedReadDirectory(context, state, budget, candidate, extensions, excludes, includes, depth)
209
- },
210
- onUnRecoverableConfigFileDiagnostic(diagnostic) { diagnostics.push(diagnostic) },
211
- trace() {},
212
- }
213
- let parsed
214
- try { parsed = ts.getParsedCommandLineOfConfigFile(configPath, {}, host) }
215
- catch { return {complete: false, reason: 'CONFIG_PARSE_FAILED'} }
216
- const errors = [...diagnostics, ...(parsed?.errors || [])]
217
- for (const plugin of parsed?.options?.plugins || []) {
218
- const name = typeof plugin?.name === 'string' ? plugin.name.trim() : ''
219
- if (name) state.configuredPlugins.add(name.slice(0, 256))
220
- }
221
- if (budget.reason) return {complete: false, reason: budget.reason}
222
- if (!parsed || state.outsideAccess || state.limitExceeded
223
- || errors.some((diagnostic) => diagnostic?.category === ts.DiagnosticCategory.Error)) {
224
- return {
225
- complete: false,
226
- reason: state.outsideAccess
227
- ? 'CONFIG_OUTSIDE_REPOSITORY'
228
- : state.limitExceeded ? 'CONFIG_INPUT_LIMIT' : 'CONFIG_PARSE_FAILED',
229
- }
230
- }
231
- const projectFiles = []
232
- const projectKeys = new Set()
233
- for (const file of parsed.fileNames) {
234
- const canonical = guardedExistingPath(root, file, state)
235
- if (!canonical) return {complete: false, reason: 'PROJECT_INPUT_OUTSIDE_REPOSITORY'}
236
- const key = caseSensitive ? canonical : canonical.toLowerCase()
237
- if (projectKeys.has(key)) continue
238
- projectKeys.add(key)
239
- projectFiles.push(norm(relative(root, canonical)))
240
- if (projectFiles.length > MAX_PROJECT_FILES) return {complete: false, reason: 'PROJECT_INPUT_LIMIT'}
241
- }
242
- projectFiles.sort()
243
- return {
244
- complete: true,
245
- parsed,
246
- projectFiles,
247
- projectKeys,
248
- configRecords: state.records,
249
- // The bundled provider runs an isolated tsserver copy whose plugin search
250
- // root contains only TypeScript runtime files. Keep configured plugin names
251
- // as evidence, but never execute them from the inspected repository/bundle.
252
- plugins: [...state.configuredPlugins].sort(),
253
- }
254
- }
@@ -1,166 +0,0 @@
1
- import {createHash} from 'node:crypto'
2
- import {readFileSync, statSync} from 'node:fs'
3
- import {relative} from 'node:path'
4
- import {
5
- canonicalKey,
6
- guardedExistingPath,
7
- nearestTypeScriptConfig,
8
- norm,
9
- parseRepoConfig,
10
- safetyBudget,
11
- typeScriptRepoContext,
12
- } from './project-host.js'
13
-
14
- const MAX_PROJECT_FILES = 8_192
15
- const MAX_CONFIG_FILES = 128
16
- const MAX_EXTRA_INPUT_BYTES = 64 * 1024 * 1024
17
- const MAX_PROJECT_INPUT_BYTES = 128 * 1024 * 1024
18
- const MAX_SINGLE_INPUT_BYTES = 4 * 1024 * 1024
19
-
20
- function referenceConfigPath(context, reference) {
21
- const {root, ts} = context
22
- let candidate
23
- try {
24
- candidate = typeof ts.resolveProjectReferencePath === 'function'
25
- ? ts.resolveProjectReferencePath(reference)
26
- : reference?.path
27
- } catch { return null }
28
- if (!candidate) return null
29
- return guardedExistingPath(root, candidate)
30
- }
31
-
32
- export function typeScriptProjectSafety(repoRoot, relFiles = [], options = {}) {
33
- const context = typeScriptRepoContext(repoRoot)
34
- if (!context) return {safe: false, reason: 'TYPESCRIPT_UNAVAILABLE', fingerprint: null}
35
- const {root} = context
36
- const budget = safetyBudget(options)
37
- const files = [...new Set((relFiles || []).map(norm).filter(Boolean))].sort()
38
- if (files.length > MAX_PROJECT_FILES) return {safe: false, reason: 'PROJECT_INPUT_LIMIT', fingerprint: null}
39
- const graphFiles = new Set(files)
40
- const mappings = []
41
- const fileConfigs = {}
42
- const queue = []
43
- const queued = new Set()
44
- for (const file of files) {
45
- const absolute = guardedExistingPath(root, file)
46
- if (!absolute) return {safe: false, reason: 'UNREADABLE_PROJECT_INPUT', fingerprint: null}
47
- const nearest = nearestTypeScriptConfig(context, absolute)
48
- if (!nearest.ok) return {safe: false, reason: nearest.reason, fingerprint: null}
49
- const configRel = nearest.configPath ? norm(relative(root, nearest.configPath)) : '<inferred>'
50
- mappings.push(`${file}=>${configRel}`)
51
- fileConfigs[file] = nearest.configPath ? configRel : null
52
- if (nearest.configPath && !queued.has(nearest.configPath)) {
53
- queued.add(nearest.configPath)
54
- queue.push(nearest.configPath)
55
- }
56
- }
57
-
58
- const configRecords = new Map()
59
- const projectFiles = new Set()
60
- const configuredPlugins = new Set()
61
- const projects = {}
62
- for (let cursor = 0; cursor < queue.length; cursor++) {
63
- if (Date.now() >= budget.deadline) return {safe: false, reason: 'SAFETY_DEADLINE', fingerprint: null}
64
- if (queue.length > MAX_CONFIG_FILES) return {safe: false, reason: 'CONFIG_INPUT_LIMIT', fingerprint: null}
65
- const configPath = queue[cursor]
66
- const parsed = parseRepoConfig(context, configPath, budget)
67
- if (!parsed.complete) return {safe: false, reason: parsed.reason, fingerprint: null}
68
- const configRel = norm(relative(root, configPath))
69
- projects[configRel] = {
70
- projectFiles: parsed.projectFiles,
71
- configFiles: [...parsed.configRecords.keys()].sort(),
72
- configuredPlugins: parsed.plugins,
73
- }
74
- for (const plugin of parsed.plugins || []) configuredPlugins.add(plugin)
75
- for (const [file, digest] of parsed.configRecords) {
76
- configRecords.set(file, digest)
77
- if (configRecords.size > MAX_CONFIG_FILES) {
78
- return {safe: false, reason: 'CONFIG_INPUT_LIMIT', fingerprint: null}
79
- }
80
- }
81
- for (const file of parsed.projectFiles) {
82
- projectFiles.add(file)
83
- if (projectFiles.size > MAX_PROJECT_FILES) {
84
- return {safe: false, reason: 'PROJECT_INPUT_LIMIT', fingerprint: null}
85
- }
86
- }
87
- for (const reference of parsed.parsed.projectReferences || []) {
88
- const referenced = referenceConfigPath(context, reference)
89
- if (!referenced) return {safe: false, reason: 'PROJECT_REFERENCE_UNRESOLVED', fingerprint: null}
90
- if (!queued.has(referenced)) {
91
- queued.add(referenced)
92
- queue.push(referenced)
93
- }
94
- }
95
- }
96
-
97
- const extraRecords = []
98
- let projectBytes = 0
99
- let extraBytes = 0
100
- for (const file of [...projectFiles].sort()) {
101
- if (Date.now() >= budget.deadline) return {safe: false, reason: 'SAFETY_DEADLINE', fingerprint: null}
102
- const absolute = guardedExistingPath(root, file)
103
- if (!absolute) return {safe: false, reason: 'UNREADABLE_PROJECT_INPUT', fingerprint: null}
104
- let size
105
- try {
106
- const stats = statSync(absolute)
107
- if (!stats.isFile()) return {safe: false, reason: 'UNREADABLE_PROJECT_INPUT', fingerprint: null}
108
- size = stats.size
109
- if (size > MAX_SINGLE_INPUT_BYTES || projectBytes + size > MAX_PROJECT_INPUT_BYTES) {
110
- return {safe: false, reason: 'PROJECT_INPUT_LIMIT', fingerprint: null}
111
- }
112
- } catch { return {safe: false, reason: 'UNREADABLE_PROJECT_INPUT', fingerprint: null} }
113
- projectBytes += size
114
- if (graphFiles.has(file)) continue
115
- if (extraBytes + size > MAX_EXTRA_INPUT_BYTES) {
116
- return {safe: false, reason: 'PROJECT_INPUT_LIMIT', fingerprint: null}
117
- }
118
- let body
119
- try { body = readFileSync(absolute) }
120
- catch { return {safe: false, reason: 'UNREADABLE_PROJECT_INPUT', fingerprint: null} }
121
- extraBytes += body.byteLength
122
- extraRecords.push(`${file}:${createHash('sha256').update(body).digest('hex')}`)
123
- }
124
- const fingerprint = createHash('sha256').update([
125
- ...mappings.map((item) => `map:${item}`),
126
- ...[...configRecords.entries()].sort(([a], [b]) => a.localeCompare(b))
127
- .map(([file, digest]) => `config:${file}:${digest}`),
128
- ...[...projectFiles].sort().map((file) => `project:${file}`),
129
- ...extraRecords.map((item) => `extra:${item}`),
130
- ].join('\n')).digest('hex')
131
- return {
132
- safe: true,
133
- reason: null,
134
- fingerprint,
135
- configFiles: [...configRecords.keys()].sort(),
136
- projectFiles: [...projectFiles].sort(),
137
- fileConfigs,
138
- projects,
139
- configuredPlugins: [...configuredPlugins].sort(),
140
- pluginsSuppressed: configuredPlugins.size,
141
- }
142
- }
143
-
144
- export function typeScriptConfiguredProjectMembership(repoRoot, relFile) {
145
- const context = typeScriptRepoContext(repoRoot)
146
- if (!context) return {complete: false, member: false, reason: 'TYPESCRIPT_UNAVAILABLE'}
147
- const {root, caseSensitive} = context
148
- const target = guardedExistingPath(root, relFile)
149
- if (!target) return {complete: false, member: false, reason: 'UNREADABLE_PATH'}
150
- const nearest = nearestTypeScriptConfig(context, target)
151
- if (!nearest.ok) return {complete: false, member: false, reason: nearest.reason}
152
- const configPath = nearest.configPath
153
- if (!configPath) return {complete: false, member: false, reason: 'NO_CONFIGURED_PROJECT'}
154
- const parsed = parseRepoConfig(context, configPath, safetyBudget())
155
- if (!parsed.complete) return {complete: false, member: false, reason: parsed.reason}
156
- const targetKey = canonicalKey(target, caseSensitive)
157
- const member = parsed.projectKeys.has(targetKey)
158
- return {
159
- complete: true,
160
- member,
161
- projectFiles: parsed.projectFiles,
162
- configFiles: [...parsed.configRecords.keys()].sort(),
163
- configFile: norm(relative(root, configPath)),
164
- reason: member ? null : 'NOT_IN_CONFIGURED_PROJECT',
165
- }
166
- }