aline-ai 0.5.3__py3-none-any.whl → 0.5.5__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 (80) hide show
  1. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/METADATA +1 -1
  2. aline_ai-0.5.5.dist-info/RECORD +93 -0
  3. realign/__init__.py +1 -1
  4. realign/adapters/antigravity.py +28 -20
  5. realign/adapters/base.py +46 -50
  6. realign/adapters/claude.py +14 -14
  7. realign/adapters/codex.py +7 -7
  8. realign/adapters/gemini.py +11 -11
  9. realign/adapters/registry.py +14 -10
  10. realign/claude_detector.py +2 -2
  11. realign/claude_hooks/__init__.py +3 -3
  12. realign/claude_hooks/permission_request_hook.py +35 -0
  13. realign/claude_hooks/permission_request_hook_installer.py +31 -32
  14. realign/claude_hooks/stop_hook.py +4 -1
  15. realign/claude_hooks/stop_hook_installer.py +30 -31
  16. realign/cli.py +24 -0
  17. realign/codex_detector.py +11 -11
  18. realign/commands/add.py +361 -35
  19. realign/commands/config.py +3 -12
  20. realign/commands/context.py +3 -1
  21. realign/commands/export_shares.py +86 -127
  22. realign/commands/import_shares.py +145 -155
  23. realign/commands/init.py +166 -30
  24. realign/commands/restore.py +18 -6
  25. realign/commands/search.py +14 -42
  26. realign/commands/upgrade.py +155 -11
  27. realign/commands/watcher.py +98 -219
  28. realign/commands/worker.py +29 -6
  29. realign/config.py +25 -20
  30. realign/context.py +1 -3
  31. realign/dashboard/app.py +4 -4
  32. realign/dashboard/screens/create_event.py +3 -1
  33. realign/dashboard/screens/event_detail.py +14 -6
  34. realign/dashboard/screens/session_detail.py +3 -1
  35. realign/dashboard/screens/share_import.py +7 -3
  36. realign/dashboard/tmux_manager.py +91 -22
  37. realign/dashboard/widgets/config_panel.py +85 -1
  38. realign/dashboard/widgets/events_table.py +3 -1
  39. realign/dashboard/widgets/header.py +1 -0
  40. realign/dashboard/widgets/search_panel.py +37 -27
  41. realign/dashboard/widgets/sessions_table.py +24 -15
  42. realign/dashboard/widgets/terminal_panel.py +207 -17
  43. realign/dashboard/widgets/watcher_panel.py +6 -2
  44. realign/dashboard/widgets/worker_panel.py +10 -1
  45. realign/db/__init__.py +1 -1
  46. realign/db/base.py +5 -15
  47. realign/db/locks.py +0 -1
  48. realign/db/migration.py +82 -76
  49. realign/db/schema.py +2 -6
  50. realign/db/sqlite_db.py +23 -41
  51. realign/events/__init__.py +0 -1
  52. realign/events/event_summarizer.py +27 -15
  53. realign/events/session_summarizer.py +29 -15
  54. realign/file_lock.py +1 -0
  55. realign/hooks.py +150 -60
  56. realign/logging_config.py +12 -15
  57. realign/mcp_server.py +30 -51
  58. realign/mcp_watcher.py +0 -1
  59. realign/models/event.py +29 -20
  60. realign/prompts/__init__.py +7 -7
  61. realign/prompts/presets.py +15 -11
  62. realign/redactor.py +99 -59
  63. realign/triggers/__init__.py +9 -9
  64. realign/triggers/antigravity_trigger.py +30 -28
  65. realign/triggers/base.py +4 -3
  66. realign/triggers/claude_trigger.py +104 -85
  67. realign/triggers/codex_trigger.py +15 -5
  68. realign/triggers/gemini_trigger.py +57 -47
  69. realign/triggers/next_turn_trigger.py +3 -1
  70. realign/triggers/registry.py +6 -2
  71. realign/triggers/turn_status.py +3 -1
  72. realign/watcher_core.py +306 -131
  73. realign/watcher_daemon.py +8 -8
  74. realign/worker_core.py +3 -1
  75. realign/worker_daemon.py +3 -1
  76. aline_ai-0.5.3.dist-info/RECORD +0 -93
  77. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/WHEEL +0 -0
  78. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/entry_points.txt +0 -0
  79. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/licenses/LICENSE +0 -0
  80. {aline_ai-0.5.3.dist-info → aline_ai-0.5.5.dist-info}/top_level.txt +0 -0
@@ -31,6 +31,7 @@ def schedule_event_summary_update(db: SQLiteDatabase, event_id: str) -> None:
31
31
  db: Database instance
32
32
  event_id: ID of the event to update
33
33
  """
34
+
34
35
  def do_update():
35
36
  _update_event_summary(db, event_id)
36
37
 
@@ -122,10 +123,17 @@ def _get_event_summary_prompt() -> str:
122
123
  logger.debug(f"Loaded user-customized event summary prompt from {user_prompt_path}")
123
124
  return text
124
125
  except Exception:
125
- logger.debug("Failed to load user-customized event summary prompt, falling back", exc_info=True)
126
+ logger.debug(
127
+ "Failed to load user-customized event summary prompt, falling back", exc_info=True
128
+ )
126
129
 
127
130
  # Fall back to built-in prompt (tools/commit_message_prompts/event_summary.md)
128
- candidate = Path(__file__).resolve().parents[2] / "tools" / "commit_message_prompts" / "event_summary.md"
131
+ candidate = (
132
+ Path(__file__).resolve().parents[2]
133
+ / "tools"
134
+ / "commit_message_prompts"
135
+ / "event_summary.md"
136
+ )
129
137
  try:
130
138
  if candidate.exists():
131
139
  text = candidate.read_text(encoding="utf-8").strip()
@@ -184,19 +192,25 @@ def _generate_event_summary_llm(sessions: List[SessionRecord]) -> Tuple[str, str
184
192
  # Build sessions payload for prompt
185
193
  sessions_data = []
186
194
  for i, session in enumerate(sessions):
187
- sessions_data.append({
188
- "session_number": i + 1,
189
- "title": session.session_title or f"Session {session.id[:8]}",
190
- "summary": session.session_summary or "(no summary)",
191
- "session_type": session.session_type,
192
- })
195
+ sessions_data.append(
196
+ {
197
+ "session_number": i + 1,
198
+ "title": session.session_title or f"Session {session.id[:8]}",
199
+ "summary": session.session_summary or "(no summary)",
200
+ "session_type": session.session_type,
201
+ }
202
+ )
193
203
 
194
204
  system_prompt = _get_event_summary_prompt()
195
205
 
196
- user_prompt = json.dumps({
197
- "total_sessions": len(sessions),
198
- "sessions": sessions_data,
199
- }, ensure_ascii=False, indent=2)
206
+ user_prompt = json.dumps(
207
+ {
208
+ "total_sessions": len(sessions),
209
+ "sessions": sessions_data,
210
+ },
211
+ ensure_ascii=False,
212
+ indent=2,
213
+ )
200
214
 
201
215
  try:
202
216
  # Use unified LLM client
@@ -205,7 +219,7 @@ def _generate_event_summary_llm(sessions: List[SessionRecord]) -> Tuple[str, str
205
219
  user_prompt=user_prompt,
206
220
  provider="auto", # Try Claude first, fallback to OpenAI
207
221
  max_tokens=500,
208
- purpose="event_summary"
222
+ purpose="event_summary",
209
223
  )
210
224
 
211
225
  if not response:
@@ -241,5 +255,3 @@ def _fallback_event_summary(sessions: List[SessionRecord]) -> Tuple[str, str]:
241
255
  description = f"Event containing {len(sessions)} sessions."
242
256
 
243
257
  return title[:100], description
244
-
245
-
@@ -176,13 +176,22 @@ def _get_session_summary_prompt() -> str:
176
176
  text = user_prompt_path.read_text(encoding="utf-8").strip()
177
177
  if text:
178
178
  _SESSION_SUMMARY_PROMPT_CACHE = text
179
- logger.debug(f"Loaded user-customized session summary prompt from {user_prompt_path}")
179
+ logger.debug(
180
+ f"Loaded user-customized session summary prompt from {user_prompt_path}"
181
+ )
180
182
  return text
181
183
  except Exception:
182
- logger.debug("Failed to load user-customized session summary prompt, falling back", exc_info=True)
184
+ logger.debug(
185
+ "Failed to load user-customized session summary prompt, falling back", exc_info=True
186
+ )
183
187
 
184
188
  # Fall back to built-in prompt (tools/commit_message_prompts/session_summary.md)
185
- candidate = Path(__file__).resolve().parents[2] / "tools" / "commit_message_prompts" / "session_summary.md"
189
+ candidate = (
190
+ Path(__file__).resolve().parents[2]
191
+ / "tools"
192
+ / "commit_message_prompts"
193
+ / "session_summary.md"
194
+ )
186
195
  try:
187
196
  if candidate.exists():
188
197
  text = candidate.read_text(encoding="utf-8").strip()
@@ -234,19 +243,25 @@ def _generate_session_summary_llm(turns: List[TurnRecord]) -> Tuple[str, str]:
234
243
  # Build turns payload for prompt
235
244
  turns_data = []
236
245
  for i, turn in enumerate(turns):
237
- turns_data.append({
238
- "turn_number": i + 1,
239
- "title": turn.llm_title or "(no title)",
240
- "summary": turn.assistant_summary or "(no summary)",
241
- "user_request": (turn.user_message or "")[:200], # Truncate long messages
242
- })
246
+ turns_data.append(
247
+ {
248
+ "turn_number": i + 1,
249
+ "title": turn.llm_title or "(no title)",
250
+ "summary": turn.assistant_summary or "(no summary)",
251
+ "user_request": (turn.user_message or "")[:200], # Truncate long messages
252
+ }
253
+ )
243
254
 
244
255
  system_prompt = _get_session_summary_prompt()
245
256
 
246
- user_prompt = json.dumps({
247
- "total_turns": len(turns),
248
- "turns": turns_data,
249
- }, ensure_ascii=False, indent=2)
257
+ user_prompt = json.dumps(
258
+ {
259
+ "total_turns": len(turns),
260
+ "turns": turns_data,
261
+ },
262
+ ensure_ascii=False,
263
+ indent=2,
264
+ )
250
265
 
251
266
  try:
252
267
  # Use unified LLM client
@@ -255,7 +270,7 @@ def _generate_session_summary_llm(turns: List[TurnRecord]) -> Tuple[str, str]:
255
270
  user_prompt=user_prompt,
256
271
  provider="auto", # Try Claude first, fallback to OpenAI
257
272
  max_tokens=500,
258
- purpose="session_summary"
273
+ purpose="session_summary",
259
274
  )
260
275
 
261
276
  if not response:
@@ -290,4 +305,3 @@ def _fallback_summary(turns: List[TurnRecord]) -> Tuple[str, str]:
290
305
  summary = "\n".join(f"- {s}" for s in recent) if recent else ""
291
306
 
292
307
  return title, summary
293
-
realign/file_lock.py CHANGED
@@ -109,6 +109,7 @@ def commit_lock(repo_path: Path, timeout: float = 10.0):
109
109
  True if lock was acquired
110
110
  """
111
111
  from realign import get_realign_dir
112
+
112
113
  realign_dir = get_realign_dir(repo_path)
113
114
  lock_file = realign_dir / ".commit.lock"
114
115
  lock = FileLock(lock_file, timeout=timeout)