scip-cli 2.4.0__tar.gz → 2.6.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.
Files changed (154) hide show
  1. scip_cli-2.6.0/.agents/commands/migration-problems.md +82 -0
  2. {scip_cli-2.4.0/.cursor → scip_cli-2.6.0/.agents}/rules/agent.mdc +111 -69
  3. scip_cli-2.6.0/.github/workflows/ci.yml +45 -0
  4. {scip_cli-2.4.0 → scip_cli-2.6.0}/.gitignore +2 -2
  5. {scip_cli-2.4.0 → scip_cli-2.6.0}/.pre-commit-config.yaml +1 -0
  6. scip_cli-2.6.0/AGENTS.md +1 -0
  7. {scip_cli-2.4.0 → scip_cli-2.6.0}/CODE_OF_CONDUCT.md +1 -1
  8. {scip_cli-2.4.0 → scip_cli-2.6.0}/PKG-INFO +56 -23
  9. {scip_cli-2.4.0 → scip_cli-2.6.0}/README.md +55 -22
  10. {scip_cli-2.4.0 → scip_cli-2.6.0}/SECURITY.md +5 -5
  11. scip_cli-2.6.0/docs/port.md +80 -0
  12. scip_cli-2.6.0/docs/ports/conclusions.md +424 -0
  13. scip_cli-2.6.0/docs/ports/experiment-summary.md +257 -0
  14. scip_cli-2.6.0/docs/ports/go-experiment.md +252 -0
  15. scip_cli-2.6.0/docs/ports/go.md +203 -0
  16. scip_cli-2.6.0/docs/ports/plan.md +161 -0
  17. scip_cli-2.6.0/docs/ports/rust-experiment.md +324 -0
  18. scip_cli-2.6.0/docs/ports/rust.md +264 -0
  19. scip_cli-2.6.0/docs/ports/summary.md +118 -0
  20. scip_cli-2.6.0/docs/ports/zig-experiment.md +333 -0
  21. scip_cli-2.6.0/docs/ports/zig.md +283 -0
  22. {scip_cli-2.4.0 → scip_cli-2.6.0}/pyproject.toml +1 -3
  23. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/SKILL.md +37 -28
  24. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/__init__.py +1 -1
  25. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/__main__.py +21 -0
  26. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/file.py +0 -10
  27. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/graph.py +34 -24
  28. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/live.py +15 -0
  29. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/project.py +8 -1
  30. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/deps.py +6 -5
  31. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/reindex.py +32 -4
  32. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/search.py +78 -72
  33. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/symbols.py +30 -0
  34. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/discover.py +53 -5
  35. scip_cli-2.6.0/scip_cli/indexing/__init__.py +30 -0
  36. scip_cli-2.6.0/scip_cli/indexing/constants.py +13 -0
  37. scip_cli-2.6.0/scip_cli/indexing/convert.py +94 -0
  38. scip_cli-2.6.0/scip_cli/indexing/core.py +210 -0
  39. scip_cli-2.6.0/scip_cli/indexing/languages.py +85 -0
  40. scip_cli-2.6.0/scip_cli/indexing/orchestrate.py +174 -0
  41. scip_cli-2.6.0/scip_cli/indexing/postprocess.py +152 -0
  42. scip_cli-2.6.0/scip_cli/indexing/runners.py +116 -0
  43. scip_cli-2.6.0/scip_cli/indexing/typescript.py +197 -0
  44. scip_cli-2.6.0/scip_cli/merge.py +168 -0
  45. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/project.py +6 -0
  46. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/scip_tool.py +5 -1
  47. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/scope.py +1 -1
  48. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/source.py +1 -1
  49. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/sql.py +10 -1
  50. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/targets.py +1 -1
  51. scip_cli-2.6.0/scip_cli/tsconfig.py +226 -0
  52. scip_cli-2.6.0/scripts/bench.sh +60 -0
  53. scip_cli-2.6.0/scripts/bench_postprocess.py +238 -0
  54. {scip_cli-2.4.0 → scip_cli-2.6.0}/scripts/publish.sh +32 -2
  55. scip_cli-2.6.0/scripts/test.sh +29 -0
  56. scip_cli-2.6.0/tests/bench_db.py +261 -0
  57. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/conftest.py +1 -1
  58. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/e2e_harness.py +1 -1
  59. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/fixture_catalog.py +5 -1
  60. scip_cli-2.6.0/tests/fixtures/typescript-project/src/helper.ts +23 -0
  61. scip_cli-2.6.0/tests/fixtures/typescript-project/src/lib/handler.ts +3 -0
  62. scip_cli-2.6.0/tests/fixtures/typescript-project/src/models/MutationAggregate.ts +32 -0
  63. scip_cli-2.6.0/tests/test_bench_queries.py +124 -0
  64. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_discover.py +72 -0
  65. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_e2e.py +90 -0
  66. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_e2e_analyze_patterns.py +1 -1
  67. scip_cli-2.6.0/tests/test_index_batching.py +75 -0
  68. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_index_prune.py +40 -3
  69. scip_cli-2.6.0/tests/test_indexer_fallback.py +315 -0
  70. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_merge.py +36 -0
  71. scip_cli-2.6.0/tests/test_python_index_integration.py +88 -0
  72. scip_cli-2.6.0/tests/test_reindex.py +128 -0
  73. scip_cli-2.6.0/tests/test_symbols_freq.py +107 -0
  74. scip_cli-2.6.0/tests/test_tsconfig.py +137 -0
  75. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_typescript_projects.py +10 -0
  76. scip_cli-2.4.0/scip_cli/indexing.py +0 -522
  77. scip_cli-2.4.0/scip_cli/merge.py +0 -108
  78. scip_cli-2.4.0/scripts/test.sh +0 -12
  79. scip_cli-2.4.0/tests/fixtures/sample-project/src/helper.ts +0 -7
  80. scip_cli-2.4.0/tests/test_reindex.py +0 -67
  81. {scip_cli-2.4.0 → scip_cli-2.6.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  82. {scip_cli-2.4.0 → scip_cli-2.6.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  83. {scip_cli-2.4.0 → scip_cli-2.6.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  84. {scip_cli-2.4.0 → scip_cli-2.6.0}/.github/pull_request_template.md +0 -0
  85. {scip_cli-2.4.0 → scip_cli-2.6.0}/CONTRIBUTING.md +0 -0
  86. {scip_cli-2.4.0 → scip_cli-2.6.0}/LICENSE +0 -0
  87. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/__init__.py +0 -0
  88. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/common.py +0 -0
  89. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/sections.py +0 -0
  90. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/symbol.py +0 -0
  91. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/analyze/targets.py +0 -0
  92. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/cache.py +0 -0
  93. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/cli_args.py +0 -0
  94. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/__init__.py +0 -0
  95. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/analyze.py +0 -0
  96. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/code.py +0 -0
  97. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/members.py +0 -0
  98. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/rdeps.py +0 -0
  99. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/refs.py +0 -0
  100. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/commands/skill.py +0 -0
  101. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/config.py +0 -0
  102. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/debug.py +0 -0
  103. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/output.py +0 -0
  104. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/paths.py +0 -0
  105. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/queries.py +0 -0
  106. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/session.py +0 -0
  107. {scip_cli-2.4.0 → scip_cli-2.6.0}/scip_cli/symbols.py +0 -0
  108. {scip_cli-2.4.0 → scip_cli-2.6.0}/scripts/build.sh +0 -0
  109. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/__init__.py +0 -0
  110. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/analyze_db.py +0 -0
  111. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/package.json +0 -0
  112. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/app/handler.ts +0 -0
  113. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/config.ts +0 -0
  114. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/consumer.ts +0 -0
  115. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/dead.ts +0 -0
  116. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/i18n/en.ts +0 -0
  117. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/i18n/index.ts +0 -0
  118. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/i18n/useLocale.ts +0 -0
  119. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/labels/index.ts +0 -0
  120. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/events/streamTypes.ts +0 -0
  121. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/gateway/index.ts +0 -0
  122. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/hooks/useHookA.ts +0 -0
  123. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/hooks/useHookB.ts +0 -0
  124. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/hooks/useItems.ts +0 -0
  125. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/index.ts +0 -0
  126. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/integrations/inferenceClient.ts +0 -0
  127. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/loaders/useInference.ts +0 -0
  128. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/pages/panelPage.ts +0 -0
  129. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/rules/applyRule.ts +0 -0
  130. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/types/a.ts +0 -0
  131. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/types/b.ts +0 -0
  132. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/Button.ts +0 -0
  133. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/LazyPanel.ts +0 -0
  134. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/buttonConsumer.ts +0 -0
  135. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/menuModule.ts +0 -0
  136. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/user.ts +0 -0
  137. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/widget.ts +0 -0
  138. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/widgets/OrphanWidget.ts +0 -0
  139. {scip_cli-2.4.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/tsconfig.json +0 -0
  140. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/perf_util.py +0 -0
  141. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_analyze.py +0 -0
  142. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_analyze_graph.py +0 -0
  143. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_analyze_perf.py +0 -0
  144. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_cache.py +0 -0
  145. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_composability.py +0 -0
  146. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_config.py +0 -0
  147. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_e2e_perf.py +0 -0
  148. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_indexer_env.py +0 -0
  149. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_multi_symbol.py +0 -0
  150. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_pure_functions.py +0 -0
  151. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_qualified_symbols.py +0 -0
  152. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_scip_tool.py +0 -0
  153. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_scope.py +0 -0
  154. {scip_cli-2.4.0 → scip_cli-2.6.0}/tests/test_targets.py +0 -0
@@ -0,0 +1,82 @@
1
+ # Document migration problems
2
+
3
+ Review this session (and any ports you just touched) and append **only** language / tooling walls to `migration-problems.md`.
4
+
5
+ ## Where to write
6
+
7
+ | Repo | File |
8
+ |------|------|
9
+ | `scip-cli-go` | `migration-problems.md` |
10
+ | `scip-cli-rust` | `migration-problems.md` |
11
+ | `scip-cli-zig` | `migration-problems.md` |
12
+ | `scip-cli` (Python) | Usually **none** — Python is the reference, not a port. Only add a note if the user asks. |
13
+
14
+ If the workspace is one of the ports, edit that repo’s file. If several ports were touched, update each relevant file. Match existing numbering and section style in that file.
15
+
16
+ Do **not** invent entries from first principles — only document walls you (or a subagent) actually hit in this work.
17
+
18
+ ---
19
+
20
+ ## Why this file exists
21
+
22
+ These repos are an experiment: **which language is better for AI to code in?**
23
+
24
+ `migration-problems.md` is evidence for that question. A reader should learn something about the **language, compiler, stdlib, or ecosystem tooling** — not about scip-cli product bugs or “we forgot a branch.”
25
+
26
+ Ask before writing:
27
+
28
+ > *If we ported a different CLI tomorrow, would this entry still teach something about coding in this language with an AI?*
29
+
30
+ If **no** → do not add it.
31
+
32
+ ---
33
+
34
+ ## What TO put (include)
35
+
36
+ Fundamental friction that slows or confuses an AI agent because of the **language or its tools**:
37
+
38
+ | Category | Examples |
39
+ |----------|----------|
40
+ | **Compiler / type system** | Borrow checker traps; Zig shadowing rules; Go’s `module/v2` path rules; errors that force many tiny fix loops |
41
+ | **Stdlib / API drift** | Zig 0.17 removed `std.fs.cwd`; training data assumes older APIs; crate APIs that don’t match Python intuition (`regex` no lookbehind) |
42
+ | **Tooling loop cost** | Full `zig build -Doptimize=ReleaseFast` ~25s+ → fewer AI iterations; `gofmt`/`cargo fmt` rewrite every commit; clippy/rustc so strict the agent flails for N cycles |
43
+ | **Ecosystem surprises** | CGO vs pure-Go SQLite; `anyhow::bail!` prefixes user errors; package name vs import path traps |
44
+ | **Agent × language interaction** | Persistent shell + language-specific env scripts hanging; test runners with no skip → vacuously green |
45
+
46
+ Entry shape (adapt to the file’s existing voice):
47
+
48
+ - **Symptom** — what the agent saw (compile error, hang, parity fail)
49
+ - **Cause** — language/tooling root cause (not “we missed a line of business logic”)
50
+ - **Lesson** — what an AI (or human) should remember next time in this language
51
+ - Optional: time sink / iteration count if it was large
52
+
53
+ Prefer **one sharp entry** over a dump of every compile error.
54
+
55
+ ---
56
+
57
+ ## What NOT to put (exclude)
58
+
59
+ | Do not document | Why |
60
+ |-----------------|-----|
61
+ | Product / logic bugs (“search printed duplicates”, “forgot DER fallback”) | Same bug in any language; says nothing about Go vs Rust vs Zig |
62
+ | “We forgot to port X” / incomplete ports | Process failure, not language |
63
+ | TODOs, wishlists, backlog | Wrong file (`todo.md` / docs) |
64
+ | One-off typos, wrong SQL, missed edge cases in *our* code | Not language-fundamental |
65
+ | Parity mismatches that are just divergent implementations | Unless caused by a real language constraint |
66
+ | Generic “AI made a mistake” | Only if the language *systematically* induces that mistake (e.g. trained on old Zig stdlib) |
67
+
68
+ **Litmus test:** Removing scip-cli from the story — does the entry still make sense?
69
+ - ✅ “Zig ReleaseFast builds dominate the edit–compile loop”
70
+ - ❌ “Search must dedupe Prisma typeLiterals by file:line”
71
+
72
+ ---
73
+
74
+ ## How to run this command
75
+
76
+ 1. Skim the conversation / diffs for walls that burned time.
77
+ 2. Open the target `migration-problems.md`; read the last few entries so style and numbers match.
78
+ 3. For each candidate, apply the litmus test. Drop application-logic noise.
79
+ 4. Append new entries (or fix an existing entry if you previously wrote the wrong *kind* of note).
80
+ 5. Do **not** commit unless the user asks. Briefly tell the user what you added (or that nothing qualified).
81
+
82
+ If nothing in the session qualifies, say so — **empty is better than polluting the experiment.**
@@ -28,15 +28,18 @@ Node.js + `npx` required for integration tests (`scip-typescript`). Optional: `S
28
28
 
29
29
  ## Lint / test
30
30
 
31
- | Task | Command |
32
- |------|---------|
33
- | Full suite | `pytest` |
34
- | E2e loop | `pytest tests/test_e2e.py tests/test_e2e_analyze_patterns.py` |
35
- | Lint / format | `ruff check .` / `ruff format .` |
36
- | Typecheck | `basedpyright scip_cli/` |
31
+ |Task|Command|
32
+ |---|---|
33
+ |**All checks**|`scripts/test.sh` (lint + format + types + tests)|
34
+ |Full suite|`pytest`|
35
+ |E2e loop|`pytest tests/test_e2e.py tests/test_e2e_analyze_patterns.py`|
36
+ |Lint / format|`ruff check .` / `ruff format .`|
37
+ |Typecheck|`basedpyright scip_cli/`|
37
38
 
38
39
  Pre-commit: ruff + ruff-format + basedpyright + full pytest. E2e before commit on command changes.
39
40
 
41
+ **Use `scripts/test.sh`** before committing to catch all issues (lint, format, types, tests). This matches what pre-commit runs.
42
+
40
43
  ## Improving this repo (do this before review subagents)
41
44
 
42
45
  **Dogfood on the repo itself** — faster and more honest than spawning reviewers:
@@ -51,12 +54,12 @@ scip-cli analyze scip_cli/queries.py --limit 20 # file (+ scoped project)
51
54
 
52
55
  Interpretation: README § *Finding easy wins with analyze*. Target = omit (project), directory, file, or symbol — not `--path` for scope.
53
56
 
54
- | Priority | Section | Action |
55
- |----------|---------|--------|
56
- | 1 | **Cycles** | Break production file dependency cycles (`cache`↔`scope` was one) |
57
- | 2 | **Unreferenced / dead exports** | No ref usage / no external refs — verify with `rg`, delete or `_` prefix |
58
- | 3 | **Same-file only** | Module-private by usage — rename to `_` |
59
- | 4 | **Stale types** | Low-consumer classes — merge or justify |
57
+ |Priority|Section|Action|
58
+ |---|---|---|
59
+ |1|**Cycles**|Break production file dependency cycles (`cache`↔`scope` was one)|
60
+ |2|**Unreferenced / dead exports**|No ref usage / no external refs — verify with `rg`, delete or `_` prefix|
61
+ |3|**Same-file only**|Module-private by usage — rename to `_`|
62
+ |4|**Stale types**|Low-consumer classes — merge or justify|
60
63
 
61
64
  `analyze` skips test paths by default (`tests/`, `*.test.*`, `*.spec.*`); `--include-tests` to include. Reindex after large edits.
62
65
 
@@ -79,19 +82,19 @@ Only skip step 1 when the issue is **outside the index** (runtime, CLI UX, docs
79
82
 
80
83
  ### Retrospective: caught manually, SQLite already had it
81
84
 
82
- | Issue we hit | Index signal | Analyze today | Gap / next check |
83
- |--------------|--------------|---------------|------------------|
84
- | `cache` ↔ `scope` import cycle | cross-file `mentions` edges | `[high] Cycles` | **Caught** — keep dogfooding cycles |
85
- | Cross-file dead export (`get_refs_for_symbols`) | def with no external `mentions` | `[high] Dead exports` | **Caught** |
86
- | Same-file-only dead code | def, `role=0` only in def file | `[high] Unreferenced` or `[medium] Same-file only` | **Caught** (since extended) |
87
- | Same-file helper without `_` (`run_with_fallback`) | same-file `role=0` or none | `[medium] Same-file only` / unreferenced | **Caught** — rename to `_` |
88
- | Typing-only dataclasses (`ProjectSettings`, `IndexScope`) | type `#` symbol, 0 consumer files | `[high] Stale types` + `stale_type_noise` | **Filtered** — index can't see annotations; document or optional `--types` |
89
- | `analyze/*` section runners “dead” | no external refs | noise filter in `common.py` | **Filtered** — framework pattern |
90
- | Unused import | `role=2` mention, no in-file use | `[high] Unused imports` (per file) | **Caught** on file target |
91
- | Hub before editing (`resolve_symbol`, `queries.py`) | fan-in / consumer count | `[medium] Change surface` / `[low] Hotspots` | **Caught** on file target; project hubs are low tier |
92
- | Symbol only used from tests | consumers all under `tests/` | `[low] Test-only consumers` | **Partial** — Python index often omits same-file `role=0`; verify with `rg` |
93
- | Indexer omits same-file Python calls | no `role=0` for in-module use | unreferenced / test-only false positives | **Index gap** — not fixable in SQL alone; demoted test-only to low |
94
- | Duplicate / parallel helpers | — | — | **Not in index** — `rg`, not analyze |
85
+ |Issue we hit|Index signal|Analyze today|Gap / next check|
86
+ |---|---|---|---|
87
+ |`cache` ↔ `scope` import cycle|cross-file `mentions` edges|`[high] Cycles`|**Caught** — keep dogfooding cycles|
88
+ |Cross-file dead export (`get_refs_for_symbols`)|def with no external `mentions`|`[high] Dead exports`|**Caught**|
89
+ |Same-file-only dead code|def, `role=0` only in def file|`[high] Unreferenced` or `[medium] Same-file only`|**Caught** (since extended)|
90
+ |Same-file helper without `_` (`run_with_fallback`)|same-file `role=0` or none|`[medium] Same-file only` / unreferenced|**Caught** — rename to `_`|
91
+ |Typing-only dataclasses (`ProjectSettings`, `IndexScope`)|type `#` symbol, 0 consumer files|`[high] Stale types` + `stale_type_noise`|**Filtered** — index can't see annotations; document or optional `--types`|
92
+ |`analyze/*` section runners “dead”|no external refs|noise filter in `common.py`|**Filtered** — framework pattern|
93
+ |Unused import|`role=2` mention, no in-file use|`[high] Unused imports` (per file)|**Caught** on file target|
94
+ |Hub before editing (`resolve_symbol`, `queries.py`)|fan-in / consumer count|`[medium] Change surface` / `[low] Hotspots`|**Caught** on file target; project hubs are low tier|
95
+ |Symbol only used from tests|consumers all under `tests/`|`[low] Test-only consumers`|**Partial** — Python index often omits same-file `role=0`; verify with `rg`|
96
+ |Indexer omits same-file Python calls|no `role=0` for in-module use|unreferenced / test-only false positives|**Index gap** — not fixable in SQL alone; demoted test-only to low|
97
+ |Duplicate / parallel helpers|—|—|**Not in index** — `rg`, not analyze|
95
98
 
96
99
  Add new rows to `dogfood.md` when you find another gap; implement the SQL check before the next manual review pass.
97
100
 
@@ -99,15 +102,15 @@ Add new rows to `dogfood.md` when you find another gap; implement the SQL check
99
102
 
100
103
  SQLite has **line ranges** (`defn_enclosing_ranges`) so LOC is cheap. That does **not** mean “big function” belongs next to dead exports.
101
104
 
102
- | Idea | In index? | Verdict |
103
- |------|-----------|---------|
104
- | **LOC ≥ N** alone | Yes | **LOW at best** — noisy (`main`, argparse, legitimate parsers). Not a nuke candidate. |
105
- | **LOC + fan-in** (large hub) | Yes | **Already covered** by `[low] Bottlenecks` (fan-in × fan-out). Add `loc=` to that output if helpful; don’t duplicate as medium. |
106
- | **LOC + consumers** on file target | Yes | **Change surface** (medium) already sorts by consumers with line ranges — drill there. |
107
- | **Symbol pressure** | Yes | **Per-symbol** `analyze Foo` shows `loc × fan_in × fan_out`. |
108
- | **God class / many members** | Yes | Use `members Class` — not analyze. |
109
- | **File byte size / cyclomatic complexity** | No | Out of scope for SCIP index. |
110
- | **Fat file (many symbols)** | Yes | Low value; coupling/hotspots approximate module heat. |
105
+ |Idea|In index?|Verdict|
106
+ |---|---|---|
107
+ |**LOC ≥ N** alone|Yes|**LOW at best** — noisy (`main`, argparse, legitimate parsers). Not a nuke candidate.|
108
+ |**LOC + fan-in** (large hub)|Yes|**Already covered** by `[low] Bottlenecks` (fan-in × fan-out). Add `loc=` to that output if helpful; don’t duplicate as medium.|
109
+ |**LOC + consumers** on file target|Yes|**Change surface** (medium) already sorts by consumers with line ranges — drill there.|
110
+ |**Symbol pressure**|Yes|**Per-symbol** `analyze Foo` shows `loc × fan_in × fan_out`.|
111
+ |**God class / many members**|Yes|Use `members Class` — not analyze.|
112
+ |**File byte size / cyclomatic complexity**|No|Out of scope for SCIP index.|
113
+ |**Fat file (many symbols)**|Yes|Low value; coupling/hotspots approximate module heat.|
111
114
 
112
115
  **Rule:** size-only checks stay **low or file-drill-down**; never high/medium unless paired with a **structural smell** (cycle, dead export, zero production consumers). Prefer enriching existing low-tier lines (e.g. show `loc` on bottlenecks) over a new dashboard section.
113
116
 
@@ -115,33 +118,55 @@ SQLite has **line ranges** (`defn_enclosing_ranges`) so LOC is cheap. That does
115
118
 
116
119
  The e2e fixture and this repo's own index are **small** — every query looks fast here. That hides blowups on real projects (40MB+ indexes, dense graphs).
117
120
 
118
- **Before merging new or heavily changed SQL** (`queries.py`, `analyze/*`):
119
-
120
- 1. Time it against **1–2 existing checks** on a **large cached index** you already have (not the fixture):
121
- ```bash
122
- python3 -u -c "
123
- import sqlite3, time, sys
124
- from pathlib import Path
125
- sys.path.insert(0, '.')
126
- from scip_cli.analyze import project as p
127
- from scip_cli.sql import configure_read_connection
128
- db_path = Path.home() / '.cache/scip-cli/projects/<project-slug>/index.db'
129
- db = sqlite3.connect(f'file:{db_path}?mode=ro', uri=True)
130
- configure_read_connection(db)
131
- for name, fn in [('hotspots', p.hotspots), ('cycles', p.cycles), ('dead_exports', p.dead_exports)]:
132
- t = time.perf_counter(); fn(db, limit=25); print(f'{name}: {(time.perf_counter()-t)*1000:.0f}ms')
133
- "
134
- ```
135
- 2. Flag anything **notably slower** than peers — orders of magnitude or multi-second, not a few ms drift.
136
- 3. Swap in your new/changed check for one of the rows; keep a fast peer (e.g. `hotspots`) and a heavy peer (e.g. `dead_exports`).
137
-
138
- **In CI:** `tests/test_e2e_perf.py` (whole commands) and `tests/test_analyze_perf.py` (per-check on mini DB) catch gross regressions on the tiny fixture only — they **will not** catch large-repo OOMs. Use the manual benchmark above for that.
121
+ ### Scaled :memory: benchmark (primary)
122
+
123
+ `tests/bench_db.py` generates a deterministic 1000-file / ~15K-symbol / ~100K-mention DB in `:memory:`. `tests/test_bench_queries.py` times all key queries on it.
124
+
125
+ **Before/after comparison flow:**
126
+
127
+ ```bash
128
+ # 1. Before changes — save baseline
129
+ scripts/bench.sh --baseline
130
+
131
+ # 2. Make your SQL/query changes
132
+
133
+ # 3. Compare — runs current, diffs against baseline
134
+ scripts/bench.sh --compare
135
+
136
+ # Or just run current without comparison
137
+ scripts/bench.sh
138
+ ```
139
+
140
+ Output per query: `BENCH:<name>:<elapsed_ms>`. The compare table shows ratio (>1.0 = regression, <1.0 = improvement).
141
+
142
+ **When to use:** Any change to `queries.py`, `analyze/*`, `symbols.py` SQL clauses, or `sql.py` pragmas. Run `scripts/bench.sh --compare` before committing.
143
+
144
+ ### Large cached index benchmark (secondary)
145
+
146
+ For queries that behave differently on real 40MB+ indexes vs the synthetic DB:
147
+
148
+ ```bash
149
+ python3 -u -c "
150
+ import sqlite3, time, sys
151
+ from pathlib import Path
152
+ sys.path.insert(0, '.')
153
+ from scip_cli.analyze import project as p
154
+ from scip_cli.sql import configure_read_connection
155
+ db_path = Path.home() / '.cache/scip-cli/projects/<project-slug>/index.db'
156
+ db = sqlite3.connect(f'file:{db_path}?mode=ro', uri=True)
157
+ configure_read_connection(db)
158
+ for name, fn in [('hotspots', p.hotspots), ('cycles', p.cycles), ('dead_exports', p.dead_exports)]:
159
+ t = time.perf_counter(); fn(db, limit=25); print(f'{name}: {(time.perf_counter()-t)*1000:.0f}ms')
160
+ "
161
+ ```
162
+
163
+ **In CI:** `tests/test_e2e_perf.py` (whole commands) and `tests/test_analyze_perf.py` (per-check on mini DB) catch gross regressions on the tiny fixture only — they **will not** catch large-repo OOMs. Use `scripts/bench.sh --compare` for that.
139
164
 
140
165
  ## TDD
141
166
 
142
167
  ### Default: extend the shared fixture
143
168
 
144
- **One indexed TS project** — `tests/fixtures/sample-project/` — indexed once per session via `indexed_fixture` (`conftest.py`). Stable names live in `tests/fixture_catalog.py`.
169
+ **One indexed TS project** — `tests/fixtures/typescript-project/` — indexed once per session via `indexed_fixture` (`conftest.py`). Stable names live in `tests/fixture_catalog.py`.
145
170
 
146
171
  1. **Red** — add a **minimal** `.ts` file (or tweak an existing one) that reproduces the SCIP shape; assert in `tests/test_e2e.py` or `tests/test_e2e_analyze_patterns.py` using `cli` / `open_index_db` + analyze helpers.
147
172
  2. **Green** — fix `scip_cli/` (commands, `analyze/*`, `queries.py`, …).
@@ -156,29 +181,29 @@ The e2e fixture and this repo's own index are **small** — every query looks fa
156
181
  When dogfooding **another repo** surfaces a bug or false positive (analyze noise, dead-export mistake, cycle, stale type, refs mismatch):
157
182
 
158
183
  1. **Capture the pattern, not the project** — note the SCIP shape (module `/`, export alias `foo0:`, lazy import, `Props#`, barrel cycle, …). Do **not** copy real repo names, paths, or filenames into tests or docs.
159
- 2. **Red on the fixture** — smallest TS repro under `tests/fixtures/sample-project/` with generic names (`LazyPanel`, `evictItem`, `OrphanWidget`, …). E2e test proves the bug against **real `scip-typescript`** output.
184
+ 2. **Red on the fixture** — smallest TS repro under `tests/fixtures/typescript-project/` with generic names (`LazyPanel`, `evictItem`, `OrphanWidget`, …). E2e test proves the bug against **real `scip-typescript`** output.
160
185
  3. **Green** — fix analyze heuristics / SQL / CLI; dogfood on this repo if applicable.
161
186
  4. **Verify** — `pytest tests/test_e2e_analyze_patterns.py` (or full `pytest`); only then trim redundant tests.
162
187
 
163
188
  **Prefer fixture e2e over fake SQLite graphs.** `tests/analyze_db.py` (`AnalyzeDbBuilder`, `:memory:`) is for SQL/dashboard **plumbing** and graph primitives (`test_analyze_graph.py`, `mini_codebase_db`) — not for reproducing production SCIP symbol shapes. Hand-built symbols often diverge from scip-typescript (path format, `0:` aliases, module rows) and can pass while production still breaks.
164
189
 
165
- | Use fixture e2e | Use `analyze_db` unit |
166
- |-----------------|----------------------|
167
- | False positives / analyze checks from real projects | Tarjan, edge-type SQL, `run_all` section wiring |
168
- | Any behavior that depends on indexer symbol strings | Noise filters with one or two synthetic rows |
169
- | CLI commands (`refs`, `search`, `analyze` output) | Merge/index prune tests |
190
+ |Use fixture e2e|Use `analyze_db` unit|
191
+ |---|---|
192
+ |False positives / analyze checks from real projects|Tarjan, edge-type SQL, `run_all` section wiring|
193
+ |Any behavior that depends on indexer symbol strings|Noise filters with one or two synthetic rows|
194
+ |CLI commands (`refs`, `search`, `analyze` output)|Merge/index prune tests|
170
195
 
171
196
  If both layers help during development, **keep both until e2e passes**, then delete duplicate in-memory repros — fixture is the source of truth.
172
197
 
173
198
  ## Codebase map (contributors)
174
199
 
175
- | Area | Path | Notes |
176
- |------|------|-------|
177
- | Commands | `scip_cli/commands/` | Thin; SQL in `queries.py` / `analyze/` |
178
- | Index build | `scip_cli/indexing.py` | `index.db.next` → promote; flock; `>10` tsconfigs log progress |
179
- | Variable prune | postprocess + `merge.py` | Omit const/let/var on **COPY**, not DELETE — no `variable` kind |
180
- | Session | `scip_cli/session.py` | `setup()`, `resolve_one_symbol` (limit 2 for ambiguity) |
181
- | Analyze filters | `scip_cli/analyze/common.py` | `is_test_path`, `analyze_noise` (`_` helpers) |
200
+ |Area|Path|Notes|
201
+ |---|---|---|
202
+ |Commands|`scip_cli/commands/`|Thin; SQL in `queries.py` / `analyze/`|
203
+ |Index build|`scip_cli/indexing.py`|`index.db.next` → promote; flock; `>10` tsconfigs log progress|
204
+ |Variable prune|postprocess + `merge.py`|Omit const/let/var on **COPY**, not DELETE — no `variable` kind|
205
+ |Session|`scip_cli/session.py`|`setup()`, `resolve_one_symbol` (limit 2 for ambiguity)|
206
+ |Analyze filters|`scip_cli/analyze/common.py`|`is_test_path`, `analyze_noise` (`_` helpers)|
182
207
 
183
208
  `todo.md` = tracked work; `dogfood.md` = future ideas only. Wishlist/backlog in `docs/` per workspace rules.
184
209
 
@@ -187,3 +212,20 @@ If both layers help during development, **keep both until e2e passes**, then del
187
212
  - User install + analyze guide → `README.md`
188
213
  - Agent/user CLI reference → `scip_cli/SKILL.md` (must match `__main__.py` flags)
189
214
  - After flag changes: update SKILL + README command list; run `scip-cli skill` to verify output
215
+
216
+
217
+ ## Dogfood Notes
218
+
219
+ Future improvements from using the CLI on real projects.
220
+
221
+ ### Workflow
222
+
223
+ Requires bare `scip-cli` mapped to local (`pip install -e ".[dev]"` from repo root).
224
+
225
+ ```bash
226
+ scip-cli reindex
227
+ scip-cli analyze --limit 25
228
+ scip-cli analyze scip_cli/queries.py --limit 20 # drill into hubs
229
+ ```
230
+
231
+ Project-wide analyze skips test paths by default; `--include-tests` to include. See README **Finding easy wins with analyze**.
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.10", "3.11", "3.12"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ id: setup_python
18
+ with:
19
+ python-version: ${{ matrix.python-version }}
20
+
21
+ - name: Restore cached virtualenv
22
+ uses: actions/cache/restore@v4
23
+ with:
24
+ key: venv-${{ runner.os }}-${{ steps.setup_python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
25
+ path: .venv
26
+
27
+ - name: Create venv and install dependencies
28
+ run: |
29
+ python -m venv .venv
30
+ source .venv/bin/activate
31
+ pip install -e ".[dev]"
32
+ npm install -g @sourcegraph/scip-typescript
33
+ mkdir -p ~/.local/bin
34
+ curl -sL https://github.com/scip-code/scip/releases/download/v0.9.0/scip-linux-amd64.tar.gz | tar xz -C ~/.local/bin
35
+ echo "$VIRTUAL_ENV/bin" >> $GITHUB_PATH
36
+ echo "VIRTUAL_ENV=$VIRTUAL_ENV" >> $GITHUB_ENV
37
+
38
+ - name: Save cached virtualenv
39
+ uses: actions/cache/save@v4
40
+ with:
41
+ key: venv-${{ runner.os }}-${{ steps.setup_python.outputs.python-version }}-${{ hashFiles('pyproject.toml') }}
42
+ path: .venv
43
+
44
+ - name: Run publish gate
45
+ run: ./scripts/test.sh
@@ -10,8 +10,6 @@ dist/
10
10
  downloads/
11
11
  eggs/
12
12
  .eggs/
13
- lib/
14
- lib64/
15
13
  parts/
16
14
  sdist/
17
15
  var/
@@ -19,6 +17,7 @@ wheels/
19
17
  *.egg-info/
20
18
  .installed.cfg
21
19
  *.egg
20
+ .ruff_cache/
22
21
 
23
22
  # Virtual environments
24
23
  venv/
@@ -51,3 +50,4 @@ dogfood.md
51
50
  # Local-only dev scripts (repo-specific smoke harnesses)
52
51
  scripts/deep-smoke.sh
53
52
  tmp/
53
+ *.db
@@ -15,5 +15,6 @@ repos:
15
15
  name: pytest
16
16
  entry: pytest
17
17
  language: python
18
+ additional_dependencies: [pytest>=7]
18
19
  pass_filenames: false
19
20
  always_run: true
@@ -0,0 +1 @@
1
+ .cursor/rules/agent.mdc
@@ -60,7 +60,7 @@ representative at an online or offline event.
60
60
 
61
61
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
62
  reported to the community leaders responsible for enforcement at
63
- ariel.flesler@gmail.com.
63
+ aflesler@gmail.com.
64
64
  All complaints will be reviewed and investigated promptly and fairly.
65
65
 
66
66
  All community leaders are obligated to respect the privacy and security of the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scip-cli
3
- Version: 2.4.0
3
+ Version: 2.6.0
4
4
  Summary: Fast code intelligence via SCIP indexes
5
5
  Project-URL: Homepage, https://github.com/flesler/scip-cli
6
6
  Author: Ariel Flesler
@@ -24,7 +24,7 @@ Description-Content-Type: text/markdown
24
24
  [![PyPI version](https://badge.fury.io/py/scip-cli.svg)](https://badge.fury.io/py/scip-cli)
25
25
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
26
26
 
27
- Token-efficient code intelligence for AI agents. Precise refs, definitions, and repo health analysis via SCIP indexes — TypeScript/JavaScript and Python.
27
+ Python CLI for AI agents. Queries SCIP indexes for precise refs, definitions, and repo health analysis — TypeScript/JavaScript, Python, Go, Rust.
28
28
 
29
29
  ## Why
30
30
 
@@ -38,6 +38,17 @@ AI agents waste tokens on grep and file scanning. scip-cli gives them precise, t
38
38
  - **`analyze`**: Find dead exports, import cycles, stale types, coupling hotspots — actionable health dashboards at project, file, or symbol scope
39
39
  - **Auto-indexing**: Indexes on first query, caches in SQLite, zero config
40
40
 
41
+ ## Ports
42
+
43
+ CLI/output parity ports of this project (Python is the reference):
44
+
45
+ | Language | Repository |
46
+ | ------------------ | ----------------------------------------------------------------- |
47
+ | Python (reference) | [flesler/scip-cli](https://github.com/flesler/scip-cli) |
48
+ | Go | [flesler/scip-cli-go](https://github.com/flesler/scip-cli-go) |
49
+ | Rust | [flesler/scip-cli-rust](https://github.com/flesler/scip-cli-rust) |
50
+ | Zig | [flesler/scip-cli-zig](https://github.com/flesler/scip-cli-zig) |
51
+
41
52
  ## For AI Agents
42
53
 
43
54
  Install as a reusable skill so your agent always knows how to navigate the codebase:
@@ -90,7 +101,7 @@ On **first index**, scip-cli runs language indexers and builds a SQLite cache. Y
90
101
 
91
102
  Install `scip-cli` and run it. On first index, scip-cli will:
92
103
 
93
- - Download `scip-typescript` / `scip-python` via `npx` when not already on PATH
104
+ - Download `scip-typescript` / `scip-python` via `npx`, `scip-go` via `go install`, or `rust-analyzer` via `rustup` when not already on PATH
94
105
  - Download the `scip` converter binary from [GitHub releases](https://github.com/scip-code/scip/releases) into `~/.cache/scip-cli/bin/` when not already on PATH
95
106
  - Walk the repo for `tsconfig*.json` project roots (TypeScript monorepos), run `scip-typescript` per project (parallel by default), convert each partial index, then merge into one `index.db`
96
107
 
@@ -107,6 +118,12 @@ npm install -g @sourcegraph/scip-typescript
107
118
  # Python indexer
108
119
  npm install -g @sourcegraph/scip-python
109
120
 
121
+ # Go indexer
122
+ go install github.com/scip-code/scip-go/cmd/scip-go@latest
123
+
124
+ # Rust indexer (rust-analyzer with SCIP support)
125
+ rustup component add rust-analyzer
126
+
110
127
  # SCIP CLI for index conversion (GitHub release — not on npm)
111
128
  # https://github.com/scip-code/scip/releases (v0.8.1+ recommended)
112
129
  ```
@@ -200,9 +217,9 @@ scip-cli deps greet --paths-only | sort -u
200
217
 
201
218
  ## How It Works
202
219
 
203
- 1. On first query, automatically detects project language from `package.json` (TS/JS) or `pyproject.toml`/`setup.py` (Python)
220
+ 1. On first query, automatically detects project language from `package.json` (TS/JS), `pyproject.toml`/`setup.py` (Python), `go.mod` (Go), or `Cargo.toml` (Rust)
204
221
  2. For TypeScript monorepos, walks the repository for `tsconfig*.json` project roots (nested ancestors deduped; root included only when its `include` is broad)
205
- 3. Runs `scip-typescript` per project (in parallel when there are multiple projects; set `SCIP_CLI_INDEX_WORKERS=1` to force serial), or `scip-python` for Python
222
+ 3. Runs `scip-typescript` per project (in parallel when there are multiple projects; set `SCIP_CLI_INDEX_WORKERS=1` to force serial), `scip-python` for Python, `scip-go` for Go, or `rust-analyzer scip` for Rust
206
223
  4. Converts each SCIP output to SQLite with `scip expt-convert`, then merges partial databases when needed
207
224
  5. Caches the result in `~/.cache/scip-cli/projects/<dirname>-<hash>/index.db` (e.g. `my-monorepo-1a3f7a`)
208
225
  6. Subsequent queries are SQLite lookups against that cache (not re-indexing)
@@ -219,11 +236,23 @@ Optional `.scip-cli.json` in the project root:
219
236
  }
220
237
  ```
221
238
 
222
- - `maxHeapMb` — Node heap for `scip-typescript` / `scip-python` (default **8192 MB** when omitted). Overridden by `SCIP_CLI_MAX_HEAP_MB`. This is the V8 heap cap, not total RAM usage.
239
+ - `maxHeapMb` — Node heap for `scip-typescript` / `scip-python` (default **8192 MB** when omitted). Overridden by `SCIP_CLI_MAX_HEAP_MB`. This is the V8 heap cap, not total RAM usage. Does not affect `scip-go`.
223
240
  - `indexRoots` — extra TypeScript project directories to include on **first index**, merged with auto-discovered projects.
224
241
  - `onlyIndexRoots` — skip auto-discovery and index **only** `indexRoots` (smaller initial index when you only care about part of a monorepo).
225
242
 
226
- `SCIP_CLI_INDEX_WORKERS` controls parallel `scip-typescript` runs during first index (default: up to 8). Merge into one database is always serial.
243
+ `SCIP_CLI_INDEX_WORKERS` controls parallel indexer runs during first index (default: up to 8). Merge into one database is always serial.
244
+
245
+ Other environment variables:
246
+
247
+ | Variable | Purpose |
248
+ | ------------------------------ | --------------------------------------------------------------------------------------------- |
249
+ | `SCIP_CLI_MAX_HEAP_MB` | Node heap for `scip-typescript` / `scip-python` (overrides `maxHeapMb` in config) |
250
+ | `SCIP_CLI_TS_INDEX_BATCH_SIZE` | Split large TS repos into multiple `scip-typescript` runs (default: all tsconfigs in one run) |
251
+ | `SCIP_CLI_MERGE_BATCH_SIZE` | SQLite ATTACH batch size when merging part DBs (max 9) |
252
+ | `SCIP_CLI_MAX_DEF_LINES` | Max definition lines in `code` output |
253
+ | `SCIP_CLI_DEBUG` | Log SQL queries to stderr |
254
+
255
+ **Version policy:** only the `scip` converter (`expt-convert`) is pinned to the 0.8.x release line because it defines the SQLite schema. Language indexers (`scip-typescript`, `scip-python` via `npx`; `scip-go` via `go install @latest`) install at latest on first use. `rust-analyzer` installs via `rustup component add`.
227
256
 
228
257
  Large monorepos (>10 tsconfig projects) log per-project progress to stderr during indexing; smaller repos stay quiet aside from the final `Indexed … (size)` line.
229
258
 
@@ -232,9 +261,13 @@ Scoped indexing without editing `.scip-cli.json`:
232
261
  ```bash
233
262
  scip-cli reindex --path packages/server
234
263
  scip-cli reindex --path packages/api --path packages/worker
264
+ scip-cli reindex --tsconfig 'apps/api/tsconfig.*.json'
265
+ scip-cli reindex --tsconfig tsconfig.app.json --tsconfig tsconfig.spec.json
235
266
  ```
236
267
 
237
- `--path` limits which discovered tsconfig projects are indexed (prefix match, same idea as query `--path`). The scope is saved as `index-scope.json` next to `index.db` and reused until you run a full `scip-cli reindex` with no `--path`.
268
+ `--path` limits which discovered tsconfig **directories** are indexed (prefix match, same idea as query `--path`). `--tsconfig` skips discovery and indexes those `tsconfig*.json` **files** (repeatable; globs are expanded inside the tool). File-based runs default to one `scip-typescript` process per file so each gets its own heap (`SCIP_CLI_TS_INDEX_BATCH_SIZE` still overrides). Cannot combine `--path` and `--tsconfig`. **TypeScript only.** The scope is saved as `index-scope.json` next to `index.db` and reused until you run a full `scip-cli reindex` with no `--path`/`--tsconfig`.
269
+
270
+ When a tsconfig (after `extends`) has `allowJs: true`, matching `.js`/`.jsx` files under that config's `include`/`files` are indexed too (same roots as `.ts`/`.tsx`). `allowJs: false` or unset leaves JavaScript out. JS-only repos with no `tsconfig.json` still use `--infer-tsconfig`.
238
271
 
239
272
  Run `scip-cli reindex` after changing scope, `.scip-cli.json` index settings, or when you want a fresh index.
240
273
 
@@ -251,24 +284,24 @@ scip-cli analyze --priority high --limit 25 # dead exports & cycles only
251
284
 
252
285
  Sections are tagged `[high]`, `[medium]`, `[low]` and listed in that order.
253
286
 
254
- | Tier | Project sections | Action |
255
- | ---- | ---------------- | ------ |
256
- | **high** | Cycles, unreferenced, dead exports, stale types | Nuke or fix cycles; delete unused; `_` prefix |
257
- | **medium** | Same-file only, change surface (file target) | Module-private by usage |
258
- | **low** | Test-only consumers, coupling, bottlenecks, hotspots | Noisy on Python (index omits many same-file calls); verify with `rg` |
287
+ | Tier | Project sections | Action |
288
+ | ---------- | ---------------------------------------------------- | -------------------------------------------------------------------- |
289
+ | **high** | Cycles, unreferenced, dead exports, stale types | Nuke or fix cycles; delete unused; `_` prefix |
290
+ | **medium** | Same-file only, change surface (file target) | Module-private by usage |
291
+ | **low** | Test-only consumers, coupling, bottlenecks, hotspots | Noisy on Python (index omits many same-file calls); verify with `rg` |
259
292
 
260
293
  Use `--priority high` for a quick gate; `--priority high,medium` adds context. File drill-down adds change surface and unused imports.
261
294
 
262
295
  **What to look at first**
263
296
 
264
- | Section | Easy pickings |
265
- | ------- | ------------- |
266
- | **Cycles** | Import/mention cycles between production files — break the edge or extract shared code |
267
- | **Unreferenced** | No usage in the index at all — delete |
268
- | **Dead exports** | No external refs — delete or `_` prefix |
269
- | **Stale types** | Classes/types with no external consumer in the index — verify in-file or type-only use before removing |
270
- | **Same-file only** | Used only inside defining file — rename to `_` |
271
- | **Test-only consumers** | Cross-file refs are all from tests — promote to e2e or accept as internal |
297
+ | Section | Easy pickings |
298
+ | ----------------------- | ------------------------------------------------------------------------------------------------------ |
299
+ | **Cycles** | Import/mention cycles between production files — break the edge or extract shared code |
300
+ | **Unreferenced** | No usage in the index at all — delete |
301
+ | **Dead exports** | No external refs — delete or `_` prefix |
302
+ | **Stale types** | Classes/types with no external consumer in the index — verify in-file or type-only use before removing |
303
+ | **Same-file only** | Used only inside defining file — rename to `_` |
304
+ | **Test-only consumers** | Cross-file refs are all from tests — promote to e2e or accept as internal |
272
305
 
273
306
  **Per-file or package drill-down** on hubs or suspects:
274
307
 
@@ -277,7 +310,7 @@ scip-cli analyze scip_cli/queries.py --limit 20 # file: scoped project + per-f
277
310
  scip-cli analyze scip_cli --limit 15 # directory: scoped project + each file under it
278
311
  ```
279
312
 
280
- `Dead exports in file` lists same-module symbols with no *external* refs — module-private `_helpers` are filtered out. Remaining rows are worth a manual `rg` check.
313
+ `Dead exports in file` lists same-module symbols with no _external_ refs — module-private `_helpers` are filtered out. Remaining rows are worth a manual `rg` check.
281
314
 
282
315
  **Defaults:** project-wide and directory analyze skip `tests/`, `*.test.*`, `*.spec.*`, `conftest.py`, and `__tests__/`. Pass `--include-tests` to include them. File-target analyze always includes that file.
283
316
 
@@ -329,7 +362,7 @@ scip_cli/
329
362
  ```bash
330
363
  pip install -e ".[dev]"
331
364
  pytest tests/ -q
332
- pytest tests/ -m integration -q # indexes tests/fixtures/sample-project (needs scip-typescript)
365
+ pytest tests/ -m integration -q # indexes tests/fixtures/typescript-project (needs scip-typescript)
333
366
  ```
334
367
 
335
368
  ### Debug Logging