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.
- {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/METADATA +3 -1
- aline_ai-0.3.0.dist-info/RECORD +41 -0
- aline_ai-0.3.0.dist-info/entry_points.txt +3 -0
- realign/__init__.py +32 -1
- realign/cli.py +203 -19
- realign/commands/__init__.py +2 -2
- realign/commands/clean.py +149 -0
- realign/commands/config.py +1 -1
- realign/commands/export_shares.py +1785 -0
- realign/commands/hide.py +112 -24
- realign/commands/import_history.py +873 -0
- realign/commands/init.py +104 -217
- realign/commands/mirror.py +131 -0
- realign/commands/pull.py +101 -0
- realign/commands/push.py +155 -245
- realign/commands/review.py +216 -54
- realign/commands/session_utils.py +139 -4
- realign/commands/share.py +965 -0
- realign/commands/status.py +559 -0
- realign/commands/sync.py +91 -0
- realign/commands/undo.py +423 -0
- realign/commands/watcher.py +805 -0
- realign/config.py +21 -10
- realign/file_lock.py +3 -1
- realign/hash_registry.py +310 -0
- realign/hooks.py +115 -411
- realign/logging_config.py +2 -2
- realign/mcp_server.py +263 -549
- realign/mcp_watcher.py +997 -139
- realign/mirror_utils.py +322 -0
- realign/prompts/__init__.py +21 -0
- realign/prompts/presets.py +238 -0
- realign/redactor.py +168 -16
- realign/tracker/__init__.py +9 -0
- realign/tracker/git_tracker.py +1123 -0
- realign/watcher_daemon.py +115 -0
- aline_ai-0.2.6.dist-info/RECORD +0 -28
- aline_ai-0.2.6.dist-info/entry_points.txt +0 -5
- realign/commands/auto_commit.py +0 -242
- realign/commands/commit.py +0 -379
- realign/commands/search.py +0 -449
- realign/commands/show.py +0 -416
- {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/WHEEL +0 -0
- {aline_ai-0.2.6.dist-info → aline_ai-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
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
|
-
|
|
253
|
-
|
|
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
|
|
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:
|
|
280
|
+
# First line: replace with [REDACTED]
|
|
279
281
|
if not redacted_lines:
|
|
280
|
-
redacted_lines.append(
|
|
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
|
-
#
|
|
311
|
-
if line.strip().startswith('
|
|
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
|
-
|
|
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(
|
|
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('
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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"],
|