seam-code 0.3.0__tar.gz
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.
- seam_code-0.3.0/.env.example +13 -0
- seam_code-0.3.0/.gitignore +66 -0
- seam_code-0.3.0/AGENTS.md +101 -0
- seam_code-0.3.0/APP_FLOW.md +151 -0
- seam_code-0.3.0/BACKEND_STRUCTURE.md +253 -0
- seam_code-0.3.0/CLAUDE.md +1061 -0
- seam_code-0.3.0/CONTEXT.md +36 -0
- seam_code-0.3.0/DISCOVERY.md +57 -0
- seam_code-0.3.0/IMPLEMENTATION_PLAN.md +211 -0
- seam_code-0.3.0/LICENSE +21 -0
- seam_code-0.3.0/Makefile +59 -0
- seam_code-0.3.0/PKG-INFO +318 -0
- seam_code-0.3.0/PRD.md +101 -0
- seam_code-0.3.0/README.md +276 -0
- seam_code-0.3.0/TECH_STACK.md +105 -0
- seam_code-0.3.0/benchmarks/run_benchmark.py +239 -0
- seam_code-0.3.0/benchmarks/semantic_recall.py +298 -0
- seam_code-0.3.0/docs/ARCHITECTURE.md +1296 -0
- seam_code-0.3.0/docs/CONCEPTS.md +352 -0
- seam_code-0.3.0/docs/CONFIGURATION.md +196 -0
- seam_code-0.3.0/docs/CONTRACT.md +594 -0
- seam_code-0.3.0/docs/adr/001-python-over-typescript.md +29 -0
- seam_code-0.3.0/docs/adr/002-sqlite-storage.md +32 -0
- seam_code-0.3.0/docs/adr/003-heuristic-execution-flows.md +33 -0
- seam_code-0.3.0/docs/adr/004-watchdog-file-watcher.md +31 -0
- seam_code-0.3.0/docs/adr/005-phase0-language-scope.md +50 -0
- seam_code-0.3.0/docs/adr/008-language-expansion.md +108 -0
- seam_code-0.3.0/docs/adr/009-swift-support.md +132 -0
- seam_code-0.3.0/docs/adr/010-frontend-explorer-architecture.md +77 -0
- seam_code-0.3.0/docs/adr/ADR-007-louvain-clustering.md +65 -0
- seam_code-0.3.0/docs/api-contracts/mcp-tools.yaml +1261 -0
- seam_code-0.3.0/docs/architecture.html +562 -0
- seam_code-0.3.0/docs/assets/seam-hero.png +0 -0
- seam_code-0.3.0/docs/benchmark.md +128 -0
- seam_code-0.3.0/docs/competitive-benchmark.md +104 -0
- seam_code-0.3.0/docs/database/schema.sql +225 -0
- seam_code-0.3.0/docs/prd/phase1-core.md +187 -0
- seam_code-0.3.0/docs/prd/phase10-swift.md +147 -0
- seam_code-0.3.0/docs/prd/phase1b-confidence.md +92 -0
- seam_code-0.3.0/docs/prd/phase1b-go-rust.md +80 -0
- seam_code-0.3.0/docs/prd/phase1b-qa-hardening.md +79 -0
- seam_code-0.3.0/docs/prd/phase1b-seam-why.md +81 -0
- seam_code-0.3.0/docs/prd/phase2-clustering.md +170 -0
- seam_code-0.3.0/docs/prd/phase3-agent-interface.md +117 -0
- seam_code-0.3.0/docs/prd/phase4-node-enrichment.md +178 -0
- seam_code-0.3.0/docs/prd/phase5-import-resolution.md +254 -0
- seam_code-0.3.0/docs/prd/phase6-context-pack.md +193 -0
- seam_code-0.3.0/docs/prd/phase7-seam-sync.md +238 -0
- seam_code-0.3.0/docs/prd/phase8-lean-output.md +191 -0
- seam_code-0.3.0/docs/prd/phase9-language-expansion.md +195 -0
- seam_code-0.3.0/lessons.md +108 -0
- seam_code-0.3.0/memory/architecture/001-graph-model.md +11 -0
- seam_code-0.3.0/memory/decisions/001-language-python.md +9 -0
- seam_code-0.3.0/memory/learnings/.gitkeep +0 -0
- seam_code-0.3.0/memory/patterns/.gitkeep +0 -0
- seam_code-0.3.0/progress.txt +862 -0
- seam_code-0.3.0/pyproject.toml +128 -0
- seam_code-0.3.0/seam/__init__.py +3 -0
- seam_code-0.3.0/seam/_web/assets/index-BL_tqprR.js +216 -0
- seam_code-0.3.0/seam/_web/assets/index-GTKUhVyD.css +1 -0
- seam_code-0.3.0/seam/_web/index.html +13 -0
- seam_code-0.3.0/seam/analysis/__init__.py +14 -0
- seam_code-0.3.0/seam/analysis/affected.py +254 -0
- seam_code-0.3.0/seam/analysis/builtins.py +966 -0
- seam_code-0.3.0/seam/analysis/byte_budget.py +217 -0
- seam_code-0.3.0/seam/analysis/changes.py +709 -0
- seam_code-0.3.0/seam/analysis/cluster_naming.py +260 -0
- seam_code-0.3.0/seam/analysis/clustering.py +216 -0
- seam_code-0.3.0/seam/analysis/confidence.py +699 -0
- seam_code-0.3.0/seam/analysis/embeddings.py +195 -0
- seam_code-0.3.0/seam/analysis/flows.py +708 -0
- seam_code-0.3.0/seam/analysis/impact.py +444 -0
- seam_code-0.3.0/seam/analysis/imports.py +994 -0
- seam_code-0.3.0/seam/analysis/imports_ext.py +780 -0
- seam_code-0.3.0/seam/analysis/imports_resolve.py +176 -0
- seam_code-0.3.0/seam/analysis/processes.py +453 -0
- seam_code-0.3.0/seam/analysis/relevance.py +155 -0
- seam_code-0.3.0/seam/analysis/rwr.py +129 -0
- seam_code-0.3.0/seam/analysis/staleness.py +328 -0
- seam_code-0.3.0/seam/analysis/steer.py +282 -0
- seam_code-0.3.0/seam/analysis/synthesis.py +253 -0
- seam_code-0.3.0/seam/analysis/synthesis_channels.py +433 -0
- seam_code-0.3.0/seam/analysis/testpaths.py +103 -0
- seam_code-0.3.0/seam/analysis/traversal.py +470 -0
- seam_code-0.3.0/seam/cli/__init__.py +0 -0
- seam_code-0.3.0/seam/cli/install.py +232 -0
- seam_code-0.3.0/seam/cli/main.py +2602 -0
- seam_code-0.3.0/seam/cli/output.py +137 -0
- seam_code-0.3.0/seam/cli/read.py +244 -0
- seam_code-0.3.0/seam/cli/serve.py +145 -0
- seam_code-0.3.0/seam/config.py +551 -0
- seam_code-0.3.0/seam/indexer/__init__.py +0 -0
- seam_code-0.3.0/seam/indexer/cluster_index.py +425 -0
- seam_code-0.3.0/seam/indexer/db.py +496 -0
- seam_code-0.3.0/seam/indexer/embedding_index.py +183 -0
- seam_code-0.3.0/seam/indexer/field_access.py +536 -0
- seam_code-0.3.0/seam/indexer/field_access_c_cpp.py +643 -0
- seam_code-0.3.0/seam/indexer/field_access_ext.py +708 -0
- seam_code-0.3.0/seam/indexer/field_access_ext2.py +408 -0
- seam_code-0.3.0/seam/indexer/field_access_go_rust.py +737 -0
- seam_code-0.3.0/seam/indexer/field_access_php_swift.py +888 -0
- seam_code-0.3.0/seam/indexer/field_access_ts.py +626 -0
- seam_code-0.3.0/seam/indexer/graph.py +321 -0
- seam_code-0.3.0/seam/indexer/graph_c.py +562 -0
- seam_code-0.3.0/seam/indexer/graph_c_cpp.py +39 -0
- seam_code-0.3.0/seam/indexer/graph_common.py +644 -0
- seam_code-0.3.0/seam/indexer/graph_cpp.py +615 -0
- seam_code-0.3.0/seam/indexer/graph_csharp.py +651 -0
- seam_code-0.3.0/seam/indexer/graph_go.py +723 -0
- seam_code-0.3.0/seam/indexer/graph_go_rust.py +39 -0
- seam_code-0.3.0/seam/indexer/graph_java.py +689 -0
- seam_code-0.3.0/seam/indexer/graph_java_csharp.py +38 -0
- seam_code-0.3.0/seam/indexer/graph_php.py +914 -0
- seam_code-0.3.0/seam/indexer/graph_python.py +628 -0
- seam_code-0.3.0/seam/indexer/graph_ruby.py +748 -0
- seam_code-0.3.0/seam/indexer/graph_rust.py +653 -0
- seam_code-0.3.0/seam/indexer/graph_scope_infer.py +902 -0
- seam_code-0.3.0/seam/indexer/graph_scope_infer_ext.py +723 -0
- seam_code-0.3.0/seam/indexer/graph_scope_infer_ext2.py +992 -0
- seam_code-0.3.0/seam/indexer/graph_swift.py +1014 -0
- seam_code-0.3.0/seam/indexer/graph_swift_infer.py +515 -0
- seam_code-0.3.0/seam/indexer/graph_typescript.py +663 -0
- seam_code-0.3.0/seam/indexer/migrations.py +816 -0
- seam_code-0.3.0/seam/indexer/parser.py +204 -0
- seam_code-0.3.0/seam/indexer/pipeline.py +197 -0
- seam_code-0.3.0/seam/indexer/signatures.py +634 -0
- seam_code-0.3.0/seam/indexer/signatures_ext.py +780 -0
- seam_code-0.3.0/seam/indexer/sync.py +287 -0
- seam_code-0.3.0/seam/indexer/synthesis_index.py +291 -0
- seam_code-0.3.0/seam/indexer/tokenize.py +79 -0
- seam_code-0.3.0/seam/installer/__init__.py +67 -0
- seam_code-0.3.0/seam/installer/claude.py +97 -0
- seam_code-0.3.0/seam/installer/codex.py +94 -0
- seam_code-0.3.0/seam/installer/core.py +127 -0
- seam_code-0.3.0/seam/installer/cursor.py +61 -0
- seam_code-0.3.0/seam/installer/guide.py +110 -0
- seam_code-0.3.0/seam/installer/jsonfile.py +85 -0
- seam_code-0.3.0/seam/installer/markdownfile.py +146 -0
- seam_code-0.3.0/seam/installer/tomlfile.py +72 -0
- seam_code-0.3.0/seam/query/__init__.py +0 -0
- seam_code-0.3.0/seam/query/clusters.py +206 -0
- seam_code-0.3.0/seam/query/comments.py +217 -0
- seam_code-0.3.0/seam/query/context.py +293 -0
- seam_code-0.3.0/seam/query/engine.py +940 -0
- seam_code-0.3.0/seam/query/fts.py +328 -0
- seam_code-0.3.0/seam/query/names.py +470 -0
- seam_code-0.3.0/seam/query/pack.py +433 -0
- seam_code-0.3.0/seam/query/semantic.py +339 -0
- seam_code-0.3.0/seam/query/structure.py +727 -0
- seam_code-0.3.0/seam/server/__init__.py +0 -0
- seam_code-0.3.0/seam/server/graph_api.py +437 -0
- seam_code-0.3.0/seam/server/handler_common.py +323 -0
- seam_code-0.3.0/seam/server/impact_handler.py +615 -0
- seam_code-0.3.0/seam/server/mcp.py +556 -0
- seam_code-0.3.0/seam/server/tools.py +697 -0
- seam_code-0.3.0/seam/server/trace_handler.py +184 -0
- seam_code-0.3.0/seam/server/web.py +922 -0
- seam_code-0.3.0/seam/watcher/__init__.py +0 -0
- seam_code-0.3.0/seam/watcher/__main__.py +56 -0
- seam_code-0.3.0/seam/watcher/daemon.py +237 -0
- seam_code-0.3.0/tests/__init__.py +0 -0
- seam_code-0.3.0/tests/eval/__init__.py +1 -0
- seam_code-0.3.0/tests/eval/eval_report.py +165 -0
- seam_code-0.3.0/tests/eval/fixtures/dispatcher.py +51 -0
- seam_code-0.3.0/tests/eval/fixtures/interfaces.py +57 -0
- seam_code-0.3.0/tests/eval/fixtures/pipeline.py +53 -0
- seam_code-0.3.0/tests/eval/fixtures/utils.py +37 -0
- seam_code-0.3.0/tests/eval/gen_golden.py +247 -0
- seam_code-0.3.0/tests/eval/golden.json +189 -0
- seam_code-0.3.0/tests/eval/recall_harness.py +176 -0
- seam_code-0.3.0/tests/eval/test_metrics.py +288 -0
- seam_code-0.3.0/tests/eval/test_recall_regression.py +478 -0
- seam_code-0.3.0/tests/fixtures/sample.c +54 -0
- seam_code-0.3.0/tests/fixtures/sample.cpp +81 -0
- seam_code-0.3.0/tests/fixtures/sample.cs +93 -0
- seam_code-0.3.0/tests/fixtures/sample.go +51 -0
- seam_code-0.3.0/tests/fixtures/sample.java +90 -0
- seam_code-0.3.0/tests/fixtures/sample.php +80 -0
- seam_code-0.3.0/tests/fixtures/sample.py +47 -0
- seam_code-0.3.0/tests/fixtures/sample.rb +38 -0
- seam_code-0.3.0/tests/fixtures/sample.rs +58 -0
- seam_code-0.3.0/tests/fixtures/sample.swift +71 -0
- seam_code-0.3.0/tests/fixtures/sample.ts +59 -0
- seam_code-0.3.0/tests/integration/__init__.py +0 -0
- seam_code-0.3.0/tests/integration/test_affected_handler.py +329 -0
- seam_code-0.3.0/tests/integration/test_changes.py +552 -0
- seam_code-0.3.0/tests/integration/test_cli_e4_surface.py +536 -0
- seam_code-0.3.0/tests/integration/test_cli_impact_max_bytes.py +498 -0
- seam_code-0.3.0/tests/integration/test_cli_json.py +401 -0
- seam_code-0.3.0/tests/integration/test_cli_read.py +95 -0
- seam_code-0.3.0/tests/integration/test_cluster_index.py +607 -0
- seam_code-0.3.0/tests/integration/test_clusters_handler.py +252 -0
- seam_code-0.3.0/tests/integration/test_composition_holds_edges_go_rust_integration.py +266 -0
- seam_code-0.3.0/tests/integration/test_composition_holds_edges_integration.py +238 -0
- seam_code-0.3.0/tests/integration/test_composition_holds_edges_java_cs_cpp_ruby_php_integration.py +397 -0
- seam_code-0.3.0/tests/integration/test_composition_holds_edges_swift_integration.py +189 -0
- seam_code-0.3.0/tests/integration/test_embedding_index.py +348 -0
- seam_code-0.3.0/tests/integration/test_field_access_integration_c_cpp.py +400 -0
- seam_code-0.3.0/tests/integration/test_field_access_integration_go_rust.py +516 -0
- seam_code-0.3.0/tests/integration/test_field_access_integration_java_csharp.py +496 -0
- seam_code-0.3.0/tests/integration/test_field_access_integration_python_ts.py +723 -0
- seam_code-0.3.0/tests/integration/test_field_access_integration_ruby_php_swift.py +627 -0
- seam_code-0.3.0/tests/integration/test_flows_cli.py +88 -0
- seam_code-0.3.0/tests/integration/test_flows_handler.py +95 -0
- seam_code-0.3.0/tests/integration/test_impact_handler.py +279 -0
- seam_code-0.3.0/tests/integration/test_impact_relevance.py +248 -0
- seam_code-0.3.0/tests/integration/test_impact_summary_parity.py +328 -0
- seam_code-0.3.0/tests/integration/test_indexer.py +128 -0
- seam_code-0.3.0/tests/integration/test_inheritance_impact.py +84 -0
- seam_code-0.3.0/tests/integration/test_init_gitignore.py +69 -0
- seam_code-0.3.0/tests/integration/test_install_cli.py +160 -0
- seam_code-0.3.0/tests/integration/test_lean_parity.py +322 -0
- seam_code-0.3.0/tests/integration/test_mcp_error_contract.py +129 -0
- seam_code-0.3.0/tests/integration/test_mcp_tools.py +326 -0
- seam_code-0.3.0/tests/integration/test_migration_v12.py +242 -0
- seam_code-0.3.0/tests/integration/test_migration_v5.py +526 -0
- seam_code-0.3.0/tests/integration/test_migration_v6.py +414 -0
- seam_code-0.3.0/tests/integration/test_migration_v7.py +321 -0
- seam_code-0.3.0/tests/integration/test_migration_v9.py +150 -0
- seam_code-0.3.0/tests/integration/test_no_mcp_profile.py +42 -0
- seam_code-0.3.0/tests/integration/test_p4_barrel_reexport.py +313 -0
- seam_code-0.3.0/tests/integration/test_pack_homonym.py +236 -0
- seam_code-0.3.0/tests/integration/test_pack_parity.py +218 -0
- seam_code-0.3.0/tests/integration/test_phase4_read_layer.py +462 -0
- seam_code-0.3.0/tests/integration/test_phase5_e2e_homonym.py +417 -0
- seam_code-0.3.0/tests/integration/test_phase5_import_promotion.py +483 -0
- seam_code-0.3.0/tests/integration/test_phase5_read_layer.py +184 -0
- seam_code-0.3.0/tests/integration/test_qa_hardening_wiring.py +263 -0
- seam_code-0.3.0/tests/integration/test_seam_why_handler.py +160 -0
- seam_code-0.3.0/tests/integration/test_semantic_engine.py +347 -0
- seam_code-0.3.0/tests/integration/test_semantic_surfaces.py +525 -0
- seam_code-0.3.0/tests/integration/test_serve_cli.py +120 -0
- seam_code-0.3.0/tests/integration/test_staleness_banner.py +369 -0
- seam_code-0.3.0/tests/integration/test_sync_cli.py +366 -0
- seam_code-0.3.0/tests/integration/test_sync_clusters.py +269 -0
- seam_code-0.3.0/tests/integration/test_synthesis_channels_integration.py +362 -0
- seam_code-0.3.0/tests/integration/test_synthesis_integration.py +237 -0
- seam_code-0.3.0/tests/integration/test_tier_a.py +537 -0
- seam_code-0.3.0/tests/integration/test_tier_a_slice4.py +428 -0
- seam_code-0.3.0/tests/integration/test_tier_b3.py +308 -0
- seam_code-0.3.0/tests/integration/test_trace_handler.py +389 -0
- seam_code-0.3.0/tests/integration/test_watcher.py +156 -0
- seam_code-0.3.0/tests/integration/test_web_api.py +531 -0
- seam_code-0.3.0/tests/unit/__init__.py +0 -0
- seam_code-0.3.0/tests/unit/test_affected.py +254 -0
- seam_code-0.3.0/tests/unit/test_b5_infer_remaining_families.py +957 -0
- seam_code-0.3.0/tests/unit/test_b6_instantiates_edges.py +905 -0
- seam_code-0.3.0/tests/unit/test_bare_method_resolution.py +168 -0
- seam_code-0.3.0/tests/unit/test_builtins.py +266 -0
- seam_code-0.3.0/tests/unit/test_byte_budget.py +385 -0
- seam_code-0.3.0/tests/unit/test_c_cpp.py +954 -0
- seam_code-0.3.0/tests/unit/test_changes_partial.py +195 -0
- seam_code-0.3.0/tests/unit/test_cluster_naming.py +242 -0
- seam_code-0.3.0/tests/unit/test_clustering.py +260 -0
- seam_code-0.3.0/tests/unit/test_clustering_migration.py +306 -0
- seam_code-0.3.0/tests/unit/test_composition_holds_edges.py +464 -0
- seam_code-0.3.0/tests/unit/test_composition_holds_edges_go_rust.py +488 -0
- seam_code-0.3.0/tests/unit/test_composition_holds_edges_java_cs_cpp_ruby_php.py +858 -0
- seam_code-0.3.0/tests/unit/test_composition_holds_edges_swift.py +399 -0
- seam_code-0.3.0/tests/unit/test_confidence.py +302 -0
- seam_code-0.3.0/tests/unit/test_confidence_global.py +150 -0
- seam_code-0.3.0/tests/unit/test_confidence_phase5.py +273 -0
- seam_code-0.3.0/tests/unit/test_db.py +323 -0
- seam_code-0.3.0/tests/unit/test_embeddings.py +350 -0
- seam_code-0.3.0/tests/unit/test_entry_score.py +127 -0
- seam_code-0.3.0/tests/unit/test_field_access_c_cpp.py +533 -0
- seam_code-0.3.0/tests/unit/test_field_access_go_rust.py +791 -0
- seam_code-0.3.0/tests/unit/test_field_access_java_csharp.py +712 -0
- seam_code-0.3.0/tests/unit/test_field_access_python.py +562 -0
- seam_code-0.3.0/tests/unit/test_field_access_ruby_php.py +782 -0
- seam_code-0.3.0/tests/unit/test_field_access_swift.py +372 -0
- seam_code-0.3.0/tests/unit/test_field_access_typescript.py +500 -0
- seam_code-0.3.0/tests/unit/test_flows.py +456 -0
- seam_code-0.3.0/tests/unit/test_flows_global_confidence.py +210 -0
- seam_code-0.3.0/tests/unit/test_fts.py +511 -0
- seam_code-0.3.0/tests/unit/test_fts_tokenize.py +126 -0
- seam_code-0.3.0/tests/unit/test_go_rust.py +809 -0
- seam_code-0.3.0/tests/unit/test_graph.py +301 -0
- seam_code-0.3.0/tests/unit/test_graph_api.py +493 -0
- seam_code-0.3.0/tests/unit/test_handler_provenance.py +505 -0
- seam_code-0.3.0/tests/unit/test_hardening.py +193 -0
- seam_code-0.3.0/tests/unit/test_impact.py +436 -0
- seam_code-0.3.0/tests/unit/test_impact_default_production.py +253 -0
- seam_code-0.3.0/tests/unit/test_impact_is_test.py +351 -0
- seam_code-0.3.0/tests/unit/test_impact_max_bytes.py +582 -0
- seam_code-0.3.0/tests/unit/test_impact_omit_null_candidate.py +136 -0
- seam_code-0.3.0/tests/unit/test_impact_summary.py +523 -0
- seam_code-0.3.0/tests/unit/test_imports.py +493 -0
- seam_code-0.3.0/tests/unit/test_inheritance_edges.py +159 -0
- seam_code-0.3.0/tests/unit/test_installer.py +349 -0
- seam_code-0.3.0/tests/unit/test_java_csharp.py +1035 -0
- seam_code-0.3.0/tests/unit/test_lean_output.py +444 -0
- seam_code-0.3.0/tests/unit/test_names.py +664 -0
- seam_code-0.3.0/tests/unit/test_output.py +201 -0
- seam_code-0.3.0/tests/unit/test_p2_cluster_quality.py +407 -0
- seam_code-0.3.0/tests/unit/test_pack.py +497 -0
- seam_code-0.3.0/tests/unit/test_pack_relevance_rank.py +137 -0
- seam_code-0.3.0/tests/unit/test_param_uses_edges.py +151 -0
- seam_code-0.3.0/tests/unit/test_parser.py +110 -0
- seam_code-0.3.0/tests/unit/test_phase9_type_parity.py +84 -0
- seam_code-0.3.0/tests/unit/test_pipeline_walk.py +72 -0
- seam_code-0.3.0/tests/unit/test_processes.py +181 -0
- seam_code-0.3.0/tests/unit/test_provenance_threading.py +380 -0
- seam_code-0.3.0/tests/unit/test_query_clusters.py +383 -0
- seam_code-0.3.0/tests/unit/test_query_engine.py +400 -0
- seam_code-0.3.0/tests/unit/test_receiver_b1.py +383 -0
- seam_code-0.3.0/tests/unit/test_receiver_b2.py +819 -0
- seam_code-0.3.0/tests/unit/test_receiver_b3.py +311 -0
- seam_code-0.3.0/tests/unit/test_relevance.py +174 -0
- seam_code-0.3.0/tests/unit/test_review_fixes.py +611 -0
- seam_code-0.3.0/tests/unit/test_review_fixes_phase4.py +864 -0
- seam_code-0.3.0/tests/unit/test_review_fixes_phase5.py +403 -0
- seam_code-0.3.0/tests/unit/test_richer_edges.py +475 -0
- seam_code-0.3.0/tests/unit/test_ruby_php.py +1030 -0
- seam_code-0.3.0/tests/unit/test_rwr.py +101 -0
- seam_code-0.3.0/tests/unit/test_schema_packaging.py +25 -0
- seam_code-0.3.0/tests/unit/test_scope_infer_b4.py +649 -0
- seam_code-0.3.0/tests/unit/test_seam_why.py +799 -0
- seam_code-0.3.0/tests/unit/test_semantic.py +520 -0
- seam_code-0.3.0/tests/unit/test_semantic_hardening.py +669 -0
- seam_code-0.3.0/tests/unit/test_semantic_review_fixes.py +707 -0
- seam_code-0.3.0/tests/unit/test_signatures.py +573 -0
- seam_code-0.3.0/tests/unit/test_smoke.py +43 -0
- seam_code-0.3.0/tests/unit/test_staleness.py +405 -0
- seam_code-0.3.0/tests/unit/test_steer.py +472 -0
- seam_code-0.3.0/tests/unit/test_structure.py +982 -0
- seam_code-0.3.0/tests/unit/test_swift.py +853 -0
- seam_code-0.3.0/tests/unit/test_symbol_uid.py +215 -0
- seam_code-0.3.0/tests/unit/test_sync.py +663 -0
- seam_code-0.3.0/tests/unit/test_synthesis_channels.py +615 -0
- seam_code-0.3.0/tests/unit/test_synthesis_engine.py +401 -0
- seam_code-0.3.0/tests/unit/test_synthesis_index.py +244 -0
- seam_code-0.3.0/tests/unit/test_testpaths.py +196 -0
- seam_code-0.3.0/tests/unit/test_tokenize.py +80 -0
- seam_code-0.3.0/tests/unit/test_tools_split_regression.py +212 -0
- seam_code-0.3.0/tests/unit/test_traversal.py +416 -0
- seam_code-0.3.0/tests/unit/test_traversal_global_confidence.py +251 -0
- seam_code-0.3.0/tests/unit/test_web_packaging.py +43 -0
- seam_code-0.3.0/uv.lock +1980 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Seam configuration — copy to .env, never commit .env
|
|
2
|
+
# All values shown are defaults. Seam works with zero config.
|
|
3
|
+
|
|
4
|
+
SEAM_LOG_LEVEL=INFO
|
|
5
|
+
|
|
6
|
+
# Override where the index database is stored (default: .seam/seam.db)
|
|
7
|
+
# SEAM_DB_PATH=.seam/seam.db
|
|
8
|
+
|
|
9
|
+
# File watcher debounce delay in milliseconds (default: 500)
|
|
10
|
+
# SEAM_WATCHER_DEBOUNCE_MS=500
|
|
11
|
+
|
|
12
|
+
# Maximum file size to index in bytes (default: 1MB)
|
|
13
|
+
# SEAM_MAX_FILE_BYTES=1048576
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
*.whl
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
|
|
18
|
+
# Testing / coverage
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.mypy_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
htmlcov/
|
|
23
|
+
.coverage
|
|
24
|
+
coverage.xml
|
|
25
|
+
|
|
26
|
+
# Environment
|
|
27
|
+
.env
|
|
28
|
+
|
|
29
|
+
# Seam index (local per-project, not committed by default)
|
|
30
|
+
.seam/
|
|
31
|
+
|
|
32
|
+
# Built SPA — produced by `make build-web` / `cd web && npm run build`.
|
|
33
|
+
# Shipped inside the wheel via hatch artifacts config; not committed to git.
|
|
34
|
+
seam/_web/
|
|
35
|
+
|
|
36
|
+
# GitNexus index
|
|
37
|
+
.gitnexus/
|
|
38
|
+
|
|
39
|
+
# Competitor index artifacts (benchmark only — never committed)
|
|
40
|
+
.codegraph/
|
|
41
|
+
graphify-out/
|
|
42
|
+
|
|
43
|
+
# macOS
|
|
44
|
+
.DS_Store
|
|
45
|
+
.AppleDouble
|
|
46
|
+
.LSOverride
|
|
47
|
+
|
|
48
|
+
# IDE
|
|
49
|
+
.idea/
|
|
50
|
+
.vscode/
|
|
51
|
+
*.swp
|
|
52
|
+
*.swo
|
|
53
|
+
|
|
54
|
+
# Distribution
|
|
55
|
+
*.tar.gz
|
|
56
|
+
*.zip
|
|
57
|
+
|
|
58
|
+
# uv lockfile (commit uv.lock in production, optional here)
|
|
59
|
+
# uv.lock
|
|
60
|
+
|
|
61
|
+
.bach/
|
|
62
|
+
.claude/
|
|
63
|
+
.koda/
|
|
64
|
+
|
|
65
|
+
# QA artifacts (gstack /qa reports + screenshots) — local, not committed
|
|
66
|
+
.gstack/
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<!-- gitnexus:start -->
|
|
2
|
+
# GitNexus — Code Intelligence
|
|
3
|
+
|
|
4
|
+
This project is indexed by GitNexus as **seam** (273 symbols, 293 relationships, 0 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
|
5
|
+
|
|
6
|
+
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
|
7
|
+
|
|
8
|
+
## Always Do
|
|
9
|
+
|
|
10
|
+
- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user.
|
|
11
|
+
- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows.
|
|
12
|
+
- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
|
|
13
|
+
- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
|
|
14
|
+
- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`.
|
|
15
|
+
|
|
16
|
+
## When Debugging
|
|
17
|
+
|
|
18
|
+
1. `gitnexus_query({query: "<error or symptom>"})` — find execution flows related to the issue
|
|
19
|
+
2. `gitnexus_context({name: "<suspect function>"})` — see all callers, callees, and process participation
|
|
20
|
+
3. `READ gitnexus://repo/seam/process/{processName}` — trace the full execution flow step by step
|
|
21
|
+
4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed
|
|
22
|
+
|
|
23
|
+
## When Refactoring
|
|
24
|
+
|
|
25
|
+
- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`.
|
|
26
|
+
- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code.
|
|
27
|
+
- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed.
|
|
28
|
+
|
|
29
|
+
## Never Do
|
|
30
|
+
|
|
31
|
+
- NEVER edit a function, class, or method without first running `gitnexus_impact` on it.
|
|
32
|
+
- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
|
|
33
|
+
- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
|
|
34
|
+
- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope.
|
|
35
|
+
|
|
36
|
+
## Tools Quick Reference
|
|
37
|
+
|
|
38
|
+
| Tool | When to use | Command |
|
|
39
|
+
|------|-------------|---------|
|
|
40
|
+
| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` |
|
|
41
|
+
| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` |
|
|
42
|
+
| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` |
|
|
43
|
+
| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` |
|
|
44
|
+
| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` |
|
|
45
|
+
| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` |
|
|
46
|
+
|
|
47
|
+
## Impact Risk Levels
|
|
48
|
+
|
|
49
|
+
| Depth | Meaning | Action |
|
|
50
|
+
|-------|---------|--------|
|
|
51
|
+
| d=1 | WILL BREAK — direct callers/importers | MUST update these |
|
|
52
|
+
| d=2 | LIKELY AFFECTED — indirect deps | Should test |
|
|
53
|
+
| d=3 | MAY NEED TESTING — transitive | Test if critical path |
|
|
54
|
+
|
|
55
|
+
## Resources
|
|
56
|
+
|
|
57
|
+
| Resource | Use for |
|
|
58
|
+
|----------|---------|
|
|
59
|
+
| `gitnexus://repo/seam/context` | Codebase overview, check index freshness |
|
|
60
|
+
| `gitnexus://repo/seam/clusters` | All functional areas |
|
|
61
|
+
| `gitnexus://repo/seam/processes` | All execution flows |
|
|
62
|
+
| `gitnexus://repo/seam/process/{name}` | Step-by-step execution trace |
|
|
63
|
+
|
|
64
|
+
## Self-Check Before Finishing
|
|
65
|
+
|
|
66
|
+
Before completing any code modification task, verify:
|
|
67
|
+
1. `gitnexus_impact` was run for all modified symbols
|
|
68
|
+
2. No HIGH/CRITICAL risk warnings were ignored
|
|
69
|
+
3. `gitnexus_detect_changes()` confirms changes match expected scope
|
|
70
|
+
4. All d=1 (WILL BREAK) dependents were updated
|
|
71
|
+
|
|
72
|
+
## Keeping the Index Fresh
|
|
73
|
+
|
|
74
|
+
After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx gitnexus analyze
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If the index previously included embeddings, preserve them by adding `--embeddings`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx gitnexus analyze --embeddings
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.**
|
|
87
|
+
|
|
88
|
+
> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`.
|
|
89
|
+
|
|
90
|
+
## CLI
|
|
91
|
+
|
|
92
|
+
| Task | Read this skill file |
|
|
93
|
+
|------|---------------------|
|
|
94
|
+
| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` |
|
|
95
|
+
| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` |
|
|
96
|
+
| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` |
|
|
97
|
+
| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` |
|
|
98
|
+
| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` |
|
|
99
|
+
| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` |
|
|
100
|
+
|
|
101
|
+
<!-- gitnexus:end -->
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# App Flow — Seam (Phase 0)
|
|
2
|
+
|
|
3
|
+
> Agent interaction flows. Written from the AI agent's perspective.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Flow 1: First-Time Setup (Developer)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Developer opens a new project
|
|
11
|
+
│
|
|
12
|
+
▼
|
|
13
|
+
$ seam init
|
|
14
|
+
│
|
|
15
|
+
├── Walks directory tree
|
|
16
|
+
├── Detects language per file (Python, TypeScript/JavaScript)
|
|
17
|
+
├── Parses each file with tree-sitter
|
|
18
|
+
├── Extracts: symbols (functions, classes, methods), edges (imports, calls)
|
|
19
|
+
├── Writes to .seam/seam.db (SQLite + FTS5)
|
|
20
|
+
└── Prints summary: "Indexed 847 files, 12,304 symbols in 8.3s"
|
|
21
|
+
│
|
|
22
|
+
▼
|
|
23
|
+
$ seam start
|
|
24
|
+
│
|
|
25
|
+
├── Starts file watcher (background daemon)
|
|
26
|
+
├── Starts MCP server (stdio transport)
|
|
27
|
+
└── MCP tools ready: seam_query, seam_context, seam_search
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Developer then adds to their Claude Code MCP config:**
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"seam": {
|
|
35
|
+
"command": "seam",
|
|
36
|
+
"args": ["start", "--stdio"],
|
|
37
|
+
"cwd": "/path/to/project"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Flow 2: Session Start (Agent)
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Agent receives task: "Add rate limiting to the API"
|
|
49
|
+
│
|
|
50
|
+
▼
|
|
51
|
+
Agent uses seam_query("rate limiting middleware")
|
|
52
|
+
│
|
|
53
|
+
├── FTS5 search: finds symbols named 'RateLimiter', 'throttle', etc.
|
|
54
|
+
├── Graph search: finds symbols in same cluster as 'middleware'
|
|
55
|
+
└── Returns: [{symbol, file, line, snippet, callers_count, callees_count}]
|
|
56
|
+
│
|
|
57
|
+
▼
|
|
58
|
+
Agent narrows to relevant symbol with seam_context("APIMiddleware")
|
|
59
|
+
│
|
|
60
|
+
├── Returns: callers (what calls this), callees (what this calls)
|
|
61
|
+
├── File location + line number
|
|
62
|
+
└── Docstring / comment if present
|
|
63
|
+
│
|
|
64
|
+
▼
|
|
65
|
+
Agent has full picture before reading a single file
|
|
66
|
+
Ready to implement without exploration tax
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Flow 3: File Change (Auto-Sync)
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Developer saves auth/middleware.py
|
|
75
|
+
│
|
|
76
|
+
▼
|
|
77
|
+
File watcher detects change (FSEvents/inotify)
|
|
78
|
+
│
|
|
79
|
+
▼
|
|
80
|
+
Debounce 500ms (coalesce rapid saves)
|
|
81
|
+
│
|
|
82
|
+
▼
|
|
83
|
+
Re-parse changed file with tree-sitter
|
|
84
|
+
│
|
|
85
|
+
├── Diff: which symbols added / removed / changed?
|
|
86
|
+
├── Update seam.db (delete old, insert new)
|
|
87
|
+
└── Update FTS5 index for changed symbols
|
|
88
|
+
│
|
|
89
|
+
▼
|
|
90
|
+
Index fresh — next seam_query returns updated results
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Flow 4: Finding a Symbol (Agent)
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Agent wants to understand how authentication works
|
|
99
|
+
│
|
|
100
|
+
▼
|
|
101
|
+
seam_search("authenticate login token")
|
|
102
|
+
│
|
|
103
|
+
└── Returns: top-10 FTS5 matches with snippets
|
|
104
|
+
[{symbol: "authenticate_user", file: "auth/service.py:47", snippet: "..."}]
|
|
105
|
+
│
|
|
106
|
+
▼
|
|
107
|
+
seam_context("authenticate_user")
|
|
108
|
+
│
|
|
109
|
+
└── Returns:
|
|
110
|
+
{
|
|
111
|
+
"symbol": "authenticate_user",
|
|
112
|
+
"file": "auth/service.py",
|
|
113
|
+
"line": 47,
|
|
114
|
+
"docstring": "Validates credentials and returns JWT token",
|
|
115
|
+
"callers": ["LoginHandler.post", "TestAuth.test_valid_login"],
|
|
116
|
+
"callees": ["hash_password", "create_token", "UserRepository.find_by_email"]
|
|
117
|
+
}
|
|
118
|
+
│
|
|
119
|
+
▼
|
|
120
|
+
Agent knows: WHERE it is, WHO calls it, WHAT it calls
|
|
121
|
+
No file reads needed to get this structural picture
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Flow 5: Status Check
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
$ seam status
|
|
130
|
+
│
|
|
131
|
+
└── Prints:
|
|
132
|
+
Project: /Users/jordi/projects/bach
|
|
133
|
+
Database: .seam/seam.db (14.2 MB)
|
|
134
|
+
Indexed: 2026-06-01 14:23:01 (3 minutes ago)
|
|
135
|
+
Files: 1,247 | Symbols: 18,432 | Edges: 41,209
|
|
136
|
+
Languages: Python (892 files), TypeScript (355 files)
|
|
137
|
+
Watcher: running (PID 84201)
|
|
138
|
+
Status: FRESH
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Error States
|
|
144
|
+
|
|
145
|
+
| State | User sees | What happens |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| Unsupported file type | Silently skipped | Added to .seam/ignored.log |
|
|
148
|
+
| Parse error (malformed file) | Warning in seam status | Skipped, rest of index proceeds |
|
|
149
|
+
| seam.db locked (concurrent write) | Retry with backoff | Automatic, transparent |
|
|
150
|
+
| File watcher loses connection | Warning + restart | Auto-restart with exponential backoff |
|
|
151
|
+
| Symbol not found | `{"results": [], "message": "No results for 'X'"}` | Empty results, not an error |
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# Backend Structure — Seam
|
|
2
|
+
|
|
3
|
+
> This is the authoritative module map. Every new file must fit this structure.
|
|
4
|
+
> Seam has no frontend. All code is in the `seam/` Python package.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Package Layout
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
seam/ ← Python package root
|
|
12
|
+
├── __init__.py ← Version + public API surface
|
|
13
|
+
├── config.py ← All settings (from env via os.getenv)
|
|
14
|
+
│ SEAM_LANGUAGE_MAP: .py→python, .ts/.tsx→typescript,
|
|
15
|
+
│ .js/.mjs/.cjs→javascript, .go→go, .rs→rust
|
|
16
|
+
│
|
|
17
|
+
├── cli/ ← CLI entry points (Typer)
|
|
18
|
+
│ ├── __init__.py
|
|
19
|
+
│ └── main.py ← app = typer.Typer(); init, start, status
|
|
20
|
+
│
|
|
21
|
+
├── analysis/ ← Read-only graph reasoning + community detection
|
|
22
|
+
│ ├── __init__.py
|
|
23
|
+
│ ├── clustering.py ← LEAF: pure-Python Louvain community detection
|
|
24
|
+
│ │ detect_communities(nodes, edges) → {name: cluster_id}
|
|
25
|
+
│ │ No SQLite, no I/O, no config. Deterministic.
|
|
26
|
+
│ └── cluster_naming.py ← LEAF: cluster label generation
|
|
27
|
+
│ deterministic_label(members) → str (always available)
|
|
28
|
+
│ label_cluster(members, naming_mode, ...) → (label, source)
|
|
29
|
+
│ Opt-in LLM path via stdlib urllib only. Never raises.
|
|
30
|
+
│
|
|
31
|
+
├── indexer/ ← Parse → extract → store pipeline
|
|
32
|
+
│ ├── __init__.py
|
|
33
|
+
│ ├── parser.py ← tree-sitter parsing per language
|
|
34
|
+
│ │ parse_python, parse_typescript, parse_javascript,
|
|
35
|
+
│ │ parse_go, parse_rust — all delegate to _parse()
|
|
36
|
+
│ ├── graph_common.py ← LEAF: shared TypedDicts, constants, helpers
|
|
37
|
+
│ │ Symbol, Edge, Comment, Confidence; _text, _node_name,
|
|
38
|
+
│ │ _make_symbol, _match_marker, _block_comment_lines,
|
|
39
|
+
│ │ _find_enclosing_function, _go_recv_type_name,
|
|
40
|
+
│ │ _rust_impl_type_name. Imports stdlib + tree_sitter only.
|
|
41
|
+
│ ├── graph_go_rust.py ← Go + Rust extractors (imports graph_common only)
|
|
42
|
+
│ │ _extract_symbols_go/rust, _extract_edges_go/rust,
|
|
43
|
+
│ │ _extract_comments_go/rust, doc-comment helpers
|
|
44
|
+
│ ├── graph.py ← Python + TypeScript dispatchers; re-exports public types
|
|
45
|
+
│ │ from graph_common; imports Go/Rust extractors from
|
|
46
|
+
│ │ graph_go_rust. Public API: extract_symbols, extract_edges,
|
|
47
|
+
│ │ extract_comments.
|
|
48
|
+
│ ├── pipeline.py ← Shared parse→extract→upsert path (CLI + watcher)
|
|
49
|
+
│ ├── cluster_index.py ← Clustering orchestration (indexer layer bridge)
|
|
50
|
+
│ │ index_clusters(conn, ...) → int (cluster count or -1)
|
|
51
|
+
│ │ Reads DB → detect_communities → label_cluster → writes
|
|
52
|
+
│ │ clusters table + symbols.cluster_id in one transaction.
|
|
53
|
+
│ │ Called by seam init only; watcher never calls this.
|
|
54
|
+
│ └── db.py ← SQLite write operations (schema + upsert)
|
|
55
|
+
│
|
|
56
|
+
├── watcher/ ← OS file watcher
|
|
57
|
+
│ ├── __init__.py
|
|
58
|
+
│ └── daemon.py ← watchdog EventHandler; debounced re-index
|
|
59
|
+
│
|
|
60
|
+
├── server/ ← MCP server
|
|
61
|
+
│ ├── __init__.py
|
|
62
|
+
│ ├── mcp.py ← MCP server setup (stdio transport)
|
|
63
|
+
│ └── tools.py ← seam_query, seam_context, seam_search implementations
|
|
64
|
+
│
|
|
65
|
+
└── query/ ← Query engine (read path)
|
|
66
|
+
├── __init__.py
|
|
67
|
+
├── engine.py ← FTS5 + graph traversal queries; context() enriched
|
|
68
|
+
│ with cluster_id, cluster_label, cluster_peers (Phase 2)
|
|
69
|
+
└── clusters.py ← Read-only cluster queries (Phase 2)
|
|
70
|
+
list_clusters(conn) → [{id, label, size}]
|
|
71
|
+
cluster_members(conn, id) → [{name, file, line, kind}]
|
|
72
|
+
cluster_peers(conn, symbol) → (id, label, peers) | None
|
|
73
|
+
Guards pre-v4 indexes (returns empty + one-time warning).
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Layer Rules (Import Hierarchy)
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
cli/ → server/ → analysis/ → query/ → indexer/db
|
|
82
|
+
↓ ↑
|
|
83
|
+
└─→ indexer/cluster_index → analysis/clustering + analysis/cluster_naming
|
|
84
|
+
↑
|
|
85
|
+
watcher/ → indexer/
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Within `indexer/`, the import order is strictly:
|
|
89
|
+
```
|
|
90
|
+
graph_common (leaf — stdlib + tree_sitter only)
|
|
91
|
+
↑ ↑
|
|
92
|
+
graph_go_rust graph.py (both import from graph_common; graph.py also imports graph_go_rust)
|
|
93
|
+
↑
|
|
94
|
+
graph.py (dispatchers + re-exports)
|
|
95
|
+
↑
|
|
96
|
+
pipeline.py
|
|
97
|
+
|
|
98
|
+
analysis/clustering (leaf — stdlib only, no seam imports)
|
|
99
|
+
analysis/cluster_naming (leaf — stdlib only, no seam imports)
|
|
100
|
+
↑
|
|
101
|
+
indexer/cluster_index (bridge: imports analysis + db)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Layer | Can import from | Cannot import from |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `cli/` | server, analysis, indexer, watcher, config | — |
|
|
107
|
+
| `server/` | analysis, query, config | cli, watcher |
|
|
108
|
+
| `analysis/` (non-clustering) | indexer.db, query, config | cli, server |
|
|
109
|
+
| `analysis/clustering` | stdlib only | any seam module (leaf) |
|
|
110
|
+
| `analysis/cluster_naming` | stdlib only | any seam module (leaf) |
|
|
111
|
+
| `indexer/cluster_index` | analysis.clustering, analysis.cluster_naming, indexer.db, config | cli, server, query, watcher |
|
|
112
|
+
| `query/` | indexer.db, config | cli, server, analysis, watcher |
|
|
113
|
+
| `indexer/pipeline` | indexer.db, indexer.graph, indexer.parser, config | cli, server, query, analysis, watcher |
|
|
114
|
+
| `indexer/graph` | graph_common, graph_go_rust, config | cli, server, query, analysis, watcher |
|
|
115
|
+
| `indexer/graph_go_rust` | graph_common only | graph.py or any other seam module |
|
|
116
|
+
| `indexer/graph_common` | stdlib, tree_sitter only | any seam module (leaf) |
|
|
117
|
+
| `indexer/parser` | config, tree_sitter grammars | any seam indexer sub-module |
|
|
118
|
+
| `indexer/db` | config | cli, server, query, analysis, watcher |
|
|
119
|
+
| `watcher/` | indexer, config | cli, server, query, analysis |
|
|
120
|
+
| `config` | stdlib only | anything in seam/ |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Module Responsibilities
|
|
125
|
+
|
|
126
|
+
### `seam/config.py`
|
|
127
|
+
- Reads all config from `os.getenv()` with defaults
|
|
128
|
+
- Exports: `SEAM_DB_PATH`, `SEAM_LOG_LEVEL`, `SEAM_DEBOUNCE_MS`, `SEAM_MAX_FILE_BYTES`,
|
|
129
|
+
`SEAM_CLUSTER_NAMING`, `SEAM_LLM_API_KEY`, `SEAM_LLM_MODEL`, `SEAM_CLUSTER_MIN_SIZE`
|
|
130
|
+
- Never import from other seam modules (avoids circular imports)
|
|
131
|
+
|
|
132
|
+
### `seam/analysis/clustering.py` (leaf — Phase 2)
|
|
133
|
+
- `detect_communities(nodes, edges) → dict[str, int]` — pure Louvain community detection
|
|
134
|
+
- No SQLite, no file I/O, no config. Input: node names + edge pairs. Output: {name: cluster_id}.
|
|
135
|
+
- Deterministic: nodes processed in sorted order, tie-breaking by community label.
|
|
136
|
+
- Never raises: falls back to singleton clusters on any internal error.
|
|
137
|
+
|
|
138
|
+
### `seam/analysis/cluster_naming.py` (leaf — Phase 2)
|
|
139
|
+
- `deterministic_label(members) → str` — derive label from dominant dir + highest-degree symbol
|
|
140
|
+
- `label_cluster(members, naming_mode, api_key, model) → (label, naming_source)` — dispatch
|
|
141
|
+
- Opt-in LLM path (`_call_llm_for_label`) uses stdlib urllib only, is isolated, and is
|
|
142
|
+
never called unless `naming_mode="llm"` AND `api_key` is set.
|
|
143
|
+
- Any LLM error falls back to deterministic silently — never raises.
|
|
144
|
+
|
|
145
|
+
### `seam/indexer/cluster_index.py` (Phase 2)
|
|
146
|
+
- `index_clusters(conn, naming_mode, llm_api_key, llm_model, min_size) → int`
|
|
147
|
+
— orchestrates: read symbols+edges → detect_communities → label_cluster → write DB
|
|
148
|
+
- Returns cluster count (≥0) or -1 on error (never raises).
|
|
149
|
+
- Called by `seam init` ONLY, never by the watcher.
|
|
150
|
+
- Clears old cluster state first (even before early returns) to avoid ghost clusters.
|
|
151
|
+
|
|
152
|
+
### `seam/indexer/parser.py`
|
|
153
|
+
- One function per language: `parse_python`, `parse_typescript`, `parse_javascript`,
|
|
154
|
+
`parse_go`, `parse_rust` — all delegate to the internal `_parse(path, language)` helper.
|
|
155
|
+
- Returns raw tree-sitter root Node for graph.py to interpret.
|
|
156
|
+
- Handles encoding, binary files, and parse errors gracefully. Never raises.
|
|
157
|
+
|
|
158
|
+
### `seam/indexer/graph_common.py` (leaf — Phase 1b addition)
|
|
159
|
+
- Shared TypedDicts: `Symbol`, `Edge`, `Comment`; type alias: `Confidence`
|
|
160
|
+
- Shared constants: `SEMANTIC_MARKERS`, `_MARKER_RE`
|
|
161
|
+
- Shared helpers: `_text`, `_node_name`, `_make_symbol`, `_match_marker`,
|
|
162
|
+
`_block_comment_lines`, `_arrow_function_name`, `_find_enclosing_function`
|
|
163
|
+
- Go/Rust receiver helpers: `_go_recv_type_name`, `_rust_impl_type_name`
|
|
164
|
+
(kept here so `_find_enclosing_function` can call them without importing from
|
|
165
|
+
graph_go_rust — this is what maintains the leaf property)
|
|
166
|
+
- MUST remain a leaf: imports stdlib and tree_sitter only.
|
|
167
|
+
|
|
168
|
+
### `seam/indexer/graph_go_rust.py` (Phase 1b addition)
|
|
169
|
+
- Go extractors: `_extract_symbols_go`, `_extract_edges_go`, `_extract_comments_go`
|
|
170
|
+
- Rust extractors: `_extract_symbols_rust`, `_extract_edges_rust`, `_extract_comments_rust`
|
|
171
|
+
- Doc-comment helpers: `_go_doc_comment`, `_rust_doc_comment`
|
|
172
|
+
- Imports from `graph_common` only — never from `graph.py`.
|
|
173
|
+
|
|
174
|
+
### `seam/indexer/graph.py`
|
|
175
|
+
- Public API: `extract_symbols(node, language, filepath) → list[Symbol]`
|
|
176
|
+
- Public API: `extract_edges(node, language, filepath, symbols) → list[Edge]`
|
|
177
|
+
- Public API: `extract_comments(node, language, filepath) → list[Comment]`
|
|
178
|
+
- Python + TypeScript/JavaScript extractors live here.
|
|
179
|
+
- Go + Rust extractors are delegated to graph_go_rust.py (imported at top level).
|
|
180
|
+
- Re-exports `Symbol`, `Edge`, `Comment`, `Confidence` from graph_common so callers
|
|
181
|
+
using `from seam.indexer.graph import Symbol` continue to work unchanged.
|
|
182
|
+
- Symbol: `{name, kind, file, start_line, end_line, docstring}`
|
|
183
|
+
- Edge: `{source, target, kind, file, line, confidence}`
|
|
184
|
+
|
|
185
|
+
### `seam/indexer/db.py`
|
|
186
|
+
- `init_db(db_path) → Connection` — create schema if not exists
|
|
187
|
+
- `upsert_file(conn, filepath, symbols, edges)` — atomic file update
|
|
188
|
+
- `delete_file(conn, filepath)` — remove all data for a file
|
|
189
|
+
- Never holds long-lived connections; pass conn as parameter
|
|
190
|
+
|
|
191
|
+
### `seam/query/engine.py`
|
|
192
|
+
- `query(conn, concept, limit) → list[QueryResult]` — FTS5 + graph hybrid
|
|
193
|
+
- `context(conn, symbol_name) → ContextResult` — callers + callees + metadata +
|
|
194
|
+
cluster_id, cluster_label, cluster_peers (Phase 2 enrichment via query/clusters.py)
|
|
195
|
+
- `search(conn, text, limit) → list[SearchResult]` — FTS5 full-text
|
|
196
|
+
|
|
197
|
+
### `seam/query/clusters.py` (Phase 2)
|
|
198
|
+
- `list_clusters(conn) → list[ClusterRow]` — all clusters sorted by id
|
|
199
|
+
- `cluster_members(conn, cluster_id) → list[MemberRow]` — symbols in one cluster
|
|
200
|
+
- `cluster_peers(conn, symbol) → (cluster_id, label, peers) | None` — cluster context
|
|
201
|
+
- Guards pre-v4 indexes (no table/column): returns empty results + one-time warning.
|
|
202
|
+
Mirrors the `_comments_table_exists` guard in `query/comments.py`.
|
|
203
|
+
|
|
204
|
+
### `seam/server/tools.py`
|
|
205
|
+
- Thin adapter: MCP tool handlers that call query.engine functions
|
|
206
|
+
- Input validation only — no business logic
|
|
207
|
+
- Returns MCP-compatible response format
|
|
208
|
+
|
|
209
|
+
### `seam/watcher/daemon.py`
|
|
210
|
+
- `SeamWatcher(db_path, root_path)` — watchdog EventHandler subclass
|
|
211
|
+
- `on_modified(event)` — debounced re-index of changed file
|
|
212
|
+
- `start()` / `stop()` — manage Observer lifecycle
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## File Naming Conventions
|
|
217
|
+
|
|
218
|
+
| Type | Convention | Example |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| Python files | snake_case | `user_service.py` |
|
|
221
|
+
| Python classes | PascalCase | `SeamWatcher` |
|
|
222
|
+
| Python functions | snake_case | `extract_symbols()` |
|
|
223
|
+
| Python constants | UPPER_SNAKE_CASE | `SEAM_DB_PATH` |
|
|
224
|
+
| Test files | `test_<module>.py` | `test_parser.py` |
|
|
225
|
+
| Test classes | `Test<Feature>` | `TestPythonParser` |
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Tests Layout
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
tests/
|
|
233
|
+
├── unit/ ← Pure function tests; no I/O
|
|
234
|
+
│ ├── test_parser.py ← parse_python, parse_typescript
|
|
235
|
+
│ ├── test_graph.py ← extract_symbols, extract_edges
|
|
236
|
+
│ └── test_query_engine.py ← query, context, search (in-memory SQLite)
|
|
237
|
+
│
|
|
238
|
+
├── integration/ ← Tests that hit real SQLite + file system
|
|
239
|
+
│ ├── test_indexer.py ← Full index pipeline
|
|
240
|
+
│ └── test_watcher.py ← Watcher → re-index cycle
|
|
241
|
+
│
|
|
242
|
+
└── fixtures/ ← Sample source files for parser tests
|
|
243
|
+
├── sample.py ← Python with functions, classes, imports
|
|
244
|
+
└── sample.ts ← TypeScript with functions, interfaces
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Max Size Rules
|
|
250
|
+
|
|
251
|
+
- Max 200 lines per function (from global CLAUDE.md)
|
|
252
|
+
- Max 1000 lines per file (from global CLAUDE.md)
|
|
253
|
+
- If a module exceeds 1000 lines, split into `_module_part_a.py` + `_module_part_b.py` and re-export from `module.py`
|