synap-git 2.4.0__tar.gz → 2.4.1__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 (56) hide show
  1. {synap_git-2.4.0 → synap_git-2.4.1}/.gitignore +1 -1
  2. {synap_git-2.4.0 → synap_git-2.4.1}/CHANGELOG.md +8 -1
  3. {synap_git-2.4.0 → synap_git-2.4.1}/PKG-INFO +1 -1
  4. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/__init__.py +1 -1
  5. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/checkpoint.py +16 -2
  6. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/lessons.py +59 -0
  7. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/main.py +425 -22
  8. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/memory.py +57 -0
  9. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/git/state.py +25 -0
  10. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/indexer/daemon.py +11 -1
  11. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/indexer/engine.py +182 -27
  12. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/mcp/server.py +7 -1
  13. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/parser/registry.py +148 -16
  14. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/storage/sqlite.py +156 -55
  15. {synap_git-2.4.0 → synap_git-2.4.1}/.synap.example/README.md +0 -0
  16. {synap_git-2.4.0 → synap_git-2.4.1}/LICENSE.md +0 -0
  17. {synap_git-2.4.0 → synap_git-2.4.1}/README.md +0 -0
  18. {synap_git-2.4.0 → synap_git-2.4.1}/pyproject.toml +0 -0
  19. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/api/__init__.py +0 -0
  20. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/api/app.py +0 -0
  21. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/api/static/index.html +0 -0
  22. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/__init__.py +0 -0
  23. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/__main__.py +0 -0
  24. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/usage.py +0 -0
  25. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/cli/wiki.py +0 -0
  26. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/config.py +0 -0
  27. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/diagnostics/__init__.py +0 -0
  28. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/diagnostics/logger.py +0 -0
  29. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/diagnostics/tracing.py +0 -0
  30. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/embeddings/__init__.py +0 -0
  31. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/git/__init__.py +0 -0
  32. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/indexer/__init__.py +0 -0
  33. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/indexer/scanner.py +0 -0
  34. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/indexer/wiki.py +0 -0
  35. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/mcp/__init__.py +0 -0
  36. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/parser/__init__.py +0 -0
  37. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/__init__.py +0 -0
  38. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/anthropic.py +0 -0
  39. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/base.py +0 -0
  40. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/factory.py +0 -0
  41. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/gemini.py +0 -0
  42. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/ollama.py +0 -0
  43. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/openai.py +0 -0
  44. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/provider/openrouter.py +0 -0
  45. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/py.typed +0 -0
  46. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/retrieval/__init__.py +0 -0
  47. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/retrieval/engine.py +0 -0
  48. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/retrieval/memory.py +0 -0
  49. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/security/__init__.py +0 -0
  50. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/security/redactor.py +0 -0
  51. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/security/sanitizer.py +0 -0
  52. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/security/validator.py +0 -0
  53. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/storage/__init__.py +0 -0
  54. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/utils/__init__.py +0 -0
  55. {synap_git-2.4.0 → synap_git-2.4.1}/src/synap_git/utils/serialization.py +0 -0
  56. {synap_git-2.4.0 → synap_git-2.4.1}/website/README.md +0 -0
@@ -7,7 +7,7 @@ __pycache__/
7
7
  .pytest_cache/
8
8
  .mypy_cache/
9
9
  .ruff_cache/
10
- .coverage
10
+ .coverage*
11
11
  htmlcov/
12
12
  dist/
13
13
  build/
@@ -5,7 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [2.4.0] - 2026-08-14
8
+ ## [2.4.1] - 2026-09-11
9
+
10
+ ### Security, Protocol & Architecture Hardening (Audit Remediation)
11
+ - **MCP Stdio Transport Isolation**: Added dedicated `synap mcp serve` command operating cleanly over stdio with zero logging pollution, error JSON-RPC handling, and clean SIGTERM/EOF exits.
12
+ - **Structural Graph & Position-Independent Symbols**: Added stable symbol IDs unaffected by blank lines or docstrings, extended cross-file AST imports to 11 Tree-sitter grammars (TS/JS, Go, Rust, Java, C++, Ruby, PHP, C#), and hardened recursive CTE cycle handling with deduplication.
13
+ - **Data Integrity & Memory**: Fixed Git revert detection via tree-delta comparisons, secured `synap rollback` against dirty working tree overwrites, and introduced persistent mid-repair backups (`.synap/repair_backup.json`).
14
+ - **CLI Commands**: Added `synap lessons list [--json]` and `synap memory decisions [--json]`, with clean empty JSON array returns on uninitialized databases.
15
+ - **Documentation & Website Parity**: Aligned documentation and landing page with exact 10 MCP tools, methodology-backed benchmarks, and comprehensive web architecture guides.
9
16
 
10
17
  ### Performance & Latency
11
18
  - **MCP Search Sub-10ms Retrieval (780x Speedup)**: Optimized MCP `search` latency from 7,200ms to 9.2ms by replacing slow synchronous LLM router calls with deterministic sub-millisecond intent classification, caching vector deserialization in SQLite, and providing direct context grounding for AI coding agents.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: synap-git
3
- Version: 2.4.0
3
+ Version: 2.4.1
4
4
  Summary: Persistent structural context infrastructure for AI coding agents.
5
5
  Project-URL: Homepage, https://github.com/saahilpal/synapse
6
6
  Project-URL: Repository, https://github.com/saahilpal/synapse
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "2.4.0"
5
+ __version__ = "2.4.1"
@@ -19,15 +19,29 @@ app = typer.Typer(help="Checkpoint commands.", no_args_is_help=True)
19
19
 
20
20
  @app.command("create")
21
21
  def checkpoint_create(
22
- path: Annotated[str, typer.Argument(help="Repository path.")] = ".",
23
22
  doing: Annotated[
24
- str, typer.Option(help="What the agent is currently doing.")
23
+ str,
24
+ typer.Argument(
25
+ help="What the agent is currently doing / checkpoint description.",
26
+ show_default=True,
27
+ ),
25
28
  ] = "Manual snapshot",
29
+ path: Annotated[
30
+ str,
31
+ typer.Option("--path", "-p", help="Repository path."),
32
+ ] = ".",
26
33
  files: Annotated[str, typer.Option(help="Comma-separated list of changed files.")] = "",
27
34
  next_step: Annotated[str, typer.Option(help="The next step to be taken.")] = "",
28
35
  blockers: Annotated[str, typer.Option(help="Current blockers or obstacles.")] = "",
29
36
  ) -> None:
30
37
  """Create a new context checkpoint."""
38
+ from pathlib import Path as FilePath
39
+
40
+ # Backward compatibility: if doing is an existing directory path and not a message
41
+ if path == "." and FilePath(doing).is_dir() and doing != "Manual snapshot":
42
+ path = doing
43
+ doing = "Manual snapshot"
44
+
31
45
  runtime = SynapRuntime(_settings(path))
32
46
 
33
47
  checkpoint_id = str(uuid.uuid4())
@@ -5,8 +5,11 @@ from typing import Annotated
5
5
  import questionary
6
6
  import typer
7
7
  from rich.panel import Panel
8
+ from rich.table import Table
8
9
 
9
10
  from synap_git.cli.main import (
11
+ JSON_OPTION,
12
+ _emit,
10
13
  _settings,
11
14
  console,
12
15
  )
@@ -15,6 +18,62 @@ from synap_git.indexer.engine import SynapRuntime
15
18
  app = typer.Typer(help="Lessons commands.", no_args_is_help=True)
16
19
 
17
20
 
21
+ @app.command("list")
22
+ def lessons_list(
23
+ path: Annotated[str, typer.Argument(help="Repository path.")] = ".",
24
+ status: Annotated[
25
+ str,
26
+ typer.Option(
27
+ "--status",
28
+ "-s",
29
+ help="Filter by status: pending, approved, rejected, or all.",
30
+ ),
31
+ ] = "all",
32
+ json_output: Annotated[bool, JSON_OPTION] = False,
33
+ ) -> None:
34
+ """List recorded architectural lessons."""
35
+ runtime = SynapRuntime(_settings(path, json_output=json_output))
36
+ lessons = runtime.store.get_lessons(status)
37
+
38
+ if json_output:
39
+ _emit({"lessons": lessons}, json_output=True)
40
+ return
41
+
42
+ if not lessons:
43
+ console.print(f"[yellow]No lessons found matching status '{status}'.[/yellow]")
44
+ return
45
+
46
+ table = Table(title=f"Synap Lessons ({status})", show_header=True, header_style="bold cyan")
47
+ table.add_column("Lesson ID", style="dim")
48
+ table.add_column("Status")
49
+ table.add_column("What Failed")
50
+ table.add_column("Why / Lesson")
51
+ table.add_column("Revert Commit", style="dim")
52
+
53
+ for item in lessons:
54
+ item_status = item.get("status", "unknown")
55
+ if item_status == "approved":
56
+ status_style = "[green]approved[/green]"
57
+ elif item_status == "pending":
58
+ status_style = "[yellow]pending[/yellow]"
59
+ elif item_status == "rejected":
60
+ status_style = "[red]rejected[/red]"
61
+ else:
62
+ status_style = item_status
63
+
64
+ table.add_row(
65
+ item.get("lesson_id", "")[:12] + "…",
66
+ status_style,
67
+ (item.get("what_failed") or "")[:40]
68
+ + ("…" if len(item.get("what_failed") or "") > 40 else ""),
69
+ (item.get("why_failed") or "")[:45]
70
+ + ("…" if len(item.get("why_failed") or "") > 45 else ""),
71
+ (item.get("revert_commit") or "")[:8],
72
+ )
73
+
74
+ console.print(table)
75
+
76
+
18
77
  @app.command("approve")
19
78
  def lessons_approve(
20
79
  lesson_id: Annotated[str, typer.Argument(help="The ID of the lesson to approve.")],