scip-cli 2.5.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 (152) hide show
  1. scip_cli-2.6.0/.agents/commands/migration-problems.md +82 -0
  2. {scip_cli-2.5.0/.cursor → scip_cli-2.6.0/.agents}/rules/agent.mdc +93 -71
  3. scip_cli-2.6.0/.github/workflows/ci.yml +45 -0
  4. {scip_cli-2.5.0 → scip_cli-2.6.0}/.gitignore +2 -2
  5. scip_cli-2.6.0/AGENTS.md +1 -0
  6. {scip_cli-2.5.0 → scip_cli-2.6.0}/CODE_OF_CONDUCT.md +1 -1
  7. {scip_cli-2.5.0 → scip_cli-2.6.0}/PKG-INFO +19 -4
  8. {scip_cli-2.5.0 → scip_cli-2.6.0}/README.md +18 -3
  9. {scip_cli-2.5.0 → scip_cli-2.6.0}/SECURITY.md +5 -5
  10. scip_cli-2.6.0/docs/port.md +80 -0
  11. scip_cli-2.6.0/docs/ports/conclusions.md +424 -0
  12. scip_cli-2.6.0/docs/ports/experiment-summary.md +257 -0
  13. scip_cli-2.6.0/docs/ports/go-experiment.md +252 -0
  14. scip_cli-2.6.0/docs/ports/go.md +203 -0
  15. scip_cli-2.6.0/docs/ports/plan.md +161 -0
  16. scip_cli-2.6.0/docs/ports/rust-experiment.md +324 -0
  17. scip_cli-2.6.0/docs/ports/rust.md +264 -0
  18. scip_cli-2.6.0/docs/ports/summary.md +118 -0
  19. scip_cli-2.6.0/docs/ports/zig-experiment.md +333 -0
  20. scip_cli-2.6.0/docs/ports/zig.md +283 -0
  21. {scip_cli-2.5.0 → scip_cli-2.6.0}/pyproject.toml +1 -3
  22. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/SKILL.md +34 -25
  23. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/__init__.py +1 -1
  24. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/__main__.py +21 -0
  25. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/file.py +0 -10
  26. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/graph.py +34 -24
  27. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/deps.py +6 -5
  28. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/reindex.py +32 -4
  29. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/search.py +78 -72
  30. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/symbols.py +30 -0
  31. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/discover.py +6 -12
  32. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/__init__.py +2 -1
  33. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/orchestrate.py +16 -0
  34. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/postprocess.py +44 -6
  35. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/typescript.py +36 -4
  36. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/merge.py +1 -1
  37. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/scip_tool.py +5 -1
  38. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/scope.py +1 -1
  39. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/source.py +1 -1
  40. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/sql.py +4 -6
  41. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/targets.py +1 -1
  42. scip_cli-2.6.0/scip_cli/tsconfig.py +226 -0
  43. scip_cli-2.6.0/scripts/bench.sh +60 -0
  44. {scip_cli-2.5.0 → scip_cli-2.6.0}/scripts/bench_postprocess.py +3 -1
  45. {scip_cli-2.5.0 → scip_cli-2.6.0}/scripts/publish.sh +26 -2
  46. {scip_cli-2.5.0 → scip_cli-2.6.0}/scripts/test.sh +2 -2
  47. scip_cli-2.6.0/tests/bench_db.py +261 -0
  48. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/conftest.py +1 -1
  49. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/e2e_harness.py +1 -1
  50. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/fixture_catalog.py +5 -1
  51. scip_cli-2.6.0/tests/fixtures/typescript-project/src/helper.ts +23 -0
  52. scip_cli-2.6.0/tests/fixtures/typescript-project/src/lib/handler.ts +3 -0
  53. scip_cli-2.6.0/tests/fixtures/typescript-project/src/models/MutationAggregate.ts +32 -0
  54. scip_cli-2.6.0/tests/test_bench_queries.py +124 -0
  55. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_e2e.py +90 -0
  56. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_e2e_analyze_patterns.py +1 -1
  57. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_index_batching.py +16 -0
  58. scip_cli-2.6.0/tests/test_reindex.py +128 -0
  59. scip_cli-2.6.0/tests/test_symbols_freq.py +107 -0
  60. scip_cli-2.6.0/tests/test_tsconfig.py +137 -0
  61. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_typescript_projects.py +10 -0
  62. scip_cli-2.5.0/.github/workflows/ci.yml +0 -22
  63. scip_cli-2.5.0/tests/fixtures/sample-project/src/helper.ts +0 -7
  64. scip_cli-2.5.0/tests/test_reindex.py +0 -67
  65. {scip_cli-2.5.0 → scip_cli-2.6.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  66. {scip_cli-2.5.0 → scip_cli-2.6.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  67. {scip_cli-2.5.0 → scip_cli-2.6.0}/.github/ISSUE_TEMPLATE/question.md +0 -0
  68. {scip_cli-2.5.0 → scip_cli-2.6.0}/.github/pull_request_template.md +0 -0
  69. {scip_cli-2.5.0 → scip_cli-2.6.0}/.pre-commit-config.yaml +0 -0
  70. {scip_cli-2.5.0 → scip_cli-2.6.0}/CONTRIBUTING.md +0 -0
  71. {scip_cli-2.5.0 → scip_cli-2.6.0}/LICENSE +0 -0
  72. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/__init__.py +0 -0
  73. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/common.py +0 -0
  74. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/live.py +0 -0
  75. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/project.py +0 -0
  76. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/sections.py +0 -0
  77. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/symbol.py +0 -0
  78. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/analyze/targets.py +0 -0
  79. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/cache.py +0 -0
  80. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/cli_args.py +0 -0
  81. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/__init__.py +0 -0
  82. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/analyze.py +0 -0
  83. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/code.py +0 -0
  84. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/members.py +0 -0
  85. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/rdeps.py +0 -0
  86. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/refs.py +0 -0
  87. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/commands/skill.py +0 -0
  88. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/config.py +0 -0
  89. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/debug.py +0 -0
  90. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/constants.py +0 -0
  91. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/convert.py +0 -0
  92. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/core.py +0 -0
  93. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/languages.py +0 -0
  94. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/indexing/runners.py +0 -0
  95. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/output.py +0 -0
  96. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/paths.py +0 -0
  97. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/project.py +0 -0
  98. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/queries.py +0 -0
  99. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/session.py +0 -0
  100. {scip_cli-2.5.0 → scip_cli-2.6.0}/scip_cli/symbols.py +0 -0
  101. {scip_cli-2.5.0 → scip_cli-2.6.0}/scripts/build.sh +0 -0
  102. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/__init__.py +0 -0
  103. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/analyze_db.py +0 -0
  104. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/package.json +0 -0
  105. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/app/handler.ts +0 -0
  106. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/config.ts +0 -0
  107. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/consumer.ts +0 -0
  108. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/dead.ts +0 -0
  109. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/i18n/en.ts +0 -0
  110. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/i18n/index.ts +0 -0
  111. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/i18n/useLocale.ts +0 -0
  112. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/domain/labels/index.ts +0 -0
  113. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/events/streamTypes.ts +0 -0
  114. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/gateway/index.ts +0 -0
  115. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/hooks/useHookA.ts +0 -0
  116. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/hooks/useHookB.ts +0 -0
  117. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/hooks/useItems.ts +0 -0
  118. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/index.ts +0 -0
  119. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/integrations/inferenceClient.ts +0 -0
  120. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/loaders/useInference.ts +0 -0
  121. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/pages/panelPage.ts +0 -0
  122. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/rules/applyRule.ts +0 -0
  123. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/types/a.ts +0 -0
  124. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/types/b.ts +0 -0
  125. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/Button.ts +0 -0
  126. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/LazyPanel.ts +0 -0
  127. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/buttonConsumer.ts +0 -0
  128. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/ui/menuModule.ts +0 -0
  129. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/user.ts +0 -0
  130. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/widget.ts +0 -0
  131. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/src/widgets/OrphanWidget.ts +0 -0
  132. {scip_cli-2.5.0/tests/fixtures/sample-project → scip_cli-2.6.0/tests/fixtures/typescript-project}/tsconfig.json +0 -0
  133. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/perf_util.py +0 -0
  134. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_analyze.py +0 -0
  135. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_analyze_graph.py +0 -0
  136. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_analyze_perf.py +0 -0
  137. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_cache.py +0 -0
  138. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_composability.py +0 -0
  139. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_config.py +0 -0
  140. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_discover.py +0 -0
  141. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_e2e_perf.py +0 -0
  142. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_index_prune.py +0 -0
  143. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_indexer_env.py +0 -0
  144. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_indexer_fallback.py +0 -0
  145. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_merge.py +0 -0
  146. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_multi_symbol.py +0 -0
  147. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_pure_functions.py +0 -0
  148. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_python_index_integration.py +0 -0
  149. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_qualified_symbols.py +0 -0
  150. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_scip_tool.py +0 -0
  151. {scip_cli-2.5.0 → scip_cli-2.6.0}/tests/test_scope.py +0 -0
  152. {scip_cli-2.5.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,13 +28,13 @@ Node.js + `npx` required for integration tests (`scip-typescript`). Optional: `S
28
28
 
29
29
  ## Lint / test
30
30
 
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/` |
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/`|
38
38
 
39
39
  Pre-commit: ruff + ruff-format + basedpyright + full pytest. E2e before commit on command changes.
40
40
 
@@ -54,12 +54,12 @@ scip-cli analyze scip_cli/queries.py --limit 20 # file (+ scoped project)
54
54
 
55
55
  Interpretation: README § *Finding easy wins with analyze*. Target = omit (project), directory, file, or symbol — not `--path` for scope.
56
56
 
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 |
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|
63
63
 
64
64
  `analyze` skips test paths by default (`tests/`, `*.test.*`, `*.spec.*`); `--include-tests` to include. Reindex after large edits.
65
65
 
@@ -82,19 +82,19 @@ Only skip step 1 when the issue is **outside the index** (runtime, CLI UX, docs
82
82
 
83
83
  ### Retrospective: caught manually, SQLite already had it
84
84
 
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 |
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|
98
98
 
99
99
  Add new rows to `dogfood.md` when you find another gap; implement the SQL check before the next manual review pass.
100
100
 
@@ -102,15 +102,15 @@ Add new rows to `dogfood.md` when you find another gap; implement the SQL check
102
102
 
103
103
  SQLite has **line ranges** (`defn_enclosing_ranges`) so LOC is cheap. That does **not** mean “big function” belongs next to dead exports.
104
104
 
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. |
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.|
114
114
 
115
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.
116
116
 
@@ -118,33 +118,55 @@ SQLite has **line ranges** (`defn_enclosing_ranges`) so LOC is cheap. That does
118
118
 
119
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).
120
120
 
121
- **Before merging new or heavily changed SQL** (`queries.py`, `analyze/*`):
122
-
123
- 1. Time it against **1–2 existing checks** on a **large cached index** you already have (not the fixture):
124
- ```bash
125
- python3 -u -c "
126
- import sqlite3, time, sys
127
- from pathlib import Path
128
- sys.path.insert(0, '.')
129
- from scip_cli.analyze import project as p
130
- from scip_cli.sql import configure_read_connection
131
- db_path = Path.home() / '.cache/scip-cli/projects/<project-slug>/index.db'
132
- db = sqlite3.connect(f'file:{db_path}?mode=ro', uri=True)
133
- configure_read_connection(db)
134
- for name, fn in [('hotspots', p.hotspots), ('cycles', p.cycles), ('dead_exports', p.dead_exports)]:
135
- t = time.perf_counter(); fn(db, limit=25); print(f'{name}: {(time.perf_counter()-t)*1000:.0f}ms')
136
- "
137
- ```
138
- 2. Flag anything **notably slower** than peers — orders of magnitude or multi-second, not a few ms drift.
139
- 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`).
140
-
141
- **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.
142
164
 
143
165
  ## TDD
144
166
 
145
167
  ### Default: extend the shared fixture
146
168
 
147
- **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`.
148
170
 
149
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.
150
172
  2. **Green** — fix `scip_cli/` (commands, `analyze/*`, `queries.py`, …).
@@ -159,29 +181,29 @@ The e2e fixture and this repo's own index are **small** — every query looks fa
159
181
  When dogfooding **another repo** surfaces a bug or false positive (analyze noise, dead-export mistake, cycle, stale type, refs mismatch):
160
182
 
161
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.
162
- 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.
163
185
  3. **Green** — fix analyze heuristics / SQL / CLI; dogfood on this repo if applicable.
164
186
  4. **Verify** — `pytest tests/test_e2e_analyze_patterns.py` (or full `pytest`); only then trim redundant tests.
165
187
 
166
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.
167
189
 
168
- | Use fixture e2e | Use `analyze_db` unit |
169
- |-----------------|----------------------|
170
- | False positives / analyze checks from real projects | Tarjan, edge-type SQL, `run_all` section wiring |
171
- | Any behavior that depends on indexer symbol strings | Noise filters with one or two synthetic rows |
172
- | 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|
173
195
 
174
196
  If both layers help during development, **keep both until e2e passes**, then delete duplicate in-memory repros — fixture is the source of truth.
175
197
 
176
198
  ## Codebase map (contributors)
177
199
 
178
- | Area | Path | Notes |
179
- |------|------|-------|
180
- | Commands | `scip_cli/commands/` | Thin; SQL in `queries.py` / `analyze/` |
181
- | Index build | `scip_cli/indexing.py` | `index.db.next` → promote; flock; `>10` tsconfigs log progress |
182
- | Variable prune | postprocess + `merge.py` | Omit const/let/var on **COPY**, not DELETE — no `variable` kind |
183
- | Session | `scip_cli/session.py` | `setup()`, `resolve_one_symbol` (limit 2 for ambiguity) |
184
- | 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)|
185
207
 
186
208
  `todo.md` = tracked work; `dogfood.md` = future ideas only. Wishlist/backlog in `docs/` per workspace rules.
187
209
 
@@ -206,4 +228,4 @@ scip-cli analyze --limit 25
206
228
  scip-cli analyze scip_cli/queries.py --limit 20 # drill into hubs
207
229
  ```
208
230
 
209
- Project-wide analyze skips test paths by default; `--include-tests` to include. See README **Finding easy wins with analyze**.
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
@@ -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.5.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, Python, Go, and Rust.
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:
@@ -250,9 +261,13 @@ Scoped indexing without editing `.scip-cli.json`:
250
261
  ```bash
251
262
  scip-cli reindex --path packages/server
252
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
253
266
  ```
254
267
 
255
- `--path` limits which discovered tsconfig projects are indexed (prefix match, same idea as query `--path`). **TypeScript only** other languages reject `reindex --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`.
256
271
 
257
272
  Run `scip-cli reindex` after changing scope, `.scip-cli.json` index settings, or when you want a fresh index.
258
273
 
@@ -347,7 +362,7 @@ scip_cli/
347
362
  ```bash
348
363
  pip install -e ".[dev]"
349
364
  pytest tests/ -q
350
- 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)
351
366
  ```
352
367
 
353
368
  ### Debug Logging
@@ -3,7 +3,7 @@
3
3
  [![PyPI version](https://badge.fury.io/py/scip-cli.svg)](https://badge.fury.io/py/scip-cli)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Token-efficient code intelligence for AI agents. Precise refs, definitions, and repo health analysis via SCIP indexes — TypeScript/JavaScript, Python, Go, and Rust.
6
+ Python CLI for AI agents. Queries SCIP indexes for precise refs, definitions, and repo health analysis — TypeScript/JavaScript, Python, Go, Rust.
7
7
 
8
8
  ## Why
9
9
 
@@ -17,6 +17,17 @@ AI agents waste tokens on grep and file scanning. scip-cli gives them precise, t
17
17
  - **`analyze`**: Find dead exports, import cycles, stale types, coupling hotspots — actionable health dashboards at project, file, or symbol scope
18
18
  - **Auto-indexing**: Indexes on first query, caches in SQLite, zero config
19
19
 
20
+ ## Ports
21
+
22
+ CLI/output parity ports of this project (Python is the reference):
23
+
24
+ | Language | Repository |
25
+ | ------------------ | ----------------------------------------------------------------- |
26
+ | Python (reference) | [flesler/scip-cli](https://github.com/flesler/scip-cli) |
27
+ | Go | [flesler/scip-cli-go](https://github.com/flesler/scip-cli-go) |
28
+ | Rust | [flesler/scip-cli-rust](https://github.com/flesler/scip-cli-rust) |
29
+ | Zig | [flesler/scip-cli-zig](https://github.com/flesler/scip-cli-zig) |
30
+
20
31
  ## For AI Agents
21
32
 
22
33
  Install as a reusable skill so your agent always knows how to navigate the codebase:
@@ -229,9 +240,13 @@ Scoped indexing without editing `.scip-cli.json`:
229
240
  ```bash
230
241
  scip-cli reindex --path packages/server
231
242
  scip-cli reindex --path packages/api --path packages/worker
243
+ scip-cli reindex --tsconfig 'apps/api/tsconfig.*.json'
244
+ scip-cli reindex --tsconfig tsconfig.app.json --tsconfig tsconfig.spec.json
232
245
  ```
233
246
 
234
- `--path` limits which discovered tsconfig projects are indexed (prefix match, same idea as query `--path`). **TypeScript only** other languages reject `reindex --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`.
247
+ `--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`.
248
+
249
+ 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`.
235
250
 
236
251
  Run `scip-cli reindex` after changing scope, `.scip-cli.json` index settings, or when you want a fresh index.
237
252
 
@@ -326,7 +341,7 @@ scip_cli/
326
341
  ```bash
327
342
  pip install -e ".[dev]"
328
343
  pytest tests/ -q
329
- pytest tests/ -m integration -q # indexes tests/fixtures/sample-project (needs scip-typescript)
344
+ pytest tests/ -m integration -q # indexes tests/fixtures/typescript-project (needs scip-typescript)
330
345
  ```
331
346
 
332
347
  ### Debug Logging
@@ -2,16 +2,16 @@
2
2
 
3
3
  ## Supported Versions
4
4
 
5
- | Version | Supported |
6
- | ------- | ------------------ |
7
- | latest | :white_check_mark: |
8
- | < latest| :x: |
5
+ |Version|Supported|
6
+ |---|---|
7
+ |latest|:white_check_mark:|
8
+ |< latest|:x:|
9
9
 
10
10
  ## Reporting a Vulnerability
11
11
 
12
12
  **Do not open public issues for security vulnerabilities.**
13
13
 
14
- If you discover a security vulnerability, please email **ariel.flesler@gmail.com** with:
14
+ If you discover a security vulnerability, please email **aflesler@gmail.com** with:
15
15
 
16
16
  - Description of the vulnerability
17
17
  - Steps to reproduce or proof of concept
@@ -0,0 +1,80 @@
1
+
2
+ ---
3
+
4
+ ## Experimental Task: Add --freq Flag to Symbols Command
5
+
6
+ **Task**: Add `--freq` flag to sort symbols by frequency of occurrence
7
+
8
+ ### Execution Summary
9
+ - **Start time**: Tue Jun 30 03:36:42 PM -03 2026
10
+ - **End time**: Tue Jun 30 03:39:51 PM -03 2026
11
+ - **Total elapsed time**: ~3 minutes
12
+ - **Tool calls made**: ~15 calls
13
+
14
+ ### Changes Made
15
+ - **scip_cli/__main__.py**: Added `--freq` boolean argument to the symbols command parser
16
+ - **scip_cli/commands/symbols.py**:
17
+ - Added `Counter` import from collections
18
+ - Implemented `_sort_by_frequency()` function that counts symbol name occurrences and sorts by frequency (descending) with alphabetical tie-breaking
19
+ - Modified `main()` to apply frequency sorting when `--freq` flag is present
20
+ - **tests/test_symbols_freq.py**: Created comprehensive test file with 3 tests:
21
+ 1. `test_freq_flag_sorts_by_frequency`: Verifies symbols are sorted by frequency
22
+ 2. `test_freq_flag_with_ties_sorts_alphabetically`: Verifies alphabetical ordering for ties
23
+ 3. `test_without_freq_flag_maintains_original_order`: Ensures original behavior without flag
24
+
25
+ ### Problems Encountered
26
+ - **Linting issues**: Initial test file had unused import and long line - fixed by removing import and breaking up assertion message
27
+ - **Formatting**: Test file needed reformatting with ruff - fixed by running `ruff format`
28
+
29
+ ### Tests Added
30
+ - **test_freq_flag_sorts_by_frequency**: Verifies that first symbol has count >= last symbol's count
31
+ - **test_freq_flag_with_ties_sorts_alphabetically**: Verifies symbols with same frequency appear in alphabetical order
32
+ - **test_without_freq_flag_maintains_original_order**: Verifies line-number ordering without --freq flag
33
+
34
+ ### Gate Results
35
+ - Tests: **passed** (298/298 tests passing, including 3 new tests)
36
+ - Linting: **passed** (ruff check clean)
37
+ - Formatting: **passed** (ruff format applied)
38
+
39
+ ### AI Experience Notes
40
+ The task was straightforward with clear code structure. The scip-cli codebase is well-organized with commands separated into individual modules. Adding the CLI flag was simple via argparse. The frequency sorting implementation using Counter was intuitive. Tests leveraged existing e2e harness patterns. Minor friction with linting/formatting but easily resolved. No type errors or unexpected issues encountered.
41
+
42
+ ---
43
+
44
+ ## Experimental Task: Add --freq Flag to Symbols Command (Verification Run)
45
+
46
+ **Task**: Verify that `--freq` flag implementation is complete and working correctly
47
+
48
+ ### Execution Summary
49
+ - **Start time**: Tue Jun 30 03:40:54 PM -03 2026
50
+ - **End time**: Tue Jun 30 03:42:10 PM -03 2026
51
+ - **Total elapsed time**: ~1.5 minutes
52
+ - **Tool calls made**: ~12 calls
53
+
54
+ ### Changes Made
55
+ No changes were needed - the implementation was already complete:
56
+ - **scip_cli/__main__.py**: `--freq` boolean argument already added to symbols command parser (lines 92-96)
57
+ - **scip_cli/commands/symbols.py**:
58
+ - `_sort_by_frequency()` function already implemented (lines 42-62)
59
+ - Frequency counting using `Counter` from collections
60
+ - Sorting by frequency descending, then alphabetically for ties
61
+ - Integration in `main()` with `getattr(args, "freq", False)` check
62
+ - **tests/test_symbols_freq.py**: 3 comprehensive tests already present and passing
63
+
64
+ ### Problems Encountered
65
+ - **None**: Implementation was already complete and all tests passing
66
+ - Verified existing implementation meets all requirements
67
+
68
+ ### Tests Added
69
+ No new tests added - verified existing tests:
70
+ - **test_freq_flag_sorts_by_frequency**: Verifies descending frequency order ✓
71
+ - **test_freq_flag_with_ties_sorts_alphabetically**: Verifies alphabetical tie-breaking ✓
72
+ - **test_without_freq_flag_maintains_original_order**: Verifies default behavior ✓
73
+
74
+ ### Gate Results
75
+ - Tests: **passed** (298/298 tests passing, including 3 freq tests)
76
+ - Python compile: **passed** (no syntax errors)
77
+ - Linting: **passed** (ruff check clean)
78
+
79
+ ### AI Experience Notes
80
+ This verification run confirmed the implementation is complete and production-ready. The code is clean, well-structured, and follows Python best practices. All tests pass without modification. The use of `getattr(args, "freq", False)` provides safe fallback if flag is missing. Counter-based frequency counting is efficient and idiomatic. No refactoring needed.