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.
- package/LICENSE +1 -0
- package/README.md +231 -199
- package/bin/native/darwin-arm64/weavatrix +0 -0
- package/bin/native/darwin-x64/weavatrix +0 -0
- package/bin/native/linux-arm64/weavatrix +0 -0
- package/bin/native/linux-x64/weavatrix +0 -0
- package/bin/native/win32-arm64/weavatrix.exe +0 -0
- package/bin/native/win32-x64/weavatrix.exe +0 -0
- package/bin/resolve-binary.mjs +73 -0
- package/bin/run-native.mjs +26 -0
- package/bin/weavatrix-mcp.mjs +7 -6
- package/bin/weavatrix.mjs +5 -0
- package/package.json +8 -65
- package/skill/SKILL.md +62 -374
- package/skill/agents/openai.yaml +4 -0
- package/skill/references/tool-routing.md +45 -0
- package/SECURITY.md +0 -101
- package/docs/adr/0001-v0.3-offline-online-split.md +0 -60
- package/docs/agent-task-benchmark.md +0 -58
- package/docs/releases/v0.2.19.md +0 -33
- package/docs/releases/v0.3.0.md +0 -43
- package/docs/releases/v0.3.1.md +0 -30
- package/docs/releases/v0.3.10.md +0 -76
- package/docs/releases/v0.3.11.md +0 -55
- package/docs/releases/v0.3.12.md +0 -44
- package/docs/releases/v0.3.13.md +0 -34
- package/docs/releases/v0.3.2.md +0 -15
- package/docs/releases/v0.3.3.md +0 -25
- package/docs/releases/v0.3.4.md +0 -40
- package/docs/releases/v0.3.5.md +0 -50
- package/docs/releases/v0.3.6.md +0 -44
- package/docs/releases/v0.3.7.md +0 -37
- package/docs/releases/v0.3.8.md +0 -21
- package/docs/releases/v0.3.9.md +0 -36
- package/scripts/run-agent-task-benchmark.mjs +0 -118
- package/src/analysis/allowed-test-runner.js +0 -70
- package/src/analysis/architecture/contract-graph.js +0 -119
- package/src/analysis/architecture/contract-schema.js +0 -110
- package/src/analysis/architecture/contract-storage.js +0 -35
- package/src/analysis/architecture/contract-verification.js +0 -168
- package/src/analysis/architecture-contract.js +0 -16
- package/src/analysis/audit-debt.js +0 -94
- package/src/analysis/audit-extensions.js +0 -60
- package/src/analysis/cargo-dependency-evidence.js +0 -108
- package/src/analysis/cargo-manifests.js +0 -81
- package/src/analysis/change-classification/diff-parser.js +0 -103
- package/src/analysis/change-classification/options.js +0 -40
- package/src/analysis/change-classification/symbol-classifier.js +0 -177
- package/src/analysis/change-classification.js +0 -188
- package/src/analysis/coverage-reports.js +0 -235
- package/src/analysis/cycle-route.js +0 -14
- package/src/analysis/data-flow-evidence.js +0 -114
- package/src/analysis/dead-check.js +0 -300
- package/src/analysis/dead-code-review/candidates.js +0 -194
- package/src/analysis/dead-code-review/policy.js +0 -23
- package/src/analysis/dead-code-review.js +0 -119
- package/src/analysis/dep-check-ecosystems.js +0 -205
- package/src/analysis/dep-check.js +0 -290
- package/src/analysis/dep-rules.js +0 -10
- package/src/analysis/dependency/conventions.js +0 -16
- package/src/analysis/dependency/scoped-dependencies.js +0 -51
- package/src/analysis/dependency/source-references.js +0 -21
- package/src/analysis/duplicate-groups.js +0 -104
- package/src/analysis/duplicates-worker.js +0 -11
- package/src/analysis/duplicates.compute.js +0 -269
- package/src/analysis/duplicates.js +0 -15
- package/src/analysis/duplicates.run.js +0 -52
- package/src/analysis/duplicates.tokenize.js +0 -199
- package/src/analysis/endpoints/common.js +0 -62
- package/src/analysis/endpoints/extract.js +0 -107
- package/src/analysis/endpoints/inventory.js +0 -84
- package/src/analysis/endpoints/mounts.js +0 -129
- package/src/analysis/endpoints-java.js +0 -260
- package/src/analysis/endpoints-rust.js +0 -124
- package/src/analysis/endpoints.js +0 -3
- package/src/analysis/findings.js +0 -70
- package/src/analysis/git-history/analytics.js +0 -177
- package/src/analysis/git-history/collector.js +0 -67
- package/src/analysis/git-history/options.js +0 -66
- package/src/analysis/git-history.js +0 -143
- package/src/analysis/git-ref-graph.js +0 -76
- package/src/analysis/go-dependency-evidence.js +0 -62
- package/src/analysis/graph-analysis.aggregate.js +0 -295
- package/src/analysis/graph-analysis.edges.js +0 -24
- package/src/analysis/graph-analysis.js +0 -7
- package/src/analysis/graph-analysis.refs.js +0 -154
- package/src/analysis/graph-analysis.summaries.js +0 -65
- package/src/analysis/health-capabilities.js +0 -83
- package/src/analysis/hot-path-review.js +0 -266
- package/src/analysis/http-contract-wrappers.js +0 -241
- package/src/analysis/http-contracts/analysis.js +0 -179
- package/src/analysis/http-contracts/client-call-detection.js +0 -82
- package/src/analysis/http-contracts/client-call-parser.js +0 -273
- package/src/analysis/http-contracts/graph-context.js +0 -143
- package/src/analysis/http-contracts/matching.js +0 -61
- package/src/analysis/http-contracts/shared.js +0 -85
- package/src/analysis/http-contracts.js +0 -6
- package/src/analysis/internal-audit/dependency-health.js +0 -113
- package/src/analysis/internal-audit/python-manifests.js +0 -78
- package/src/analysis/internal-audit/repo-files.js +0 -50
- package/src/analysis/internal-audit/supply-chain.js +0 -149
- package/src/analysis/internal-audit.collect.js +0 -213
- package/src/analysis/internal-audit.js +0 -9
- package/src/analysis/internal-audit.reach.js +0 -173
- package/src/analysis/internal-audit.run.js +0 -256
- package/src/analysis/java-source.js +0 -36
- package/src/analysis/jvm-artifact-index.js +0 -87
- package/src/analysis/jvm-dependency-evidence.js +0 -138
- package/src/analysis/jvm-manifests.js +0 -114
- package/src/analysis/manifests.js +0 -123
- package/src/analysis/package-reachability.js +0 -39
- package/src/analysis/source-complexity.ast.js +0 -97
- package/src/analysis/source-complexity.constants.js +0 -55
- package/src/analysis/source-complexity.js +0 -14
- package/src/analysis/source-complexity.report.js +0 -81
- package/src/analysis/source-complexity.walk.js +0 -228
- package/src/analysis/source-correctness/retry-patterns.js +0 -93
- package/src/analysis/source-correctness.js +0 -222
- package/src/analysis/static-test-reachability.js +0 -150
- package/src/analysis/structure/dependency-graph.js +0 -151
- package/src/analysis/structure/findings.js +0 -162
- package/src/analysis/task-retrieval.js +0 -107
- package/src/analysis/transport-contracts.js +0 -224
- package/src/analysis/transport-runtime-evidence.js +0 -155
- package/src/analysis-kit.mjs +0 -17
- package/src/bounds.js +0 -4
- package/src/build-graph.js +0 -209
- package/src/child-env.js +0 -7
- package/src/config.js +0 -5
- package/src/extension/local-services.mjs +0 -75
- package/src/git-exec.js +0 -67
- package/src/graph/build-worker.js +0 -49
- package/src/graph/builder/go-receiver-resolution.js +0 -112
- package/src/graph/builder/js/dynamic-import.js +0 -26
- package/src/graph/builder/js/queries.js +0 -48
- package/src/graph/builder/lang-csharp.js +0 -40
- package/src/graph/builder/lang-css.js +0 -29
- package/src/graph/builder/lang-go.js +0 -140
- package/src/graph/builder/lang-html.js +0 -29
- package/src/graph/builder/lang-java-calls.js +0 -142
- package/src/graph/builder/lang-java.js +0 -215
- package/src/graph/builder/lang-js.js +0 -291
- package/src/graph/builder/lang-python.js +0 -235
- package/src/graph/builder/lang-rust-calls.js +0 -63
- package/src/graph/builder/lang-rust.js +0 -299
- package/src/graph/builder/lang-solidity.js +0 -126
- package/src/graph/builder/lang-sql.js +0 -263
- package/src/graph/builder/pass2-resolution.js +0 -81
- package/src/graph/builder/spec-pkg.js +0 -87
- package/src/graph/community.js +0 -27
- package/src/graph/edge-provenance.js +0 -31
- package/src/graph/file-lock.js +0 -69
- package/src/graph/freshness-probe.js +0 -142
- package/src/graph/graph-filter.js +0 -63
- package/src/graph/incremental-refresh.js +0 -235
- package/src/graph/internal-builder.barrels.js +0 -235
- package/src/graph/internal-builder.build.js +0 -300
- package/src/graph/internal-builder.java.js +0 -33
- package/src/graph/internal-builder.js +0 -12
- package/src/graph/internal-builder.langs.js +0 -157
- package/src/graph/internal-builder.pass2.js +0 -163
- package/src/graph/internal-builder.resolvers.js +0 -286
- package/src/graph/layout.js +0 -51
- package/src/graph/node-id.js +0 -7
- package/src/graph/parser-artifact-boundary.js +0 -55
- package/src/graph/relations.js +0 -4
- package/src/graph/repo-registry.js +0 -124
- package/src/graph/resolvers/rust.js +0 -117
- package/src/infra/infra-items.js +0 -255
- package/src/infra/infra-registry.js +0 -184
- package/src/infra/infra.detect.js +0 -119
- package/src/infra/infra.js +0 -38
- package/src/infra/infra.match.js +0 -102
- package/src/infra/infra.scan.js +0 -93
- package/src/mcp/actions/graph-lifecycle.mjs +0 -148
- package/src/mcp/architecture-bootstrap.mjs +0 -168
- package/src/mcp/architecture-starter.mjs +0 -234
- package/src/mcp/catalog.mjs +0 -233
- package/src/mcp/company-contract-page.mjs +0 -142
- package/src/mcp/company-contract-reconcile.mjs +0 -87
- package/src/mcp/company-contract-verdict.mjs +0 -42
- package/src/mcp/evidence/bun-lock-graph.mjs +0 -209
- package/src/mcp/evidence/duplicate-member-order.mjs +0 -8
- package/src/mcp/evidence/package-graph-common.mjs +0 -115
- package/src/mcp/evidence/package-lock-graph.mjs +0 -92
- package/src/mcp/evidence-snapshot.architecture.mjs +0 -80
- package/src/mcp/evidence-snapshot.common.mjs +0 -158
- package/src/mcp/evidence-snapshot.duplicates.mjs +0 -213
- package/src/mcp/evidence-snapshot.health.mjs +0 -102
- package/src/mcp/evidence-snapshot.inventory.mjs +0 -148
- package/src/mcp/evidence-snapshot.mjs +0 -50
- package/src/mcp/evidence-snapshot.package-graph.mjs +0 -34
- package/src/mcp/evidence-snapshot.structure.mjs +0 -84
- package/src/mcp/extension-api.mjs +0 -77
- package/src/mcp/git-output.mjs +0 -7
- package/src/mcp/graph/context-core.mjs +0 -111
- package/src/mcp/graph/context-seeds.mjs +0 -207
- package/src/mcp/graph/context-state.mjs +0 -85
- package/src/mcp/graph/reverse-reach.mjs +0 -42
- package/src/mcp/graph/tools-core.mjs +0 -143
- package/src/mcp/graph/tools-query.mjs +0 -276
- package/src/mcp/graph-context.mjs +0 -5
- package/src/mcp/graph-diff.mjs +0 -218
- package/src/mcp/health/audit-format.mjs +0 -199
- package/src/mcp/health/audit.mjs +0 -174
- package/src/mcp/health/dead-code.mjs +0 -110
- package/src/mcp/health/duplicates.mjs +0 -85
- package/src/mcp/health/endpoints.mjs +0 -71
- package/src/mcp/health/structure.mjs +0 -219
- package/src/mcp/runtime-version.mjs +0 -31
- package/src/mcp/server/auto-refresh.mjs +0 -66
- package/src/mcp/server/runtime-config.mjs +0 -43
- package/src/mcp/server/shutdown.mjs +0 -40
- package/src/mcp/staleness-notice.mjs +0 -20
- package/src/mcp/sync/evidence-architecture.mjs +0 -54
- package/src/mcp/sync/evidence-common.mjs +0 -88
- package/src/mcp/sync/evidence-duplicates.mjs +0 -97
- package/src/mcp/sync/evidence-health.mjs +0 -56
- package/src/mcp/sync/evidence-packages.mjs +0 -95
- package/src/mcp/sync/payload-common.mjs +0 -97
- package/src/mcp/sync/payload-v2.mjs +0 -54
- package/src/mcp/sync/payload-v3.mjs +0 -79
- package/src/mcp/sync-evidence.mjs +0 -23
- package/src/mcp/sync-payload.mjs +0 -70
- package/src/mcp/tool-result.mjs +0 -54
- package/src/mcp/tools-actions.mjs +0 -11
- package/src/mcp/tools-architecture.mjs +0 -177
- package/src/mcp/tools-company.mjs +0 -251
- package/src/mcp/tools-context.mjs +0 -222
- package/src/mcp/tools-endpoints.mjs +0 -207
- package/src/mcp/tools-graph-hubs.mjs +0 -78
- package/src/mcp/tools-graph.mjs +0 -17
- package/src/mcp/tools-health.mjs +0 -24
- package/src/mcp/tools-history.mjs +0 -28
- package/src/mcp/tools-impact-change.mjs +0 -220
- package/src/mcp/tools-impact-precision.mjs +0 -89
- package/src/mcp/tools-impact.mjs +0 -169
- package/src/mcp/tools-source.mjs +0 -238
- package/src/mcp/tools-verified-change.mjs +0 -200
- package/src/mcp-rg.mjs +0 -50
- package/src/mcp-runtime.mjs +0 -2
- package/src/mcp-server.mjs +0 -298
- package/src/mcp-source-tools.mjs +0 -163
- package/src/path-classification.js +0 -220
- package/src/path-ignore.js +0 -69
- package/src/precision/lsp-client/constants.js +0 -12
- package/src/precision/lsp-client/environment.js +0 -20
- package/src/precision/lsp-client/errors.js +0 -15
- package/src/precision/lsp-client/lifecycle.js +0 -114
- package/src/precision/lsp-client/message-parser.js +0 -81
- package/src/precision/lsp-client/protocol.js +0 -212
- package/src/precision/lsp-client/registry.js +0 -59
- package/src/precision/lsp-client/repo-uri.js +0 -60
- package/src/precision/lsp-client/stdio-client.js +0 -140
- package/src/precision/lsp-client.js +0 -10
- package/src/precision/lsp-overlay/budget-policy.js +0 -78
- package/src/precision/lsp-overlay/build.js +0 -261
- package/src/precision/lsp-overlay/contract.js +0 -61
- package/src/precision/lsp-overlay/reference-results.js +0 -108
- package/src/precision/lsp-overlay/semantic-inputs.js +0 -62
- package/src/precision/lsp-overlay/source-session.js +0 -142
- package/src/precision/lsp-overlay/store.js +0 -150
- package/src/precision/lsp-overlay/target-index.js +0 -152
- package/src/precision/lsp-overlay/target-query.js +0 -55
- package/src/precision/lsp-overlay.js +0 -11
- package/src/precision/symbol-query.js +0 -224
- package/src/precision/typescript-lsp-provider.js +0 -12
- package/src/precision/typescript-provider/client.js +0 -89
- package/src/precision/typescript-provider/discovery.js +0 -124
- package/src/precision/typescript-provider/isolated-runtime.js +0 -39
- package/src/precision/typescript-provider/project-host.js +0 -254
- package/src/precision/typescript-provider/project-safety.js +0 -166
- package/src/precision/typescript-provider/reference-usage.js +0 -53
- package/src/process.js +0 -95
- package/src/repo-path.js +0 -53
- package/src/scan/discover.inventory.js +0 -78
- package/src/scan/discover.js +0 -5
- package/src/scan/discover.list.js +0 -79
- package/src/scan/discover.stack.js +0 -227
- package/src/scan/search.core.js +0 -24
- package/src/scan/search.git.js +0 -102
- package/src/scan/search.js +0 -9
- package/src/scan/search.node.js +0 -83
- package/src/scan/search.preview.js +0 -49
- package/src/scan/search.rg.js +0 -145
- package/src/security/advisory-store.js +0 -172
- package/src/security/installed-jvm-rust.js +0 -46
- package/src/security/installed.js +0 -280
- package/src/security/malware-file-heuristics.js +0 -121
- package/src/security/malware-heuristics.exclusions.js +0 -134
- package/src/security/malware-heuristics.js +0 -15
- package/src/security/malware-heuristics.roots.js +0 -145
- package/src/security/malware-heuristics.scan.js +0 -89
- package/src/security/malware-heuristics.sweep.js +0 -122
- package/src/security/malware-scoring.js +0 -105
- package/src/security/match.js +0 -85
- package/src/security/registry-sig.classify.js +0 -137
- package/src/security/registry-sig.js +0 -18
- package/src/security/registry-sig.rules.js +0 -192
- package/src/security/rust-advisory-report.js +0 -60
- package/src/security/typosquat.js +0 -81
- package/src/util.js +0 -40
- package/src/version.js +0 -7
package/src/analysis-kit.mjs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Read-only analysis primitives the weavatrix-refactor package composes into refactoring
|
|
2
|
-
// plan producers. Everything exported here is PURE READ: graph identity helpers, cycle
|
|
3
|
-
// detection, architecture verification, the bundled tree-sitter grammars, the read-only
|
|
4
|
-
// TypeScript language-server client, and dead-code risk signals. None of it writes, applies,
|
|
5
|
-
// or references applying a change — the core catalog and the release gate keep the core
|
|
6
|
-
// provably free of any source-write or edit-plan path. The refactoring engines live in
|
|
7
|
-
// weavatrix-refactor and import this surface.
|
|
8
|
-
|
|
9
|
-
export {graphEndpointId, fileOfId} from './graph/node-id.js'
|
|
10
|
-
export {Parser, Query, EXT_LANG, ensureParser} from './graph/internal-builder.langs.js'
|
|
11
|
-
export {querySymbolPrecision} from './precision/symbol-query.js'
|
|
12
|
-
export {createTypeScriptLspClient} from './precision/typescript-provider/client.js'
|
|
13
|
-
export {verifyArchitecture} from './analysis/architecture/contract-verification.js'
|
|
14
|
-
export {normalizeArchitectureContract} from './analysis/architecture-contract.js'
|
|
15
|
-
export {buildFileImportGraph, findSccs} from './analysis/structure/dependency-graph.js'
|
|
16
|
-
export {isFrameworkEntryFile} from './analysis/dead-check.js'
|
|
17
|
-
export {hasDynamicCode, REFLECTION_CODE_RE} from './analysis/dead-code-review/policy.js'
|
package/src/bounds.js
DELETED
package/src/build-graph.js
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
// Graph build — weavatrix's own web-tree-sitter builder.
|
|
2
|
-
// Emits <weavatrix-graphs/<repo>>/graph.json for the rest of the pipeline.
|
|
3
|
-
//
|
|
4
|
-
// The parse itself runs in a WORKER THREAD (build-worker.js): in-process it pinned Electron's main
|
|
5
|
-
// event loop for the whole repo walk, and since Windows routes window input through the main process
|
|
6
|
-
// the ENTIRE app froze on big repos. The worker writes graph.json itself and returns only counts +
|
|
7
|
-
// summaries. If the worker can't even start (exotic packaging), we fall back to the in-process build
|
|
8
|
-
// rather than lose the feature.
|
|
9
|
-
import { existsSync, readFileSync, mkdirSync } from "node:fs";
|
|
10
|
-
import { join, resolve } from "node:path";
|
|
11
|
-
import { Worker } from "node:worker_threads";
|
|
12
|
-
import { childProcessEnv } from "./child-env.js";
|
|
13
|
-
import { graphHomeDir, graphOutDirForRepo, graphStorageKey, repoTopFolders, summarizeCommunities, summarizeHotspots, filterGraphForMode, filterGraphByScope } from "./graph/layout.js";
|
|
14
|
-
import { registerRepository } from "./graph/repo-registry.js";
|
|
15
|
-
import { refreshGraphIncrementally, snapshotRepository } from "./graph/incremental-refresh.js";
|
|
16
|
-
import { atomicWriteFileSync, withFileLock } from "./graph/file-lock.js";
|
|
17
|
-
import { graphSchemaIsCurrent, repositoryFreshnessProbe, stampRepositoryFreshness } from "./graph/freshness-probe.js";
|
|
18
|
-
import { buildLspPrecisionOverlay, invalidatePrecisionOverlay, precisionSummary } from "./precision/lsp-overlay.js";
|
|
19
|
-
|
|
20
|
-
// The worker path deadlocks web-tree-sitter's WASM in Electron's worker threads (fine in plain Node) — off
|
|
21
|
-
// until that's Electron-safe. In-process + event-loop yielding keeps the window responsive without it.
|
|
22
|
-
const USE_BUILD_WORKER = false;
|
|
23
|
-
|
|
24
|
-
// Hard ceiling so a wedged parse (WASM stuck, pathological file, symlink loop) can NEVER leave the UI on
|
|
25
|
-
// an eternal "BUILDING GRAPH…". On timeout we terminate the worker and reject as a REAL failure (no
|
|
26
|
-
// workerStartFailed → we do NOT fall back to the in-process build, which would hang the same way and
|
|
27
|
-
// freeze the whole app on the main thread). 4 min is generous for very large repos.
|
|
28
|
-
const BUILD_WORKER_TIMEOUT_MS = 4 * 60 * 1000;
|
|
29
|
-
|
|
30
|
-
export function defaultPrecisionMode(env = process.env) {
|
|
31
|
-
return env?.WEAVATRIX_PRECISION === "off" ? "off" : "lsp";
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// One-line human status for a precision summary (precisionSummary shape) — the graph_stats
|
|
35
|
-
// composition, shared by the build log and open_repo so every surface reads the same fraction.
|
|
36
|
-
export function precisionStatusLine(precision) {
|
|
37
|
-
const p = precision || {};
|
|
38
|
-
if (p.state === "NONE") return `Semantic precision: NONE — ${p.reason || "no eligible JavaScript/TypeScript semantic targets"}`;
|
|
39
|
-
return `Semantic precision: ${p.state || "UNAVAILABLE"} — ${p.queried || 0}/${p.candidates || 0} bounded target(s) queried${p.truncated ? " (truncated)" : ""}; ${p.verifiedEdges || 0} EXACT_LSP edge(s)${p.state !== "COMPLETE" && p.reason ? `; ${p.reason}` : ""}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function buildGraphInWorker(payload) {
|
|
43
|
-
return new Promise((resolve, reject) => {
|
|
44
|
-
let worker;
|
|
45
|
-
try {
|
|
46
|
-
worker = new Worker(new URL("./graph/build-worker.js", import.meta.url), { workerData: payload, env: childProcessEnv() });
|
|
47
|
-
} catch (e) {
|
|
48
|
-
reject(Object.assign(e, { workerStartFailed: true }));
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
let settled = false;
|
|
52
|
-
let timer = null;
|
|
53
|
-
const done = (fn, v) => {
|
|
54
|
-
if (settled) return;
|
|
55
|
-
settled = true;
|
|
56
|
-
if (timer) { clearTimeout(timer); timer = null; }
|
|
57
|
-
fn(v);
|
|
58
|
-
};
|
|
59
|
-
timer = setTimeout(() => {
|
|
60
|
-
try { worker.terminate(); } catch { /* already gone */ }
|
|
61
|
-
done(reject, new Error(`graph build timed out after ${Math.round(BUILD_WORKER_TIMEOUT_MS / 1000)}s (the parser is wedged on this repo — try again, or report it)`));
|
|
62
|
-
}, BUILD_WORKER_TIMEOUT_MS);
|
|
63
|
-
worker.once("message", (msg) => {
|
|
64
|
-
if (msg && msg.ok) done(resolve, msg);
|
|
65
|
-
else done(reject, new Error((msg && msg.error) || "graph worker failed"));
|
|
66
|
-
});
|
|
67
|
-
worker.once("error", (e) => done(reject, Object.assign(e, { workerStartFailed: true })));
|
|
68
|
-
worker.once("exit", (code) => { if (code !== 0) done(reject, Object.assign(new Error(`graph worker exited with code ${code}`), { workerStartFailed: true })); });
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function buildAndWriteInProcess(repoPath, { mode, scope, precision, graphJson, central }) {
|
|
73
|
-
const { buildInternalGraph } = await import("./graph/internal-builder.js");
|
|
74
|
-
// Capture the cheap Git state on both sides of the authoritative build. Only an unchanged pair is
|
|
75
|
-
// safe to persist: if the working tree moves while parsing, the next process must take the slow path.
|
|
76
|
-
const probeBefore = scope ? null : repositoryFreshnessProbe(repoPath);
|
|
77
|
-
let graph;
|
|
78
|
-
let refresh = null;
|
|
79
|
-
if (mode === "full" && !scope && existsSync(graphJson)) {
|
|
80
|
-
try {
|
|
81
|
-
const existing = JSON.parse(readFileSync(graphJson, "utf8"));
|
|
82
|
-
if (existing.graphBuildMode === "full" && !existing.graphBuildScope && graphSchemaIsCurrent(existing)) {
|
|
83
|
-
refresh = await refreshGraphIncrementally(repoPath, existing, { buildGraph: buildInternalGraph });
|
|
84
|
-
graph = refresh.graph;
|
|
85
|
-
}
|
|
86
|
-
} catch { /* malformed/legacy graph: the safe path below is a full rebuild */ }
|
|
87
|
-
}
|
|
88
|
-
if (!graph && mode !== "full" && !scope && existsSync(graphJson)) {
|
|
89
|
-
try {
|
|
90
|
-
const existing = JSON.parse(readFileSync(graphJson, "utf8"));
|
|
91
|
-
if (existing.graphBuildMode === mode && existing.graphRevision && graphSchemaIsCurrent(existing)) {
|
|
92
|
-
const snapshot = snapshotRepository(repoPath);
|
|
93
|
-
if (snapshot.revision === existing.graphRevision) {
|
|
94
|
-
graph = existing;
|
|
95
|
-
refresh = { kind: "none", changedFiles: [], reason: "content-unchanged", revision: snapshot.revision };
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
} catch { /* malformed/legacy filtered graph: rebuild below */ }
|
|
99
|
-
}
|
|
100
|
-
if (!graph) {
|
|
101
|
-
graph = await buildInternalGraph(repoPath);
|
|
102
|
-
refresh = { kind: "full", changedFiles: [], reason: "full-build-requested", revision: graph.graphRevision };
|
|
103
|
-
}
|
|
104
|
-
// mode (no-tests/tests-only) + path-scope reuse the same pure filters graph-builder used.
|
|
105
|
-
if (mode === "no-tests" || mode === "tests-only") graph = filterGraphForMode(graph, mode, { repoRoot: repoPath });
|
|
106
|
-
if (scope) graph = filterGraphByScope(graph, scope);
|
|
107
|
-
graph.graphBuildMode = mode;
|
|
108
|
-
graph.graphBuildScope = scope || "";
|
|
109
|
-
const requestedPrecision = precision === "off" ? "off" : "lsp";
|
|
110
|
-
const precisionModeChanged = graph.graphPrecisionMode !== requestedPrecision;
|
|
111
|
-
graph.graphPrecisionMode = requestedPrecision;
|
|
112
|
-
const probeAfter = scope ? null : repositoryFreshnessProbe(repoPath);
|
|
113
|
-
const stableProbe = probeBefore && probeAfter === probeBefore ? probeAfter : null;
|
|
114
|
-
const freshnessMetadataChanged = stampRepositoryFreshness(graph, stableProbe, mode);
|
|
115
|
-
// Auto-refresh runs before every graph/health call. A no-op must not serialize and rewrite a
|
|
116
|
-
// multi-megabyte graph merely to answer that nothing changed (or manufacture a newer mtime).
|
|
117
|
-
// A one-time metadata-only write is intentional for legacy graphs so the next MCP process can use
|
|
118
|
-
// the persisted probe instead of repeating a full repository snapshot.
|
|
119
|
-
if (refresh?.kind !== "none" || freshnessMetadataChanged || precisionModeChanged) {
|
|
120
|
-
mkdirSync(central, { recursive: true });
|
|
121
|
-
atomicWriteFileSync(graphJson, JSON.stringify(graph), "utf8");
|
|
122
|
-
}
|
|
123
|
-
mkdirSync(central, { recursive: true });
|
|
124
|
-
let precisionOverlay = await buildLspPrecisionOverlay({
|
|
125
|
-
repoRoot: repoPath,
|
|
126
|
-
graph,
|
|
127
|
-
graphPath: graphJson,
|
|
128
|
-
mode: requestedPrecision,
|
|
129
|
-
});
|
|
130
|
-
if (requestedPrecision === "lsp") {
|
|
131
|
-
try {
|
|
132
|
-
// LSP deliberately runs after graph serialization and can outlive the initial snapshot. A
|
|
133
|
-
// complete second content snapshot catches source/config add-delete races (including Git
|
|
134
|
-
// assume-unchanged paths) that a status-only token cannot prove away.
|
|
135
|
-
if (snapshotRepository(repoPath).revision !== graph.graphRevision) {
|
|
136
|
-
precisionOverlay = invalidatePrecisionOverlay(graphJson, graph);
|
|
137
|
-
}
|
|
138
|
-
} catch {
|
|
139
|
-
precisionOverlay = invalidatePrecisionOverlay(
|
|
140
|
-
graphJson,
|
|
141
|
-
graph,
|
|
142
|
-
"repository freshness could not be verified after semantic precision",
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return {
|
|
147
|
-
nodes: graph.nodes.length,
|
|
148
|
-
links: graph.links.length,
|
|
149
|
-
communities: summarizeCommunities(graphJson),
|
|
150
|
-
hotspots: summarizeHotspots(graphJson),
|
|
151
|
-
refresh,
|
|
152
|
-
precision: precisionSummary(precisionOverlay),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export async function buildGraphForRepo(repoPath, {
|
|
157
|
-
mode = "full",
|
|
158
|
-
scope = "",
|
|
159
|
-
precision = defaultPrecisionMode(),
|
|
160
|
-
outDir,
|
|
161
|
-
graphHome,
|
|
162
|
-
} = {}) {
|
|
163
|
-
if (!existsSync(repoPath)) return { ok: false, error: "Repo path not found", builder: "internal" };
|
|
164
|
-
const registryHome = graphHome || graphHomeDir();
|
|
165
|
-
const canonicalDir = graphHome ? join(registryHome, graphStorageKey(repoPath)) : graphOutDirForRepo(repoPath);
|
|
166
|
-
const central = outDir || canonicalDir;
|
|
167
|
-
const graphJson = join(central, "graph.json");
|
|
168
|
-
try {
|
|
169
|
-
// In-process is the ONLY path now. The worker (buildGraphInWorker) hung web-tree-sitter's WASM inside an
|
|
170
|
-
// Electron worker thread → an eternal "BUILDING GRAPH…" for JS repos, even though the same code finishes
|
|
171
|
-
// in ~3s on the main thread (and in a plain-Node worker). buildInternalGraph now YIELDS the event loop
|
|
172
|
-
// between file chunks, so the main-thread parse no longer freezes the window — the reason the worker was
|
|
173
|
-
// introduced. buildGraphInWorker/USE_BUILD_WORKER are kept for a future Electron-safe re-enable.
|
|
174
|
-
const build = () => USE_BUILD_WORKER
|
|
175
|
-
? buildGraphInWorker({ repoPath, mode, scope, precision, graphJson, central }).catch((e) => {
|
|
176
|
-
if (e && e.workerStartFailed) return buildAndWriteInProcess(repoPath, { mode, scope, precision, graphJson, central });
|
|
177
|
-
throw e;
|
|
178
|
-
})
|
|
179
|
-
: buildAndWriteInProcess(repoPath, { mode, scope, precision, graphJson, central });
|
|
180
|
-
// Canonical graphs are shared by all local MCP clients. Serialize the complete read/refresh/write
|
|
181
|
-
// transaction so an older process cannot overwrite a newer incremental result.
|
|
182
|
-
const canonical = !scope && resolve(central) === resolve(canonicalDir);
|
|
183
|
-
const built = canonical
|
|
184
|
-
? await withFileLock(join(central, ".graph.lock"), build, { timeoutMs: 5 * 60_000, staleMs: 10 * 60_000 })
|
|
185
|
-
: await build();
|
|
186
|
-
// Scoped builds are disposable diagnostics under modules/<scope>; registering one would retarget
|
|
187
|
-
// list_known_repos and cross-repo analysis away from the complete canonical graph.
|
|
188
|
-
if (canonical) {
|
|
189
|
-
registerRepository({ repoPath, graphDir: central, graphHome: registryHome });
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
ok: true,
|
|
193
|
-
builder: "internal",
|
|
194
|
-
mode,
|
|
195
|
-
scope,
|
|
196
|
-
topFolders: repoTopFolders(repoPath),
|
|
197
|
-
report: "",
|
|
198
|
-
graphFile: "", // no graph.html — weavatrix renders its own GUI board/relations views
|
|
199
|
-
graphDir: central,
|
|
200
|
-
communities: built.communities,
|
|
201
|
-
hotspots: built.hotspots,
|
|
202
|
-
refresh: built.refresh,
|
|
203
|
-
precision: built.precision,
|
|
204
|
-
log: `built-in builder: ${built.nodes} nodes, ${built.links} static links (${built.refresh?.kind || "full"}: ${built.refresh?.reason || "build"}); ${precisionStatusLine(built.precision)}`
|
|
205
|
-
};
|
|
206
|
-
} catch (error) {
|
|
207
|
-
return { ok: false, error: `graph build failed: ${error.message}`, builder: "internal" };
|
|
208
|
-
}
|
|
209
|
-
}
|
package/src/child-env.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Child processes and worker threads never need credentials owned by a composing connector.
|
|
2
|
-
// Keep connector secrets in the parent MCP process and out of Git/LSP/test subprocesses.
|
|
3
|
-
export function childProcessEnv(overrides = {}) {
|
|
4
|
-
const env = { ...process.env, ...overrides };
|
|
5
|
-
delete env.WEAVATRIX_SYNC_TOKEN;
|
|
6
|
-
return env;
|
|
7
|
-
}
|
package/src/config.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import {readFileSync, statSync} from 'node:fs'
|
|
2
|
-
import {createHash} from 'node:crypto'
|
|
3
|
-
import {basename} from 'node:path'
|
|
4
|
-
import {graphStaleness} from '../mcp/graph-context.mjs'
|
|
5
|
-
import {createSyncPayload, createSyncPayloadV3, MAX_SYNC_BODY_BYTES} from '../mcp/sync-payload.mjs'
|
|
6
|
-
import {createEvidenceSnapshot} from '../mcp/evidence-snapshot.mjs'
|
|
7
|
-
import {graphHomeDir, graphOutDirForRepo} from '../graph/layout.js'
|
|
8
|
-
import {registerRepository, repositoryRecord} from '../graph/repo-registry.js'
|
|
9
|
-
import {writeCachedArchitectureContract} from '../analysis/architecture-contract.js'
|
|
10
|
-
import {collectInstalled} from '../security/installed.js'
|
|
11
|
-
import {toolResult} from '../mcp/tool-result.mjs'
|
|
12
|
-
import {
|
|
13
|
-
commitAdvisoryRefresh, createAdvisoryQueryPlan, DEFAULT_STORE, storeMeta,
|
|
14
|
-
} from '../security/advisory-store.js'
|
|
15
|
-
|
|
16
|
-
const MAX_GRAPH_FILE_BYTES = 64 * 1024 * 1024
|
|
17
|
-
|
|
18
|
-
const repositoryLabel = (repoRoot) => {
|
|
19
|
-
const safe = basename(String(repoRoot || '')).normalize('NFKC').replace(/[^a-z0-9._-]+/gi, '-').replace(/^-+|-+$/g, '')
|
|
20
|
-
return (safe || 'repo').slice(0, 128)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const identityFor = (repoRoot) => repositoryRecord(repoRoot, graphHomeDir())
|
|
24
|
-
|| registerRepository({repoPath: repoRoot, graphDir: graphOutDirForRepo(repoRoot), graphHome: graphHomeDir()})
|
|
25
|
-
|
|
26
|
-
// Produces the exact source-free wire material locally. It reads no credentials and performs no
|
|
27
|
-
// network I/O; the caller owns destination policy, consent, authentication and transport.
|
|
28
|
-
export async function createSourceFreeSyncMaterial(graph, {payloadVersion = 3} = {}, ctx = {}) {
|
|
29
|
-
if (!graph) throw new Error('No graph loaded — build one first (open_repo / rebuild_graph).')
|
|
30
|
-
if (!ctx.graphPath || !ctx.repoRoot) throw new Error('No active repository graph — open_repo first.')
|
|
31
|
-
const size = statSync(ctx.graphPath).size
|
|
32
|
-
if (size > MAX_GRAPH_FILE_BYTES) throw new Error(`graph.json exceeds the ${MAX_GRAPH_FILE_BYTES / 1024 / 1024} MB local safety limit`)
|
|
33
|
-
const raw = JSON.parse(readFileSync(ctx.graphPath, 'utf8'))
|
|
34
|
-
let payload
|
|
35
|
-
if (Number(payloadVersion) === 2) {
|
|
36
|
-
payload = createSyncPayload(raw)
|
|
37
|
-
} else {
|
|
38
|
-
if (graphStaleness(ctx).stale) throw new Error('Cannot produce synchronized evidence from a stale graph. Run rebuild_graph first.')
|
|
39
|
-
payload = createSyncPayloadV3(raw, await createEvidenceSnapshot({repoRoot: ctx.repoRoot, graph: raw}))
|
|
40
|
-
}
|
|
41
|
-
const body = JSON.stringify(payload)
|
|
42
|
-
const bodyBytes = Buffer.byteLength(body)
|
|
43
|
-
if (bodyBytes > MAX_SYNC_BODY_BYTES) throw new Error(`source-free payload exceeds the ${MAX_SYNC_BODY_BYTES / 1024} KB safety limit`)
|
|
44
|
-
const identity = identityFor(ctx.repoRoot)
|
|
45
|
-
return Object.freeze({
|
|
46
|
-
payload,
|
|
47
|
-
body,
|
|
48
|
-
bodyBytes,
|
|
49
|
-
bodyHash: createHash('sha256').update(body).digest('hex'),
|
|
50
|
-
repoName: repositoryLabel(ctx.repoRoot),
|
|
51
|
-
repositoryId: identity.repositoryId,
|
|
52
|
-
graphPath: ctx.graphPath,
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function activeRepositoryIdentity(ctx = {}) {
|
|
57
|
-
if (!ctx.repoRoot || !ctx.graphPath) throw new Error('No active repository graph — open_repo first.')
|
|
58
|
-
const identity = identityFor(ctx.repoRoot)
|
|
59
|
-
return Object.freeze({repositoryId: identity.repositoryId, repoName: repositoryLabel(ctx.repoRoot), graphPath: ctx.graphPath})
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export const cacheArchitectureContract = (graphPath, contract) => writeCachedArchitectureContract(graphPath, contract)
|
|
63
|
-
|
|
64
|
-
export function installedPackageCoordinates(repoRoot) {
|
|
65
|
-
if (!repoRoot) throw new Error('No repository root is active.')
|
|
66
|
-
return collectInstalled(repoRoot).installed
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const advisoryCacheMetadata = (storePath = DEFAULT_STORE) => ({
|
|
70
|
-
path: storePath,
|
|
71
|
-
...storeMeta(storePath),
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
export {commitAdvisoryRefresh, createAdvisoryQueryPlan}
|
|
75
|
-
export {toolResult}
|
package/src/git-exec.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// The single chokepoint for launching git. Every git subprocess in the package routes through here,
|
|
2
|
-
// so there is one place that applies `-C <repoRoot>` containment, a credential-stripped child
|
|
3
|
-
// environment, a hidden Windows window and a bounded timeout — instead of a dozen near-identical
|
|
4
|
-
// spawnSync wrappers scattered across the analysis, graph and MCP layers.
|
|
5
|
-
import { spawnSync, spawn } from "node:child_process";
|
|
6
|
-
import { childProcessEnv } from "./child-env.js";
|
|
7
|
-
|
|
8
|
-
// Synchronous git. Returns the raw spawnSync result ({status, stdout, stderr, error}) so callers keep
|
|
9
|
-
// their existing status/stdout/error handling. encoding defaults to "utf8" (pass "buffer" for binary
|
|
10
|
-
// stdout); maxBuffer and stdio are forwarded only when provided so Node's defaults are preserved.
|
|
11
|
-
export function runGit(repoRoot, args, options = {}) {
|
|
12
|
-
const spawnOptions = {
|
|
13
|
-
encoding: options.encoding ?? "utf8",
|
|
14
|
-
windowsHide: true,
|
|
15
|
-
timeout: options.timeout ?? 8000,
|
|
16
|
-
env: childProcessEnv(options.env),
|
|
17
|
-
};
|
|
18
|
-
if (options.maxBuffer != null) spawnOptions.maxBuffer = options.maxBuffer;
|
|
19
|
-
if (options.stdio != null) spawnOptions.stdio = options.stdio;
|
|
20
|
-
return spawnSync("git", ["-C", repoRoot, ...args], spawnOptions);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Streaming git for the history collector: byte-bounded stdout, a hard timeout that SIGKILLs the child,
|
|
24
|
-
// and a resolved {stdout, stderr, exitCode, truncated}. The caller owns cwd/env so reads can be scoped
|
|
25
|
-
// to a specific worktree.
|
|
26
|
-
export function boundedGitCommand(command, args, options) {
|
|
27
|
-
return new Promise((resolve, reject) => {
|
|
28
|
-
const child = spawn(command, args, {
|
|
29
|
-
cwd: options.cwd, env: options.env, shell: false, windowsHide: true,
|
|
30
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
31
|
-
});
|
|
32
|
-
const stdout = [], stderr = [];
|
|
33
|
-
let stdoutBytes = 0, stderrBytes = 0, truncated = false, timedOut = false, settled = false;
|
|
34
|
-
const finish = (callback) => {
|
|
35
|
-
if (settled) return;
|
|
36
|
-
settled = true;
|
|
37
|
-
clearTimeout(timer);
|
|
38
|
-
callback();
|
|
39
|
-
};
|
|
40
|
-
const stop = () => { try { child.kill("SIGKILL"); } catch { /* process already exited */ } };
|
|
41
|
-
const timer = setTimeout(() => { timedOut = true; stop(); }, options.timeoutMs);
|
|
42
|
-
child.stdout?.on("data", (chunk) => {
|
|
43
|
-
if (truncated) return;
|
|
44
|
-
const remaining = options.maxOutputBytes - stdoutBytes;
|
|
45
|
-
if (remaining <= 0) { truncated = true; stop(); return; }
|
|
46
|
-
const kept = chunk.length <= remaining ? chunk : chunk.subarray(0, remaining);
|
|
47
|
-
stdout.push(kept); stdoutBytes += kept.length;
|
|
48
|
-
if (kept.length !== chunk.length) { truncated = true; stop(); }
|
|
49
|
-
});
|
|
50
|
-
child.stderr?.on("data", (chunk) => {
|
|
51
|
-
const remaining = 64 * 1024 - stderrBytes;
|
|
52
|
-
if (remaining <= 0) return;
|
|
53
|
-
const kept = chunk.length <= remaining ? chunk : chunk.subarray(0, remaining);
|
|
54
|
-
stderr.push(kept); stderrBytes += kept.length;
|
|
55
|
-
});
|
|
56
|
-
child.on("error", (error) => finish(() => reject(error)));
|
|
57
|
-
child.on("close", (exitCode) => finish(() => {
|
|
58
|
-
if (timedOut) return reject(new Error("git history collection timed out"));
|
|
59
|
-
resolve({
|
|
60
|
-
stdout: Buffer.concat(stdout),
|
|
61
|
-
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
62
|
-
exitCode: Number(exitCode ?? 1),
|
|
63
|
-
truncated,
|
|
64
|
-
});
|
|
65
|
-
}));
|
|
66
|
-
});
|
|
67
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// build-worker.js — runs the web-tree-sitter graph build OFF Electron's main thread. In-process the
|
|
2
|
-
// parse blocks the main event loop for the whole repo walk (big repos = many seconds), and on Windows
|
|
3
|
-
// window input routing lives on the main process — so the ENTIRE app froze during "BUILDING THE
|
|
4
|
-
// GRAPH…". The worker builds, filters, writes graph.json and computes the summaries; only the small
|
|
5
|
-
// result object crosses back (never the graph itself — structured-cloning a huge graph would stall
|
|
6
|
-
// the main thread again).
|
|
7
|
-
import { parentPort, workerData } from "node:worker_threads";
|
|
8
|
-
import { buildInternalGraph } from "./internal-builder.js";
|
|
9
|
-
import { filterGraphForMode, filterGraphByScope, summarizeCommunities, summarizeHotspots } from "./layout.js";
|
|
10
|
-
import { atomicWriteFileSync } from "./file-lock.js";
|
|
11
|
-
import { snapshotRepository } from "./incremental-refresh.js";
|
|
12
|
-
import { buildLspPrecisionOverlay, invalidatePrecisionOverlay, precisionSummary } from "../precision/lsp-overlay.js";
|
|
13
|
-
|
|
14
|
-
(async () => {
|
|
15
|
-
const { repoPath, mode, scope, precision, graphJson, central } = workerData || {};
|
|
16
|
-
try {
|
|
17
|
-
let graph = await buildInternalGraph(repoPath);
|
|
18
|
-
if (mode === "no-tests" || mode === "tests-only") graph = filterGraphForMode(graph, mode, { repoRoot: repoPath });
|
|
19
|
-
if (scope) graph = filterGraphByScope(graph, scope);
|
|
20
|
-
graph.graphBuildMode = mode;
|
|
21
|
-
graph.graphBuildScope = scope || "";
|
|
22
|
-
graph.graphPrecisionMode = precision === "off" ? "off" : "lsp";
|
|
23
|
-
atomicWriteFileSync(graphJson, JSON.stringify(graph), "utf8");
|
|
24
|
-
let overlay = await buildLspPrecisionOverlay({repoRoot: repoPath, graph, graphPath: graphJson, mode: graph.graphPrecisionMode});
|
|
25
|
-
if (graph.graphPrecisionMode === "lsp") {
|
|
26
|
-
try {
|
|
27
|
-
if (snapshotRepository(repoPath).revision !== graph.graphRevision) {
|
|
28
|
-
overlay = invalidatePrecisionOverlay(graphJson, graph);
|
|
29
|
-
}
|
|
30
|
-
} catch {
|
|
31
|
-
overlay = invalidatePrecisionOverlay(
|
|
32
|
-
graphJson,
|
|
33
|
-
graph,
|
|
34
|
-
"repository freshness could not be verified after semantic precision",
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
parentPort.postMessage({
|
|
39
|
-
ok: true,
|
|
40
|
-
nodes: graph.nodes.length,
|
|
41
|
-
links: graph.links.length,
|
|
42
|
-
communities: summarizeCommunities(graphJson),
|
|
43
|
-
hotspots: summarizeHotspots(graphJson),
|
|
44
|
-
precision: precisionSummary(overlay),
|
|
45
|
-
});
|
|
46
|
-
} catch (e) {
|
|
47
|
-
parentPort.postMessage({ ok: false, error: (e && e.message) || String(e) });
|
|
48
|
-
}
|
|
49
|
-
})();
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import {goTypeName} from './lang-go.js'
|
|
2
|
-
|
|
3
|
-
const dirOf = (file) => file.includes('/') ? file.slice(0, file.lastIndexOf('/')) : ''
|
|
4
|
-
|
|
5
|
-
export function createGoReceiverResolution({resolution, nodeById, importedLocals}) {
|
|
6
|
-
const {dirSymbols, dirMethods, dirMethodsByName, dirTypes, resolveCall} = resolution
|
|
7
|
-
const typeRef = (rawType, contextFile, fallbackDir = dirOf(contextFile)) => {
|
|
8
|
-
const raw = String(rawType || '').trim()
|
|
9
|
-
if (!raw) return null
|
|
10
|
-
const dot = raw.indexOf('.')
|
|
11
|
-
if (dot > 0) {
|
|
12
|
-
const imported = importedLocals.get(contextFile)?.get(raw.slice(0, dot))
|
|
13
|
-
return imported?.targetDir ? {dir: imported.targetDir, name: raw.slice(dot + 1)} : null
|
|
14
|
-
}
|
|
15
|
-
return {dir: fallbackDir, name: raw}
|
|
16
|
-
}
|
|
17
|
-
const fieldType = (receiver, fieldName) => {
|
|
18
|
-
if (!receiver?.name || !fieldName) return null
|
|
19
|
-
const typeId = dirTypes.get(receiver.dir)?.get(receiver.name)
|
|
20
|
-
const typeNode = typeId && nodeById.get(typeId)
|
|
21
|
-
const rawFieldType = typeNode?.field_types?.[fieldName]
|
|
22
|
-
return rawFieldType ? typeRef(rawFieldType, typeNode.source_file, receiver.dir) : null
|
|
23
|
-
}
|
|
24
|
-
const exactMethod = (receiver, methodName) => {
|
|
25
|
-
const candidates = receiver && dirMethods.get(receiver.dir)?.get(receiver.name)?.get(methodName)
|
|
26
|
-
return candidates?.length === 1 ? candidates[0] : null
|
|
27
|
-
}
|
|
28
|
-
const uniqueMethod = (dir, methodName) => {
|
|
29
|
-
const candidates = dirMethodsByName.get(dir)?.get(methodName) || []
|
|
30
|
-
return candidates.length === 1 ? candidates[0] : null
|
|
31
|
-
}
|
|
32
|
-
const returnType = (targetId, callerFile) => {
|
|
33
|
-
const target = targetId && nodeById.get(targetId)
|
|
34
|
-
return target?.return_type
|
|
35
|
-
? typeRef(target.return_type, target.source_file || callerFile, dirOf(target.source_file || callerFile))
|
|
36
|
-
: null
|
|
37
|
-
}
|
|
38
|
-
const fieldChildren = (node, name) => {
|
|
39
|
-
const children = node?.childrenForFieldName?.(name)
|
|
40
|
-
if (Array.isArray(children) && children.length) return children
|
|
41
|
-
const child = node?.childForFieldName?.(name)
|
|
42
|
-
return child ? [child] : []
|
|
43
|
-
}
|
|
44
|
-
const receiverBindings = (selector, file) => {
|
|
45
|
-
const bindings = new Map()
|
|
46
|
-
let scope = selector
|
|
47
|
-
while (scope?.parent && !['function_declaration', 'method_declaration'].includes(scope.type)) scope = scope.parent
|
|
48
|
-
if (!scope || !['function_declaration', 'method_declaration'].includes(scope.type)) return bindings
|
|
49
|
-
const callRow = selector.startPosition.row
|
|
50
|
-
const containsCall = (node) => node.startIndex <= selector.startIndex && node.endIndex >= selector.endIndex
|
|
51
|
-
const expressionType = (node) => {
|
|
52
|
-
if (!node) return null
|
|
53
|
-
const declared = goTypeName(node)
|
|
54
|
-
if (declared) return typeRef(declared, file)
|
|
55
|
-
if (['parenthesized_expression', 'unary_expression'].includes(node.type)) {
|
|
56
|
-
return expressionType(node.childForFieldName?.('operand') || node.namedChildren?.[0])
|
|
57
|
-
}
|
|
58
|
-
if (node.type === 'composite_literal') return typeRef(goTypeName(node.childForFieldName?.('type')), file)
|
|
59
|
-
if (node.type === 'identifier') return bindings.get(node.text) || null
|
|
60
|
-
if (node.type === 'selector_expression') return fieldType(expressionType(node.childForFieldName?.('operand')), node.childForFieldName?.('field')?.text)
|
|
61
|
-
if (node.type !== 'call_expression') return null
|
|
62
|
-
const fn = node.childForFieldName?.('function')
|
|
63
|
-
if (fn?.type === 'identifier') {
|
|
64
|
-
const returned = returnType(resolveCall(fn.text, file), file)
|
|
65
|
-
if (returned) return returned
|
|
66
|
-
if (dirTypes.get(dirOf(file))?.has(fn.text)) return typeRef(fn.text, file)
|
|
67
|
-
if (/^New[A-Z_]/.test(fn.text)) return typeRef(fn.text.slice(3), file)
|
|
68
|
-
}
|
|
69
|
-
if (fn?.type === 'selector_expression') {
|
|
70
|
-
const operand = fn.childForFieldName?.('operand'), member = fn.childForFieldName?.('field')?.text
|
|
71
|
-
const imported = operand?.type === 'identifier' && importedLocals.get(file)?.get(operand.text)
|
|
72
|
-
if (imported?.targetDir && member) {
|
|
73
|
-
const returned = returnType(dirSymbols.get(imported.targetDir)?.get(member), file)
|
|
74
|
-
if (returned) return returned
|
|
75
|
-
if (/^New[A-Z_]/.test(member)) return {dir: imported.targetDir, name: member.slice(3)}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return null
|
|
79
|
-
}
|
|
80
|
-
const bindTyped = (node) => {
|
|
81
|
-
const reference = typeRef(goTypeName(node.childForFieldName?.('type')), file)
|
|
82
|
-
const names = fieldChildren(node, 'name').filter((name) => ['identifier', 'field_identifier'].includes(name.type))
|
|
83
|
-
if (reference) for (const name of names) bindings.set(name.text, reference)
|
|
84
|
-
else if (node.type === 'var_spec') {
|
|
85
|
-
const values = node.childForFieldName?.('value')?.namedChildren || []
|
|
86
|
-
for (let index = 0; index < Math.min(names.length, values.length); index++) {
|
|
87
|
-
const inferred = expressionType(values[index])
|
|
88
|
-
if (inferred) bindings.set(names[index].text, inferred)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
const bindAssignment = (node) => {
|
|
93
|
-
const left = node.childForFieldName?.('left')?.namedChildren || []
|
|
94
|
-
const right = node.childForFieldName?.('right')?.namedChildren || []
|
|
95
|
-
for (let index = 0; index < Math.min(left.length, right.length); index++) {
|
|
96
|
-
if (left[index].type !== 'identifier') continue
|
|
97
|
-
const inferred = expressionType(right[index])
|
|
98
|
-
if (inferred) bindings.set(left[index].text, inferred)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
const visit = (node) => {
|
|
102
|
-
if (!node || node.startPosition.row > callRow) return
|
|
103
|
-
if (node !== scope && ['function_declaration', 'method_declaration', 'func_literal'].includes(node.type) && !containsCall(node)) return
|
|
104
|
-
if (['parameter_declaration', 'var_spec'].includes(node.type)) bindTyped(node)
|
|
105
|
-
else if (['short_var_declaration', 'assignment_statement'].includes(node.type)) bindAssignment(node)
|
|
106
|
-
for (const child of node.namedChildren || []) visit(child)
|
|
107
|
-
}
|
|
108
|
-
visit(scope)
|
|
109
|
-
return bindings
|
|
110
|
-
}
|
|
111
|
-
return {dirOf, fieldType, exactMethod, uniqueMethod, receiverBindings}
|
|
112
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// Resolve only the bounded local-file portion of URL-based dynamic imports.
|
|
2
|
-
// Runtime substitutions remain uncertain; this candidate exists solely so a
|
|
3
|
-
// statically named module is not mislabeled as an orphan.
|
|
4
|
-
export function boundedUrlImportTarget(arg, {field, fileRel, resolveJsImport}) {
|
|
5
|
-
if (!arg || arg.type !== "member_expression" || field(arg, "property")?.text !== "href") return null;
|
|
6
|
-
const created = field(arg, "object");
|
|
7
|
-
if (!created || created.type !== "new_expression" || field(created, "constructor")?.text !== "URL") return null;
|
|
8
|
-
const urlArgs = field(created, "arguments")?.namedChildren || [];
|
|
9
|
-
if (urlArgs.length !== 2 || urlArgs[1].text !== "import.meta.url") return null;
|
|
10
|
-
|
|
11
|
-
const source = urlArgs[0];
|
|
12
|
-
let rawSpec = "";
|
|
13
|
-
if (source.type === "string") {
|
|
14
|
-
rawSpec = source.text.replace(/^['"`]|['"`]$/g, "");
|
|
15
|
-
} else if (source.type === "template_string") {
|
|
16
|
-
const parts = source.namedChildren || [];
|
|
17
|
-
if (parts.length !== 2 || parts[0].type !== "string_fragment" || parts[1].type !== "template_substitution") return null;
|
|
18
|
-
rawSpec = parts[0].text;
|
|
19
|
-
} else return null;
|
|
20
|
-
|
|
21
|
-
if (!/^\.\.?\//.test(rawSpec)) return null;
|
|
22
|
-
const staticPath = rawSpec.split(/[?#]/)[0];
|
|
23
|
-
if (!/\.[cm]?[jt]sx?$/i.test(staticPath)) return null;
|
|
24
|
-
const target = resolveJsImport(fileRel, staticPath);
|
|
25
|
-
return target ? {rawSpec: staticPath, target} : null;
|
|
26
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
export const CALLABLE = /arrow_function|function|function_expression|generator_function/
|
|
2
|
-
|
|
3
|
-
export const FUNCS = `
|
|
4
|
-
(function_declaration name: (identifier) @fn)
|
|
5
|
-
(generator_function_declaration name: (identifier) @fn)
|
|
6
|
-
(class_declaration name: (_) @class)
|
|
7
|
-
(method_definition name: (_) @method)`
|
|
8
|
-
|
|
9
|
-
export const TOPVARS = `
|
|
10
|
-
(program (lexical_declaration (variable_declarator) @decl))
|
|
11
|
-
(program (variable_declaration (variable_declarator) @decl))
|
|
12
|
-
(program (export_statement (lexical_declaration (variable_declarator) @decl)))
|
|
13
|
-
(program (export_statement (variable_declaration (variable_declarator) @decl)))`
|
|
14
|
-
|
|
15
|
-
export const TYPES = `
|
|
16
|
-
(interface_declaration name: (_) @interface)
|
|
17
|
-
(type_alias_declaration name: (_) @type)
|
|
18
|
-
(enum_declaration name: (_) @enum)`
|
|
19
|
-
|
|
20
|
-
export const REQUIRE = `(variable_declarator name: (_) @lhs value: (call_expression function: (identifier) @req arguments: (arguments (string (string_fragment) @src))))`
|
|
21
|
-
|
|
22
|
-
export function parseExportSpecifiers(raw) {
|
|
23
|
-
return String(raw || '').split(',').map((part) => {
|
|
24
|
-
const text = part.trim()
|
|
25
|
-
const typeOnly = /^type\s+/.test(text)
|
|
26
|
-
const clean = text.replace(/^type\s+/, '').trim()
|
|
27
|
-
const match = clean.match(/^([A-Za-z_$][\w$]*|default)(?:\s+as\s+([A-Za-z_$][\w$]*|default))?$/)
|
|
28
|
-
return match ? {imported: match[1], exported: match[2] || match[1], typeOnly} : null
|
|
29
|
-
}).filter(Boolean)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function importTypeOnly(node) {
|
|
33
|
-
if (/^\s*import\s+type\b/.test(node.text)) return true
|
|
34
|
-
const clause = node.namedChildren.find((child) => child.type === 'import_clause')
|
|
35
|
-
if (!clause) return false
|
|
36
|
-
const parts = clause.namedChildren
|
|
37
|
-
if (parts.some((child) => child.type === 'identifier' || child.type === 'namespace_import')) return false
|
|
38
|
-
const named = parts.find((child) => child.type === 'named_imports')
|
|
39
|
-
const specifiers = named?.namedChildren.filter((child) => child.type === 'import_specifier') || []
|
|
40
|
-
return specifiers.length > 0 && specifiers.every((specifier) => /^\s*type\b/.test(specifier.text))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function reexportTypeOnly(node) {
|
|
44
|
-
if (/^\s*export\s+type\b/.test(node.text)) return true
|
|
45
|
-
const clause = node.namedChildren.find((child) => child.type === 'export_clause')
|
|
46
|
-
const specifiers = clause?.namedChildren.filter((child) => child.type === 'export_specifier') || []
|
|
47
|
-
return specifiers.length > 0 && specifiers.every((specifier) => /^\s*type\b/.test(specifier.text))
|
|
48
|
-
}
|