ragtime-cli 0.2.11__py3-none-any.whl → 0.2.12__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ragtime-cli
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Summary: Local-first memory and RAG system for Claude Code - semantic search over code, docs, and team knowledge
5
5
  Author-email: Bret Martineau <bretwardjames@gmail.com>
6
6
  License-Expression: MIT
@@ -1,10 +1,10 @@
1
- ragtime_cli-0.2.11.dist-info/licenses/LICENSE,sha256=9A0wJs2PRDciGRH4F8JUJ-aMKYQyq_gVu2ixrXs-l5A,1070
1
+ ragtime_cli-0.2.12.dist-info/licenses/LICENSE,sha256=9A0wJs2PRDciGRH4F8JUJ-aMKYQyq_gVu2ixrXs-l5A,1070
2
2
  src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- src/cli.py,sha256=HDZNFg5shUU1s6JLi9Wn_TydEXx-92JCginJYgH3BlE,74375
3
+ src/cli.py,sha256=Do9R2ItJAGQ3tkTXpTs-4zJhIwDo97clmIuWzM5TVAA,75989
4
4
  src/config.py,sha256=tQ6gPLr4ksn2bJPIUjtELFr-k01Eg4g-LDo3GNE6P0Q,4600
5
5
  src/db.py,sha256=ueSThFXkhI5MFwXICkNW3zqCawGDi3kqFQnbm4st_Ew,8186
6
- src/mcp_server.py,sha256=SvkoGkBqoaZkW3KXiE5qHbbkTIjby94mcxMXgJKv8ik,21559
7
- src/memory.py,sha256=lmDgC9AH24dog6dvbGgHt95TANUgdBZSnLcqM0isx10,15639
6
+ src/mcp_server.py,sha256=BFu6LcaGkKgFhQf52t9hUyrBL2nX1LT3YuACg6OwD2M,21559
7
+ src/memory.py,sha256=VHbKGaBRLQEkUhlzryM0HIZZANipZGLd4Jw_LbY0gwY,16131
8
8
  src/commands/audit.md,sha256=Xkucm-gfBIMalK9wf7NBbyejpsqBTUAGGlb7GxMtMPY,5137
9
9
  src/commands/create-pr.md,sha256=u6-jVkDP_6bJQp6ImK039eY9F6B9E2KlAVlvLY-WV6Q,9483
10
10
  src/commands/generate-docs.md,sha256=9W2Yy-PDyC3p5k39uEb31z5YAHkSKsQLg6gV3tLgSnQ,7015
@@ -18,8 +18,8 @@ src/commands/start.md,sha256=qoqhkMgET74DBx8YPIT1-wqCiVBUDxlmevigsCinHSY,6506
18
18
  src/indexers/__init__.py,sha256=MYoCPZUpHakMX1s2vWnc9shjWfx_X1_0JzUhpKhnKUQ,454
19
19
  src/indexers/code.py,sha256=G2TbiKbWj0e7DV5KsU8-Ggw6ziDb4zTuZ4Bu3ryV4g8,18059
20
20
  src/indexers/docs.py,sha256=nyewQ4Ug4SCuhne4TuLDlUDzz9GH2STInddj81ocz50,3555
21
- ragtime_cli-0.2.11.dist-info/METADATA,sha256=M0M_WyDQE5zDvpoMeo3RG18NJNRUw6IMOVqKh4mexVY,11269
22
- ragtime_cli-0.2.11.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
23
- ragtime_cli-0.2.11.dist-info/entry_points.txt,sha256=cWLbeyMxZNbew-THS3bHXTpCRXt1EaUy5QUOXGXLjl4,75
24
- ragtime_cli-0.2.11.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
25
- ragtime_cli-0.2.11.dist-info/RECORD,,
21
+ ragtime_cli-0.2.12.dist-info/METADATA,sha256=s8nahuddN_C6gMGMt0TFp62HU8gD1Agz_da8lnQMMoU,11269
22
+ ragtime_cli-0.2.12.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
23
+ ragtime_cli-0.2.12.dist-info/entry_points.txt,sha256=cWLbeyMxZNbew-THS3bHXTpCRXt1EaUy5QUOXGXLjl4,75
24
+ ragtime_cli-0.2.12.dist-info/top_level.txt,sha256=74rtVfumQlgAPzR5_2CgYN24MB0XARCg0t-gzk6gTrM,4
25
+ ragtime_cli-0.2.12.dist-info/RECORD,,
src/cli.py CHANGED
@@ -734,6 +734,51 @@ def reindex(path: Path):
734
734
  click.echo(f"✓ Reindexed {count} memory files")
735
735
 
736
736
 
737
+ @main.command()
738
+ @click.option("--path", type=click.Path(exists=True, path_type=Path), default=".")
739
+ @click.option("--dry-run", is_flag=True, help="Show duplicates without removing them")
740
+ def dedupe(path: Path, dry_run: bool):
741
+ """Remove duplicate entries from the index.
742
+
743
+ Keeps one entry per unique file path, removing duplicates created
744
+ by older versions of reindex that generated random IDs.
745
+ """
746
+ path = Path(path).resolve()
747
+ db = get_db(path)
748
+
749
+ # Get all entries with their file paths
750
+ results = db.collection.get(include=["metadatas"])
751
+
752
+ # Group by file path
753
+ by_file: dict[str, list[str]] = {}
754
+ for i, mem_id in enumerate(results["ids"]):
755
+ file_path = results["metadatas"][i].get("file", "")
756
+ if file_path:
757
+ if file_path not in by_file:
758
+ by_file[file_path] = []
759
+ by_file[file_path].append(mem_id)
760
+
761
+ # Find duplicates
762
+ duplicates_to_remove = []
763
+ for file_path, ids in by_file.items():
764
+ if len(ids) > 1:
765
+ # Keep the first one, remove the rest
766
+ duplicates_to_remove.extend(ids[1:])
767
+ if dry_run:
768
+ click.echo(f" {file_path}: {len(ids)} copies (would remove {len(ids) - 1})")
769
+
770
+ if not duplicates_to_remove:
771
+ click.echo("✓ No duplicates found")
772
+ return
773
+
774
+ if dry_run:
775
+ click.echo(f"\nWould remove {len(duplicates_to_remove)} duplicate entries")
776
+ click.echo("Run without --dry-run to remove them")
777
+ else:
778
+ db.delete(duplicates_to_remove)
779
+ click.echo(f"✓ Removed {len(duplicates_to_remove)} duplicate entries")
780
+
781
+
737
782
  @main.command("new-branch")
738
783
  @click.argument("issue", type=int)
739
784
  @click.option("--path", type=click.Path(exists=True, path_type=Path), default=".")
src/mcp_server.py CHANGED
@@ -493,7 +493,7 @@ class RagtimeMCPServer:
493
493
  "protocolVersion": "2024-11-05",
494
494
  "serverInfo": {
495
495
  "name": "ragtime",
496
- "version": "0.2.11",
496
+ "version": "0.2.12",
497
497
  },
498
498
  "capabilities": {
499
499
  "tools": {},
src/memory.py CHANGED
@@ -10,6 +10,7 @@ from dataclasses import dataclass, field
10
10
  from datetime import date
11
11
  from typing import Optional
12
12
  import uuid
13
+ import hashlib
13
14
  import re
14
15
  import yaml
15
16
 
@@ -139,8 +140,19 @@ class Memory:
139
140
  except ValueError:
140
141
  pass # path not relative to base, will regenerate
141
142
 
143
+ # Use frontmatter ID if present, otherwise derive stable ID from file path
144
+ # This ensures reindex is idempotent - same file always gets same ID
145
+ if "id" in frontmatter:
146
+ memory_id = frontmatter["id"]
147
+ elif file_path:
148
+ # Stable hash of relative path
149
+ memory_id = hashlib.sha256(file_path.encode()).hexdigest()[:8]
150
+ else:
151
+ # Fallback: hash of absolute path
152
+ memory_id = hashlib.sha256(str(path).encode()).hexdigest()[:8]
153
+
142
154
  return cls(
143
- id=frontmatter.get("id", str(uuid.uuid4())[:8]),
155
+ id=memory_id,
144
156
  content=content,
145
157
  namespace=frontmatter.get("namespace", "app"),
146
158
  type=frontmatter.get("type", "unknown"),