weavatrix 0.2.13 → 0.2.14

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 (130) hide show
  1. package/README.md +83 -39
  2. package/SECURITY.md +2 -2
  3. package/docs/releases/v0.2.14.md +93 -0
  4. package/package.json +2 -2
  5. package/skill/SKILL.md +57 -38
  6. package/src/analysis/architecture/contract-graph.js +119 -0
  7. package/src/analysis/architecture/contract-schema.js +110 -0
  8. package/src/analysis/architecture/contract-storage.js +35 -0
  9. package/src/analysis/architecture/contract-verification.js +168 -0
  10. package/src/analysis/architecture-contract.js +16 -343
  11. package/src/analysis/change-classification/diff-parser.js +103 -0
  12. package/src/analysis/change-classification/options.js +40 -0
  13. package/src/analysis/change-classification/symbol-classifier.js +177 -0
  14. package/src/analysis/change-classification.js +120 -519
  15. package/src/analysis/dead-code-review/policy.js +23 -0
  16. package/src/analysis/dead-code-review.js +9 -19
  17. package/src/analysis/dep-check.js +10 -57
  18. package/src/analysis/dep-rules.js +10 -303
  19. package/src/analysis/dependency/scoped-dependencies.js +40 -0
  20. package/src/analysis/endpoints/common.js +62 -0
  21. package/src/analysis/endpoints/extract.js +107 -0
  22. package/src/analysis/endpoints/inventory.js +84 -0
  23. package/src/analysis/endpoints/mounts.js +129 -0
  24. package/src/analysis/endpoints-java.js +80 -3
  25. package/src/analysis/endpoints.js +3 -448
  26. package/src/analysis/git-history/analytics.js +177 -0
  27. package/src/analysis/git-history/collector.js +109 -0
  28. package/src/analysis/git-history/options.js +68 -0
  29. package/src/analysis/git-history.js +128 -577
  30. package/src/analysis/health-capabilities.js +82 -0
  31. package/src/analysis/http-contracts/analysis.js +169 -0
  32. package/src/analysis/http-contracts/client-call-detection.js +81 -0
  33. package/src/analysis/http-contracts/client-call-parser.js +255 -0
  34. package/src/analysis/http-contracts/graph-context.js +143 -0
  35. package/src/analysis/http-contracts/matching.js +61 -0
  36. package/src/analysis/http-contracts/shared.js +86 -0
  37. package/src/analysis/http-contracts.js +6 -822
  38. package/src/analysis/internal-audit/dependency-health.js +111 -0
  39. package/src/analysis/internal-audit/python-manifests.js +65 -0
  40. package/src/analysis/internal-audit/repo-files.js +55 -0
  41. package/src/analysis/internal-audit/supply-chain.js +132 -0
  42. package/src/analysis/internal-audit.collect.js +5 -106
  43. package/src/analysis/internal-audit.run.js +113 -200
  44. package/src/analysis/jvm-dependency-evidence.js +69 -0
  45. package/src/analysis/source-correctness/retry-patterns.js +93 -0
  46. package/src/analysis/source-correctness.js +225 -0
  47. package/src/analysis/structure/dependency-graph.js +156 -0
  48. package/src/analysis/structure/findings.js +142 -0
  49. package/src/graph/builder/go-receiver-resolution.js +112 -0
  50. package/src/graph/builder/js/queries.js +48 -0
  51. package/src/graph/builder/lang-go.js +89 -4
  52. package/src/graph/builder/lang-js.js +4 -44
  53. package/src/graph/builder/pass2-resolution.js +68 -0
  54. package/src/graph/freshness-probe.js +2 -1
  55. package/src/graph/incremental-refresh.js +3 -2
  56. package/src/graph/internal-builder.build.js +22 -183
  57. package/src/graph/internal-builder.pass2.js +161 -0
  58. package/src/graph/internal-builder.resolvers.js +2 -105
  59. package/src/graph/resolvers/rust.js +117 -0
  60. package/src/mcp/actions/advisories.mjs +18 -0
  61. package/src/mcp/actions/graph-lifecycle.mjs +148 -0
  62. package/src/mcp/actions/graph-sync.mjs +195 -0
  63. package/src/mcp/actions/hosted-architecture.mjs +57 -0
  64. package/src/mcp/architecture-bootstrap.mjs +168 -0
  65. package/src/mcp/architecture-starter.mjs +234 -0
  66. package/src/mcp/catalog.mjs +20 -6
  67. package/src/mcp/evidence/bun-lock-graph.mjs +209 -0
  68. package/src/mcp/evidence/package-graph-common.mjs +115 -0
  69. package/src/mcp/evidence/package-lock-graph.mjs +92 -0
  70. package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
  71. package/src/mcp/graph/context-core.mjs +111 -0
  72. package/src/mcp/graph/context-seeds.mjs +208 -0
  73. package/src/mcp/graph/context-state.mjs +86 -0
  74. package/src/mcp/graph/tools-core.mjs +143 -0
  75. package/src/mcp/graph/tools-query.mjs +223 -0
  76. package/src/mcp/graph-context.mjs +4 -496
  77. package/src/mcp/health/audit-format.mjs +172 -0
  78. package/src/mcp/health/audit.mjs +171 -0
  79. package/src/mcp/health/dead-code.mjs +110 -0
  80. package/src/mcp/health/duplicates.mjs +83 -0
  81. package/src/mcp/health/endpoints.mjs +42 -0
  82. package/src/mcp/health/structure.mjs +219 -0
  83. package/src/mcp/runtime-version.mjs +32 -0
  84. package/src/mcp/server/auto-refresh.mjs +66 -0
  85. package/src/mcp/server/runtime-config.mjs +43 -0
  86. package/src/mcp/server/shutdown.mjs +40 -0
  87. package/src/mcp/sync/evidence-architecture.mjs +54 -0
  88. package/src/mcp/sync/evidence-common.mjs +88 -0
  89. package/src/mcp/sync/evidence-duplicates.mjs +100 -0
  90. package/src/mcp/sync/evidence-health.mjs +56 -0
  91. package/src/mcp/sync/evidence-packages.mjs +95 -0
  92. package/src/mcp/sync/payload-common.mjs +97 -0
  93. package/src/mcp/sync/payload-v2.mjs +53 -0
  94. package/src/mcp/sync/payload-v3.mjs +79 -0
  95. package/src/mcp/sync-evidence.mjs +7 -402
  96. package/src/mcp/sync-payload.mjs +10 -244
  97. package/src/mcp/tools-actions.mjs +18 -414
  98. package/src/mcp/tools-architecture.mjs +18 -70
  99. package/src/mcp/tools-context.mjs +56 -15
  100. package/src/mcp/tools-endpoints.mjs +4 -1
  101. package/src/mcp/tools-graph.mjs +17 -331
  102. package/src/mcp/tools-health.mjs +24 -705
  103. package/src/mcp-server.mjs +35 -146
  104. package/src/precision/lsp-client/constants.js +12 -0
  105. package/src/precision/lsp-client/environment.js +20 -0
  106. package/src/precision/lsp-client/errors.js +15 -0
  107. package/src/precision/lsp-client/lifecycle.js +127 -0
  108. package/src/precision/lsp-client/message-parser.js +81 -0
  109. package/src/precision/lsp-client/protocol.js +212 -0
  110. package/src/precision/lsp-client/registry.js +58 -0
  111. package/src/precision/lsp-client/repo-uri.js +60 -0
  112. package/src/precision/lsp-client/stdio-client.js +151 -0
  113. package/src/precision/lsp-client.js +10 -682
  114. package/src/precision/lsp-overlay/build.js +238 -0
  115. package/src/precision/lsp-overlay/contract.js +61 -0
  116. package/src/precision/lsp-overlay/reference-results.js +108 -0
  117. package/src/precision/lsp-overlay/semantic-inputs.js +62 -0
  118. package/src/precision/lsp-overlay/source-session.js +134 -0
  119. package/src/precision/lsp-overlay/store.js +150 -0
  120. package/src/precision/lsp-overlay/target-index.js +147 -0
  121. package/src/precision/lsp-overlay/target-query.js +55 -0
  122. package/src/precision/lsp-overlay.js +11 -868
  123. package/src/precision/typescript-lsp-provider.js +12 -682
  124. package/src/precision/typescript-provider/client.js +69 -0
  125. package/src/precision/typescript-provider/discovery.js +124 -0
  126. package/src/precision/typescript-provider/project-host.js +249 -0
  127. package/src/precision/typescript-provider/project-safety.js +161 -0
  128. package/src/precision/typescript-provider/reference-usage.js +53 -0
  129. package/src/version.js +7 -0
  130. package/docs/releases/v0.2.13.md +0 -48
@@ -0,0 +1,109 @@
1
+ import {spawn} from 'node:child_process'
2
+ import {isWeavatrixIgnored} from '../../path-ignore.js'
3
+ import {
4
+ boundedHistoryInteger,
5
+ GIT_HISTORY_DEFAULTS as DEFAULTS,
6
+ GIT_HISTORY_HARD_CAPS as HARD_CAPS,
7
+ safeHistoryPath,
8
+ } from './options.js'
9
+
10
+ const HEADER_SEPARATOR = '\x1e'
11
+ const FIELD_SEPARATOR = '\x1f'
12
+
13
+ export function boundedGitCommand(command, args, options) {
14
+ return new Promise((resolve, reject) => {
15
+ const child = spawn(command, args, {
16
+ cwd: options.cwd, env: options.env, shell: false, windowsHide: true,
17
+ stdio: ['ignore', 'pipe', 'pipe'],
18
+ })
19
+ const stdout = [], stderr = []
20
+ let stdoutBytes = 0, stderrBytes = 0, truncated = false, timedOut = false, settled = false
21
+ const finish = (callback) => {
22
+ if (settled) return
23
+ settled = true
24
+ clearTimeout(timer)
25
+ callback()
26
+ }
27
+ const stop = () => { try { child.kill('SIGKILL') } catch { /* process already exited */ } }
28
+ const timer = setTimeout(() => { timedOut = true; stop() }, options.timeoutMs)
29
+ child.stdout?.on('data', (chunk) => {
30
+ if (truncated) return
31
+ const remaining = options.maxOutputBytes - stdoutBytes
32
+ if (remaining <= 0) { truncated = true; stop(); return }
33
+ const kept = chunk.length <= remaining ? chunk : chunk.subarray(0, remaining)
34
+ stdout.push(kept); stdoutBytes += kept.length
35
+ if (kept.length !== chunk.length) { truncated = true; stop() }
36
+ })
37
+ child.stderr?.on('data', (chunk) => {
38
+ const remaining = 64 * 1024 - stderrBytes
39
+ if (remaining <= 0) return
40
+ const kept = chunk.length <= remaining ? chunk : chunk.subarray(0, remaining)
41
+ stderr.push(kept); stderrBytes += kept.length
42
+ })
43
+ child.on('error', (error) => finish(() => reject(error)))
44
+ child.on('close', (exitCode) => finish(() => {
45
+ if (timedOut) return reject(new Error('git history collection timed out'))
46
+ resolve({
47
+ stdout: Buffer.concat(stdout),
48
+ stderr: Buffer.concat(stderr).toString('utf8'),
49
+ exitCode: Number(exitCode ?? 1),
50
+ truncated,
51
+ })
52
+ }))
53
+ })
54
+ }
55
+
56
+ const statNumber = (value) => value === '-'
57
+ ? {value: 0, binary: true}
58
+ : {value: Number(value), binary: false}
59
+
60
+ export function parseGitNumstatLog(raw, options = {}) {
61
+ const maxFiles = boundedHistoryInteger(options.maxFilesPerCommit, DEFAULTS.maxFilesPerCommit, 2, HARD_CAPS.maxFilesPerCommit)
62
+ const ignoreRules = options.ignoreRules || []
63
+ const text = Buffer.isBuffer(raw) ? raw.toString('utf8') : String(raw || '')
64
+ const segments = text.split(HEADER_SEPARATOR).slice(1)
65
+ if (options.dropLastIncomplete && segments.length) segments.pop()
66
+ const commits = []
67
+ for (const segment of segments) {
68
+ const firstNul = segment.indexOf('\0')
69
+ if (firstNul < 0) continue
70
+ const header = segment.slice(0, firstNul).replace(/^[\r\n]+/, '')
71
+ const separator = header.indexOf(FIELD_SEPARATOR)
72
+ if (separator < 0) continue
73
+ const hash = header.slice(0, separator), timestamp = Number(header.slice(separator + 1))
74
+ if (!/^[a-f0-9]{40,64}$/i.test(hash) || !Number.isInteger(timestamp) || timestamp < 0) continue
75
+ const tokens = segment.slice(firstNul + 1).split('\0'), files = new Map()
76
+ let fileCount = 0, ignoredFiles = 0, invalidPaths = 0, oversized = false
77
+ for (let index = 0; index < tokens.length; index += 1) {
78
+ const token = tokens[index].replace(/^[\r\n]+/, '')
79
+ const match = /^(\d+|-)\t(\d+|-)\t(.*)$/s.exec(token)
80
+ if (!match) continue
81
+ let rawPath = match[3], renamedFrom = null
82
+ if (!rawPath) {
83
+ renamedFrom = safeHistoryPath(tokens[index + 1])
84
+ rawPath = tokens[index + 2]
85
+ index += 2
86
+ }
87
+ const path = safeHistoryPath(rawPath)
88
+ if (!path) { invalidPaths++; continue }
89
+ if (isWeavatrixIgnored(path, ignoreRules)) { ignoredFiles++; continue }
90
+ const additions = statNumber(match[1]), deletions = statNumber(match[2])
91
+ fileCount++
92
+ if (fileCount > maxFiles) { oversized = true; files.clear(); continue }
93
+ if (oversized) continue
94
+ const previous = files.get(path)
95
+ files.set(path, {
96
+ file: path,
97
+ additions: (previous?.additions || 0) + additions.value,
98
+ deletions: (previous?.deletions || 0) + deletions.value,
99
+ binary: Boolean(previous?.binary || additions.binary || deletions.binary),
100
+ ...(renamedFrom ? {renamedFrom} : previous?.renamedFrom ? {renamedFrom: previous.renamedFrom} : {}),
101
+ })
102
+ }
103
+ commits.push({
104
+ hash, timestamp, fileCount, ignoredFiles, invalidPaths, oversized,
105
+ files: oversized ? [] : [...files.values()].sort((a, b) => a.file.localeCompare(b.file)),
106
+ })
107
+ }
108
+ return commits
109
+ }
@@ -0,0 +1,68 @@
1
+ import {isAbsolute} from 'node:path'
2
+
3
+ export const GIT_HISTORY_V = 1
4
+ export const GIT_HISTORY_WINDOWS = Object.freeze([3, 6, 12])
5
+ export const GIT_HISTORY_DEFAULTS = Object.freeze({
6
+ months: 6,
7
+ maxCommits: 500,
8
+ maxFilesPerCommit: 80,
9
+ maxPairs: 100,
10
+ minPairCount: 2,
11
+ maxPairCandidates: 100_000,
12
+ maxOutputBytes: 16 * 1024 * 1024,
13
+ timeoutMs: 20_000,
14
+ })
15
+ export const GIT_HISTORY_HARD_CAPS = Object.freeze({
16
+ maxCommits: 2_000,
17
+ maxFilesPerCommit: 200,
18
+ maxPairs: 500,
19
+ maxPairCandidates: 250_000,
20
+ maxOutputBytes: 64 * 1024 * 1024,
21
+ timeoutMs: 60_000,
22
+ })
23
+ export const GIT_FORMAT = '%x1e%H%x1f%ct'
24
+
25
+ export const graphEndpoint = (value) => value && typeof value === 'object' ? value.id : value
26
+ export const roundHistoryNumber = (value, digits = 4) => {
27
+ if (!Number.isFinite(value)) return 0
28
+ const scale = 10 ** digits
29
+ return Math.round(value * scale) / scale
30
+ }
31
+ export const boundedHistoryInteger = (value, fallback, min, max) => {
32
+ const number = Number(value)
33
+ return Number.isInteger(number) ? Math.max(min, Math.min(max, number)) : fallback
34
+ }
35
+
36
+ export function safeHistoryPath(value) {
37
+ const path = String(value || '').replace(/\\/g, '/').replace(/^\.\//, '')
38
+ if (!path || path.includes('\0') || isAbsolute(path) || /^[a-z]:\//i.test(path)) return null
39
+ if (/[\x00-\x1f\x7f]/.test(path)) return null
40
+ const parts = path.split('/')
41
+ return parts.some((part) => !part || part === '.' || part === '..') ? null : path
42
+ }
43
+
44
+ export function utcMonthsBefore(date, months) {
45
+ const source = new Date(date)
46
+ if (!Number.isFinite(source.getTime())) throw new Error('now must be a valid date')
47
+ const targetMonth = source.getUTCMonth() - months
48
+ const first = new Date(Date.UTC(source.getUTCFullYear(), targetMonth, 1, source.getUTCHours(), source.getUTCMinutes(), source.getUTCSeconds(), source.getUTCMilliseconds()))
49
+ const lastDay = new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth() + 1, 0)).getUTCDate()
50
+ first.setUTCDate(Math.min(source.getUTCDate(), lastDay))
51
+ return first
52
+ }
53
+
54
+ export function normalizeGitHistoryOptions(input = {}) {
55
+ const defaults = GIT_HISTORY_DEFAULTS, caps = GIT_HISTORY_HARD_CAPS
56
+ const months = Number(input.months ?? defaults.months)
57
+ if (!GIT_HISTORY_WINDOWS.includes(months)) throw new Error('months must be one of 3, 6 or 12')
58
+ return {
59
+ months,
60
+ maxCommits: boundedHistoryInteger(input.maxCommits, defaults.maxCommits, 1, caps.maxCommits),
61
+ maxFilesPerCommit: boundedHistoryInteger(input.maxFilesPerCommit, defaults.maxFilesPerCommit, 2, caps.maxFilesPerCommit),
62
+ maxPairs: boundedHistoryInteger(input.maxPairs, defaults.maxPairs, 1, caps.maxPairs),
63
+ minPairCount: boundedHistoryInteger(input.minPairCount, defaults.minPairCount, 1, 100),
64
+ maxPairCandidates: boundedHistoryInteger(input.maxPairCandidates, defaults.maxPairCandidates, 100, caps.maxPairCandidates),
65
+ maxOutputBytes: boundedHistoryInteger(input.maxOutputBytes, defaults.maxOutputBytes, 64 * 1024, caps.maxOutputBytes),
66
+ timeoutMs: boundedHistoryInteger(input.timeoutMs, defaults.timeoutMs, 1_000, caps.timeoutMs),
67
+ }
68
+ }