@titan-design/code-graph 0.10.0 → 0.13.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/README.md +135 -5
- package/dist/analysis/browser.d.ts +2 -0
- package/dist/analysis/browser.js +84 -0
- package/dist/analysis/browser.js.map +1 -0
- package/dist/browser-BBzShneN.d.ts +936 -0
- package/dist/{change-coupling-CyqHgRsm.d.ts → change-coupling-CT3bcZMD.d.ts} +5 -1
- package/dist/{chunk-PFI5XMUG.js → chunk-GX563F6R.js} +79 -89
- package/dist/chunk-GX563F6R.js.map +1 -0
- package/dist/chunk-HIVVDGWE.js +83 -0
- package/dist/chunk-HIVVDGWE.js.map +1 -0
- package/dist/chunk-L5KU543A.js +1395 -0
- package/dist/chunk-L5KU543A.js.map +1 -0
- package/dist/history/index.d.ts +25 -4
- package/dist/history/index.js +11 -3
- package/dist/index.d.ts +406 -353
- package/dist/index.js +1753 -889
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
- package/dist/chunk-PFI5XMUG.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@titan-design/code-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "TypeScript/Python code graph: ts-morph + tree-sitter extraction with incremental reuse, on the store kit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"./history": {
|
|
14
14
|
"types": "./dist/history/index.d.ts",
|
|
15
15
|
"import": "./dist/history/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./analysis": {
|
|
18
|
+
"types": "./dist/analysis/browser.d.ts",
|
|
19
|
+
"import": "./dist/analysis/browser.js"
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
"files": [
|
|
@@ -37,10 +41,10 @@
|
|
|
37
41
|
"dependencies": {
|
|
38
42
|
"ts-morph": "^25.0.0",
|
|
39
43
|
"web-tree-sitter": "^0.26.6",
|
|
40
|
-
"@titan-design/code-parser": "^0.1.0",
|
|
41
44
|
"@titan-design/embed": "^0.2.0",
|
|
42
|
-
"@titan-design/
|
|
43
|
-
"@titan-design/store-sqlite": "^0.3.
|
|
45
|
+
"@titan-design/code-parser": "^0.1.0",
|
|
46
|
+
"@titan-design/store-sqlite": "^0.3.3",
|
|
47
|
+
"@titan-design/retrieval": "^0.3.0"
|
|
44
48
|
},
|
|
45
49
|
"scripts": {
|
|
46
50
|
"build": "tsup",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/history/log.ts","../src/history/git.ts","../src/history/window.ts","../src/history/first-seen.ts","../src/history/churn.ts","../src/history/ownership.ts","../src/history/change-coupling.ts"],"sourcesContent":["import { realpathSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { detectGitToplevel, runGitLarge } from \"./git.js\";\nimport { windowCutoff, type ChurnWindow } from \"./window.js\";\n\nexport interface ChurnEntry {\n commit: string;\n /** Author identity: git author email (%ae), stable across name spelling drift. */\n author: string;\n /** Committer time (%ct), epoch seconds; lets one wide log be sliced per window. */\n epoch: number;\n /** Repo-relative posix path, rebased onto the caller's root. */\n filePath: string;\n added: number;\n deleted: number;\n}\n\nexport interface LoadChurnOptions {\n /** Directory paths are made relative to; entries outside it are dropped. */\n repoRoot: string;\n windowDays?: ChurnWindow;\n}\n\nexport const DEFAULT_WINDOW_DAYS = 30;\nexport const COMMIT_HASH_RE = /^[0-9a-f]{7,40}$/;\nconst NUMSTAT_FIRST_RE = /^(\\d+|-)$/;\n\n/**\n * Parse the last `windowDays` of git history into ChurnEntry[] rebased onto\n * `repoRoot`. Returns null if git isn't available; [] if no commits matched.\n * Used both for churn metrics and for change-coupling.\n */\nexport function loadChurnEntries(options: LoadChurnOptions): ChurnEntry[] | null {\n const windowDays = options.windowDays ?? DEFAULT_WINDOW_DAYS;\n const gitRoot = detectGitToplevel(options.repoRoot);\n if (gitRoot === null) return null;\n const log = runChurnLog(options.repoRoot, windowDays);\n if (log === null) return null;\n const canonicalRoot = canonicalize(options.repoRoot);\n return parseChurnLog(log).flatMap((entry) => {\n const rel = rebasePath(entry.filePath, gitRoot, canonicalRoot);\n return rel === null ? [] : [{ ...entry, filePath: rel }];\n });\n}\n\n/** A toplevel-relative git path re-expressed relative to `rootDir`, or null when outside it. */\nexport function rebasePath(gitPath: string, gitRoot: string, rootDir: string): string | null {\n const rel = path.relative(rootDir, path.resolve(gitRoot, gitPath));\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return null;\n return rel.split(path.sep).join(\"/\");\n}\n\nexport function canonicalize(p: string): string {\n try {\n return realpathSync(p);\n } catch {\n return path.resolve(p);\n }\n}\n\nexport function parseChurnLog(text: string): ChurnEntry[] {\n const out: ChurnEntry[] = [];\n let header: Pick<ChurnEntry, \"commit\" | \"author\" | \"epoch\"> | null = null;\n for (const rawLine of text.split(\"\\n\")) {\n const line = rawLine.trimEnd();\n if (!line) continue;\n const parts = line.split(\"\\t\");\n // A numstat row's two leading fields are number-or-`-`; a header's second field (an email) never is.\n if (parts.length === 3 && header && NUMSTAT_FIRST_RE.test(parts[0]!) && NUMSTAT_FIRST_RE.test(parts[1]!)) {\n out.push({ ...header, ...parseNumstat(parts), filePath: resolveRenamedPath(parts[2]!) });\n continue;\n }\n if (parts.length >= 2 && COMMIT_HASH_RE.test(parts[0]!)) {\n header = { commit: parts[0]!, author: parts[1]!, epoch: parts.length >= 3 ? Number(parts[2]) : 0 };\n }\n }\n return out;\n}\n\nfunction parseNumstat(parts: readonly string[]): { added: number; deleted: number } {\n return {\n added: parts[0] === \"-\" ? 0 : Number(parts[0]),\n deleted: parts[1] === \"-\" ? 0 : Number(parts[1]),\n };\n}\n\nexport function resolveRenamedPath(rawPath: string): string {\n const braceMatch = /^(.*)\\{(.*) => (.*)\\}(.*)$/.exec(rawPath);\n if (braceMatch) {\n const [, prefix, , newSeg, suffix] = braceMatch;\n return `${prefix}${newSeg}${suffix}`.replace(/\\/+/g, \"/\");\n }\n const arrow = rawPath.indexOf(\" => \");\n if (arrow >= 0) return rawPath.slice(arrow + 4);\n return rawPath;\n}\n\n/** Entries whose commit landed within the last `windowDays` of `nowEpoch`. */\nexport function entriesWithin(entries: readonly ChurnEntry[], windowDays: number, nowEpoch: number): ChurnEntry[] {\n const cutoff = windowCutoff(windowDays, nowEpoch);\n return entries.filter((e) => e.epoch >= cutoff);\n}\n\nfunction runChurnLog(repoRoot: string, windowDays: ChurnWindow): string | null {\n // Lifetime drops `--since` entirely, so the log is full history.\n const sinceArgs = windowDays === \"lifetime\" ? [] : [`--since=${windowDays}.days.ago`];\n // %ae is a steadier identity than %an; %ct lets one wide log be sliced into narrower windows.\n const format = \"--pretty=format:%H%x09%ae%x09%ct\";\n return runGitLarge(repoRoot, [\"log\", ...sinceArgs, \"--no-merges\", \"--numstat\", \"-M\", format], 64 * 1024 * 1024);\n}\n","import { execFileSync } from \"node:child_process\";\n\n/**\n * Strip the inherited GIT_DIR / GIT_INDEX_FILE / GIT_WORK_TREE vars when we\n * invoke git as a *repo-discovery* sub-tool. Those vars are set by git itself\n * when running hooks (and by some IDE integrations) to point the *parent* git\n * at a specific repo; if they leak into our subprocess, `git rev-parse\n * --show-toplevel` returns cwd rather than the real toplevel, and other\n * discovery commands misbehave similarly.\n */\nexport function discoveryEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n delete env.GIT_DIR;\n delete env.GIT_INDEX_FILE;\n delete env.GIT_WORK_TREE;\n return env;\n}\n\n/** Run a short git command and return its trimmed stdout, or null on any failure. */\nexport function runGit(cwd: string, args: readonly string[]): string | null {\n try {\n return execFileSync(\"git\", [...args], {\n cwd,\n encoding: \"utf-8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n env: discoveryEnv(),\n }).trim();\n } catch {\n return null;\n }\n}\n\nexport function detectGitToplevel(cwd: string): string | null {\n return runGit(cwd, [\"rev-parse\", \"--show-toplevel\"]);\n}\n\n/** Run a git command whose output can be large; null when git is missing or fails. */\nexport function runGitLarge(cwd: string, args: readonly string[], maxBuffer: number): string | null {\n try {\n return execFileSync(\"git\", [...args], {\n cwd,\n encoding: \"utf-8\",\n maxBuffer,\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n env: discoveryEnv(),\n });\n } catch {\n return null;\n }\n}\n","/**\n * A churn window is either a rolling N-day window or `\"lifetime\"` = all of git\n * history (no `--since` bound). Lifetime mode lets an unfamiliar repo be audited\n * cold, where any recent rolling slice is thin relative to the repo's whole\n * life, so a windowed view reads an established repo as nearly churn-free.\n */\nexport type ChurnWindow = number | \"lifetime\";\n\nexport const DAY_SECONDS = 86400;\n\n/** Lower bound (epoch seconds) of a finite window ending at `nowEpoch`. */\nexport function windowCutoff(windowDays: number, nowEpoch: number): number {\n return nowEpoch - windowDays * DAY_SECONDS;\n}\n","import { detectGitToplevel, runGitLarge } from \"./git.js\";\nimport { canonicalize, COMMIT_HASH_RE, rebasePath, resolveRenamedPath } from \"./log.js\";\n\nexport interface FirstSeenOptions {\n /** Directory paths are made relative to; paths outside it are dropped. */\n repoRoot: string;\n knownPaths?: ReadonlySet<string>;\n}\n\n/**\n * Earliest commit time (epoch seconds) per path, from one reverse-ordered pass\n * over full history: the first commit that touched a path approximates its birth.\n * Rebased onto `repoRoot` and filtered to `knownPaths` when given. Renames slightly\n * underestimate age (pre-rename history lives under the old path). Returns null\n * when git is unavailable, so callers degrade to \"no age discount\".\n */\nexport function loadFileFirstSeen(options: FirstSeenOptions): Map<string, number> | null {\n const gitRoot = detectGitToplevel(options.repoRoot);\n if (gitRoot === null) return null;\n const log = runFirstSeenLog(options.repoRoot);\n if (log === null) return null;\n const canonicalRoot = canonicalize(options.repoRoot);\n const firstSeen = new Map<string, number>();\n for (const { epoch, gitPath } of parseFirstSeenLog(log)) {\n const rel = rebasePath(resolveRenamedPath(gitPath), gitRoot, canonicalRoot);\n if (rel === null) continue;\n if (options.knownPaths && !options.knownPaths.has(rel)) continue;\n if (!firstSeen.has(rel)) firstSeen.set(rel, epoch); // --reverse, so the first sighting wins\n }\n return firstSeen;\n}\n\n/** (commit epoch, touched path) rows from `%H%x09%ct` headers followed by `--name-only` paths. */\nexport function parseFirstSeenLog(text: string): { epoch: number; gitPath: string }[] {\n const out: { epoch: number; gitPath: string }[] = [];\n let epoch = 0;\n for (const rawLine of text.split(\"\\n\")) {\n const line = rawLine.trimEnd();\n if (!line) continue;\n const parts = line.split(\"\\t\");\n if (parts.length === 2 && COMMIT_HASH_RE.test(parts[0]!)) {\n epoch = Number(parts[1]);\n continue;\n }\n if (epoch) out.push({ epoch, gitPath: line });\n }\n return out;\n}\n\n/** `--reverse` so the first time a path is seen is its birth; `--no-renames` keeps name lines bare. */\nfunction runFirstSeenLog(repoRoot: string): string | null {\n const args = [\"log\", \"--reverse\", \"--no-merges\", \"--no-renames\", \"--name-only\", \"--pretty=format:%H%x09%ct\"];\n return runGitLarge(repoRoot, args, 128 * 1024 * 1024);\n}\n","import { entriesWithin, type ChurnEntry } from \"./log.js\";\nimport type { ChurnWindow } from \"./window.js\";\n\n/** One path's churn over a set of entries. */\nexport interface PathChurn {\n /** Lines added plus lines deleted. */\n lines: number;\n /** Distinct commits that touched the path. */\n commits: number;\n /** Distinct author identities that touched the path. */\n authors: number;\n}\n\n/** Per-path churn, in first-touched order, filtered to `knownPaths` when given. */\nexport function aggregateChurn(\n entries: readonly ChurnEntry[],\n knownPaths?: ReadonlySet<string>,\n): Map<string, PathChurn> {\n const lines = new Map<string, number>();\n const commits = new Map<string, Set<string>>();\n const authors = new Map<string, Set<string>>();\n for (const e of entries) {\n if (knownPaths && !knownPaths.has(e.filePath)) continue;\n lines.set(e.filePath, (lines.get(e.filePath) ?? 0) + e.added + e.deleted);\n setAdd(commits, e.filePath, e.commit);\n setAdd(authors, e.filePath, e.author);\n }\n const out = new Map<string, PathChurn>();\n for (const [filePath, total] of lines) {\n out.set(filePath, {\n lines: total,\n commits: commits.get(filePath)!.size,\n authors: authors.get(filePath)!.size,\n });\n }\n return out;\n}\n\n/**\n * Churn for several windows from one wide log: slice `entries` by commit time\n * per window and aggregate each slice independently, so 30/90/180-day churn can\n * be stored side by side from a single git pass.\n */\nexport function aggregateChurnWindows(\n entries: readonly ChurnEntry[],\n windowsDays: readonly ChurnWindow[],\n nowEpoch: number,\n knownPaths?: ReadonlySet<string>,\n): Map<ChurnWindow, Map<string, PathChurn>> {\n const out = new Map<ChurnWindow, Map<string, PathChurn>>();\n for (const windowDays of windowsDays) {\n // Lifetime is the whole wide log (all history); finite windows slice by time.\n const within = windowDays === \"lifetime\" ? entries : entriesWithin(entries, windowDays, nowEpoch);\n out.set(windowDays, aggregateChurn(within, knownPaths));\n }\n return out;\n}\n\nfunction setAdd(map: Map<string, Set<string>>, key: string, value: string): void {\n let set = map.get(key);\n if (!set) {\n set = new Set();\n map.set(key, set);\n }\n set.add(value);\n}\n","import type { ChurnEntry } from \"./log.js\";\n\nexport interface OwnershipForFile {\n /** Distinct contributing authors. */\n authors: number;\n /** Fraction of churn (lines) from the single largest contributor (0..1), unrounded. */\n topAuthorShare: number;\n /** Min number of authors whose combined contribution covers >= the threshold of churn. */\n busFactor: number;\n}\n\nexport interface ComputeOwnershipOptions {\n knownPaths?: ReadonlySet<string>;\n /** Coverage threshold for busFactor (default 0.5 = 50% of churn). */\n busFactorThreshold?: number;\n}\n\nexport const DEFAULT_BUS_FACTOR_THRESHOLD = 0.5;\n\n/** Ownership per path with non-zero churn, keyed by repo-relative path. */\nexport function computeOwnership(\n entries: readonly ChurnEntry[],\n options: ComputeOwnershipOptions = {},\n): Map<string, OwnershipForFile> {\n const threshold = options.busFactorThreshold ?? DEFAULT_BUS_FACTOR_THRESHOLD;\n const out = new Map<string, OwnershipForFile>();\n for (const [filePath, byAuthor] of authorLinesByPath(entries, options.knownPaths)) {\n const summary = summarizeOwnership(byAuthor, threshold);\n if (summary !== null) out.set(filePath, summary);\n }\n return out;\n}\n\n/** Lines changed per author per path, skipping zero-line entries (binary files). */\nexport function authorLinesByPath(\n entries: readonly ChurnEntry[],\n known: ReadonlySet<string> | undefined,\n): Map<string, Map<string, number>> {\n const out = new Map<string, Map<string, number>>();\n for (const e of entries) {\n if (known && !known.has(e.filePath)) continue;\n const lines = e.added + e.deleted;\n if (lines === 0) continue;\n let byAuthor = out.get(e.filePath);\n if (!byAuthor) {\n byAuthor = new Map();\n out.set(e.filePath, byAuthor);\n }\n byAuthor.set(e.author, (byAuthor.get(e.author) ?? 0) + lines);\n }\n return out;\n}\n\n/** Summarize one author tally; null when it holds no churn. */\nexport function summarizeOwnership(\n byAuthor: ReadonlyMap<string, number>,\n threshold: number = DEFAULT_BUS_FACTOR_THRESHOLD,\n): OwnershipForFile | null {\n let total = 0;\n for (const v of byAuthor.values()) total += v;\n if (total === 0) return null;\n const sorted = [...byAuthor.values()].sort((a, b) => b - a);\n const topAuthorShare = sorted[0]! / total;\n const busFactor = minAuthorsToReach(sorted, total, threshold);\n return { authors: sorted.length, topAuthorShare, busFactor };\n}\n\nfunction minAuthorsToReach(sortedDesc: readonly number[], total: number, threshold: number): number {\n let acc = 0;\n for (let i = 0; i < sortedDesc.length; i++) {\n acc += sortedDesc[i]!;\n if (acc / total >= threshold) return i + 1;\n }\n return sortedDesc.length;\n}\n","import type { ChurnEntry } from \"./log.js\";\n\nexport interface CoEditPair {\n fileA: string;\n fileB: string;\n /** Commits in which both files changed. */\n count: number;\n /** Most recent commits (up to maxCommitsPerPair). */\n commits: string[];\n}\n\nexport interface ComputeChangeCouplingOptions {\n /** Skip pairs that co-occur in fewer than this many commits. Default 2. */\n minCount?: number;\n /** Truncate the commits sample per pair. Default 10. */\n maxCommitsPerPair?: number;\n /**\n * Skip commits touching more than this many files (sweeping refactors, mass\n * renames). Default 50: beyond that the O(n²) pair explosion is signal-poor.\n */\n largeCommitThreshold?: number;\n /** Filter file paths to this set before pairing. */\n knownPaths?: ReadonlySet<string>;\n}\n\nexport interface ChangeCouplingResult {\n pairs: CoEditPair[];\n /** Commits dropped by largeCommitThreshold, so callers can say when sweeps suppressed the signal. */\n skippedLargeCommits: number;\n /** Threshold that was applied (echoed for diagnostic messages). */\n largeCommitThreshold: number;\n}\n\nexport interface CouplingPartner {\n partner: string;\n count: number;\n commits: string[];\n}\n\ninterface PairAccum {\n count: number;\n commits: string[];\n}\n\nconst DEFAULT_MIN_COUNT = 2;\nconst DEFAULT_MAX_COMMITS_PER_PAIR = 10;\nconst DEFAULT_LARGE_COMMIT_THRESHOLD = 50;\n\nexport function computeChangeCoupling(\n entries: readonly ChurnEntry[],\n options: ComputeChangeCouplingOptions = {},\n): ChangeCouplingResult {\n const maxCommits = options.maxCommitsPerPair ?? DEFAULT_MAX_COMMITS_PER_PAIR;\n const largeThreshold = options.largeCommitThreshold ?? DEFAULT_LARGE_COMMIT_THRESHOLD;\n const pairs = new Map<string, PairAccum>();\n let skippedLargeCommits = 0;\n for (const [commit, files] of groupByCommit(entries, options.knownPaths)) {\n if (files.length < 2) continue;\n if (files.length > largeThreshold) {\n skippedLargeCommits++;\n continue;\n }\n accumulatePairs(commit, files, pairs, maxCommits);\n }\n return {\n pairs: finalize(pairs, options.minCount ?? DEFAULT_MIN_COUNT),\n skippedLargeCommits,\n largeCommitThreshold: largeThreshold,\n };\n}\n\nfunction groupByCommit(entries: readonly ChurnEntry[], known: ReadonlySet<string> | undefined): Map<string, string[]> {\n const out = new Map<string, string[]>();\n for (const e of entries) {\n if (known && !known.has(e.filePath)) continue;\n let files = out.get(e.commit);\n if (!files) {\n files = [];\n out.set(e.commit, files);\n }\n if (!files.includes(e.filePath)) files.push(e.filePath);\n }\n return out;\n}\n\nfunction accumulatePairs(commit: string, files: readonly string[], pairs: Map<string, PairAccum>, maxCommits: number): void {\n const sorted = [...files].sort();\n for (let i = 0; i < sorted.length; i++) {\n for (let j = i + 1; j < sorted.length; j++) {\n const key = `${sorted[i]!}\\t${sorted[j]!}`;\n let acc = pairs.get(key);\n if (!acc) {\n acc = { count: 0, commits: [] };\n pairs.set(key, acc);\n }\n acc.count++;\n if (acc.commits.length < maxCommits) acc.commits.push(commit);\n }\n }\n}\n\nfunction finalize(pairs: ReadonlyMap<string, PairAccum>, minCount: number): CoEditPair[] {\n const out: CoEditPair[] = [];\n for (const [key, acc] of pairs) {\n if (acc.count < minCount) continue;\n const [a, b] = key.split(\"\\t\");\n out.push({ fileA: a!, fileB: b!, count: acc.count, commits: acc.commits });\n }\n return out.sort(comparePairs);\n}\n\nfunction comparePairs(a: CoEditPair, b: CoEditPair): number {\n if (b.count !== a.count) return b.count - a.count;\n if (a.fileA !== b.fileA) return a.fileA < b.fileA ? -1 : 1;\n return a.fileB < b.fileB ? -1 : a.fileB > b.fileB ? 1 : 0;\n}\n\n/** Files most coupled to `seed`, by co-edit count desc then path; the seed itself is excluded. */\nexport function couplingFor(pairs: readonly CoEditPair[], seed: string): CouplingPartner[] {\n const out: CouplingPartner[] = [];\n for (const p of pairs) {\n if (p.fileA === seed) out.push({ partner: p.fileB, count: p.count, commits: p.commits });\n else if (p.fileB === seed) out.push({ partner: p.fileA, count: p.count, commits: p.commits });\n }\n out.sort((a, b) => {\n if (b.count !== a.count) return b.count - a.count;\n return a.partner < b.partner ? -1 : a.partner > b.partner ? 1 : 0;\n });\n return out;\n}\n"],"mappings":"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","names":[]}
|