aline-ai 0.2.0__py3-none-any.whl → 0.2.1__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.0.dist-info → aline_ai-0.2.1.dist-info}/METADATA +1 -1
- {aline_ai-0.2.0.dist-info → aline_ai-0.2.1.dist-info}/RECORD +9 -9
- realign/__init__.py +1 -1
- realign/commands/init.py +8 -2
- realign/hooks.py +95 -7
- {aline_ai-0.2.0.dist-info → aline_ai-0.2.1.dist-info}/WHEEL +0 -0
- {aline_ai-0.2.0.dist-info → aline_ai-0.2.1.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.2.0.dist-info → aline_ai-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.2.0.dist-info → aline_ai-0.2.1.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
aline_ai-0.2.
|
|
2
|
-
realign/__init__.py,sha256=
|
|
1
|
+
aline_ai-0.2.1.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
|
|
2
|
+
realign/__init__.py,sha256=sNvIfQwzqITXLdabCJUP5PXKHVVX4aRdXM2HnStJpuY,68
|
|
3
3
|
realign/claude_detector.py,sha256=NLxI0zJWcqNxNha9jAy9AslTMwHKakCc9yPGdkrbiFE,3028
|
|
4
4
|
realign/cli.py,sha256=bkwS329jMDEkrUEihXRN2DDyeTKE6HbAysoDxxskZ8g,941
|
|
5
5
|
realign/codex_detector.py,sha256=RI3JbZgebrhoqpRfTBMfclYCAISN7hZAHVW3bgftJpU,4428
|
|
6
6
|
realign/config.py,sha256=jarinbr0mA6e5DmgY19b_VpMnxk6SOYTwyvB9luq0ww,7207
|
|
7
7
|
realign/file_lock.py,sha256=-9c3tMdMj_ZxmasK5y6hV9Gfo6KDsSO3Q7PXiTBhsu4,3369
|
|
8
|
-
realign/hooks.py,sha256=
|
|
8
|
+
realign/hooks.py,sha256=kJXtmATg627dR_5ytER-lyGJwWCgfoANUjIg7gNgAJE,48724
|
|
9
9
|
realign/logging_config.py,sha256=KvkKktF-bkUu031y9vgUoHpsbnOw7ud25jhpzliNZwA,4929
|
|
10
10
|
realign/mcp_server.py,sha256=dntFatMpozI80K5hHrIiQ9sviC6ARKTP89goULhi1T4,16477
|
|
11
11
|
realign/mcp_watcher.py,sha256=D6qVM0yD2hQPxrD_HnHkDob78_dqK96klHIogh48cw4,23971
|
|
@@ -14,12 +14,12 @@ realign/commands/__init__.py,sha256=GG6IMw6fUBQAXGJDFJvOOQgv6pkiRSfMh8z3AYXTyRM,
|
|
|
14
14
|
realign/commands/auto_commit.py,sha256=jgjAYZHqN34NmQkncZg3Vtwsl3MyAlsvucxEBwUj7ko,7450
|
|
15
15
|
realign/commands/commit.py,sha256=mlwrv5nfTRY17WlcAdiJKKGh5uM7dGvT7sMxhdbsfkw,12605
|
|
16
16
|
realign/commands/config.py,sha256=iiu7usqw00djKZja5bx0iDH8DB0vU2maUPMkXLdgXwI,6609
|
|
17
|
-
realign/commands/init.py,sha256=
|
|
17
|
+
realign/commands/init.py,sha256=52WkcgdTdsvYXYOuTQ0zR1QF6QOWsjWOuu0f8vLhbL4,13452
|
|
18
18
|
realign/commands/search.py,sha256=xTWuX0lpjQPX8cen0ewl-BNF0FeWgjMwN06bdeesED8,18770
|
|
19
19
|
realign/commands/session_utils.py,sha256=L1DwZIGCOBirp6tkAswACJEeDa6i9aAAfsialAs4rRY,864
|
|
20
20
|
realign/commands/show.py,sha256=A9LvhOBcY6_HoI76irPB2rBOSgdftBuX2uZiO8IwNoU,16338
|
|
21
|
-
aline_ai-0.2.
|
|
22
|
-
aline_ai-0.2.
|
|
23
|
-
aline_ai-0.2.
|
|
24
|
-
aline_ai-0.2.
|
|
25
|
-
aline_ai-0.2.
|
|
21
|
+
aline_ai-0.2.1.dist-info/METADATA,sha256=oG0lXeu_ljDF-lXinBIrfA_Hhk-fbxNG9KqKnw7V8vw,1398
|
|
22
|
+
aline_ai-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
aline_ai-0.2.1.dist-info/entry_points.txt,sha256=h-NocHDzSueXfsepHTIdRPNQzhNZQPAztJfldd-mQTE,202
|
|
24
|
+
aline_ai-0.2.1.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
|
|
25
|
+
aline_ai-0.2.1.dist-info/RECORD,,
|
realign/__init__.py
CHANGED
realign/commands/init.py
CHANGED
|
@@ -119,10 +119,16 @@ def init_repository(
|
|
|
119
119
|
hook_path.chmod(0o755)
|
|
120
120
|
result["hooks_created"].append(f"prepare-commit-msg ({action})")
|
|
121
121
|
|
|
122
|
-
# Create .gitignore for sessions
|
|
122
|
+
# Create .gitignore for sessions and metadata
|
|
123
123
|
gitignore_path = realign_dir / ".gitignore"
|
|
124
124
|
if not gitignore_path.exists():
|
|
125
|
-
|
|
125
|
+
gitignore_content = (
|
|
126
|
+
"# Uncomment to ignore session files\n"
|
|
127
|
+
"# sessions/\n\n"
|
|
128
|
+
"# Ignore metadata files (used internally to prevent duplicate processing)\n"
|
|
129
|
+
".metadata/\n"
|
|
130
|
+
)
|
|
131
|
+
gitignore_path.write_text(gitignore_content, encoding="utf-8")
|
|
126
132
|
|
|
127
133
|
# Backup and set core.hooksPath
|
|
128
134
|
backup_file = realign_dir / "backup_hook_config.yaml"
|
realign/hooks.py
CHANGED
|
@@ -689,12 +689,12 @@ def copy_session_to_repo(
|
|
|
689
689
|
repo_root: Path,
|
|
690
690
|
user: str,
|
|
691
691
|
config: Optional[ReAlignConfig] = None
|
|
692
|
-
) -> Tuple[Path, str, bool]:
|
|
692
|
+
) -> Tuple[Path, str, bool, int]:
|
|
693
693
|
"""
|
|
694
694
|
Copy session file to repository .realign/sessions/ directory.
|
|
695
695
|
Optionally redacts sensitive information if configured.
|
|
696
696
|
If the source filename is in UUID format, renames it to include username for better identification.
|
|
697
|
-
Returns (absolute_path, relative_path, was_redacted).
|
|
697
|
+
Returns (absolute_path, relative_path, was_redacted, content_size).
|
|
698
698
|
"""
|
|
699
699
|
logger.info(f"Copying session to repo: {session_file.name}")
|
|
700
700
|
logger.debug(f"Source: {session_file}, Repo root: {repo_root}, User: {user}")
|
|
@@ -746,7 +746,12 @@ def copy_session_to_repo(
|
|
|
746
746
|
temp_path.rename(dest_path)
|
|
747
747
|
rel_path = dest_path.relative_to(repo_root)
|
|
748
748
|
logger.warning(f"Copied session with fallback (no agent detection): {rel_path}")
|
|
749
|
-
|
|
749
|
+
# Get file size for the fallback case
|
|
750
|
+
try:
|
|
751
|
+
fallback_size = dest_path.stat().st_size
|
|
752
|
+
except Exception:
|
|
753
|
+
fallback_size = 0
|
|
754
|
+
return dest_path, str(rel_path), False, fallback_size
|
|
750
755
|
|
|
751
756
|
# Detect agent type from session content
|
|
752
757
|
agent_type = "unknown"
|
|
@@ -843,9 +848,68 @@ def copy_session_to_repo(
|
|
|
843
848
|
shutil.copy2(session_file, dest_path)
|
|
844
849
|
logger.warning("Fallback to simple copy")
|
|
845
850
|
|
|
846
|
-
# Return both absolute and relative paths, plus redaction status
|
|
851
|
+
# Return both absolute and relative paths, plus redaction status and content size
|
|
847
852
|
rel_path = dest_path.relative_to(repo_root)
|
|
848
|
-
|
|
853
|
+
content_size = len(content)
|
|
854
|
+
return dest_path, str(rel_path), was_redacted, content_size
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
def save_session_metadata(repo_root: Path, session_relpath: str, content_size: int):
|
|
858
|
+
"""
|
|
859
|
+
Save metadata about a processed session to avoid reprocessing.
|
|
860
|
+
|
|
861
|
+
Args:
|
|
862
|
+
repo_root: Path to repository root
|
|
863
|
+
session_relpath: Relative path to session file
|
|
864
|
+
content_size: Size of session content when processed
|
|
865
|
+
"""
|
|
866
|
+
metadata_dir = repo_root / ".realign" / ".metadata"
|
|
867
|
+
metadata_dir.mkdir(parents=True, exist_ok=True)
|
|
868
|
+
|
|
869
|
+
# Use session filename as metadata key
|
|
870
|
+
session_name = Path(session_relpath).name
|
|
871
|
+
metadata_file = metadata_dir / f"{session_name}.meta"
|
|
872
|
+
|
|
873
|
+
metadata = {
|
|
874
|
+
"processed_at": time.time(),
|
|
875
|
+
"content_size": content_size,
|
|
876
|
+
"session_relpath": session_relpath,
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
try:
|
|
880
|
+
with open(metadata_file, 'w', encoding='utf-8') as f:
|
|
881
|
+
json.dump(metadata, f)
|
|
882
|
+
logger.debug(f"Saved metadata for {session_relpath}: {content_size} bytes")
|
|
883
|
+
except Exception as e:
|
|
884
|
+
logger.warning(f"Failed to save metadata for {session_relpath}: {e}")
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
def get_session_metadata(repo_root: Path, session_relpath: str) -> Optional[Dict[str, Any]]:
|
|
888
|
+
"""
|
|
889
|
+
Get metadata about a previously processed session.
|
|
890
|
+
|
|
891
|
+
Args:
|
|
892
|
+
repo_root: Path to repository root
|
|
893
|
+
session_relpath: Relative path to session file
|
|
894
|
+
|
|
895
|
+
Returns:
|
|
896
|
+
Metadata dictionary or None if not found
|
|
897
|
+
"""
|
|
898
|
+
metadata_dir = repo_root / ".realign" / ".metadata"
|
|
899
|
+
session_name = Path(session_relpath).name
|
|
900
|
+
metadata_file = metadata_dir / f"{session_name}.meta"
|
|
901
|
+
|
|
902
|
+
if not metadata_file.exists():
|
|
903
|
+
return None
|
|
904
|
+
|
|
905
|
+
try:
|
|
906
|
+
with open(metadata_file, 'r', encoding='utf-8') as f:
|
|
907
|
+
metadata = json.load(f)
|
|
908
|
+
logger.debug(f"Loaded metadata for {session_relpath}: {metadata.get('content_size')} bytes")
|
|
909
|
+
return metadata
|
|
910
|
+
except Exception as e:
|
|
911
|
+
logger.warning(f"Failed to load metadata for {session_relpath}: {e}")
|
|
912
|
+
return None
|
|
849
913
|
|
|
850
914
|
|
|
851
915
|
def process_sessions(
|
|
@@ -915,13 +979,15 @@ def process_sessions(
|
|
|
915
979
|
|
|
916
980
|
# Copy all sessions to repo (with optional redaction)
|
|
917
981
|
session_relpaths = []
|
|
982
|
+
session_metadata_map = {} # Map session_relpath -> content_size
|
|
918
983
|
any_redacted = False
|
|
919
984
|
for session_file in session_files:
|
|
920
985
|
try:
|
|
921
|
-
_, session_relpath, was_redacted = copy_session_to_repo(
|
|
986
|
+
_, session_relpath, was_redacted, content_size = copy_session_to_repo(
|
|
922
987
|
session_file, repo_root, user, config
|
|
923
988
|
)
|
|
924
989
|
session_relpaths.append(session_relpath)
|
|
990
|
+
session_metadata_map[session_relpath] = content_size
|
|
925
991
|
if was_redacted:
|
|
926
992
|
any_redacted = True
|
|
927
993
|
except Exception as e:
|
|
@@ -941,8 +1007,13 @@ def process_sessions(
|
|
|
941
1007
|
|
|
942
1008
|
logger.info(f"Copied {len(session_relpaths)} session(s): {session_relpaths}")
|
|
943
1009
|
|
|
944
|
-
# If pre-commit mode,
|
|
1010
|
+
# If pre-commit mode, save metadata and return session paths (summary will be generated later)
|
|
945
1011
|
if pre_commit_mode:
|
|
1012
|
+
# Save metadata for each session to prevent reprocessing
|
|
1013
|
+
for session_relpath, content_size in session_metadata_map.items():
|
|
1014
|
+
save_session_metadata(repo_root, session_relpath, content_size)
|
|
1015
|
+
logger.debug(f"Saved metadata for {session_relpath} in pre-commit")
|
|
1016
|
+
|
|
946
1017
|
elapsed = time.time() - start_time
|
|
947
1018
|
logger.info(f"======== Hook completed: {hook_type} in {elapsed:.2f}s ========")
|
|
948
1019
|
return {
|
|
@@ -974,6 +1045,19 @@ def process_sessions(
|
|
|
974
1045
|
summary_model_label: Optional[str] = None
|
|
975
1046
|
|
|
976
1047
|
for session_relpath in session_relpaths:
|
|
1048
|
+
# Check if this session was already processed in pre-commit hook
|
|
1049
|
+
previous_metadata = get_session_metadata(repo_root, session_relpath)
|
|
1050
|
+
current_size = session_metadata_map.get(session_relpath, 0)
|
|
1051
|
+
|
|
1052
|
+
if previous_metadata:
|
|
1053
|
+
previous_size = previous_metadata.get("content_size", 0)
|
|
1054
|
+
if previous_size == current_size:
|
|
1055
|
+
logger.info(f"Session {session_relpath} unchanged since pre-commit (size: {current_size}), skipping")
|
|
1056
|
+
print(f"⏭️ Skipping {Path(session_relpath).name} (no new content since pre-commit)", file=sys.stderr)
|
|
1057
|
+
continue
|
|
1058
|
+
else:
|
|
1059
|
+
logger.info(f"Session {session_relpath} size changed: {previous_size} -> {current_size}")
|
|
1060
|
+
|
|
977
1061
|
# Extract NEW content using git diff
|
|
978
1062
|
new_content = get_new_content_from_git_diff(repo_root, session_relpath)
|
|
979
1063
|
|
|
@@ -1020,6 +1104,10 @@ def process_sessions(
|
|
|
1020
1104
|
})
|
|
1021
1105
|
legacy_summary_chunks.append(f"[{agent_name}] {summary_text}")
|
|
1022
1106
|
|
|
1107
|
+
# Update metadata after successfully generating summary
|
|
1108
|
+
save_session_metadata(repo_root, session_relpath, current_size)
|
|
1109
|
+
logger.debug(f"Updated metadata for {session_relpath} in prepare-commit-msg")
|
|
1110
|
+
|
|
1023
1111
|
# Combine all summaries
|
|
1024
1112
|
if summary_entries:
|
|
1025
1113
|
if summary_model_label is None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|