@rkarim08/sia 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/.claude-plugin/marketplace.json +35 -0
- package/.claude-plugin/plugin.json +27 -0
- package/.mcp.json +13 -0
- package/CLAUDE.md +226 -0
- package/LICENSE +202 -0
- package/PLUGIN_README.md +253 -0
- package/README.md +1013 -0
- package/agents/sia-changelog-writer.md +89 -0
- package/agents/sia-code-reviewer.md +86 -0
- package/agents/sia-conflict-resolver.md +100 -0
- package/agents/sia-convention-enforcer.md +69 -0
- package/agents/sia-debug.md +106 -0
- package/agents/sia-decision-reviewer.md +101 -0
- package/agents/sia-dependency-tracker.md +80 -0
- package/agents/sia-explain.md +126 -0
- package/agents/sia-feature.md +116 -0
- package/agents/sia-knowledge-capture.md +117 -0
- package/agents/sia-lead-architecture-advisor.md +93 -0
- package/agents/sia-lead-team-health.md +107 -0
- package/agents/sia-migration.md +100 -0
- package/agents/sia-onboarding.md +115 -0
- package/agents/sia-orientation.md +99 -0
- package/agents/sia-pm-briefing.md +106 -0
- package/agents/sia-pm-risk-advisor.md +82 -0
- package/agents/sia-qa-analyst.md +116 -0
- package/agents/sia-qa-regression-map.md +94 -0
- package/agents/sia-refactor.md +115 -0
- package/agents/sia-regression.md +112 -0
- package/agents/sia-security-audit.md +125 -0
- package/agents/sia-test-advisor.md +91 -0
- package/hooks/hooks.json +98 -0
- package/migrations/bridge/001_initial.sql +34 -0
- package/migrations/episodic/001_initial.sql +35 -0
- package/migrations/meta/001_initial.sql +68 -0
- package/migrations/semantic/001_initial.sql +292 -0
- package/migrations/semantic/002_ontology.sql +89 -0
- package/migrations/semantic/003_freshness.sql +63 -0
- package/migrations/semantic/004_v5_unified_schema.sql +194 -0
- package/migrations/semantic/005_backfill_event_kinds.sql +8 -0
- package/migrations/semantic/006_tree_sitter.sql +6 -0
- package/migrations/semantic/007_branch_snapshots.sql +22 -0
- package/package.json +110 -0
- package/scripts/branch-switch.sh +13 -0
- package/scripts/build-wasm-grammars.sh +81 -0
- package/scripts/post-compact.sh +8 -0
- package/scripts/post-tool-use.sh +10 -0
- package/scripts/pre-compact.sh +8 -0
- package/scripts/session-end.sh +8 -0
- package/scripts/session-start.sh +8 -0
- package/scripts/start-mcp.ts +45 -0
- package/scripts/stop-hook.sh +8 -0
- package/scripts/user-prompt-submit.sh +8 -0
- package/scripts/viz-server.ts +152 -0
- package/skills/sia-brainstorm/SKILL.md +156 -0
- package/skills/sia-brainstorm/scripts/frame-template.html +214 -0
- package/skills/sia-brainstorm/scripts/helper.js +95 -0
- package/skills/sia-brainstorm/scripts/server.cjs +338 -0
- package/skills/sia-brainstorm/scripts/start-server.sh +153 -0
- package/skills/sia-brainstorm/scripts/stop-server.sh +55 -0
- package/skills/sia-brainstorm/spec-document-reviewer-prompt.md +49 -0
- package/skills/sia-brainstorm/visual-companion.md +286 -0
- package/skills/sia-capture/SKILL.md +64 -0
- package/skills/sia-compare/SKILL.md +33 -0
- package/skills/sia-conflicts/SKILL.md +38 -0
- package/skills/sia-debug-workflow/SKILL.md +120 -0
- package/skills/sia-debug-workflow/root-cause-tracing.md +70 -0
- package/skills/sia-debug-workflow/scripts/find-polluter.sh +64 -0
- package/skills/sia-debug-workflow/temporal-investigation.md +72 -0
- package/skills/sia-digest/SKILL.md +23 -0
- package/skills/sia-dispatch/SKILL.md +69 -0
- package/skills/sia-dispatch/agent-task-template.md +99 -0
- package/skills/sia-doctor/SKILL.md +39 -0
- package/skills/sia-execute/SKILL.md +70 -0
- package/skills/sia-execute-plan/SKILL.md +85 -0
- package/skills/sia-export-import/SKILL.md +49 -0
- package/skills/sia-export-knowledge/SKILL.md +46 -0
- package/skills/sia-finish/SKILL.md +100 -0
- package/skills/sia-finish/pr-summary-template.md +54 -0
- package/skills/sia-freshness/SKILL.md +38 -0
- package/skills/sia-history/SKILL.md +42 -0
- package/skills/sia-impact/SKILL.md +70 -0
- package/skills/sia-index/SKILL.md +54 -0
- package/skills/sia-install/SKILL.md +39 -0
- package/skills/sia-lead-compliance/SKILL.md +16 -0
- package/skills/sia-lead-drift-report/SKILL.md +16 -0
- package/skills/sia-lead-knowledge-map/SKILL.md +16 -0
- package/skills/sia-learn/SKILL.md +58 -0
- package/skills/sia-plan/SKILL.md +68 -0
- package/skills/sia-plan/plan-reviewer-prompt.md +63 -0
- package/skills/sia-playbooks/SKILL.md +29 -0
- package/skills/sia-playbooks/reference-feature.md +100 -0
- package/skills/sia-playbooks/reference-flagging.md +50 -0
- package/skills/sia-playbooks/reference-orientation.md +92 -0
- package/skills/sia-playbooks/reference-regression.md +115 -0
- package/skills/sia-playbooks/reference-review.md +64 -0
- package/skills/sia-playbooks/reference-tools.md +239 -0
- package/skills/sia-pm-decision-log/SKILL.md +28 -0
- package/skills/sia-pm-risk-dashboard/SKILL.md +24 -0
- package/skills/sia-pm-sprint-summary/SKILL.md +27 -0
- package/skills/sia-prune/SKILL.md +45 -0
- package/skills/sia-qa-coverage/SKILL.md +28 -0
- package/skills/sia-qa-flaky/SKILL.md +20 -0
- package/skills/sia-qa-report/SKILL.md +26 -0
- package/skills/sia-reindex/SKILL.md +30 -0
- package/skills/sia-review-respond/SKILL.md +88 -0
- package/skills/sia-review-respond/pushback-patterns.md +90 -0
- package/skills/sia-search/SKILL.md +47 -0
- package/skills/sia-setup/SKILL.md +82 -0
- package/skills/sia-setup/setup-checklist.md +97 -0
- package/skills/sia-stats/SKILL.md +36 -0
- package/skills/sia-status/SKILL.md +44 -0
- package/skills/sia-sync/SKILL.md +46 -0
- package/skills/sia-team/SKILL.md +64 -0
- package/skills/sia-test/SKILL.md +92 -0
- package/skills/sia-test/testing-anti-patterns.md +104 -0
- package/skills/sia-tour/SKILL.md +29 -0
- package/skills/sia-upgrade/SKILL.md +43 -0
- package/skills/sia-verify/SKILL.md +81 -0
- package/skills/sia-visualize/SKILL.md +28 -0
- package/skills/sia-visualize-live/SKILL.md +55 -0
- package/skills/sia-visualize-live/scripts/graph-template.html +389 -0
- package/skills/sia-visualize-live/scripts/start-visualizer.sh +161 -0
- package/skills/sia-visualize-live/scripts/stop-visualizer.sh +55 -0
- package/skills/sia-visualize-live/scripts/visualizer-server.cjs +264 -0
- package/skills/sia-workspace/SKILL.md +57 -0
- package/src/agent/claude-md-template-flagging.md +219 -0
- package/src/agent/claude-md-template.md +213 -0
- package/src/agent/modules/sia-feature.md +100 -0
- package/src/agent/modules/sia-flagging.md +50 -0
- package/src/agent/modules/sia-orientation.md +92 -0
- package/src/agent/modules/sia-regression.md +115 -0
- package/src/agent/modules/sia-review.md +64 -0
- package/src/agent/modules/sia-tools.md +239 -0
- package/src/ast/extractors/c-include.ts +189 -0
- package/src/ast/extractors/csharp-project.ts +260 -0
- package/src/ast/extractors/prisma-schema.ts +44 -0
- package/src/ast/extractors/project-manifest.ts +111 -0
- package/src/ast/extractors/sql-schema.ts +67 -0
- package/src/ast/extractors/tier-a.ts +423 -0
- package/src/ast/extractors/tier-b.ts +289 -0
- package/src/ast/extractors/tier-dispatch.ts +247 -0
- package/src/ast/index-worker.ts +108 -0
- package/src/ast/indexer.ts +484 -0
- package/src/ast/languages.ts +408 -0
- package/src/ast/pagerank-builder.ts +125 -0
- package/src/ast/path-utils.ts +137 -0
- package/src/ast/tree-sitter/backends/native.ts +57 -0
- package/src/ast/tree-sitter/backends/wasm.ts +39 -0
- package/src/ast/tree-sitter/call-walker.ts +44 -0
- package/src/ast/tree-sitter/edit-computer.ts +55 -0
- package/src/ast/tree-sitter/query-runner.ts +46 -0
- package/src/ast/tree-sitter/service.ts +174 -0
- package/src/ast/tree-sitter/tree-cache.ts +39 -0
- package/src/ast/tree-sitter/types.ts +79 -0
- package/src/ast/watcher.ts +322 -0
- package/src/capture/chunker.ts +169 -0
- package/src/capture/consolidate.ts +127 -0
- package/src/capture/edge-inferrer.ts +161 -0
- package/src/capture/embedder.ts +166 -0
- package/src/capture/embedding-cache.ts +73 -0
- package/src/capture/flag-processor.ts +64 -0
- package/src/capture/hook.ts +67 -0
- package/src/capture/pipeline.ts +450 -0
- package/src/capture/prompts/consolidate.ts +25 -0
- package/src/capture/prompts/edge-infer.ts +29 -0
- package/src/capture/prompts/extract-flagged.ts +36 -0
- package/src/capture/prompts/extract.ts +42 -0
- package/src/capture/tokenizer.ts +147 -0
- package/src/capture/track-a-ast.ts +93 -0
- package/src/capture/track-b-llm.ts +149 -0
- package/src/capture/types.ts +64 -0
- package/src/cli/commands/community.ts +137 -0
- package/src/cli/commands/compare.ts +123 -0
- package/src/cli/commands/conflicts.ts +41 -0
- package/src/cli/commands/digest.ts +197 -0
- package/src/cli/commands/disable-flagging.ts +34 -0
- package/src/cli/commands/doctor.ts +240 -0
- package/src/cli/commands/download-model.ts +161 -0
- package/src/cli/commands/enable-flagging.ts +34 -0
- package/src/cli/commands/export-knowledge.ts +208 -0
- package/src/cli/commands/export.ts +85 -0
- package/src/cli/commands/freshness.ts +164 -0
- package/src/cli/commands/graph.ts +51 -0
- package/src/cli/commands/history.ts +139 -0
- package/src/cli/commands/import.ts +335 -0
- package/src/cli/commands/install.ts +156 -0
- package/src/cli/commands/lead-report.ts +241 -0
- package/src/cli/commands/learn.ts +321 -0
- package/src/cli/commands/pm-report.ts +413 -0
- package/src/cli/commands/prune.ts +75 -0
- package/src/cli/commands/qa-report.ts +278 -0
- package/src/cli/commands/reindex.ts +104 -0
- package/src/cli/commands/rollback.ts +70 -0
- package/src/cli/commands/search.ts +103 -0
- package/src/cli/commands/server.ts +91 -0
- package/src/cli/commands/share.ts +33 -0
- package/src/cli/commands/stats.ts +79 -0
- package/src/cli/commands/status.ts +176 -0
- package/src/cli/commands/sync.ts +96 -0
- package/src/cli/commands/team.ts +118 -0
- package/src/cli/commands/tour.ts +157 -0
- package/src/cli/commands/visualize-live.ts +162 -0
- package/src/cli/commands/workspace.ts +117 -0
- package/src/cli/index.ts +424 -0
- package/src/cli/learn-progress.ts +87 -0
- package/src/community/detection-bridge.ts +344 -0
- package/src/community/leiden.ts +462 -0
- package/src/community/raptor.ts +210 -0
- package/src/community/scheduler.ts +74 -0
- package/src/community/summarize.ts +115 -0
- package/src/decay/archiver.ts +73 -0
- package/src/decay/bridge-orphan-cleanup.ts +212 -0
- package/src/decay/consolidation-sweep.ts +112 -0
- package/src/decay/decay.ts +116 -0
- package/src/decay/deep-validator.ts +62 -0
- package/src/decay/episodic-promoter.ts +132 -0
- package/src/decay/maintenance-scheduler.ts +326 -0
- package/src/decay/scheduler.ts +6 -0
- package/src/decay/session-sweeper.ts +79 -0
- package/src/decay/types.ts +17 -0
- package/src/freshness/confidence-decay.ts +122 -0
- package/src/freshness/cuckoo-filter.ts +176 -0
- package/src/freshness/deep-validation.ts +345 -0
- package/src/freshness/dirty-tracker.ts +237 -0
- package/src/freshness/file-watcher-layer.ts +119 -0
- package/src/freshness/firewall.ts +64 -0
- package/src/freshness/git-reconcile-layer.ts +161 -0
- package/src/freshness/inverted-index.ts +158 -0
- package/src/freshness/stale-read-layer.ts +222 -0
- package/src/graph/audit.ts +69 -0
- package/src/graph/bridge-db.ts +141 -0
- package/src/graph/communities.ts +195 -0
- package/src/graph/db-interface.ts +259 -0
- package/src/graph/edges.ts +163 -0
- package/src/graph/entities.ts +327 -0
- package/src/graph/episodic-db.ts +113 -0
- package/src/graph/flags.ts +31 -0
- package/src/graph/meta-db.ts +200 -0
- package/src/graph/semantic-db.ts +101 -0
- package/src/graph/session-resume.ts +56 -0
- package/src/graph/snapshots.ts +342 -0
- package/src/graph/staging.ts +151 -0
- package/src/graph/types.ts +128 -0
- package/src/hooks/adapters/claude-code.ts +21 -0
- package/src/hooks/adapters/cline.ts +43 -0
- package/src/hooks/adapters/cursor.ts +65 -0
- package/src/hooks/adapters/generic.ts +12 -0
- package/src/hooks/agent-detect.ts +34 -0
- package/src/hooks/claude-md-directives.ts +32 -0
- package/src/hooks/event-router.ts +182 -0
- package/src/hooks/extractors/pattern-detector.ts +111 -0
- package/src/hooks/handlers/post-compact.ts +30 -0
- package/src/hooks/handlers/post-tool-use.ts +403 -0
- package/src/hooks/handlers/pre-compact.ts +100 -0
- package/src/hooks/handlers/session-end.ts +47 -0
- package/src/hooks/handlers/session-start.ts +154 -0
- package/src/hooks/handlers/stop.ts +128 -0
- package/src/hooks/handlers/user-prompt-submit.ts +68 -0
- package/src/hooks/plugin-branch-switch.ts +68 -0
- package/src/hooks/plugin-common.ts +47 -0
- package/src/hooks/plugin-post-compact.ts +28 -0
- package/src/hooks/plugin-post-tool-use.ts +38 -0
- package/src/hooks/plugin-pre-compact.ts +37 -0
- package/src/hooks/plugin-session-end.ts +37 -0
- package/src/hooks/plugin-session-start.ts +75 -0
- package/src/hooks/plugin-stop.ts +61 -0
- package/src/hooks/plugin-user-prompt-submit.ts +47 -0
- package/src/hooks/types.ts +43 -0
- package/src/knowledge/discovery.ts +238 -0
- package/src/knowledge/external-refs.ts +98 -0
- package/src/knowledge/freshness.ts +221 -0
- package/src/knowledge/ingest.ts +330 -0
- package/src/knowledge/markdown-export.ts +229 -0
- package/src/knowledge/markdown-import.ts +359 -0
- package/src/knowledge/patterns.ts +74 -0
- package/src/knowledge/templates.ts +307 -0
- package/src/llm/ai-sdk-adapter.ts +46 -0
- package/src/llm/config.ts +88 -0
- package/src/llm/cost-tracker.ts +110 -0
- package/src/llm/prompts/extraction.ts +55 -0
- package/src/llm/prompts/summarization.ts +36 -0
- package/src/llm/prompts/validation.ts +37 -0
- package/src/llm/provider-registry.ts +68 -0
- package/src/llm/reliability.ts +179 -0
- package/src/llm/schemas.ts +52 -0
- package/src/mcp/freshness-annotator.ts +69 -0
- package/src/mcp/server.ts +949 -0
- package/src/mcp/tools/sia-ast-query.ts +225 -0
- package/src/mcp/tools/sia-at-time.ts +151 -0
- package/src/mcp/tools/sia-backlinks.ts +87 -0
- package/src/mcp/tools/sia-batch-execute.ts +169 -0
- package/src/mcp/tools/sia-by-file.ts +89 -0
- package/src/mcp/tools/sia-community.ts +113 -0
- package/src/mcp/tools/sia-doctor.ts +73 -0
- package/src/mcp/tools/sia-execute-file.ts +122 -0
- package/src/mcp/tools/sia-execute.ts +104 -0
- package/src/mcp/tools/sia-expand.ts +158 -0
- package/src/mcp/tools/sia-fetch-and-index.ts +241 -0
- package/src/mcp/tools/sia-flag.ts +65 -0
- package/src/mcp/tools/sia-index.ts +111 -0
- package/src/mcp/tools/sia-note.ts +134 -0
- package/src/mcp/tools/sia-search.ts +105 -0
- package/src/mcp/tools/sia-stats.ts +63 -0
- package/src/mcp/tools/sia-sync-status.ts +44 -0
- package/src/mcp/tools/sia-upgrade.ts +247 -0
- package/src/mcp/truncate.ts +231 -0
- package/src/native/bridge.ts +167 -0
- package/src/native/fallback-ast-diff.ts +144 -0
- package/src/native/fallback-graph.ts +325 -0
- package/src/ontology/constraints.ts +56 -0
- package/src/ontology/errors.ts +8 -0
- package/src/ontology/middleware.ts +266 -0
- package/src/retrieval/bm25-search.ts +151 -0
- package/src/retrieval/context-assembly.ts +76 -0
- package/src/retrieval/graph-traversal.ts +168 -0
- package/src/retrieval/pagerank.ts +40 -0
- package/src/retrieval/query-classifier.ts +106 -0
- package/src/retrieval/reranker.ts +156 -0
- package/src/retrieval/search.ts +236 -0
- package/src/retrieval/throttle.ts +102 -0
- package/src/retrieval/vector-search.ts +203 -0
- package/src/retrieval/workspace-search.ts +130 -0
- package/src/sandbox/context-mode.ts +285 -0
- package/src/sandbox/credential-pass.ts +55 -0
- package/src/sandbox/executor.ts +235 -0
- package/src/security/pattern-detector.ts +127 -0
- package/src/security/rule-of-two.ts +50 -0
- package/src/security/sanitize.ts +46 -0
- package/src/security/semantic-consistency.ts +93 -0
- package/src/security/staging-promoter.ts +154 -0
- package/src/shared/config.ts +302 -0
- package/src/shared/diagnostics.ts +210 -0
- package/src/shared/errors.ts +48 -0
- package/src/shared/git-utils.ts +143 -0
- package/src/shared/llm-client.ts +120 -0
- package/src/shared/logger.ts +99 -0
- package/src/shared/types.ts +79 -0
- package/src/sync/client.ts +43 -0
- package/src/sync/conflict.ts +106 -0
- package/src/sync/dedup.ts +183 -0
- package/src/sync/hlc.ts +117 -0
- package/src/sync/keychain.ts +144 -0
- package/src/sync/pull.ts +232 -0
- package/src/sync/push.ts +131 -0
- package/src/types/chokidar.d.ts +23 -0
- package/src/visualization/graph-renderer.ts +312 -0
- package/src/visualization/subgraph-extract.ts +208 -0
- package/src/visualization/views/community-clusters.ts +246 -0
- package/src/visualization/views/dependency-map.ts +189 -0
- package/src/visualization/views/graph-explorer.ts +364 -0
- package/src/visualization/views/timeline.ts +247 -0
- package/src/workspace/api-contracts.ts +226 -0
- package/src/workspace/cross-repo.ts +61 -0
- package/src/workspace/detector.ts +190 -0
- package/src/workspace/manifest.ts +141 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
// Module: languages — Language registry for AST extraction
|
|
2
|
+
import { basename, extname } from "node:path";
|
|
3
|
+
import type { AdditionalLanguage } from "@/shared/config";
|
|
4
|
+
|
|
5
|
+
/** Extraction tier: A = full, B = partial, C = schema-only, D = manifest */
|
|
6
|
+
export type ExtractionTier = "A" | "B" | "C" | "D";
|
|
7
|
+
|
|
8
|
+
/** Special handling hints for certain languages */
|
|
9
|
+
export type SpecialHandling =
|
|
10
|
+
| "c-include-paths"
|
|
11
|
+
| "csharp-project"
|
|
12
|
+
| "sql-schema"
|
|
13
|
+
| "prisma-schema"
|
|
14
|
+
| "project-manifest";
|
|
15
|
+
|
|
16
|
+
/** Extractor capabilities for a language */
|
|
17
|
+
export interface Extractors {
|
|
18
|
+
functions: boolean;
|
|
19
|
+
classes: boolean;
|
|
20
|
+
imports: boolean;
|
|
21
|
+
calls: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Full language configuration */
|
|
25
|
+
export interface LanguageConfig {
|
|
26
|
+
name: string;
|
|
27
|
+
extensions: string[];
|
|
28
|
+
treeSitterGrammar: string;
|
|
29
|
+
tier: ExtractionTier;
|
|
30
|
+
extractors: Extractors;
|
|
31
|
+
specialHandling?: SpecialHandling;
|
|
32
|
+
nativePackage?: string;
|
|
33
|
+
wasmFile?: string;
|
|
34
|
+
queryDir?: string;
|
|
35
|
+
parserEntrypoint?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** LanguageConfig with all tree-sitter resolution fields populated */
|
|
39
|
+
export interface ResolvedLanguageConfig extends LanguageConfig {
|
|
40
|
+
nativePackage: string;
|
|
41
|
+
wasmFile: string;
|
|
42
|
+
queryDir: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a LanguageConfig, deriving nativePackage, wasmFile, and queryDir
|
|
47
|
+
* from treeSitterGrammar if not explicitly provided.
|
|
48
|
+
*/
|
|
49
|
+
export function resolveLanguageConfig(lang: LanguageConfig): ResolvedLanguageConfig {
|
|
50
|
+
return {
|
|
51
|
+
...lang,
|
|
52
|
+
nativePackage: lang.nativePackage ?? lang.treeSitterGrammar,
|
|
53
|
+
wasmFile: lang.wasmFile ?? `${lang.treeSitterGrammar}.wasm`,
|
|
54
|
+
queryDir: lang.queryDir ?? lang.name,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The canonical language registry keyed by language name */
|
|
59
|
+
export type LanguageRegistry = Record<string, LanguageConfig>;
|
|
60
|
+
|
|
61
|
+
// ---------- Tier A (15 languages) ----------
|
|
62
|
+
// All have functions: true, imports: true, calls: true
|
|
63
|
+
// All have classes: true except go, rust, elixir
|
|
64
|
+
|
|
65
|
+
const TIER_A: LanguageConfig[] = [
|
|
66
|
+
{
|
|
67
|
+
name: "typescript",
|
|
68
|
+
extensions: [".ts"],
|
|
69
|
+
treeSitterGrammar: "tree-sitter-typescript",
|
|
70
|
+
tier: "A",
|
|
71
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "tsx",
|
|
75
|
+
extensions: [".tsx"],
|
|
76
|
+
treeSitterGrammar: "tree-sitter-tsx",
|
|
77
|
+
tier: "A",
|
|
78
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "javascript",
|
|
82
|
+
extensions: [".js", ".mjs", ".cjs"],
|
|
83
|
+
treeSitterGrammar: "tree-sitter-javascript",
|
|
84
|
+
tier: "A",
|
|
85
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "jsx",
|
|
89
|
+
extensions: [".jsx"],
|
|
90
|
+
treeSitterGrammar: "tree-sitter-javascript",
|
|
91
|
+
tier: "A",
|
|
92
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "python",
|
|
96
|
+
extensions: [".py"],
|
|
97
|
+
treeSitterGrammar: "tree-sitter-python",
|
|
98
|
+
tier: "A",
|
|
99
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "go",
|
|
103
|
+
extensions: [".go"],
|
|
104
|
+
treeSitterGrammar: "tree-sitter-go",
|
|
105
|
+
tier: "A",
|
|
106
|
+
extractors: { functions: true, classes: false, imports: true, calls: true },
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "rust",
|
|
110
|
+
extensions: [".rs"],
|
|
111
|
+
treeSitterGrammar: "tree-sitter-rust",
|
|
112
|
+
tier: "A",
|
|
113
|
+
extractors: { functions: true, classes: false, imports: true, calls: true },
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "java",
|
|
117
|
+
extensions: [".java"],
|
|
118
|
+
treeSitterGrammar: "tree-sitter-java",
|
|
119
|
+
tier: "A",
|
|
120
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "kotlin",
|
|
124
|
+
extensions: [".kt", ".kts"],
|
|
125
|
+
treeSitterGrammar: "tree-sitter-kotlin",
|
|
126
|
+
tier: "A",
|
|
127
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "swift",
|
|
131
|
+
extensions: [".swift"],
|
|
132
|
+
treeSitterGrammar: "tree-sitter-swift",
|
|
133
|
+
tier: "A",
|
|
134
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "php",
|
|
138
|
+
extensions: [".php"],
|
|
139
|
+
treeSitterGrammar: "tree-sitter-php",
|
|
140
|
+
tier: "A",
|
|
141
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "ruby",
|
|
145
|
+
extensions: [".rb"],
|
|
146
|
+
treeSitterGrammar: "tree-sitter-ruby",
|
|
147
|
+
tier: "A",
|
|
148
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: "scala",
|
|
152
|
+
extensions: [".scala"],
|
|
153
|
+
treeSitterGrammar: "tree-sitter-scala",
|
|
154
|
+
tier: "A",
|
|
155
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "elixir",
|
|
159
|
+
extensions: [".ex", ".exs"],
|
|
160
|
+
treeSitterGrammar: "tree-sitter-elixir",
|
|
161
|
+
tier: "A",
|
|
162
|
+
extractors: { functions: true, classes: false, imports: true, calls: true },
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: "dart",
|
|
166
|
+
extensions: [".dart"],
|
|
167
|
+
treeSitterGrammar: "tree-sitter-dart",
|
|
168
|
+
tier: "A",
|
|
169
|
+
extractors: { functions: true, classes: true, imports: true, calls: true },
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
// ---------- Tier B (10 languages) ----------
|
|
174
|
+
// All have calls: false. Most have classes: false except cpp and csharp.
|
|
175
|
+
|
|
176
|
+
const TIER_B: LanguageConfig[] = [
|
|
177
|
+
{
|
|
178
|
+
name: "c",
|
|
179
|
+
extensions: [".c", ".h"],
|
|
180
|
+
treeSitterGrammar: "tree-sitter-c",
|
|
181
|
+
tier: "B",
|
|
182
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
183
|
+
specialHandling: "c-include-paths",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: "cpp",
|
|
187
|
+
extensions: [".cpp", ".cc", ".cxx", ".hpp", ".hxx", ".h++"],
|
|
188
|
+
treeSitterGrammar: "tree-sitter-cpp",
|
|
189
|
+
tier: "B",
|
|
190
|
+
extractors: { functions: true, classes: true, imports: true, calls: false },
|
|
191
|
+
specialHandling: "c-include-paths",
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: "csharp",
|
|
195
|
+
extensions: [".cs"],
|
|
196
|
+
treeSitterGrammar: "tree-sitter-c-sharp",
|
|
197
|
+
tier: "B",
|
|
198
|
+
extractors: { functions: true, classes: true, imports: true, calls: false },
|
|
199
|
+
specialHandling: "csharp-project",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: "bash",
|
|
203
|
+
extensions: [".sh", ".bash", ".zsh", ".fish"],
|
|
204
|
+
treeSitterGrammar: "tree-sitter-bash",
|
|
205
|
+
tier: "B",
|
|
206
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "lua",
|
|
210
|
+
extensions: [".lua"],
|
|
211
|
+
treeSitterGrammar: "tree-sitter-lua",
|
|
212
|
+
tier: "B",
|
|
213
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "zig",
|
|
217
|
+
extensions: [".zig"],
|
|
218
|
+
treeSitterGrammar: "tree-sitter-zig",
|
|
219
|
+
tier: "B",
|
|
220
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "r",
|
|
224
|
+
extensions: [".r", ".R"],
|
|
225
|
+
treeSitterGrammar: "tree-sitter-r",
|
|
226
|
+
tier: "B",
|
|
227
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: "ocaml",
|
|
231
|
+
extensions: [".ml", ".mli"],
|
|
232
|
+
treeSitterGrammar: "tree-sitter-ocaml",
|
|
233
|
+
tier: "B",
|
|
234
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: "haskell",
|
|
238
|
+
extensions: [".hs", ".lhs"],
|
|
239
|
+
treeSitterGrammar: "tree-sitter-haskell",
|
|
240
|
+
tier: "B",
|
|
241
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "perl",
|
|
245
|
+
extensions: [".pl", ".pm"],
|
|
246
|
+
treeSitterGrammar: "tree-sitter-perl",
|
|
247
|
+
tier: "B",
|
|
248
|
+
extractors: { functions: true, classes: false, imports: true, calls: false },
|
|
249
|
+
},
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
// ---------- Tier C (2 languages) ----------
|
|
253
|
+
|
|
254
|
+
const TIER_C: LanguageConfig[] = [
|
|
255
|
+
{
|
|
256
|
+
name: "sql",
|
|
257
|
+
extensions: [".sql"],
|
|
258
|
+
treeSitterGrammar: "tree-sitter-sql",
|
|
259
|
+
tier: "C",
|
|
260
|
+
extractors: { functions: false, classes: false, imports: false, calls: false },
|
|
261
|
+
specialHandling: "sql-schema",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: "prisma",
|
|
265
|
+
extensions: [".prisma"],
|
|
266
|
+
treeSitterGrammar: "tree-sitter-prisma",
|
|
267
|
+
tier: "C",
|
|
268
|
+
extractors: { functions: false, classes: false, imports: false, calls: false },
|
|
269
|
+
specialHandling: "prisma-schema",
|
|
270
|
+
},
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
// ---------- Tier D (3 languages) ----------
|
|
274
|
+
|
|
275
|
+
const TIER_D: LanguageConfig[] = [
|
|
276
|
+
{
|
|
277
|
+
name: "cargo_toml",
|
|
278
|
+
extensions: ["Cargo.toml"],
|
|
279
|
+
treeSitterGrammar: "tree-sitter-toml",
|
|
280
|
+
tier: "D",
|
|
281
|
+
extractors: { functions: false, classes: false, imports: false, calls: false },
|
|
282
|
+
specialHandling: "project-manifest",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: "go_mod",
|
|
286
|
+
extensions: ["go.mod"],
|
|
287
|
+
treeSitterGrammar: "tree-sitter-gomod",
|
|
288
|
+
tier: "D",
|
|
289
|
+
extractors: { functions: false, classes: false, imports: false, calls: false },
|
|
290
|
+
specialHandling: "project-manifest",
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: "pyproject",
|
|
294
|
+
extensions: ["pyproject.toml", "setup.py", "setup.cfg"],
|
|
295
|
+
treeSitterGrammar: "tree-sitter-toml",
|
|
296
|
+
tier: "D",
|
|
297
|
+
extractors: { functions: false, classes: false, imports: false, calls: false },
|
|
298
|
+
specialHandling: "project-manifest",
|
|
299
|
+
},
|
|
300
|
+
];
|
|
301
|
+
|
|
302
|
+
/** The complete language registry (30 languages) */
|
|
303
|
+
export const LANGUAGE_REGISTRY: LanguageRegistry = {};
|
|
304
|
+
|
|
305
|
+
// Populate the registry from the tier arrays
|
|
306
|
+
for (const lang of [...TIER_A, ...TIER_B, ...TIER_C, ...TIER_D]) {
|
|
307
|
+
LANGUAGE_REGISTRY[lang.name] = lang;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ---------- Extension lookup cache ----------
|
|
311
|
+
|
|
312
|
+
let extensionCache: Map<string, LanguageConfig> | null = null;
|
|
313
|
+
|
|
314
|
+
function buildExtensionCache(registry: LanguageRegistry): Map<string, LanguageConfig> {
|
|
315
|
+
const cache = new Map<string, LanguageConfig>();
|
|
316
|
+
for (const lang of Object.values(registry)) {
|
|
317
|
+
for (const ext of lang.extensions) {
|
|
318
|
+
cache.set(ext.toLowerCase(), lang);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return cache;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function getCache(registry: LanguageRegistry): Map<string, LanguageConfig> {
|
|
325
|
+
if (registry === LANGUAGE_REGISTRY && extensionCache !== null) {
|
|
326
|
+
return extensionCache;
|
|
327
|
+
}
|
|
328
|
+
const cache = buildExtensionCache(registry);
|
|
329
|
+
if (registry === LANGUAGE_REGISTRY) {
|
|
330
|
+
extensionCache = cache;
|
|
331
|
+
}
|
|
332
|
+
return cache;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Look up a LanguageConfig by file extension (e.g. ".ts", ".py").
|
|
337
|
+
* Extension should include the leading dot for normal extensions,
|
|
338
|
+
* or be a full filename for manifest files (e.g. "Cargo.toml").
|
|
339
|
+
*
|
|
340
|
+
* Accepts an optional registry for custom/merged registries.
|
|
341
|
+
*/
|
|
342
|
+
export function getLanguageByExtension(
|
|
343
|
+
ext: string,
|
|
344
|
+
registry: LanguageRegistry = LANGUAGE_REGISTRY,
|
|
345
|
+
): LanguageConfig | null {
|
|
346
|
+
const cache = getCache(registry);
|
|
347
|
+
return cache.get(ext.toLowerCase()) ?? null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Resolve a file path to its LanguageConfig (convenience wrapper).
|
|
352
|
+
* Handles both extension-based and filename-based lookups (e.g. "Cargo.toml").
|
|
353
|
+
*/
|
|
354
|
+
export function getLanguageForFile(
|
|
355
|
+
filePath: string,
|
|
356
|
+
registry: LanguageRegistry = LANGUAGE_REGISTRY,
|
|
357
|
+
): LanguageConfig | null {
|
|
358
|
+
const base = basename(filePath).toLowerCase();
|
|
359
|
+
const cache = getCache(registry);
|
|
360
|
+
|
|
361
|
+
// Try full filename first (for manifests like Cargo.toml, go.mod)
|
|
362
|
+
if (cache.has(base)) {
|
|
363
|
+
return cache.get(base) ?? null;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Fall back to extension
|
|
367
|
+
const ext = extname(base);
|
|
368
|
+
if (ext) {
|
|
369
|
+
return cache.get(ext.toLowerCase()) ?? null;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Merge additional languages into a registry.
|
|
377
|
+
* Does NOT overwrite languages that already exist (by name).
|
|
378
|
+
* Invalidates the extension cache so new languages are discoverable.
|
|
379
|
+
*/
|
|
380
|
+
export function mergeAdditionalLanguages(
|
|
381
|
+
registry: LanguageRegistry,
|
|
382
|
+
additions: AdditionalLanguage[],
|
|
383
|
+
): void {
|
|
384
|
+
for (const lang of additions) {
|
|
385
|
+
// Do not overwrite existing languages
|
|
386
|
+
if (registry[lang.name]) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const tier: ExtractionTier =
|
|
391
|
+
lang.tier === "A" || lang.tier === "B" || lang.tier === "C" || lang.tier === "D"
|
|
392
|
+
? (lang.tier as ExtractionTier)
|
|
393
|
+
: "D";
|
|
394
|
+
|
|
395
|
+
const config: LanguageConfig = {
|
|
396
|
+
name: lang.name,
|
|
397
|
+
extensions: lang.extensions.map((e) => e.toLowerCase()),
|
|
398
|
+
treeSitterGrammar: lang.grammar,
|
|
399
|
+
tier,
|
|
400
|
+
extractors: { functions: false, classes: false, imports: false, calls: false },
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
registry[lang.name] = config;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Invalidate cache so new extensions are picked up
|
|
407
|
+
extensionCache = null;
|
|
408
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
2
|
+
|
|
3
|
+
export interface PageRankResult {
|
|
4
|
+
iterations: number;
|
|
5
|
+
converged: boolean;
|
|
6
|
+
finalDelta: number;
|
|
7
|
+
nodesScored: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface EdgeRow {
|
|
11
|
+
from_id: string;
|
|
12
|
+
to_id: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function buildTeleportVector(nodes: string[], activeFileIds: string[]): Map<string, number> {
|
|
16
|
+
const bias = new Set(activeFileIds ?? []);
|
|
17
|
+
if (bias.size === 0) {
|
|
18
|
+
const uniform = 1 / nodes.length;
|
|
19
|
+
return new Map(nodes.map((id) => [id, uniform]));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const epsilon = 0.01;
|
|
23
|
+
const activeWeight = (1 - epsilon) / bias.size;
|
|
24
|
+
const passiveWeight = epsilon / nodes.length;
|
|
25
|
+
return new Map(nodes.map((id) => [id, bias.has(id) ? activeWeight : passiveWeight]));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function computePageRank(
|
|
29
|
+
db: SiaDb,
|
|
30
|
+
activeFileIds: string[] = [],
|
|
31
|
+
): Promise<PageRankResult> {
|
|
32
|
+
const { rows } = await db.execute(
|
|
33
|
+
"SELECT from_id, to_id FROM graph_edges WHERE t_valid_until IS NULL AND type IN ('calls','imports','inherits_from')",
|
|
34
|
+
);
|
|
35
|
+
const edges = rows as unknown as EdgeRow[];
|
|
36
|
+
|
|
37
|
+
const nodes = new Set<string>();
|
|
38
|
+
const outgoing = new Map<string, string[]>();
|
|
39
|
+
const incoming = new Map<string, string[]>();
|
|
40
|
+
|
|
41
|
+
for (const edge of edges) {
|
|
42
|
+
nodes.add(edge.from_id);
|
|
43
|
+
nodes.add(edge.to_id);
|
|
44
|
+
|
|
45
|
+
if (!outgoing.has(edge.from_id)) outgoing.set(edge.from_id, []);
|
|
46
|
+
outgoing.get(edge.from_id)?.push(edge.to_id);
|
|
47
|
+
|
|
48
|
+
if (!incoming.has(edge.to_id)) incoming.set(edge.to_id, []);
|
|
49
|
+
incoming.get(edge.to_id)?.push(edge.from_id);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (nodes.size === 0) {
|
|
53
|
+
return { iterations: 0, converged: true, finalDelta: 0, nodesScored: 0 };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const nodeList = [...nodes];
|
|
57
|
+
const teleport = buildTeleportVector(
|
|
58
|
+
nodeList,
|
|
59
|
+
activeFileIds.filter((id) => nodes.has(id)),
|
|
60
|
+
);
|
|
61
|
+
const damping = 0.85;
|
|
62
|
+
const maxIter = 30;
|
|
63
|
+
const n = nodeList.length;
|
|
64
|
+
|
|
65
|
+
let scores = new Map<string, number>(nodeList.map((id) => [id, teleport.get(id) ?? 1 / n]));
|
|
66
|
+
let converged = false;
|
|
67
|
+
let finalDelta = 0;
|
|
68
|
+
let iterationCount = 0;
|
|
69
|
+
|
|
70
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
71
|
+
iterationCount = iter + 1;
|
|
72
|
+
const newScores = new Map<string, number>();
|
|
73
|
+
const danglingSum = nodeList.reduce((sum, id) => {
|
|
74
|
+
const out = outgoing.get(id);
|
|
75
|
+
return out && out.length > 0 ? sum : sum + (scores.get(id) ?? 0);
|
|
76
|
+
}, 0);
|
|
77
|
+
|
|
78
|
+
for (const node of nodeList) {
|
|
79
|
+
const incomingNodes = incoming.get(node) ?? [];
|
|
80
|
+
let rank = danglingSum / n;
|
|
81
|
+
|
|
82
|
+
for (const source of incomingNodes) {
|
|
83
|
+
const out = outgoing.get(source) ?? [];
|
|
84
|
+
const weight = out.length === 0 ? 0 : 1 / out.length;
|
|
85
|
+
rank += (scores.get(source) ?? 0) * weight;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const teleportWeight = teleport.get(node) ?? 1 / n;
|
|
89
|
+
const value = (1 - damping) * teleportWeight + damping * rank;
|
|
90
|
+
newScores.set(node, value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let delta = 0;
|
|
94
|
+
for (const node of nodeList) {
|
|
95
|
+
delta += Math.abs((newScores.get(node) ?? 0) - (scores.get(node) ?? 0));
|
|
96
|
+
}
|
|
97
|
+
scores = newScores;
|
|
98
|
+
finalDelta = delta;
|
|
99
|
+
if (delta < 1e-6) {
|
|
100
|
+
converged = true;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!converged) {
|
|
106
|
+
console.warn(`PageRank did not converge after ${maxIter} iterations (delta=${finalDelta})`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const BATCH_SIZE = 500;
|
|
110
|
+
for (let i = 0; i < nodeList.length; i += BATCH_SIZE) {
|
|
111
|
+
const batch = nodeList.slice(i, i + BATCH_SIZE);
|
|
112
|
+
const statements = batch.map((id) => ({
|
|
113
|
+
sql: "UPDATE graph_nodes SET importance = ? WHERE id = ?",
|
|
114
|
+
params: [scores.get(id) ?? 0, id],
|
|
115
|
+
}));
|
|
116
|
+
await db.executeMany(statements);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
iterations: iterationCount,
|
|
121
|
+
converged,
|
|
122
|
+
finalDelta,
|
|
123
|
+
nodesScored: nodeList.length,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, relative, resolve, sep } from "node:path";
|
|
3
|
+
|
|
4
|
+
export interface IgnoreMatcher {
|
|
5
|
+
shouldIgnore(absPath: string, isDir: boolean): boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface GitignoreRule {
|
|
9
|
+
regex: RegExp;
|
|
10
|
+
dirOnly: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Normalize a path to posix-style separators for consistent matching. */
|
|
14
|
+
export function toPosixPath(path: string): string {
|
|
15
|
+
return path.split(sep).join("/");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function patternToRegExp(pattern: string): RegExp {
|
|
19
|
+
const trimmed = pattern.trim();
|
|
20
|
+
if (!trimmed) return /^$/; // unused
|
|
21
|
+
|
|
22
|
+
const escaped = trimmed.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
23
|
+
const wildcarded = escaped.replace(/\\\*\\\*/g, ".*").replace(/\\\*/g, "[^/]*");
|
|
24
|
+
|
|
25
|
+
if (trimmed.startsWith("/")) {
|
|
26
|
+
return new RegExp(`^${wildcarded.slice(1)}(/.*)?$`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return new RegExp(`(^|/)${wildcarded}(/.*)?$`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function loadGitignorePatterns(repoRoot: string): {
|
|
33
|
+
ignore: GitignoreRule[];
|
|
34
|
+
negate: GitignoreRule[];
|
|
35
|
+
} {
|
|
36
|
+
const gitignorePath = join(repoRoot, ".gitignore");
|
|
37
|
+
if (!existsSync(gitignorePath)) return { ignore: [], negate: [] };
|
|
38
|
+
|
|
39
|
+
const lines = readFileSync(gitignorePath, "utf-8")
|
|
40
|
+
.split("\n")
|
|
41
|
+
.map((line) => line.trim())
|
|
42
|
+
.filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
43
|
+
|
|
44
|
+
const ignoreRules: GitignoreRule[] = [];
|
|
45
|
+
const negateRules: GitignoreRule[] = [];
|
|
46
|
+
|
|
47
|
+
for (const line of lines) {
|
|
48
|
+
if (line.startsWith("!")) {
|
|
49
|
+
const raw = line.slice(1);
|
|
50
|
+
const isDirOnly = raw.endsWith("/");
|
|
51
|
+
const cleanLine = isDirOnly ? raw.slice(0, -1) : raw;
|
|
52
|
+
negateRules.push({ regex: patternToRegExp(cleanLine), dirOnly: isDirOnly });
|
|
53
|
+
} else {
|
|
54
|
+
const isDirOnly = line.endsWith("/");
|
|
55
|
+
const cleanLine = isDirOnly ? line.slice(0, -1) : line;
|
|
56
|
+
ignoreRules.push({ regex: patternToRegExp(cleanLine), dirOnly: isDirOnly });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { ignore: ignoreRules, negate: negateRules };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build a matcher that applies default ignores, .gitignore rules, and config.excludePaths.
|
|
65
|
+
*/
|
|
66
|
+
export function createIgnoreMatcher(repoRoot: string, excludePaths: string[] = []): IgnoreMatcher {
|
|
67
|
+
const root = resolve(repoRoot);
|
|
68
|
+
const gitignoreResult = loadGitignorePatterns(root);
|
|
69
|
+
const defaultExcludes = [
|
|
70
|
+
"node_modules",
|
|
71
|
+
".git",
|
|
72
|
+
".idea",
|
|
73
|
+
".vscode",
|
|
74
|
+
".sia",
|
|
75
|
+
"dist",
|
|
76
|
+
"build",
|
|
77
|
+
"coverage",
|
|
78
|
+
"out",
|
|
79
|
+
"tmp",
|
|
80
|
+
].map((p) => toPosixPath(p));
|
|
81
|
+
|
|
82
|
+
const configuredExcludes = excludePaths.map((p) => toPosixPath(p.replace(/^\/+/, "")));
|
|
83
|
+
|
|
84
|
+
function isOutside(rel: string): boolean {
|
|
85
|
+
return rel.startsWith("..");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
shouldIgnore(absPath: string, isDir: boolean): boolean {
|
|
90
|
+
const rel = toPosixPath(relative(root, resolve(absPath)));
|
|
91
|
+
if (isOutside(rel)) return true;
|
|
92
|
+
if (rel === "" || rel === ".") return false;
|
|
93
|
+
|
|
94
|
+
for (const prefix of [...defaultExcludes, ...configuredExcludes]) {
|
|
95
|
+
if (rel === prefix || rel.startsWith(`${prefix}/`)) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Apply gitignore patterns with negation support
|
|
101
|
+
let gitIgnored = false;
|
|
102
|
+
for (const rule of gitignoreResult.ignore) {
|
|
103
|
+
if (rule.dirOnly && !isDir) continue;
|
|
104
|
+
if (rule.regex.test(rel)) {
|
|
105
|
+
gitIgnored = true;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (gitIgnored) {
|
|
110
|
+
for (const rule of gitignoreResult.negate) {
|
|
111
|
+
if (rule.dirOnly && !isDir) continue;
|
|
112
|
+
if (rule.regex.test(rel)) {
|
|
113
|
+
gitIgnored = false;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (gitIgnored) return true;
|
|
119
|
+
|
|
120
|
+
return false;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Best-effort monorepo package detector for paths like packages/foo/src/index.ts */
|
|
126
|
+
export function detectPackagePath(relativePath: string): string | null {
|
|
127
|
+
const parts = relativePath.split("/");
|
|
128
|
+
const packagesIdx = parts.indexOf("packages");
|
|
129
|
+
if (packagesIdx !== -1 && packagesIdx + 1 < parts.length) {
|
|
130
|
+
return parts.slice(0, packagesIdx + 2).join("/");
|
|
131
|
+
}
|
|
132
|
+
const appsIdx = parts.indexOf("apps");
|
|
133
|
+
if (appsIdx !== -1 && appsIdx + 1 < parts.length) {
|
|
134
|
+
return parts.slice(0, appsIdx + 2).join("/");
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|