aline-ai 0.1.7__py3-none-any.whl → 0.1.9__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: aline-ai
3
- Version: 0.1.7
3
+ Version: 0.1.9
4
4
  Summary: Shared AI memory; everyone knows everything in teams
5
5
  Author: Sharemind
6
6
  License: MIT
@@ -1,13 +1,13 @@
1
- aline_ai-0.1.7.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
2
- realign/__init__.py,sha256=GAkpHLIQWfGF0lu7nkgDnXCA2GC4tJrr6dGTk8GMQB4,68
1
+ aline_ai-0.1.9.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
2
+ realign/__init__.py,sha256=XAZn0QmHa9QpFynxcqvNBgMblMHb6ppHrHzvnAj8p1s,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/hooks.py,sha256=qhAeuln_62OgTq0vboZcUAuP2apOrNn58vSZqKwNmWQ,36456
8
8
  realign/logging_config.py,sha256=KvkKktF-bkUu031y9vgUoHpsbnOw7ud25jhpzliNZwA,4929
9
- realign/mcp_server.py,sha256=srR1leOYbPyi6L0KALkOs94_djELi-SRLFQgrubQuhc,17760
10
- realign/mcp_watcher.py,sha256=xL35Nz35YF6Mc9yu-nCbDzKzTFHQaYmtPNfyBzKKOhc,16038
9
+ realign/mcp_server.py,sha256=HGg0nW9_cJnW-22bSBwBONpid3Lq8UICyWyzOAny4OM,18963
10
+ realign/mcp_watcher.py,sha256=0bMD1Ah7hmmpozJzopnjFTDJrpq76jyTZaXat-Ropy0,19708
11
11
  realign/redactor.py,sha256=uZvLKKGrRGJm-qM8S4XJyJK6i0CSSby_wbKiay7VGJw,8148
12
12
  realign/commands/__init__.py,sha256=GG6IMw6fUBQAXGJDFJvOOQgv6pkiRSfMh8z3AYXTyRM,31
13
13
  realign/commands/auto_commit.py,sha256=_DOw7nt9q3tD_Y3qDL9IFKAUG1hM4qH_xZ-9nyBc2Bc,7451
@@ -16,8 +16,8 @@ realign/commands/config.py,sha256=oarvn6UuGT8svd2h5_8M_ueV5QWOCUOn8SYoa4XYjs8,65
16
16
  realign/commands/init.py,sha256=EpSzh2Dd2EmEQ_wo3vAsg6Uq7_YOlQWIpzIkZa_2y0A,11863
17
17
  realign/commands/search.py,sha256=0CZaXll99wtd01MRiZk5NAblxgogc4RUAzMyJunvckE,18044
18
18
  realign/commands/show.py,sha256=P1waa94-AKJr9XjagkE40OHMXzE6IwC74DpeDKqwsqw,16693
19
- aline_ai-0.1.7.dist-info/METADATA,sha256=lgNJRQ4b1lDkDVvchqzD9VbvXB7bTkxgy9LgmmNaq34,1398
20
- aline_ai-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- aline_ai-0.1.7.dist-info/entry_points.txt,sha256=h-NocHDzSueXfsepHTIdRPNQzhNZQPAztJfldd-mQTE,202
22
- aline_ai-0.1.7.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
23
- aline_ai-0.1.7.dist-info/RECORD,,
19
+ aline_ai-0.1.9.dist-info/METADATA,sha256=H1PCZ5ZGFkeRCgZM7krMrVc9tRcMdBKwP4L25Sncj18,1398
20
+ aline_ai-0.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ aline_ai-0.1.9.dist-info/entry_points.txt,sha256=h-NocHDzSueXfsepHTIdRPNQzhNZQPAztJfldd-mQTE,202
22
+ aline_ai-0.1.9.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
23
+ aline_ai-0.1.9.dist-info/RECORD,,
realign/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Aline - AI Agent Chat Session Tracker."""
2
2
 
3
- __version__ = "0.1.7"
3
+ __version__ = "0.1.9"
realign/mcp_server.py CHANGED
@@ -410,6 +410,22 @@ def _server_log(msg: str):
410
410
  pass
411
411
 
412
412
 
413
+ # Log immediately when module is imported
414
+ _early_log_path = Path.home() / ".aline_mcp_startup.log"
415
+ try:
416
+ with open(_early_log_path, "a") as f:
417
+ from datetime import datetime
418
+ f.write(f"\n{'='*60}\n")
419
+ f.write(f"[{datetime.now()}] MCP SERVER MODULE LOADED\n")
420
+ f.write(f"Python: {sys.executable}\n")
421
+ f.write(f"CWD: {Path.cwd()}\n")
422
+ f.write(f"HOME: {Path.home()}\n")
423
+ f.write(f"Version: {__version__}\n")
424
+ f.write(f"{'='*60}\n")
425
+ except Exception as e:
426
+ print(f"[MCP Server] Early log failed: {e}", file=sys.stderr)
427
+
428
+
413
429
  async def async_main():
414
430
  """Run the MCP server (async)."""
415
431
  _server_log("Starting Aline MCP server...")
@@ -487,7 +503,27 @@ async def async_main():
487
503
 
488
504
  def main():
489
505
  """Entry point for the MCP server command."""
490
- asyncio.run(async_main())
506
+ # Log entry point
507
+ try:
508
+ with open(_early_log_path, "a") as f:
509
+ from datetime import datetime
510
+ f.write(f"[{datetime.now()}] main() called, starting asyncio.run\n")
511
+ except Exception:
512
+ pass
513
+
514
+ try:
515
+ asyncio.run(async_main())
516
+ except Exception as e:
517
+ # Log any exceptions
518
+ try:
519
+ with open(_early_log_path, "a") as f:
520
+ from datetime import datetime
521
+ import traceback
522
+ f.write(f"[{datetime.now()}] EXCEPTION in main: {e}\n")
523
+ f.write(traceback.format_exc())
524
+ except Exception:
525
+ pass
526
+ raise
491
527
 
492
528
 
493
529
  if __name__ == "__main__":
realign/mcp_watcher.py CHANGED
@@ -261,29 +261,111 @@ class DialogueWatcher:
261
261
  Extract the actual project path from a Claude session file's location.
262
262
 
263
263
  Claude Code stores sessions in: ~/.claude/projects/-Users-username-path/session.jsonl
264
- The directory name encodes the project path with dashes replacing slashes.
264
+ The directory name encodes the project path with dashes replacing both slashes and underscores.
265
+ This means we need to intelligently reconstruct the path by testing which separators work.
265
266
  """
266
267
  try:
267
268
  project_dir_name = session_file.parent.name
268
269
  _log(f"Extracting project path from: {project_dir_name}")
269
270
 
270
271
  if project_dir_name.startswith('-'):
271
- # Convert back to path: -Users-foo-bar -> /Users/foo/bar
272
- path_str = '/' + project_dir_name[1:].replace('-', '/')
273
- candidate_path = Path(path_str)
274
- _log(f"Candidate project path: {candidate_path}")
272
+ # Split into segments
273
+ segments = project_dir_name[1:].split('-')
274
+ _log(f"Path segments: {segments}")
275
275
 
276
- if candidate_path.exists():
276
+ # Try to reconstruct the path by checking which combinations exist
277
+ candidate_path = self._reconstruct_path_from_segments(segments)
278
+
279
+ if candidate_path and candidate_path.exists():
277
280
  _log(f"Project path exists: {candidate_path}")
278
281
  return candidate_path
279
282
  else:
280
- _log(f"WARNING: Project path does not exist: {candidate_path}")
283
+ # Fallback: try simple replacement (for backward compatibility)
284
+ simple_path = Path('/' + project_dir_name[1:].replace('-', '/'))
285
+ if simple_path.exists():
286
+ _log(f"Project path exists (simple method): {simple_path}")
287
+ return simple_path
288
+ _log(f"WARNING: Could not find valid project path for: {project_dir_name}")
281
289
  else:
282
290
  _log(f"WARNING: Directory name doesn't start with '-': {project_dir_name}")
283
291
  except Exception as e:
284
292
  _log(f"Error extracting project path: {e}")
285
293
  return None
286
294
 
295
+ def _reconstruct_path_from_segments(self, segments: list) -> Optional[Path]:
296
+ """
297
+ Reconstruct a file path from encoded segments.
298
+
299
+ Claude Code encodes paths by replacing both '/' and '_' with '-'.
300
+ This method tries to find the correct path by testing which separators
301
+ produce valid paths.
302
+
303
+ Strategy:
304
+ 1. Start from root '/'
305
+ 2. Build path incrementally, checking if each partial path exists
306
+ 3. When a segment doesn't match, try combining with next segment using '_' or '-'
307
+ """
308
+ if not segments:
309
+ return None
310
+
311
+ current_path = Path('/')
312
+ i = 0
313
+
314
+ while i < len(segments):
315
+ segment = segments[i]
316
+
317
+ # Try direct match first (segment is a directory/file name)
318
+ test_path = current_path / segment
319
+ if test_path.exists():
320
+ current_path = test_path
321
+ i += 1
322
+ continue
323
+
324
+ # If direct match fails, try combining with next segments using '_' or '-'
325
+ found_match = False
326
+ for lookahead in range(1, min(10, len(segments) - i)): # Try up to 10 segments ahead
327
+ # Try combining segments with underscores
328
+ combined_underscore = '_'.join(segments[i:i+lookahead+1])
329
+ test_path_underscore = current_path / combined_underscore
330
+
331
+ # Try combining segments with hyphens
332
+ combined_hyphen = '-'.join(segments[i:i+lookahead+1])
333
+ test_path_hyphen = current_path / combined_hyphen
334
+
335
+ # Try mixed combinations for longer paths
336
+ if test_path_underscore.exists():
337
+ current_path = test_path_underscore
338
+ i += lookahead + 1
339
+ found_match = True
340
+ _log(f"Found match with underscores: {combined_underscore}")
341
+ break
342
+ elif test_path_hyphen.exists():
343
+ current_path = test_path_hyphen
344
+ i += lookahead + 1
345
+ found_match = True
346
+ _log(f"Found match with hyphens: {combined_hyphen}")
347
+ break
348
+
349
+ if not found_match:
350
+ # If no match found, this might be the final segment (file or non-existent dir)
351
+ # Just append remaining segments with '/' and check
352
+ remaining = '/'.join(segments[i:])
353
+ final_path = current_path / remaining
354
+ if final_path.exists():
355
+ return final_path
356
+
357
+ # Try treating remaining as underscore-joined
358
+ remaining_underscore = '_'.join(segments[i:])
359
+ final_path_underscore = current_path / remaining_underscore
360
+ if final_path_underscore.exists():
361
+ return final_path_underscore
362
+
363
+ # Nothing worked, return what we have
364
+ _log(f"Could not match segment '{segment}' at path {current_path}")
365
+ return None
366
+
367
+ return current_path if current_path != Path('/') else None
368
+
287
369
  async def _do_commit(self, project_path: Path):
288
370
  """Perform the actual commit for a specific project."""
289
371
  try: