aline-ai 0.2.6__py3-none-any.whl → 0.3.0__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.
Files changed (45) hide show
  1. {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/METADATA +3 -1
  2. aline_ai-0.3.0.dist-info/RECORD +41 -0
  3. aline_ai-0.3.0.dist-info/entry_points.txt +3 -0
  4. realign/__init__.py +32 -1
  5. realign/cli.py +203 -19
  6. realign/commands/__init__.py +2 -2
  7. realign/commands/clean.py +149 -0
  8. realign/commands/config.py +1 -1
  9. realign/commands/export_shares.py +1785 -0
  10. realign/commands/hide.py +112 -24
  11. realign/commands/import_history.py +873 -0
  12. realign/commands/init.py +104 -217
  13. realign/commands/mirror.py +131 -0
  14. realign/commands/pull.py +101 -0
  15. realign/commands/push.py +155 -245
  16. realign/commands/review.py +216 -54
  17. realign/commands/session_utils.py +139 -4
  18. realign/commands/share.py +965 -0
  19. realign/commands/status.py +559 -0
  20. realign/commands/sync.py +91 -0
  21. realign/commands/undo.py +423 -0
  22. realign/commands/watcher.py +805 -0
  23. realign/config.py +21 -10
  24. realign/file_lock.py +3 -1
  25. realign/hash_registry.py +310 -0
  26. realign/hooks.py +115 -411
  27. realign/logging_config.py +2 -2
  28. realign/mcp_server.py +263 -549
  29. realign/mcp_watcher.py +997 -139
  30. realign/mirror_utils.py +322 -0
  31. realign/prompts/__init__.py +21 -0
  32. realign/prompts/presets.py +238 -0
  33. realign/redactor.py +168 -16
  34. realign/tracker/__init__.py +9 -0
  35. realign/tracker/git_tracker.py +1123 -0
  36. realign/watcher_daemon.py +115 -0
  37. aline_ai-0.2.6.dist-info/RECORD +0 -28
  38. aline_ai-0.2.6.dist-info/entry_points.txt +0 -5
  39. realign/commands/auto_commit.py +0 -242
  40. realign/commands/commit.py +0 -379
  41. realign/commands/search.py +0 -449
  42. realign/commands/show.py +0 -416
  43. {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/WHEEL +0 -0
  44. {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/licenses/LICENSE +0 -0
  45. {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/top_level.txt +0 -0
realign/commands/hide.py CHANGED
@@ -246,22 +246,23 @@ def redact_commit_message(original_message: str) -> str:
246
246
  """
247
247
  Redact commit message.
248
248
 
249
- Original format:
250
- chore: Auto-commit MCP session (2025-11-22 19:24:29)
249
+ Supports both new format (with LLM-Summary) and old format (with Request:).
251
250
 
252
- --- LLM-Summary (claude-3-5-haiku) ---
253
- * [Claude] Discussed database credentials and API keys
254
-
255
- Agent-Redacted: false
256
-
257
- Redacted format:
258
- chore: Auto-commit MCP session (2025-11-22 19:24:29) [REDACTED]
251
+ New format becomes:
252
+ [REDACTED]
259
253
 
260
254
  --- LLM-Summary (claude-3-5-haiku) ---
261
- * [Claude] [REDACTED - Content hidden by user on 2025-11-22T19:30:00]
255
+ * [Claude] [REDACTED - Content hidden by user on timestamp]
262
256
 
263
257
  Agent-Redacted: true
264
258
 
259
+ Old format becomes:
260
+ [REDACTED]
261
+
262
+ ---
263
+ Session: xxx | Turn: #2 | Model: gpt-3.5-turbo
264
+ Request: [REDACTED - Content hidden by user on timestamp]
265
+
265
266
  Args:
266
267
  original_message: Original commit message
267
268
 
@@ -271,18 +272,22 @@ def redact_commit_message(original_message: str) -> str:
271
272
  lines = original_message.split('\n')
272
273
  redacted_lines = []
273
274
  in_summary = False
275
+ found_session_metadata = False
274
276
 
275
277
  timestamp = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
276
278
 
277
279
  for line in lines:
278
- # First line: add [REDACTED] marker
280
+ # First line: replace with [REDACTED]
279
281
  if not redacted_lines:
280
- redacted_lines.append(line.rstrip() + " [REDACTED]")
282
+ redacted_lines.append("[REDACTED]")
281
283
  continue
282
284
 
283
- # LLM Summary section
285
+ # LLM Summary section (new format)
284
286
  if '--- LLM-Summary' in line:
285
287
  in_summary = True
288
+ # Add blank line before summary if we haven't added session metadata
289
+ if not found_session_metadata:
290
+ redacted_lines.append('')
286
291
  redacted_lines.append(line)
287
292
  continue
288
293
 
@@ -307,11 +312,29 @@ def redact_commit_message(original_message: str) -> str:
307
312
  redacted_lines.append(line)
308
313
 
309
314
  else:
310
- # Update Agent-Redacted flag
311
- if line.strip().startswith('Agent-Redacted:'):
315
+ # Check for session metadata line (Session: xxx | Turn: xxx | Model: xxx)
316
+ if line.strip().startswith('Session:') or line.strip().startswith('---'):
317
+ found_session_metadata = True
318
+ # Add blank line before session metadata if not already present
319
+ if redacted_lines and redacted_lines[-1].strip() != '':
320
+ redacted_lines.append('')
321
+ redacted_lines.append(line)
322
+ # Old format: Redact "Request:" line
323
+ elif line.strip().startswith('Request:'):
324
+ redacted_lines.append(f"Request: [REDACTED - Content hidden by user on {timestamp}]")
325
+ # Update Agent-Redacted flag (new format)
326
+ elif line.strip().startswith('Agent-Redacted:'):
312
327
  redacted_lines.append('Agent-Redacted: true')
328
+ # Skip the descriptive summary paragraph in old format
329
+ elif found_session_metadata or line.strip() == '':
330
+ # Keep blank lines and lines after session metadata
331
+ if line.strip() == '' or line.strip().startswith('Session:') or line.strip().startswith('Request:') or line.strip().startswith('---'):
332
+ continue # Will be handled by specific conditions above
333
+ else:
334
+ continue # Skip other content between title and session metadata
313
335
  else:
314
- redacted_lines.append(line)
336
+ # This is likely descriptive text before session metadata - skip it
337
+ continue
315
338
 
316
339
  return '\n'.join(redacted_lines)
317
340
 
@@ -563,16 +586,19 @@ elif commit_hash in commits_to_redact:
563
586
  lines = original_message.split('\\n')
564
587
  redacted_lines = []
565
588
  in_summary = False
589
+ found_session_metadata = False
566
590
 
567
591
  timestamp = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
568
592
 
569
593
  for line in lines:
570
594
  if not redacted_lines:
571
- redacted_lines.append(line.rstrip() + " [REDACTED]")
595
+ redacted_lines.append("[REDACTED]")
572
596
  continue
573
597
 
574
598
  if '--- LLM-Summary' in line:
575
599
  in_summary = True
600
+ if not found_session_metadata:
601
+ redacted_lines.append('')
576
602
  redacted_lines.append(line)
577
603
  continue
578
604
 
@@ -589,10 +615,22 @@ elif commit_hash in commits_to_redact:
589
615
  else:
590
616
  redacted_lines.append(line)
591
617
  else:
592
- if line.strip().startswith('Agent-Redacted:'):
618
+ if line.strip().startswith('Session:') or line.strip().startswith('---'):
619
+ found_session_metadata = True
620
+ if redacted_lines and redacted_lines[-1].strip() != '':
621
+ redacted_lines.append('')
622
+ redacted_lines.append(line)
623
+ elif line.strip().startswith('Request:'):
624
+ redacted_lines.append(f"Request: [REDACTED - Content hidden by user on {timestamp}]")
625
+ elif line.strip().startswith('Agent-Redacted:'):
593
626
  redacted_lines.append('Agent-Redacted: true')
627
+ elif found_session_metadata or line.strip() == '':
628
+ if line.strip() == '' or line.strip().startswith('Session:') or line.strip().startswith('Request:') or line.strip().startswith('---'):
629
+ continue
630
+ else:
631
+ continue
594
632
  else:
595
- redacted_lines.append(line)
633
+ continue
596
634
 
597
635
  print('\\n'.join(redacted_lines))
598
636
  else:
@@ -783,7 +821,9 @@ def apply_redaction_to_working_dir(
783
821
 
784
822
  # Also update the backup file in sessions-original if it exists
785
823
  # This ensures pre-commit hook will use the redacted version
786
- backup_file = repo_root / ".realign" / "sessions-original" / Path(session_file).name
824
+ from realign import get_realign_dir
825
+ realign_dir = get_realign_dir(repo_root)
826
+ backup_file = realign_dir / "sessions-original" / Path(session_file).name
787
827
  if backup_file.exists():
788
828
  with open(backup_file, 'w', encoding='utf-8') as f:
789
829
  f.write(content)
@@ -816,7 +856,7 @@ def hide_command(
816
856
  """
817
857
  logger.info(f"======== Hide command started: indices={indices} ========")
818
858
 
819
- # Auto-detect repo root if not provided
859
+ # Auto-detect user project root if not provided
820
860
  if repo_root is None:
821
861
  try:
822
862
  result = subprocess.run(
@@ -826,12 +866,36 @@ def hide_command(
826
866
  check=True
827
867
  )
828
868
  repo_root = Path(result.stdout.strip())
829
- logger.debug(f"Detected repo root: {repo_root}")
869
+ logger.debug(f"Detected user project root: {repo_root}")
830
870
  except subprocess.CalledProcessError:
831
871
  print("Error: Not in a git repository", file=sys.stderr)
832
872
  logger.error("Not in a git repository")
833
873
  return 1
834
874
 
875
+ # Get shadow git repository path
876
+ from realign import get_realign_dir
877
+ shadow_dir = get_realign_dir(repo_root)
878
+ shadow_git = shadow_dir
879
+
880
+ # Verify shadow git exists
881
+ if not shadow_git.exists():
882
+ print(f"Error: Shadow git repository not found at {shadow_git}", file=sys.stderr)
883
+ print("Run 'aline init' first to initialize the repository.", file=sys.stderr)
884
+ logger.error(f"Shadow git not found at {shadow_git}")
885
+ return 1
886
+
887
+ # Check if it's a git repository
888
+ git_dir = shadow_git / '.git'
889
+ if not git_dir.exists():
890
+ print(f"Error: {shadow_git} is not a git repository", file=sys.stderr)
891
+ print("Run 'aline init' first to initialize the repository.", file=sys.stderr)
892
+ logger.error(f"No .git found in {shadow_git}")
893
+ return 1
894
+
895
+ logger.info(f"Using shadow git repository: {shadow_git}")
896
+ # Override repo_root to point to shadow git
897
+ repo_root = shadow_git
898
+
835
899
  # Perform safety checks
836
900
  safe, message = perform_safety_checks(repo_root)
837
901
  if not safe:
@@ -922,7 +986,7 @@ def hide_reset_command(
922
986
  """
923
987
  logger.info("======== Hide reset command started ========")
924
988
 
925
- # Auto-detect repo root if not provided
989
+ # Auto-detect user project root if not provided
926
990
  if repo_root is None:
927
991
  try:
928
992
  result = subprocess.run(
@@ -932,12 +996,36 @@ def hide_reset_command(
932
996
  check=True
933
997
  )
934
998
  repo_root = Path(result.stdout.strip())
935
- logger.debug(f"Detected repo root: {repo_root}")
999
+ logger.debug(f"Detected user project root: {repo_root}")
936
1000
  except subprocess.CalledProcessError:
937
1001
  print("Error: Not in a git repository", file=sys.stderr)
938
1002
  logger.error("Not in a git repository")
939
1003
  return 1
940
1004
 
1005
+ # Get shadow git repository path
1006
+ from realign import get_realign_dir
1007
+ shadow_dir = get_realign_dir(repo_root)
1008
+ shadow_git = shadow_dir
1009
+
1010
+ # Verify shadow git exists
1011
+ if not shadow_git.exists():
1012
+ print(f"Error: Shadow git repository not found at {shadow_git}", file=sys.stderr)
1013
+ print("Run 'aline init' first to initialize the repository.", file=sys.stderr)
1014
+ logger.error(f"Shadow git not found at {shadow_git}")
1015
+ return 1
1016
+
1017
+ # Check if it's a git repository
1018
+ git_dir = shadow_git / '.git'
1019
+ if not git_dir.exists():
1020
+ print(f"Error: {shadow_git} is not a git repository", file=sys.stderr)
1021
+ print("Run 'aline init' first to initialize the repository.", file=sys.stderr)
1022
+ logger.error(f"No .git found in {shadow_git}")
1023
+ return 1
1024
+
1025
+ logger.info(f"Using shadow git repository: {shadow_git}")
1026
+ # Override repo_root to point to shadow git
1027
+ repo_root = shadow_git
1028
+
941
1029
  # Find all backup refs
942
1030
  result = subprocess.run(
943
1031
  ["git", "for-each-ref", "refs/realign/", "--format=%(refname) %(objectname) %(creatordate:unix)", "--sort=-creatordate"],