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.
- package/README.md +83 -39
- package/SECURITY.md +2 -2
- package/docs/releases/v0.2.14.md +93 -0
- package/package.json +2 -2
- package/skill/SKILL.md +57 -38
- package/src/analysis/architecture/contract-graph.js +119 -0
- package/src/analysis/architecture/contract-schema.js +110 -0
- package/src/analysis/architecture/contract-storage.js +35 -0
- package/src/analysis/architecture/contract-verification.js +168 -0
- package/src/analysis/architecture-contract.js +16 -343
- package/src/analysis/change-classification/diff-parser.js +103 -0
- package/src/analysis/change-classification/options.js +40 -0
- package/src/analysis/change-classification/symbol-classifier.js +177 -0
- package/src/analysis/change-classification.js +120 -519
- package/src/analysis/dead-code-review/policy.js +23 -0
- package/src/analysis/dead-code-review.js +9 -19
- package/src/analysis/dep-check.js +10 -57
- package/src/analysis/dep-rules.js +10 -303
- package/src/analysis/dependency/scoped-dependencies.js +40 -0
- package/src/analysis/endpoints/common.js +62 -0
- package/src/analysis/endpoints/extract.js +107 -0
- package/src/analysis/endpoints/inventory.js +84 -0
- package/src/analysis/endpoints/mounts.js +129 -0
- package/src/analysis/endpoints-java.js +80 -3
- package/src/analysis/endpoints.js +3 -448
- package/src/analysis/git-history/analytics.js +177 -0
- package/src/analysis/git-history/collector.js +109 -0
- package/src/analysis/git-history/options.js +68 -0
- package/src/analysis/git-history.js +128 -577
- package/src/analysis/health-capabilities.js +82 -0
- package/src/analysis/http-contracts/analysis.js +169 -0
- package/src/analysis/http-contracts/client-call-detection.js +81 -0
- package/src/analysis/http-contracts/client-call-parser.js +255 -0
- package/src/analysis/http-contracts/graph-context.js +143 -0
- package/src/analysis/http-contracts/matching.js +61 -0
- package/src/analysis/http-contracts/shared.js +86 -0
- package/src/analysis/http-contracts.js +6 -822
- package/src/analysis/internal-audit/dependency-health.js +111 -0
- package/src/analysis/internal-audit/python-manifests.js +65 -0
- package/src/analysis/internal-audit/repo-files.js +55 -0
- package/src/analysis/internal-audit/supply-chain.js +132 -0
- package/src/analysis/internal-audit.collect.js +5 -106
- package/src/analysis/internal-audit.run.js +113 -200
- package/src/analysis/jvm-dependency-evidence.js +69 -0
- package/src/analysis/source-correctness/retry-patterns.js +93 -0
- package/src/analysis/source-correctness.js +225 -0
- package/src/analysis/structure/dependency-graph.js +156 -0
- package/src/analysis/structure/findings.js +142 -0
- package/src/graph/builder/go-receiver-resolution.js +112 -0
- package/src/graph/builder/js/queries.js +48 -0
- package/src/graph/builder/lang-go.js +89 -4
- package/src/graph/builder/lang-js.js +4 -44
- package/src/graph/builder/pass2-resolution.js +68 -0
- package/src/graph/freshness-probe.js +2 -1
- package/src/graph/incremental-refresh.js +3 -2
- package/src/graph/internal-builder.build.js +22 -183
- package/src/graph/internal-builder.pass2.js +161 -0
- package/src/graph/internal-builder.resolvers.js +2 -105
- package/src/graph/resolvers/rust.js +117 -0
- package/src/mcp/actions/advisories.mjs +18 -0
- package/src/mcp/actions/graph-lifecycle.mjs +148 -0
- package/src/mcp/actions/graph-sync.mjs +195 -0
- package/src/mcp/actions/hosted-architecture.mjs +57 -0
- package/src/mcp/architecture-bootstrap.mjs +168 -0
- package/src/mcp/architecture-starter.mjs +234 -0
- package/src/mcp/catalog.mjs +20 -6
- package/src/mcp/evidence/bun-lock-graph.mjs +209 -0
- package/src/mcp/evidence/package-graph-common.mjs +115 -0
- package/src/mcp/evidence/package-lock-graph.mjs +92 -0
- package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
- package/src/mcp/graph/context-core.mjs +111 -0
- package/src/mcp/graph/context-seeds.mjs +208 -0
- package/src/mcp/graph/context-state.mjs +86 -0
- package/src/mcp/graph/tools-core.mjs +143 -0
- package/src/mcp/graph/tools-query.mjs +223 -0
- package/src/mcp/graph-context.mjs +4 -496
- package/src/mcp/health/audit-format.mjs +172 -0
- package/src/mcp/health/audit.mjs +171 -0
- package/src/mcp/health/dead-code.mjs +110 -0
- package/src/mcp/health/duplicates.mjs +83 -0
- package/src/mcp/health/endpoints.mjs +42 -0
- package/src/mcp/health/structure.mjs +219 -0
- package/src/mcp/runtime-version.mjs +32 -0
- package/src/mcp/server/auto-refresh.mjs +66 -0
- package/src/mcp/server/runtime-config.mjs +43 -0
- package/src/mcp/server/shutdown.mjs +40 -0
- package/src/mcp/sync/evidence-architecture.mjs +54 -0
- package/src/mcp/sync/evidence-common.mjs +88 -0
- package/src/mcp/sync/evidence-duplicates.mjs +100 -0
- package/src/mcp/sync/evidence-health.mjs +56 -0
- package/src/mcp/sync/evidence-packages.mjs +95 -0
- package/src/mcp/sync/payload-common.mjs +97 -0
- package/src/mcp/sync/payload-v2.mjs +53 -0
- package/src/mcp/sync/payload-v3.mjs +79 -0
- package/src/mcp/sync-evidence.mjs +7 -402
- package/src/mcp/sync-payload.mjs +10 -244
- package/src/mcp/tools-actions.mjs +18 -414
- package/src/mcp/tools-architecture.mjs +18 -70
- package/src/mcp/tools-context.mjs +56 -15
- package/src/mcp/tools-endpoints.mjs +4 -1
- package/src/mcp/tools-graph.mjs +17 -331
- package/src/mcp/tools-health.mjs +24 -705
- package/src/mcp-server.mjs +35 -146
- package/src/precision/lsp-client/constants.js +12 -0
- package/src/precision/lsp-client/environment.js +20 -0
- package/src/precision/lsp-client/errors.js +15 -0
- package/src/precision/lsp-client/lifecycle.js +127 -0
- package/src/precision/lsp-client/message-parser.js +81 -0
- package/src/precision/lsp-client/protocol.js +212 -0
- package/src/precision/lsp-client/registry.js +58 -0
- package/src/precision/lsp-client/repo-uri.js +60 -0
- package/src/precision/lsp-client/stdio-client.js +151 -0
- package/src/precision/lsp-client.js +10 -682
- package/src/precision/lsp-overlay/build.js +238 -0
- package/src/precision/lsp-overlay/contract.js +61 -0
- package/src/precision/lsp-overlay/reference-results.js +108 -0
- package/src/precision/lsp-overlay/semantic-inputs.js +62 -0
- package/src/precision/lsp-overlay/source-session.js +134 -0
- package/src/precision/lsp-overlay/store.js +150 -0
- package/src/precision/lsp-overlay/target-index.js +147 -0
- package/src/precision/lsp-overlay/target-query.js +55 -0
- package/src/precision/lsp-overlay.js +11 -868
- package/src/precision/typescript-lsp-provider.js +12 -682
- package/src/precision/typescript-provider/client.js +69 -0
- package/src/precision/typescript-provider/discovery.js +124 -0
- package/src/precision/typescript-provider/project-host.js +249 -0
- package/src/precision/typescript-provider/project-safety.js +161 -0
- package/src/precision/typescript-provider/reference-usage.js +53 -0
- package/src/version.js +7 -0
- 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
|
+
}
|