weavatrix 0.2.13 → 0.2.15
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 +99 -39
- package/SECURITY.md +2 -2
- package/docs/releases/v0.2.15.md +37 -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 +14 -71
- package/src/analysis/dep-rules.js +10 -303
- package/src/analysis/dependency/conventions.js +16 -0
- package/src/analysis/dependency/scoped-dependencies.js +45 -0
- package/src/analysis/dependency/source-references.js +21 -0
- package/src/analysis/duplicates.tokenize.js +12 -2
- 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.reach.js +20 -0
- package/src/analysis/internal-audit.run.js +114 -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/analysis/task-retrieval.js +3 -14
- 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/duplicate-member-order.mjs +8 -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.duplicates.mjs +3 -7
- package/src/mcp/evidence-snapshot.package-graph.mjs +5 -474
- package/src/mcp/git-output.mjs +10 -0
- package/src/mcp/graph/context-core.mjs +111 -0
- package/src/mcp/graph/context-seeds.mjs +197 -0
- package/src/mcp/graph/context-state.mjs +86 -0
- package/src/mcp/graph/reverse-reach.mjs +42 -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 +97 -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/tools-impact-change.mjs +2 -38
- package/src/mcp/tools-impact.mjs +2 -43
- package/src/mcp-server.mjs +35 -146
- package/src/path-classification.js +14 -0
- 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/security/malware-heuristics.sweep.js +1 -1
- package/src/security/registry-sig.classify.js +2 -1
- package/src/security/registry-sig.rules.js +3 -3
- 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
|
+
}
|