homegraph 1.2.0 → 1.4.1
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/dist/bin/homegraph.js +3 -0
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js +85 -0
- package/dist/context/index.js.map +1 -1
- package/dist/db/index.d.ts +64 -5
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +178 -14
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +19 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +117 -2
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +299 -6
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +32 -1
- package/dist/db/wal-valve.d.ts +106 -0
- package/dist/db/wal-valve.d.ts.map +1 -0
- package/dist/db/wal-valve.js +208 -0
- package/dist/db/wal-valve.js.map +1 -0
- package/dist/directory.d.ts +9 -5
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +210 -19
- package/dist/directory.js.map +1 -1
- package/dist/extraction/cfml-extractor.d.ts +107 -0
- package/dist/extraction/cfml-extractor.d.ts.map +1 -0
- package/dist/extraction/cfml-extractor.js +494 -0
- package/dist/extraction/cfml-extractor.js.map +1 -0
- package/dist/extraction/grammars.d.ts +25 -1
- package/dist/extraction/grammars.d.ts.map +1 -1
- package/dist/extraction/grammars.js +177 -24
- package/dist/extraction/grammars.js.map +1 -1
- package/dist/extraction/index.d.ts +43 -4
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +308 -5
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/c-cpp.d.ts +42 -0
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/dist/extraction/languages/c-cpp.js +369 -4
- package/dist/extraction/languages/c-cpp.js.map +1 -1
- package/dist/extraction/languages/cfquery.d.ts +12 -0
- package/dist/extraction/languages/cfquery.d.ts.map +1 -0
- package/dist/extraction/languages/cfquery.js +28 -0
- package/dist/extraction/languages/cfquery.js.map +1 -0
- package/dist/extraction/languages/cfscript.d.ts +3 -0
- package/dist/extraction/languages/cfscript.d.ts.map +1 -0
- package/dist/extraction/languages/cfscript.js +73 -0
- package/dist/extraction/languages/cfscript.js.map +1 -0
- package/dist/extraction/languages/cobol.d.ts +33 -0
- package/dist/extraction/languages/cobol.d.ts.map +1 -0
- package/dist/extraction/languages/cobol.js +499 -0
- package/dist/extraction/languages/cobol.js.map +1 -0
- package/dist/extraction/languages/erlang.d.ts +3 -0
- package/dist/extraction/languages/erlang.d.ts.map +1 -0
- package/dist/extraction/languages/erlang.js +350 -0
- package/dist/extraction/languages/erlang.js.map +1 -0
- package/dist/extraction/languages/index.d.ts.map +1 -1
- package/dist/extraction/languages/index.js +16 -0
- package/dist/extraction/languages/index.js.map +1 -1
- package/dist/extraction/languages/nix.d.ts +3 -0
- package/dist/extraction/languages/nix.d.ts.map +1 -0
- package/dist/extraction/languages/nix.js +294 -0
- package/dist/extraction/languages/nix.js.map +1 -0
- package/dist/extraction/languages/solidity.d.ts +3 -0
- package/dist/extraction/languages/solidity.d.ts.map +1 -0
- package/dist/extraction/languages/solidity.js +293 -0
- package/dist/extraction/languages/solidity.js.map +1 -0
- package/dist/extraction/languages/terraform.d.ts +3 -0
- package/dist/extraction/languages/terraform.d.ts.map +1 -0
- package/dist/extraction/languages/terraform.js +641 -0
- package/dist/extraction/languages/terraform.js.map +1 -0
- package/dist/extraction/languages/vbnet.d.ts +11 -0
- package/dist/extraction/languages/vbnet.d.ts.map +1 -0
- package/dist/extraction/languages/vbnet.js +141 -0
- package/dist/extraction/languages/vbnet.js.map +1 -0
- package/dist/extraction/mybatis-extractor.d.ts +30 -10
- package/dist/extraction/mybatis-extractor.d.ts.map +1 -1
- package/dist/extraction/mybatis-extractor.js +140 -38
- package/dist/extraction/mybatis-extractor.js.map +1 -1
- package/dist/extraction/parse-pool.d.ts +27 -1
- package/dist/extraction/parse-pool.d.ts.map +1 -1
- package/dist/extraction/parse-pool.js +75 -7
- package/dist/extraction/parse-pool.js.map +1 -1
- package/dist/extraction/parse-worker.js +9 -2
- package/dist/extraction/parse-worker.js.map +1 -1
- package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/dist/extraction/tree-sitter-helpers.js +1 -0
- package/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/dist/extraction/tree-sitter-types.d.ts +3 -1
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.d.ts +38 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +754 -10
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/dist/graph/traversal.d.ts.map +1 -1
- package/dist/graph/traversal.js +1 -1
- package/dist/graph/traversal.js.map +1 -1
- package/dist/index.d.ts +60 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +348 -5
- package/dist/index.js.map +1 -1
- package/dist/installer/index.d.ts +42 -0
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +97 -2
- package/dist/installer/index.js.map +1 -1
- package/dist/mcp/daemon.d.ts +25 -3
- package/dist/mcp/daemon.d.ts.map +1 -1
- package/dist/mcp/daemon.js +62 -8
- package/dist/mcp/daemon.js.map +1 -1
- package/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
- package/dist/mcp/dynamic-boundaries.js +2 -1
- package/dist/mcp/dynamic-boundaries.js.map +1 -1
- package/dist/mcp/early-ppid.d.ts +26 -0
- package/dist/mcp/early-ppid.d.ts.map +1 -0
- package/dist/mcp/early-ppid.js +29 -0
- package/dist/mcp/early-ppid.js.map +1 -0
- package/dist/mcp/engine.d.ts +4 -5
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +27 -1
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +41 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/liveness-watchdog.d.ts +18 -1
- package/dist/mcp/liveness-watchdog.d.ts.map +1 -1
- package/dist/mcp/liveness-watchdog.js +73 -13
- package/dist/mcp/liveness-watchdog.js.map +1 -1
- package/dist/mcp/memory-budget.d.ts +30 -0
- package/dist/mcp/memory-budget.d.ts.map +1 -0
- package/dist/mcp/memory-budget.js +123 -0
- package/dist/mcp/memory-budget.js.map +1 -0
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +88 -4
- package/dist/mcp/proxy.js.map +1 -1
- package/dist/mcp/query-cache.d.ts +35 -4
- package/dist/mcp/query-cache.d.ts.map +1 -1
- package/dist/mcp/query-cache.js +89 -19
- package/dist/mcp/query-cache.js.map +1 -1
- package/dist/mcp/query-pool.d.ts +46 -12
- package/dist/mcp/query-pool.d.ts.map +1 -1
- package/dist/mcp/query-pool.js +100 -23
- package/dist/mcp/query-pool.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +4 -27
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +39 -84
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/session.d.ts +14 -0
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +28 -1
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/startup-handshake.d.ts +44 -0
- package/dist/mcp/startup-handshake.d.ts.map +1 -0
- package/dist/mcp/startup-handshake.js +73 -0
- package/dist/mcp/startup-handshake.js.map +1 -0
- package/dist/mcp/tools.d.ts +104 -4
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +2390 -191
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/transport.d.ts.map +1 -1
- package/dist/mcp/transport.js +18 -0
- package/dist/mcp/transport.js.map +1 -1
- package/dist/project-config.d.ts +38 -0
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +101 -2
- package/dist/project-config.js.map +1 -1
- package/dist/resolution/c-fnptr-synthesizer.d.ts +2 -1
- package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
- package/dist/resolution/c-fnptr-synthesizer.js +178 -146
- package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
- package/dist/resolution/callback-synthesizer.d.ts +9 -1
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +1164 -176
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/resolution/frameworks/cics.d.ts +20 -0
- package/dist/resolution/frameworks/cics.d.ts.map +1 -0
- package/dist/resolution/frameworks/cics.js +90 -0
- package/dist/resolution/frameworks/cics.js.map +1 -0
- package/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/dist/resolution/frameworks/index.js +3 -0
- package/dist/resolution/frameworks/index.js.map +1 -1
- package/dist/resolution/frameworks/java.d.ts.map +1 -1
- package/dist/resolution/frameworks/java.js +14 -6
- package/dist/resolution/frameworks/java.js.map +1 -1
- package/dist/resolution/frameworks/terraform.d.ts +38 -0
- package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
- package/dist/resolution/frameworks/terraform.js +277 -0
- package/dist/resolution/frameworks/terraform.js.map +1 -0
- package/dist/resolution/goframe-synthesizer.d.ts +2 -1
- package/dist/resolution/goframe-synthesizer.d.ts.map +1 -1
- package/dist/resolution/goframe-synthesizer.js +8 -3
- package/dist/resolution/goframe-synthesizer.js.map +1 -1
- package/dist/resolution/import-resolver.d.ts +7 -0
- package/dist/resolution/import-resolver.d.ts.map +1 -1
- package/dist/resolution/import-resolver.js +129 -4
- package/dist/resolution/import-resolver.js.map +1 -1
- package/dist/resolution/index.d.ts +60 -7
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +430 -80
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/name-matcher.d.ts +0 -3
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +354 -33
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/resolution/strip-comments.d.ts +1 -1
- package/dist/resolution/strip-comments.d.ts.map +1 -1
- package/dist/resolution/strip-comments.js +49 -0
- package/dist/resolution/strip-comments.js.map +1 -1
- package/dist/resolution/types.d.ts +29 -0
- package/dist/resolution/types.d.ts.map +1 -1
- package/dist/resolution/workspace-packages.d.ts +10 -0
- package/dist/resolution/workspace-packages.d.ts.map +1 -1
- package/dist/resolution/workspace-packages.js +142 -4
- package/dist/resolution/workspace-packages.js.map +1 -1
- package/dist/search/identifier-segments.d.ts +60 -0
- package/dist/search/identifier-segments.d.ts.map +1 -0
- package/dist/search/identifier-segments.js +176 -0
- package/dist/search/identifier-segments.js.map +1 -0
- package/dist/search/query-utils.d.ts +201 -0
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +919 -2
- package/dist/search/query-utils.js.map +1 -1
- package/dist/sync/git-hooks.d.ts.map +1 -1
- package/dist/sync/git-hooks.js +2 -0
- package/dist/sync/git-hooks.js.map +1 -1
- package/dist/sync/watcher.d.ts +10 -5
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +51 -14
- package/dist/sync/watcher.js.map +1 -1
- package/dist/sync/worktree.d.ts.map +1 -1
- package/dist/sync/worktree.js +5 -0
- package/dist/sync/worktree.js.map +1 -1
- package/dist/types.d.ts +19 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -1
- package/dist/upgrade/index.d.ts +32 -0
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +162 -14
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/remove-binary.d.ts +87 -0
- package/dist/upgrade/remove-binary.d.ts.map +1 -0
- package/dist/upgrade/remove-binary.js +289 -0
- package/dist/upgrade/remove-binary.js.map +1 -0
- package/dist/upgrade/update-check.d.ts +92 -0
- package/dist/upgrade/update-check.d.ts.map +1 -0
- package/dist/upgrade/update-check.js +258 -0
- package/dist/upgrade/update-check.js.map +1 -0
- package/package.json +2 -2
- package/scripts/agent-eval/run-all.sh +6 -0
- package/scripts/build-bundle.sh +5 -0
- package/scripts/npm-shim.js +8 -1
- package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/data/agents.json +0 -109
- package/scripts/exp_boundary_eval/data/experiments.json +0 -140
- package/scripts/qa_eval/README.md +0 -407
- package/scripts/qa_eval/_test_deveco_probe.py +0 -41
- package/scripts/qa_eval/agent_runner.py +0 -526
- package/scripts/qa_eval/data/.gitignore +0 -4
- package/scripts/qa_eval/data/test-set.jsonl +0 -2
- package/scripts/qa_eval/eval_metrics.py +0 -274
- package/scripts/qa_eval/external_agent.py +0 -976
- package/scripts/qa_eval/llm_config.py +0 -92
- package/scripts/qa_eval/memory_monitor.py +0 -132
- package/scripts/qa_eval/my_answer_accuracy.py +0 -187
- package/scripts/qa_eval/requirements.txt +0 -2
- package/scripts/qa_eval/run_pipeline.py +0 -804
- package/scripts/qa_eval/stats_efficiency.py +0 -279
- package/scripts/qa_eval/stats_scores.py +0 -207
package/dist/extraction/index.js
CHANGED
|
@@ -46,6 +46,7 @@ exports.hashContent = hashContent;
|
|
|
46
46
|
exports.buildDefaultIgnore = buildDefaultIgnore;
|
|
47
47
|
exports.buildScopeIgnore = buildScopeIgnore;
|
|
48
48
|
exports.discoverEmbeddedRepoRoots = discoverEmbeddedRepoRoots;
|
|
49
|
+
exports.findUnindexedIgnoredRepos = findUnindexedIgnoredRepos;
|
|
49
50
|
exports.scanDirectory = scanDirectory;
|
|
50
51
|
exports.scanDirectoryAsync = scanDirectoryAsync;
|
|
51
52
|
const fs = __importStar(require("fs"));
|
|
@@ -304,6 +305,160 @@ function loadExcludeMatcher(rootDir) {
|
|
|
304
305
|
const patterns = (0, project_config_1.loadExcludePatterns)(rootDir);
|
|
305
306
|
return patterns.length > 0 ? (0, ignore_1.default)().add(patterns) : null;
|
|
306
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Matcher for the project's `homegraph.json` `include` patterns — first-party
|
|
310
|
+
* source to force INTO the index even when `.gitignore` drops it (the general
|
|
311
|
+
* whitelist `includeIgnored` never was — that one only revives *embedded git
|
|
312
|
+
* repos*). The case it exists for: a project under a second VCS (SVN/Perforce)
|
|
313
|
+
* `.gitignore`s its own real source so it stays out of Git, yet we still want it
|
|
314
|
+
* indexed. Returns `null` when nothing is force-included (the zero-config
|
|
315
|
+
* default → no overhead, no extra walk). Built once per scan/sync/scope
|
|
316
|
+
* operation from the scan root.
|
|
317
|
+
*/
|
|
318
|
+
function loadIncludeMatcher(rootDir) {
|
|
319
|
+
const patterns = (0, project_config_1.loadIncludePatterns)(rootDir);
|
|
320
|
+
return patterns.length > 0 ? (0, ignore_1.default)().add(patterns) : null;
|
|
321
|
+
}
|
|
322
|
+
/** Glob metacharacters that end the static (literal) prefix of an `include` pattern. */
|
|
323
|
+
const GLOB_META = /[*?[\]{}!]/;
|
|
324
|
+
/**
|
|
325
|
+
* The static directory prefix of each `include` pattern — the literal leading
|
|
326
|
+
* path up to the first glob segment — trailing-slashed, used to (a) walk only
|
|
327
|
+
* the opted-in subtrees in `collectIncludedFiles` and (b) let `ScopeIgnore` keep
|
|
328
|
+
* the watcher descending toward them. `Tools/` stays `Tools/`; a recursive
|
|
329
|
+
* `Tools/**` glob yields `Tools/`; `src/local/file.ts` yields `src/local/` (the
|
|
330
|
+
* file's dir); a pattern that starts with a glob (like a leading `**`) yields
|
|
331
|
+
* `''`, meaning "no static root — walk the whole tree". Duplicates and roots
|
|
332
|
+
* nested under a broader root are collapsed so each subtree is walked once.
|
|
333
|
+
*/
|
|
334
|
+
function includeStaticRoots(patterns) {
|
|
335
|
+
const roots = new Set();
|
|
336
|
+
for (const pattern of patterns) {
|
|
337
|
+
let p = pattern.replace(/^\/+/, '');
|
|
338
|
+
const trailingSlash = p.endsWith('/');
|
|
339
|
+
if (trailingSlash)
|
|
340
|
+
p = p.slice(0, -1);
|
|
341
|
+
const segs = p.split('/').filter(Boolean);
|
|
342
|
+
const lead = [];
|
|
343
|
+
for (const s of segs) {
|
|
344
|
+
if (GLOB_META.test(s))
|
|
345
|
+
break;
|
|
346
|
+
lead.push(s);
|
|
347
|
+
}
|
|
348
|
+
const hadWildcard = lead.length < segs.length;
|
|
349
|
+
// A wholly-literal pattern with no trailing slash names a file (or a dir we
|
|
350
|
+
// can't tell apart) — drop its last segment so we walk the containing dir
|
|
351
|
+
// and let the matcher pick the file. A trailing slash or a glob means the
|
|
352
|
+
// remaining `lead` is already the directory to walk.
|
|
353
|
+
if (!hadWildcard && !trailingSlash && lead.length > 0)
|
|
354
|
+
lead.pop();
|
|
355
|
+
if (lead.length === 0) {
|
|
356
|
+
roots.clear();
|
|
357
|
+
roots.add('');
|
|
358
|
+
return ['']; // a top-level glob forces a whole-tree walk; nothing narrower matters
|
|
359
|
+
}
|
|
360
|
+
roots.add(lead.join('/') + '/');
|
|
361
|
+
}
|
|
362
|
+
// Collapse roots nested under a broader one (e.g. drop `a/b/` if `a/` is present).
|
|
363
|
+
const all = [...roots];
|
|
364
|
+
return all.filter((r) => !all.some((other) => other !== r && r.startsWith(other)));
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Actively discover the source files an `include` whitelist forces in. `git
|
|
368
|
+
* ls-files` never lists gitignored files, so a filtered filesystem walk of just
|
|
369
|
+
* the opted-in subtrees (`includeStaticRoots`) is the only way to find them.
|
|
370
|
+
* Returns project-root-relative, normalized source-file paths.
|
|
371
|
+
*
|
|
372
|
+
* A file is collected when it MATCHES `include`, is NOT hit by `exclude` (an
|
|
373
|
+
* explicit exclude always wins), is a recognized source file, and does not live
|
|
374
|
+
* under a built-in default-ignored dir (`node_modules`, `dist`, …), `.git`, or
|
|
375
|
+
* HomeGraph's data dir — those are never resurfaced, mirroring `ScopeIgnore`.
|
|
376
|
+
* `.gitignore` is deliberately NOT consulted: overriding it is the whole point.
|
|
377
|
+
*/
|
|
378
|
+
function collectIncludedFiles(rootDir, include, exclude, roots, overrides) {
|
|
379
|
+
const out = new Set();
|
|
380
|
+
const defaults = defaultsOnlyIgnore();
|
|
381
|
+
const visited = new Set();
|
|
382
|
+
const consider = (abs, rel, isDir) => {
|
|
383
|
+
if (isDir) {
|
|
384
|
+
if (defaults.ignores(rel + '/'))
|
|
385
|
+
return; // never node_modules/dist/… via include
|
|
386
|
+
// An explicit `exclude` always wins over `include`; prune the whole subtree
|
|
387
|
+
// here so a large excluded dir (a committed frontend's own vendored deps,
|
|
388
|
+
// build output, …) is never walked — the per-file guard below still catches
|
|
389
|
+
// anything a directory pattern doesn't, so this is a pure efficiency win.
|
|
390
|
+
if (exclude && exclude.ignores(rel + '/'))
|
|
391
|
+
return;
|
|
392
|
+
walk(abs);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
if (defaults.ignores(rel))
|
|
396
|
+
return;
|
|
397
|
+
if (!include.ignores(rel))
|
|
398
|
+
return;
|
|
399
|
+
if (exclude && exclude.ignores(rel))
|
|
400
|
+
return;
|
|
401
|
+
if (!(0, grammars_1.isSourceFile)(rel, overrides))
|
|
402
|
+
return;
|
|
403
|
+
out.add(rel);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
function walk(absDir) {
|
|
407
|
+
let realDir;
|
|
408
|
+
try {
|
|
409
|
+
realDir = fs.realpathSync(absDir);
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (visited.has(realDir))
|
|
415
|
+
return; // symlink-cycle guard
|
|
416
|
+
visited.add(realDir);
|
|
417
|
+
let entries;
|
|
418
|
+
try {
|
|
419
|
+
entries = fs.readdirSync(absDir, { withFileTypes: true });
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
for (const entry of entries) {
|
|
425
|
+
if (entry.name === '.git' || (0, directory_1.isHomeGraphDataDir)(entry.name))
|
|
426
|
+
continue;
|
|
427
|
+
const abs = path.join(absDir, entry.name);
|
|
428
|
+
const rel = (0, utils_1.normalizePath)(path.relative(rootDir, abs));
|
|
429
|
+
if (!rel || rel.startsWith('..'))
|
|
430
|
+
continue;
|
|
431
|
+
if (entry.isSymbolicLink()) {
|
|
432
|
+
try {
|
|
433
|
+
const st = fs.statSync(fs.realpathSync(abs));
|
|
434
|
+
consider(abs, rel, st.isDirectory());
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
// broken symlink — skip
|
|
438
|
+
}
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
consider(abs, rel, entry.isDirectory());
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
for (const root of roots) {
|
|
445
|
+
walk(root === '' ? rootDir : path.join(rootDir, root));
|
|
446
|
+
}
|
|
447
|
+
return out;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* The included source files (`homegraph.json` `include`) for a scan root, or an
|
|
451
|
+
* empty set when nothing is force-included. Centralizes loading the matcher,
|
|
452
|
+
* roots, exclude, and overrides so both enumeration paths (git and filesystem
|
|
453
|
+
* walk) add the same files.
|
|
454
|
+
*/
|
|
455
|
+
function collectIncludedFilesForRoot(rootDir) {
|
|
456
|
+
const include = loadIncludeMatcher(rootDir);
|
|
457
|
+
if (!include)
|
|
458
|
+
return new Set();
|
|
459
|
+
const roots = includeStaticRoots((0, project_config_1.loadIncludePatterns)(rootDir));
|
|
460
|
+
return collectIncludedFiles(rootDir, include, loadExcludeMatcher(rootDir), roots, (0, project_config_1.loadExtensionOverrides)(rootDir));
|
|
461
|
+
}
|
|
307
462
|
/**
|
|
308
463
|
* `git ls-files --directory` collapses a wholly-untracked/ignored directory into
|
|
309
464
|
* one entry — and when the command's own cwd is such a directory (the indexed
|
|
@@ -444,17 +599,31 @@ function findNestedGitRepos(absDir, relPrefix) {
|
|
|
444
599
|
class ScopeIgnore {
|
|
445
600
|
rootMatcher;
|
|
446
601
|
exclude;
|
|
602
|
+
include;
|
|
603
|
+
includeRoots;
|
|
447
604
|
embedded;
|
|
448
605
|
defaults = defaultsOnlyIgnore();
|
|
449
606
|
constructor(rootMatcher, embedded,
|
|
450
607
|
/**
|
|
451
|
-
* Project `
|
|
608
|
+
* Project `homegraph.json` `exclude` patterns (#999), matched against the
|
|
452
609
|
* full root-relative path. Wins over everything else — an explicit user
|
|
453
610
|
* exclude applies even to tracked files and even inside embedded repos.
|
|
454
611
|
*/
|
|
455
|
-
exclude = null
|
|
612
|
+
exclude = null,
|
|
613
|
+
/**
|
|
614
|
+
* Project `homegraph.json` `include` patterns — first-party source forced
|
|
615
|
+
* INTO the index despite `.gitignore`. When a path matches, it is NOT
|
|
616
|
+
* ignored (so the watcher watches it), overriding `.gitignore`/`rootMatcher`
|
|
617
|
+
* — but never `exclude` (checked first) and never a built-in default-ignored
|
|
618
|
+
* dir. `includeRoots` are the static prefixes so a gitignored ANCESTOR
|
|
619
|
+
* directory of an included subtree still isn't pruned by the directory
|
|
620
|
+
* walker/watcher.
|
|
621
|
+
*/
|
|
622
|
+
include = null, includeRoots = []) {
|
|
456
623
|
this.rootMatcher = rootMatcher;
|
|
457
624
|
this.exclude = exclude;
|
|
625
|
+
this.include = include;
|
|
626
|
+
this.includeRoots = includeRoots;
|
|
458
627
|
// Longest root first so paths in nested embedded repos hit the innermost matcher.
|
|
459
628
|
this.embedded = [...embedded].sort((a, b) => b.root.length - a.root.length);
|
|
460
629
|
}
|
|
@@ -464,6 +633,20 @@ class ScopeIgnore {
|
|
|
464
633
|
// everywhere, including ancestors of embedded repos.
|
|
465
634
|
if (this.exclude && this.exclude.ignores(rel))
|
|
466
635
|
return true;
|
|
636
|
+
// User `include`: force first-party source in despite `.gitignore`. Never
|
|
637
|
+
// resurfaces a built-in default-ignored dir (node_modules/dist/…), so an
|
|
638
|
+
// include pattern can't accidentally pull in dependency/build trees.
|
|
639
|
+
if (this.include && !this.defaults.ignores(rel)) {
|
|
640
|
+
if (rel.endsWith('/')) {
|
|
641
|
+
// A directory on (or leading to) an included subtree must stay walkable
|
|
642
|
+
// so the watcher/walker descends to reach the forced-in files.
|
|
643
|
+
if (this.includeRoots.some((r) => r.startsWith(rel) || rel.startsWith(r)))
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
else if (this.include.ignores(rel)) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
467
650
|
for (const { root, matcher } of this.embedded) {
|
|
468
651
|
if (rel.startsWith(root)) {
|
|
469
652
|
const inner = rel.slice(root.length);
|
|
@@ -490,7 +673,8 @@ exports.ScopeIgnore = ScopeIgnore;
|
|
|
490
673
|
*/
|
|
491
674
|
function buildScopeIgnore(rootDir, embeddedRoots) {
|
|
492
675
|
const roots = embeddedRoots ? [...embeddedRoots] : discoverEmbeddedRepoRoots(rootDir);
|
|
493
|
-
|
|
676
|
+
const include = loadIncludeMatcher(rootDir);
|
|
677
|
+
return new ScopeIgnore(buildDefaultIgnore(rootDir), roots.map((root) => ({ root, matcher: buildDefaultIgnore(path.join(rootDir, root)) })), loadExcludeMatcher(rootDir), include, include ? includeStaticRoots((0, project_config_1.loadIncludePatterns)(rootDir)) : []);
|
|
494
678
|
}
|
|
495
679
|
/**
|
|
496
680
|
* Whether an embedded repo found as a tracked gitlink (mode 160000, #1031/#1033)
|
|
@@ -503,7 +687,7 @@ function buildScopeIgnore(rootDir, embeddedRoots) {
|
|
|
503
687
|
* under `node_modules` is never project code; not even an explicit opt-in
|
|
504
688
|
* revives it (matches `findIgnoredEmbeddedRepos`).
|
|
505
689
|
* 2. The parent repo's own `.gitignore` covers its path and the project did
|
|
506
|
-
* NOT opt that path in via `
|
|
690
|
+
* NOT opt that path in via `homegraph.json` `includeIgnored`. The gitignore
|
|
507
691
|
* rule is the user's stated intent to keep that path out of scope, exactly
|
|
508
692
|
* as for an UNtracked embedded repo — respect it by default, opt back in
|
|
509
693
|
* with `includeIgnored` (#514, #970, #976).
|
|
@@ -580,6 +764,50 @@ function discoverEmbeddedRepoRoots(rootDir) {
|
|
|
580
764
|
visit(rootDir, '');
|
|
581
765
|
return out;
|
|
582
766
|
}
|
|
767
|
+
/**
|
|
768
|
+
* Cap on how many skipped gitignored repos the CLI hint enumerates — a huge
|
|
769
|
+
* gitignored data dir full of clones must never turn the hint scan into a long
|
|
770
|
+
* walk. Enough to make the point; the caller says "+N more" past this.
|
|
771
|
+
*/
|
|
772
|
+
const UNINDEXED_IGNORED_REPO_HINT_CAP = 100;
|
|
773
|
+
/**
|
|
774
|
+
* The INVERSE of the gitignored side of {@link discoverEmbeddedRepoRoots}:
|
|
775
|
+
* nested git repositories under a gitignored directory that the project has NOT
|
|
776
|
+
* opted into via `homegraph.json` `includeIgnored`. These are real repos the
|
|
777
|
+
* default `init`/`index` deliberately skips because `.gitignore` excludes them
|
|
778
|
+
* (#970, #976) — most visibly the "super-repo `.gitignore`s its child repos"
|
|
779
|
+
* layout (#1156), where `init` at the parent correctly indexes ~nothing while
|
|
780
|
+
* `init` inside each child works. The CLI uses this to turn that silent empty
|
|
781
|
+
* index into an actionable hint: it names the skipped repos and offers to opt
|
|
782
|
+
* them in. Paths are `rootDir`-relative and trailing-slashed (valid
|
|
783
|
+
* `includeIgnored` patterns as-is). Returns `[]` for a non-git root (a
|
|
784
|
+
* filesystem walk already descends into nested repos there), skips built-in
|
|
785
|
+
* default-ignored dirs (`node_modules`, …), and is bounded so it never stalls
|
|
786
|
+
* on a giant ignored tree.
|
|
787
|
+
*/
|
|
788
|
+
function findUnindexedIgnoredRepos(rootDir) {
|
|
789
|
+
try {
|
|
790
|
+
(0, child_process_1.execFileSync)('git', ['rev-parse', '--git-dir'], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
return [];
|
|
794
|
+
}
|
|
795
|
+
const defaults = defaultsOnlyIgnore();
|
|
796
|
+
const includeIgnored = loadIncludeIgnoredMatcher(rootDir);
|
|
797
|
+
const repos = [];
|
|
798
|
+
for (const dir of listIgnoredDirs(rootDir)) {
|
|
799
|
+
if (defaults.ignores(dir))
|
|
800
|
+
continue; // node_modules etc. — never project code
|
|
801
|
+
if (includeIgnored?.ignores((0, utils_1.normalizePath)(dir)))
|
|
802
|
+
continue; // already opted in — nothing to nag about
|
|
803
|
+
for (const repo of findNestedGitRepos(path.join(rootDir, dir), dir)) {
|
|
804
|
+
repos.push(repo);
|
|
805
|
+
if (repos.length >= UNINDEXED_IGNORED_REPO_HINT_CAP)
|
|
806
|
+
return repos;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return repos;
|
|
810
|
+
}
|
|
583
811
|
/**
|
|
584
812
|
* Discover embedded repos hidden by `repoDir`'s OWN gitignore rules: for each
|
|
585
813
|
* gitignored directory, search for nested `.git` roots. Returns repo paths
|
|
@@ -787,7 +1015,11 @@ function getGitVisibleFiles(rootDir) {
|
|
|
787
1015
|
// not the parent's: the parent's .gitignore hides the child repo from git,
|
|
788
1016
|
// not from the index. (#514)
|
|
789
1017
|
const ig = buildScopeIgnore(rootDir, embeddedRoots);
|
|
790
|
-
|
|
1018
|
+
const visible = new Set([...files].filter((f) => !ig.ignores(f)));
|
|
1019
|
+
// Force-include first-party source whitelisted in `homegraph.json` `include`.
|
|
1020
|
+
for (const f of collectIncludedFilesForRoot(rootDir))
|
|
1021
|
+
visible.add(f);
|
|
1022
|
+
return visible;
|
|
791
1023
|
}
|
|
792
1024
|
catch {
|
|
793
1025
|
return null;
|
|
@@ -1050,8 +1282,52 @@ function scanDirectoryWalk(rootDir, onProgress) {
|
|
|
1050
1282
|
if (exclude)
|
|
1051
1283
|
baseMatchers.push({ dir: rootDir, ig: exclude });
|
|
1052
1284
|
walk(rootDir, baseMatchers);
|
|
1285
|
+
// Force-include first-party source whitelisted in `homegraph.json` `include`.
|
|
1286
|
+
const included = collectIncludedFilesForRoot(rootDir);
|
|
1287
|
+
if (included.size > 0) {
|
|
1288
|
+
const seen = new Set(files);
|
|
1289
|
+
for (const f of included) {
|
|
1290
|
+
if (!seen.has(f)) {
|
|
1291
|
+
files.push(f);
|
|
1292
|
+
seen.add(f);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1053
1296
|
return files;
|
|
1054
1297
|
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Extraction orchestrator
|
|
1300
|
+
*/
|
|
1301
|
+
/**
|
|
1302
|
+
* Resurrect a resolution edge that is about to be dropped (its target symbol
|
|
1303
|
+
* was removed, renamed, or its whole file deleted) as the ORIGINAL unresolved
|
|
1304
|
+
* reference that created it, read from the refName/refKind stamp
|
|
1305
|
+
* `createEdges` writes into edge metadata. Inserted as status='pending', the
|
|
1306
|
+
* ref is consumed by the same sync's resolution sweep: it rebinds to an
|
|
1307
|
+
* alternative definition if one exists, or parks as status='failed' where the
|
|
1308
|
+
* #1240 retry finds it if the symbol later reappears.
|
|
1309
|
+
*
|
|
1310
|
+
* Returns null — drop silently, the pre-#1240 behavior — for edges without a
|
|
1311
|
+
* refName stamp (created before the stamp existed, or synthesized): rebuilding
|
|
1312
|
+
* a ref from the target's plain node name would strip the receiver/qualifier
|
|
1313
|
+
* context the original text carried (`h.greet` → `greet`) and could rebind
|
|
1314
|
+
* somewhere a full re-index never would. Silent beats wrong.
|
|
1315
|
+
*/
|
|
1316
|
+
function resurrectRefFromDroppedEdge(e) {
|
|
1317
|
+
const refName = e.metadata?.refName;
|
|
1318
|
+
if (typeof refName !== 'string' || refName.length === 0)
|
|
1319
|
+
return null;
|
|
1320
|
+
const refKind = typeof e.metadata?.refKind === 'string' ? e.metadata.refKind : e.kind;
|
|
1321
|
+
return {
|
|
1322
|
+
fromNodeId: e.source,
|
|
1323
|
+
referenceName: refName,
|
|
1324
|
+
referenceKind: refKind,
|
|
1325
|
+
line: e.line ?? 0,
|
|
1326
|
+
column: e.column ?? 0,
|
|
1327
|
+
filePath: e.sourceFilePath,
|
|
1328
|
+
language: e.sourceLanguage,
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1055
1331
|
/**
|
|
1056
1332
|
* Extraction orchestrator
|
|
1057
1333
|
*/
|
|
@@ -1478,6 +1754,7 @@ class ExtractionOrchestrator {
|
|
|
1478
1754
|
filesIndexed,
|
|
1479
1755
|
filesSkipped,
|
|
1480
1756
|
filesErrored,
|
|
1757
|
+
filesDiscovered: total,
|
|
1481
1758
|
nodesCreated: totalNodes,
|
|
1482
1759
|
edgesCreated: totalEdges,
|
|
1483
1760
|
errors: [{ message: 'Aborted', severity: 'error' }, ...errors],
|
|
@@ -1600,6 +1877,7 @@ class ExtractionOrchestrator {
|
|
|
1600
1877
|
filesIndexed,
|
|
1601
1878
|
filesSkipped,
|
|
1602
1879
|
filesErrored,
|
|
1880
|
+
filesDiscovered: total,
|
|
1603
1881
|
nodesCreated: totalNodes,
|
|
1604
1882
|
edgesCreated: totalEdges,
|
|
1605
1883
|
errors,
|
|
@@ -1824,15 +2102,24 @@ class ExtractionOrchestrator {
|
|
|
1824
2102
|
newNodesByKindName.set(`${n.kind}\0${n.name}`, n.id);
|
|
1825
2103
|
}
|
|
1826
2104
|
const reinserted = [];
|
|
2105
|
+
const resurrected = [];
|
|
1827
2106
|
for (const e of crossFileIncomingEdges) {
|
|
1828
2107
|
const newTargetId = newNodesByKindName.get(`${e.targetKind}\0${e.targetName}`);
|
|
1829
2108
|
if (newTargetId) {
|
|
1830
2109
|
reinserted.push({ source: e.source, target: newTargetId, kind: e.kind, metadata: e.metadata, line: e.line, column: e.column, provenance: e.provenance });
|
|
1831
2110
|
}
|
|
2111
|
+
else {
|
|
2112
|
+
const ref = resurrectRefFromDroppedEdge(e);
|
|
2113
|
+
if (ref)
|
|
2114
|
+
resurrected.push(ref);
|
|
2115
|
+
}
|
|
1832
2116
|
}
|
|
1833
2117
|
if (reinserted.length > 0) {
|
|
1834
2118
|
this.queries.insertEdges(reinserted);
|
|
1835
2119
|
}
|
|
2120
|
+
if (resurrected.length > 0) {
|
|
2121
|
+
this.queries.insertUnresolvedRefsBatch(resurrected);
|
|
2122
|
+
}
|
|
1836
2123
|
}
|
|
1837
2124
|
// Insert unresolved references in batch with denormalized filePath/language
|
|
1838
2125
|
if (result.unresolvedReferences.length > 0) {
|
|
@@ -1909,6 +2196,17 @@ class ExtractionOrchestrator {
|
|
|
1909
2196
|
let reconcileChecks = 0;
|
|
1910
2197
|
for (const tracked of trackedFiles) {
|
|
1911
2198
|
if (!currentSet.has(tracked.path) || !fs.existsSync(path.join(this.rootDir, tracked.path))) {
|
|
2199
|
+
// Before the cascade deletes them, resurrect incoming cross-file
|
|
2200
|
+
// resolution edges as their original refs (#1240 removal case).
|
|
2201
|
+
const incoming = this.queries.getCrossFileIncomingEdgesWithTarget(tracked.path);
|
|
2202
|
+
if (incoming.length > 0) {
|
|
2203
|
+
const resurrected = incoming
|
|
2204
|
+
.map((e) => resurrectRefFromDroppedEdge(e))
|
|
2205
|
+
.filter((r) => r !== null);
|
|
2206
|
+
if (resurrected.length > 0) {
|
|
2207
|
+
this.queries.insertUnresolvedRefsBatch(resurrected);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
1912
2210
|
this.queries.deleteFile(tracked.path);
|
|
1913
2211
|
filesRemoved++;
|
|
1914
2212
|
}
|
|
@@ -1922,6 +2220,11 @@ class ExtractionOrchestrator {
|
|
|
1922
2220
|
// synchronous-stat loop that wedges the main thread on a large repo (#905).
|
|
1923
2221
|
// Yield at the top of the body so the `continue` fast-paths below still hit it.
|
|
1924
2222
|
if (++reconcileChecks % SYNC_RECONCILE_YIELD_INTERVAL === 0) {
|
|
2223
|
+
onProgress?.({
|
|
2224
|
+
phase: 'scanning',
|
|
2225
|
+
current: reconcileChecks,
|
|
2226
|
+
total: currentFiles.length,
|
|
2227
|
+
});
|
|
1925
2228
|
await new Promise((resolve) => setImmediate(resolve));
|
|
1926
2229
|
}
|
|
1927
2230
|
const fullPath = path.join(this.rootDir, filePath);
|