know-cli 0.3.4__tar.gz → 0.3.6__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 (62) hide show
  1. {know_cli-0.3.4 → know_cli-0.3.6}/PKG-INFO +1 -1
  2. {know_cli-0.3.4 → know_cli-0.3.6}/pyproject.toml +1 -1
  3. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/lexical_index.py +6 -2
  4. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/semantic_search.py +27 -8
  5. {know_cli-0.3.4 → know_cli-0.3.6}/.github/actions/know-cli/action.yml +0 -0
  6. {know_cli-0.3.4 → know_cli-0.3.6}/.github/workflows/example-advanced.yml +0 -0
  7. {know_cli-0.3.4 → know_cli-0.3.6}/.github/workflows/example-basic.yml +0 -0
  8. {know_cli-0.3.4 → know_cli-0.3.6}/.gitignore +0 -0
  9. {know_cli-0.3.4 → know_cli-0.3.6}/AGENTS.md +0 -0
  10. {know_cli-0.3.4 → know_cli-0.3.6}/KNOW_SKILL.md +0 -0
  11. {know_cli-0.3.4 → know_cli-0.3.6}/README.md +0 -0
  12. {know_cli-0.3.4 → know_cli-0.3.6}/docs/IMPLEMENTATION_PLAN.md +0 -0
  13. {know_cli-0.3.4 → know_cli-0.3.6}/docs/IMPROVEMENTS.md +0 -0
  14. {know_cli-0.3.4 → know_cli-0.3.6}/docs/STRATEGIC_AUDIT.md +0 -0
  15. {know_cli-0.3.4 → know_cli-0.3.6}/docs/arc.md +0 -0
  16. {know_cli-0.3.4 → know_cli-0.3.6}/docs/architecture-diff.md +0 -0
  17. {know_cli-0.3.4 → know_cli-0.3.6}/docs/architecture.md +0 -0
  18. {know_cli-0.3.4 → know_cli-0.3.6}/docs/dependencies.md +0 -0
  19. {know_cli-0.3.4 → know_cli-0.3.6}/docs/digest-compact.md +0 -0
  20. {know_cli-0.3.4 → know_cli-0.3.6}/docs/digest-llm.md +0 -0
  21. {know_cli-0.3.4 → know_cli-0.3.6}/docs/onboarding-new-devs.md +0 -0
  22. {know_cli-0.3.4 → know_cli-0.3.6}/docs/onboarding-new_devs.md +0 -0
  23. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/__init__.py +0 -0
  24. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/ai.py +0 -0
  25. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/cli.py +0 -0
  26. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/config.py +0 -0
  27. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/context_engine.py +0 -0
  28. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/cost.py +0 -0
  29. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/diff.py +0 -0
  30. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/exceptions.py +0 -0
  31. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/generator.py +0 -0
  32. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/git_hooks.py +0 -0
  33. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/history.py +0 -0
  34. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/import_graph.py +0 -0
  35. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/index.py +0 -0
  36. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/knowledge_base.py +0 -0
  37. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/logger.py +0 -0
  38. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/mcp_server.py +0 -0
  39. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/models.py +0 -0
  40. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/parsers.py +0 -0
  41. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/quality.py +0 -0
  42. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/scanner.py +0 -0
  43. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/state.py +0 -0
  44. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/stats.py +0 -0
  45. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/token_counter.py +0 -0
  46. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/tools.py +0 -0
  47. {know_cli-0.3.4 → know_cli-0.3.6}/src/know/watcher.py +0 -0
  48. {know_cli-0.3.4 → know_cli-0.3.6}/tests/README.md +0 -0
  49. {know_cli-0.3.4 → know_cli-0.3.6}/tests/conftest.py +0 -0
  50. {know_cli-0.3.4 → know_cli-0.3.6}/tests/mcp_stub/mcp/__init__.py +0 -0
  51. {know_cli-0.3.4 → know_cli-0.3.6}/tests/mcp_stub/mcp/server/__init__.py +0 -0
  52. {know_cli-0.3.4 → know_cli-0.3.6}/tests/mcp_stub/mcp/server/fastmcp.py +0 -0
  53. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_efficiency.py +0 -0
  54. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_history_cost.py +0 -0
  55. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_know.py +0 -0
  56. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_search_hybrid.py +0 -0
  57. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_state.py +0 -0
  58. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_unit.py +0 -0
  59. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_week2.py +0 -0
  60. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_week3.py +0 -0
  61. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_week4.py +0 -0
  62. {know_cli-0.3.4 → know_cli-0.3.6}/tests/test_week6_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: know-cli
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Context Intelligence for AI Coding Agents — smart, token-budgeted code context
5
5
  Project-URL: Homepage, https://github.com/vic/know-cli
6
6
  Project-URL: Repository, https://github.com/vic/know-cli
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "know-cli"
7
- version = "0.3.4"
7
+ version = "0.3.6"
8
8
  description = "Context Intelligence for AI Coding Agents — smart, token-budgeted code context"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -217,8 +217,12 @@ class ChunkFTSIndex:
217
217
  cleaned = re.sub(r"[^A-Za-z0-9_]+", " ", q).strip()
218
218
  if not cleaned:
219
219
  return q
220
- # AND all terms for higher precision.
221
- return " ".join(cleaned.split())
220
+ terms = cleaned.split()
221
+ if len(terms) == 1:
222
+ return terms[0]
223
+ # Use OR to avoid over-strict matching on multi-word queries.
224
+ # Ranking still handled by BM25.
225
+ return " OR ".join(terms)
222
226
 
223
227
  query_sanitized = _sanitize(query)
224
228
 
@@ -684,7 +684,10 @@ class SemanticSearcher:
684
684
  # Hard fallback: plain text grep when hybrid/vector/lexical all miss.
685
685
  # This guarantees useful results for exact keyword queries in TS/React projects.
686
686
  if not results and query.strip():
687
+ import re
688
+
687
689
  q = query.strip().lower()
690
+ q_tokens = [t for t in re.findall(r"[a-z0-9_]+", q) if len(t) >= 3]
688
691
  exts = {".py", ".ts", ".tsx", ".js", ".jsx", ".go", ".rs", ".java", ".cpp", ".c", ".h", ".md"}
689
692
  fallback = []
690
693
  for p in root.rglob("*"):
@@ -703,16 +706,32 @@ class SemanticSearcher:
703
706
  text = p.read_text(encoding="utf-8", errors="ignore")
704
707
  except Exception:
705
708
  continue
706
- idx = text.lower().find(q)
709
+
710
+ text_l = text.lower()
711
+ # Prefer exact phrase, fallback to token hits.
712
+ idx = text_l.find(q)
713
+ if idx < 0 and q_tokens:
714
+ token_positions = [text_l.find(tok) for tok in q_tokens]
715
+ token_positions = [pos for pos in token_positions if pos >= 0]
716
+ if not token_positions:
717
+ continue
718
+ idx = min(token_positions)
719
+
707
720
  if idx < 0:
708
721
  continue
722
+
709
723
  line_no = text[:idx].count("\n") + 1
710
724
  snippet = _format_snippet(p, line_no, line_no, context=2, include_line_numbers=include_line_numbers)
711
- fallback.append((rel, line_no, snippet))
712
- if len(fallback) >= top_k:
713
- break
725
+ # crude relevance: token coverage in file text
726
+ coverage = 0
727
+ if q_tokens:
728
+ coverage = sum(1 for tok in q_tokens if tok in text_l)
729
+ fallback.append((coverage, rel, line_no, snippet))
730
+
731
+ fallback.sort(key=lambda x: (-x[0], x[1]))
732
+ fallback = fallback[:top_k]
714
733
 
715
- for i, (rel, line_no, snippet) in enumerate(fallback, start=1):
734
+ for i, (coverage, rel, line_no, snippet) in enumerate(fallback, start=1):
716
735
  results.append({
717
736
  "schema": "know.search.v1",
718
737
  "engine": "text-fallback",
@@ -723,7 +742,7 @@ class SemanticSearcher:
723
742
  "chunk_type": "line",
724
743
  "start_line": line_no,
725
744
  "end_line": line_no,
726
- "scores": {"rrf": 0.01, "lexical_bm25": None, "vector": None},
745
+ "scores": {"rrf": 0.01 + min(0.01, 0.002 * coverage), "lexical_bm25": None, "vector": None},
727
746
  "snippet": snippet,
728
747
  "rationale": {"lexical_available": lexical_available, "vector_available": vector_available},
729
748
  })
@@ -834,8 +853,8 @@ class SemanticSearcher:
834
853
 
835
854
  results = []
836
855
  for i in top_indices:
837
- if similarities[i] <= 0:
838
- continue
856
+ # Keep top-k even when cosine is <= 0. In sparse/short queries,
857
+ # all scores can be near/under 0 and filtering causes empty results.
839
858
  chunk_key = file_paths[i]
840
859
  # Parse chunk key: "file_path::name::line_start"
841
860
  parts = chunk_key.split("::")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes