aline-ai 0.6.5__py3-none-any.whl → 0.6.7__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 (42) hide show
  1. {aline_ai-0.6.5.dist-info → aline_ai-0.6.7.dist-info}/METADATA +1 -1
  2. {aline_ai-0.6.5.dist-info → aline_ai-0.6.7.dist-info}/RECORD +41 -34
  3. realign/__init__.py +1 -1
  4. realign/agent_names.py +79 -0
  5. realign/claude_hooks/stop_hook.py +3 -0
  6. realign/claude_hooks/terminal_state.py +43 -1
  7. realign/claude_hooks/user_prompt_submit_hook.py +3 -0
  8. realign/cli.py +62 -0
  9. realign/codex_detector.py +18 -3
  10. realign/codex_home.py +65 -16
  11. realign/codex_terminal_linker.py +18 -7
  12. realign/commands/agent.py +109 -0
  13. realign/commands/doctor.py +74 -1
  14. realign/commands/export_shares.py +448 -0
  15. realign/commands/import_shares.py +203 -1
  16. realign/commands/search.py +58 -29
  17. realign/commands/sync_agent.py +347 -0
  18. realign/dashboard/app.py +9 -9
  19. realign/dashboard/clipboard.py +54 -0
  20. realign/dashboard/screens/__init__.py +4 -0
  21. realign/dashboard/screens/agent_detail.py +333 -0
  22. realign/dashboard/screens/create_agent_info.py +244 -0
  23. realign/dashboard/screens/event_detail.py +6 -27
  24. realign/dashboard/styles/dashboard.tcss +22 -28
  25. realign/dashboard/tmux_manager.py +36 -10
  26. realign/dashboard/widgets/__init__.py +2 -2
  27. realign/dashboard/widgets/agents_panel.py +1248 -0
  28. realign/dashboard/widgets/events_table.py +4 -27
  29. realign/dashboard/widgets/sessions_table.py +4 -27
  30. realign/db/base.py +69 -0
  31. realign/db/locks.py +4 -0
  32. realign/db/schema.py +111 -2
  33. realign/db/sqlite_db.py +360 -2
  34. realign/events/agent_summarizer.py +157 -0
  35. realign/events/session_summarizer.py +25 -0
  36. realign/watcher_core.py +193 -5
  37. realign/worker_core.py +59 -1
  38. realign/dashboard/widgets/terminal_panel.py +0 -1653
  39. {aline_ai-0.6.5.dist-info → aline_ai-0.6.7.dist-info}/WHEEL +0 -0
  40. {aline_ai-0.6.5.dist-info → aline_ai-0.6.7.dist-info}/entry_points.txt +0 -0
  41. {aline_ai-0.6.5.dist-info → aline_ai-0.6.7.dist-info}/licenses/LICENSE +0 -0
  42. {aline_ai-0.6.5.dist-info → aline_ai-0.6.7.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aline-ai
3
- Version: 0.6.5
3
+ Version: 0.6.7
4
4
  Summary: Shared AI memory; everyone knows everything in teams
5
5
  Author: Sharemind
6
6
  License: MIT
@@ -1,11 +1,12 @@
1
- aline_ai-0.6.5.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
2
- realign/__init__.py,sha256=02FiDcPQx1TGbGJO98rtDO7k-JAA9WrZKtygoavnEY8,1623
1
+ aline_ai-0.6.7.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
2
+ realign/__init__.py,sha256=_XHUZdw-wtPtpgm845liUkFT-VXg86ZiqDK3pdnnh9Q,1623
3
+ realign/agent_names.py,sha256=H4oVJMkqg1ZYCk58vD_Jh9apaAHSFJRswa-C9SPdJxc,1171
3
4
  realign/auth.py,sha256=d_1yvCwluN5iIrdgjtuSKpOYAksDzrzNgntKacLVJrw,16583
4
5
  realign/claude_detector.py,sha256=ZLSJacMo6zzQclXByABKA70UNpstxqIv3fPGqdpA934,2792
5
- realign/cli.py,sha256=HZ_1Rm50z1oszCwvPAZcAdPt0Gl-dj0S0NMLy2sWu_4,35665
6
- realign/codex_detector.py,sha256=xTpYgMfUwL6UL76xeHl8xF2ZBPHdjwmgXmbmZkvHA0A,5523
7
- realign/codex_home.py,sha256=gAAosBDru4jfz0QCn12A2bZEC_lZxytpOAzk7GOXTpI,2512
8
- realign/codex_terminal_linker.py,sha256=9cDUHhN7MhCIUOfb-3kApPY-l6s91jq2qq_WI0ccexY,5926
6
+ realign/cli.py,sha256=IctmQ0OTb6kLlWRFRQumdhY6-CpcpFtocdc68KiwxvM,37748
7
+ realign/codex_detector.py,sha256=WGIClvlrFVCqJ5vR9DrKVsp1eJhOShvcaXibTHb0Nfc,6304
8
+ realign/codex_home.py,sha256=ljkW8uCfQD4cisEJtPNQmIgaR0yEfWSyHwoVQFY-6p4,4374
9
+ realign/codex_terminal_linker.py,sha256=L2Ha4drlZ7Sbq2jzXyxczOdUY3S5fu1gJqoI5WN9CKk,6211
9
10
  realign/config.py,sha256=Znfs43AjiK90LGWnArDPWyrE859sdZQAPIb0KAcU3Ig,9252
10
11
  realign/context.py,sha256=8hzgNOg-7_eMW22wt7OM5H9IsmMveKXCv0epG7E0G7w,13917
11
12
  realign/file_lock.py,sha256=kLNm1Rra4TCrTMyPM5fwjVascq-CUz2Bzh9HHKtCKOE,3444
@@ -15,9 +16,9 @@ realign/logging_config.py,sha256=LCAigKFhTj86PSJm4-kUl3Ag9h_GENh3x2iPnMv7qUI,487
15
16
  realign/mcp_server.py,sha256=LWiQ2qukYoNLsoV2ID2f0vF9jkJlBvB587HpM5jymgE,10193
16
17
  realign/mcp_watcher.py,sha256=aK4jWStv7CoCroS4tXFHgZ_y_-q4QDjrpWgm4DxcEj4,1260
17
18
  realign/redactor.py,sha256=Zsoi5HfYak2yPmck20JArhm-1cPSB78IdkBJiNVXfrc,17096
18
- realign/watcher_core.py,sha256=0XCoA5giuie-Ytc_tlPTVbZH8EFRPmODu7DUYRhRBGo,108598
19
+ realign/watcher_core.py,sha256=XOJarc_jjlf51Gj8ytcdEeaDUkVIq3Ow0bMbFHbKfAM,116690
19
20
  realign/watcher_daemon.py,sha256=OHUQ9P1LlagKJHfrf6uRnzO-zDtBRXIxt8ydMFHf5S8,3475
20
- realign/worker_core.py,sha256=TXioUVJlOO-8EgmKssCTLIyuh0aaupRLb1sh9s3kSuc,10194
21
+ realign/worker_core.py,sha256=IXDFvkmeboOUvWyNJ3iZ7xlfxAulPnmFlAtuuJSdgRo,12362
21
22
  realign/worker_daemon.py,sha256=X7Xyjw_u6m6KG4E84nx0HpDFw4cWMv8ja1G8btc9PiM,3957
22
23
  realign/adapters/__init__.py,sha256=alkJr7DRn_CrJecSJRjRJOHHnkz9EnZ5TnsU8n1Bb0k,719
23
24
  realign/adapters/base.py,sha256=2IdAZKGjg5gPB3YLf_8r3V4XAdbK7fHpj06GjjsYEFY,7409
@@ -28,62 +29,68 @@ realign/adapters/registry.py,sha256=yM6nf9nGTJ1vaK2Uixp-VacseK7PmxZkCdKedmWI8MA,
28
29
  realign/claude_hooks/__init__.py,sha256=MT9c8TWjLO23xDCM-uBBMy_mOThNd7O-AgN_Khn30qs,594
29
30
  realign/claude_hooks/permission_request_hook.py,sha256=jMN7UtL6bMqHObUCP5A5ysvFrooDEcd9KxtmF2-3nCw,6448
30
31
  realign/claude_hooks/permission_request_hook_installer.py,sha256=_8Wr_L5MES7iGukJzcaj4bqR0BH8kFL44U_X4iKtw2Y,7791
31
- realign/claude_hooks/stop_hook.py,sha256=GWADlzaTGzV8_BUKLLGhHmwJDIXSLQGVUUBuP_rdJ0o,13431
32
+ realign/claude_hooks/stop_hook.py,sha256=Bzf6CjHQ-0q61SrDrpIvcwt_BmDO1FE-f8cws_aA-Is,13582
32
33
  realign/claude_hooks/stop_hook_installer.py,sha256=uyqKOqpix7CQP64ERBvvh7viSPp_wx_JVGNAX18rKh0,7228
33
- realign/claude_hooks/terminal_state.py,sha256=i8B6b_2_9ttPEemp7SrGdFRJSa-vm5lc7YSTRTvAWNg,5397
34
- realign/claude_hooks/user_prompt_submit_hook.py,sha256=kMrmhAVtfV41oTX7JZcq2HPXjgQQ5gX26iOJoHJkfqA,10474
34
+ realign/claude_hooks/terminal_state.py,sha256=2ygTbVnh2b59vRLuN-TyWcXR94NKFlaVwOhS3ipqn58,6647
35
+ realign/claude_hooks/user_prompt_submit_hook.py,sha256=8e0zNonT95TH2uuISYp3am_RD7c84Ghh1WRPgs023DI,10625
35
36
  realign/claude_hooks/user_prompt_submit_hook_installer.py,sha256=2xLF8yZcE7Iwib9gU-xCkA1NWxNH9Nc5CFKPYK7rtXw,5371
36
37
  realign/commands/__init__.py,sha256=WVaVT1orM2Z0PYaG3X6tkKb_t2v3n_3siCadh1qd_QA,107
37
38
  realign/commands/add.py,sha256=_Xzt9P15mwndA3JvBBVrki8tn9Cc0UP6SiLwM4RS8Nc,27232
39
+ realign/commands/agent.py,sha256=3CS48bMn7tkdDWKRrfg7CYbhcJK4Pz40YjYMvwD7c2w,3173
38
40
  realign/commands/auth.py,sha256=QrPukpP-ogYEDSwztV0NOYI-HDgn5fPxlCQ1-e2n7gU,11082
39
41
  realign/commands/config.py,sha256=nYnu_h2pk7GODcrzrV04K51D-s7v06FlRXHJ0HJ-gvU,6732
40
42
  realign/commands/context.py,sha256=pM2KfZHVkB-ou4nBhFvKSwnYliLBzwN3zerLyBAbhfE,7095
41
- realign/commands/doctor.py,sha256=q5UOrUR5Uai4AxgaeOnK1Hig5I5UX7m3Vt00tPnUllg,18289
42
- realign/commands/export_shares.py,sha256=WNOR7FBE2om9qPO_28edZKhs94lyUAcbRgP_kNaDi5M,132574
43
- realign/commands/import_shares.py,sha256=HiswLlYHqR0dR3wgB7Rs54_WownqahIs5IdyJOHuot8,25572
43
+ realign/commands/doctor.py,sha256=0c1TZuA_cw1CSU0yKMVRU-18uTxdqjXKJ8lP2CTTNSQ,20656
44
+ realign/commands/export_shares.py,sha256=b8dpVBx2HkbHVk9pSFXnErlAr0umciAOPpuxvTJyOBI,148467
45
+ realign/commands/import_shares.py,sha256=qAH007WCQ6bwWP09MEJVmgJlRC8c-QicB2HYvMBqyRM,32966
44
46
  realign/commands/init.py,sha256=6rBr1LVIrQLbUH_UvoDhkF1qXmMh2xkjNWCYAUz5Tho,35274
45
47
  realign/commands/restore.py,sha256=s2BxQZHxQw9r12NzRVsK20KlGafy5AIoSjWMo5PcnHY,11173
46
- realign/commands/search.py,sha256=QJrC0hln9sCDFxXbpo0nPGMHXrud18qA5QfRyD0z6fQ,25926
48
+ realign/commands/search.py,sha256=QlUDzRDD6ebq21LTtLe5-OZM62iwDrDqfbnXbuxfklU,27516
49
+ realign/commands/sync_agent.py,sha256=XRcHN00TjfzGwTw3O_OXqb9Yj0lMFfDX0S7oizVpS6E,12454
47
50
  realign/commands/upgrade.py,sha256=L3PLOUIN5qAQTbkfoVtSsIbbzEezA_xjjk9F1GMVfjw,12781
48
51
  realign/commands/watcher.py,sha256=4WTThIgr-Z5guKh_JqGDcPmerr97XiHrVaaijmckHsA,134350
49
52
  realign/commands/worker.py,sha256=jTu7Pj60nTnn7SsH3oNCNnO6zl4TIFCJVNSC1OoQ_0o,23363
50
53
  realign/dashboard/__init__.py,sha256=QZkHTsGityH8UkF8rmvA3xW7dMXNe0swEWr443qfgCM,128
51
- realign/dashboard/app.py,sha256=aB1pvuJu-qJ94UqNegB4lvIxUzQJovuC82WQjFnQIFc,10464
54
+ realign/dashboard/app.py,sha256=e257euP0gR9nA0w1susuLkG9tnYQk1IJJdgAICnIYxs,10398
55
+ realign/dashboard/clipboard.py,sha256=81frq83E_urqLkwuCvtl0hiTEjavtdQn8kCi72jJWcs,1207
52
56
  realign/dashboard/layout.py,sha256=sZxmFj6QTbkois9MHTvBEMMcnaRVehCDqugdbiFx10k,9072
53
57
  realign/dashboard/terminal_backend.py,sha256=MlDfwtqhftyQK6jDNizQGFjAWIo5Bx2TDpSnP3MCZVM,3375
54
- realign/dashboard/tmux_manager.py,sha256=Fc6OQbnOO4YV47BnrIkcr0SHnQuSFwUSqhepNkpqKLs,32942
58
+ realign/dashboard/tmux_manager.py,sha256=sS6fo7UVPHWxYm1RYtLDPmwsagFh5RO6TRwYd1CuHaI,34581
55
59
  realign/dashboard/backends/__init__.py,sha256=POROX7YKtukYZcLB1pi_kO0sSEpuO3y-hwmF3WIN1Kk,163
56
60
  realign/dashboard/backends/iterm2.py,sha256=XYYJT5lrrp4pW_MyEqPZYkRI0qyKUwJlezwMidgnsHc,21390
57
61
  realign/dashboard/backends/kitty.py,sha256=5jdkR1f2PwB8a4SnS3EG6uOQ2XU-PB7-cpKBfIJq3hU,12066
58
- realign/dashboard/screens/__init__.py,sha256=US6sAmQs5VVkH2tFkH_z0WDT4H8cVhLL-JckfSR1yQY,446
62
+ realign/dashboard/screens/__init__.py,sha256=MiefFamCYRrzTwQXiCUdybaJaFxlK5XKtLHaSQmqDv0,597
63
+ realign/dashboard/screens/agent_detail.py,sha256=N-iUC4434C91OcDu4dkQaxS_NXQ5Yl5sqNBb2mTmoBw,10490
59
64
  realign/dashboard/screens/create_agent.py,sha256=06uiQYvz-Xvn4Xm689o3tdhzb2HQ0gdzAA1WHVEwziM,11706
65
+ realign/dashboard/screens/create_agent_info.py,sha256=K2Rbp4zHVdanPT3Fp82We4qlSAM-0IBZXPLuQuevuME,7838
60
66
  realign/dashboard/screens/create_event.py,sha256=oiQY1zKpUYnQU-5fQLeuZH9BV5NClE5B5XZIVBYG5A8,5506
61
- realign/dashboard/screens/event_detail.py,sha256=Fcm1CPAJkrNzolnFyIAzLeE_-NAoqdjQ0dLW0YyyER8,20842
67
+ realign/dashboard/screens/event_detail.py,sha256=-pqt3NBoeTXGJKtbndZy-msklwXTeNWMS4H12oMG5ks,20175
62
68
  realign/dashboard/screens/help_screen.py,sha256=Icrcvbgyz49R2tBiu8vBZ4CLm6iYclv_-FTa2pCFRRQ,3398
63
69
  realign/dashboard/screens/session_detail.py,sha256=TBkHqSHyMxsLB2QdZq9m1EoiH8oRVDbPrjt-a8I9sHs,9561
64
70
  realign/dashboard/screens/share_import.py,sha256=hl2x0yGVycsoUI76AmdZTAV-br3Q6191g5xHHrZ8hOA,6318
65
- realign/dashboard/styles/dashboard.tcss,sha256=ewonevBGLN-dfSsgxUk4VBCPchtxY4rx_vj1u6Ox2Fw,3454
66
- realign/dashboard/widgets/__init__.py,sha256=3Pf2_K9obrertgv_psfxradgkI9RXlmjoXYQH7oBKm0,583
71
+ realign/dashboard/styles/dashboard.tcss,sha256=9W5Tx0lgyGb4HU-z-Kn7gBdexIK0aPe0bkVn2k_AseM,3288
72
+ realign/dashboard/widgets/__init__.py,sha256=33qjCa6WCQ7XojRiStdR73jX2xpKV_RlBqodVDQWkxs,577
73
+ realign/dashboard/widgets/agents_panel.py,sha256=TtOX9RlF0CuwRTe1sXoo1xaf7ZykJA-YFmMu0-SKe2g,43299
67
74
  realign/dashboard/widgets/config_panel.py,sha256=eRJRuqImQ8eJIKCEj4O8EvYxI-ht_anrcYbT5JskWyU,15972
68
- realign/dashboard/widgets/events_table.py,sha256=MKB1G1_xdQCujEhmMz_GKI4hs-PeEiqGEAH7Y3ZGanE,30852
75
+ realign/dashboard/widgets/events_table.py,sha256=0cMvE0KdZFBZyvywv7vlt005qsR0aLQnQiMf3ZzK7RY,30218
69
76
  realign/dashboard/widgets/header.py,sha256=0HHCFXX7F3C6HII-WDwOJwWkJrajmKPWmdoMWyOkn9E,1587
70
77
  realign/dashboard/widgets/openable_table.py,sha256=GeJPDEYp0kRHShqvmPMzAePpYXRZHUNqcWNnxqsqxjA,1963
71
78
  realign/dashboard/widgets/search_panel.py,sha256=ZNJDfwDSxUFnCeltYQYsQsPJ6t4HDeNWpENoTOoBdVM,8951
72
- realign/dashboard/widgets/sessions_table.py,sha256=oMkYhQ55pUGOGYxEXM5P37mpGYA350BK8Rb8fVq9AS4,34008
73
- realign/dashboard/widgets/terminal_panel.py,sha256=8WX2_EewlyFlxJYokw2akEqkJUjNt_-F8tzE7St3084,60132
79
+ realign/dashboard/widgets/sessions_table.py,sha256=6y78pEkyAmNsU4_o46PbwXRFW17fc5khgheBi4LjBNg,33374
74
80
  realign/dashboard/widgets/watcher_panel.py,sha256=emVY1-aot9Dnf5UI9yyNeEmp4d2Gb-lrC28DjkeLjKA,19575
75
81
  realign/dashboard/widgets/worker_panel.py,sha256=F_jKWABuCNmjQgeeuCr4KnFRKdY4CLTNcEXMYwsNaSk,18691
76
82
  realign/db/__init__.py,sha256=65LsNdsq_rkwNC1eg1OAr3HC0ORXtelOh0I8MhNGr-g,3288
77
- realign/db/base.py,sha256=5baEwoGR5X2SyQXkXuyeUP2zelcuQardVouD2S-qils,13703
78
- realign/db/locks.py,sha256=yzCiPJZ4eOQX-Q4mXB6s76U2U7lXAzIBBy1t59w-AVU,1698
83
+ realign/db/base.py,sha256=ShufW-c0ntKYsTWCbiXJ5W-G_H_mWN4YlnUuspWWu34,15589
84
+ realign/db/locks.py,sha256=dUQu9Yo5nZstMSPXZPYzN0xqX8UXhJgNV_PmYEJ-rK0,1801
79
85
  realign/db/migrate_agents.py,sha256=cDeVUzKW950dJ0lV74QObHuONqKwErSrXI5akU2vBmQ,9633
80
86
  realign/db/migration.py,sha256=af1QFEfIh_qX0pFyXzm5gWFVbQn0sKOUNLSJHlr__FU,13405
81
- realign/db/schema.py,sha256=YHj5PGZWbCl0VG0epnMF_Ofg3jRiLHq6SLHCi1q34eQ,30181
82
- realign/db/sqlite_db.py,sha256=nihEZ71wg1BXiVG1QU488ed9Q-ZasoVKYVS4j20hhtY,107223
87
+ realign/db/schema.py,sha256=IWPbeDYrbC1eZGQAy8k1rk0r2NnABJzXSSg8bb00XBw,33885
88
+ realign/db/sqlite_db.py,sha256=u4yybbXzOApYPnHkHlR59qBSyWPoIqgRppTB4ht5taM,119736
83
89
  realign/events/__init__.py,sha256=IM-NxF4Zk2hYFD07k4WrfNRuuiC9ihGjf4GBpJhjd2E,35
90
+ realign/events/agent_summarizer.py,sha256=vh65tYgo1NOYsIpVPR253nnOr-MIejC4KG5dGvDzKv4,5413
84
91
  realign/events/debouncer.py,sha256=U3Q7dYpnMsAgWsW_E_IbSC4lrdEoi6H_SFLGLOAazs4,3062
85
92
  realign/events/event_summarizer.py,sha256=jJtWM8UWtsG4KGdzYicMqcTxrncWzGNEQs5vdBJPyew,10185
86
- realign/events/session_summarizer.py,sha256=EzFFjgcUEAqm1IJuxOAPx74GTUIStyXTvQ9maZ-V10U,12888
93
+ realign/events/session_summarizer.py,sha256=LqBoICEF5cggdv3px2O2TP0Xk7h_LofE1DDRv2TyJ5I,13868
87
94
  realign/models/event.py,sha256=ypz74D4l6U2U0RhgL8fzEhiq7iQjhHybmAdLUNDY7P4,5521
88
95
  realign/prompts/__init__.py,sha256=PpYR7f-T96fd-QyNYJDRS1U6h9O0rIt_SMsREy9i3aA,443
89
96
  realign/prompts/presets.py,sha256=h9oEy0XP4JQ4DCnp8HN_FfF0LmI-yOV6xWJLknIghJ8,7256
@@ -97,8 +104,8 @@ realign/triggers/next_turn_trigger.py,sha256=-x80_I-WmIjXXzQHEPBykgx_GQW6oKaLDQx
97
104
  realign/triggers/registry.py,sha256=dkIjSd8Bg-hF0nxaO2Fi2K-0Zipqv6vVjc-HYSrA_fY,3656
98
105
  realign/triggers/turn_status.py,sha256=wAZEhXDAmDoX5F-ohWfSnZZ0eA6DAJ9svSPiSv_f6sg,6041
99
106
  realign/triggers/turn_summary.py,sha256=f3hEUshgv9skJ9AbfWpoYs417lsv_HK2A_vpPjgryO4,4467
100
- aline_ai-0.6.5.dist-info/METADATA,sha256=RmD0VjSn_0nGStyFKgkNYUL3i2foaqg8UWUT3kOUTOc,1597
101
- aline_ai-0.6.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
102
- aline_ai-0.6.5.dist-info/entry_points.txt,sha256=TvYELpMoWsUTcQdMV8tBHxCbEf_LbK4sESqK3r8PM6Y,78
103
- aline_ai-0.6.5.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
104
- aline_ai-0.6.5.dist-info/RECORD,,
107
+ aline_ai-0.6.7.dist-info/METADATA,sha256=GyI08kzWpN5QDEsgynocnlk8Cp5zSTiKXRltp86xrsM,1597
108
+ aline_ai-0.6.7.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
109
+ aline_ai-0.6.7.dist-info/entry_points.txt,sha256=TvYELpMoWsUTcQdMV8tBHxCbEf_LbK4sESqK3r8PM6Y,78
110
+ aline_ai-0.6.7.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
111
+ aline_ai-0.6.7.dist-info/RECORD,,
realign/__init__.py CHANGED
@@ -3,7 +3,7 @@
3
3
  import hashlib
4
4
  from pathlib import Path
5
5
 
6
- __version__ = "0.6.5"
6
+ __version__ = "0.6.7"
7
7
 
8
8
 
9
9
  def get_realign_dir(project_root: Path) -> Path:
realign/agent_names.py ADDED
@@ -0,0 +1,79 @@
1
+ """Random Docker-style agent name generator.
2
+
3
+ Generates names like "bold-turing", "swift-hopper", etc.
4
+ """
5
+
6
+ import random
7
+
8
+ ADJECTIVES = [
9
+ "bold",
10
+ "bright",
11
+ "calm",
12
+ "clever",
13
+ "crisp",
14
+ "deft",
15
+ "eager",
16
+ "fast",
17
+ "firm",
18
+ "glad",
19
+ "keen",
20
+ "lucid",
21
+ "neat",
22
+ "noble",
23
+ "prime",
24
+ "quick",
25
+ "sharp",
26
+ "sleek",
27
+ "smart",
28
+ "solid",
29
+ "steady",
30
+ "strong",
31
+ "subtle",
32
+ "sure",
33
+ "swift",
34
+ "tidy",
35
+ "vivid",
36
+ "warm",
37
+ "wise",
38
+ "witty",
39
+ ]
40
+
41
+ SURNAMES = [
42
+ "babbage",
43
+ "bell",
44
+ "boole",
45
+ "cerf",
46
+ "church",
47
+ "conway",
48
+ "curie",
49
+ "darwin",
50
+ "dijkstra",
51
+ "euler",
52
+ "faraday",
53
+ "feynman",
54
+ "gauss",
55
+ "hopper",
56
+ "johnson",
57
+ "kahn",
58
+ "knuth",
59
+ "lamarr",
60
+ "leibniz",
61
+ "lovelace",
62
+ "maxwell",
63
+ "neumann",
64
+ "noether",
65
+ "pascal",
66
+ "planck",
67
+ "ritchie",
68
+ "shannon",
69
+ "tesla",
70
+ "thompson",
71
+ "turing",
72
+ ]
73
+
74
+ _rng = random.SystemRandom()
75
+
76
+
77
+ def generate_agent_name() -> str:
78
+ """Return a random name, e.g. 'Bold Turing'."""
79
+ return f"{_rng.choice(ADJECTIVES).capitalize()} {_rng.choice(SURNAMES).capitalize()}"
@@ -66,6 +66,7 @@ def main():
66
66
  terminal_id = os.environ.get("ALINE_TERMINAL_ID", "")
67
67
  inner_socket = os.environ.get("ALINE_INNER_TMUX_SOCKET", "")
68
68
  inner_session = os.environ.get("ALINE_INNER_TMUX_SESSION", "")
69
+ agent_id = os.environ.get("ALINE_AGENT_ID", "")
69
70
 
70
71
  if not terminal_id:
71
72
  try:
@@ -104,6 +105,7 @@ def main():
104
105
  signal_data = {
105
106
  "session_id": session_id,
106
107
  "terminal_id": terminal_id,
108
+ "agent_id": agent_id,
107
109
  "project_dir": project_dir,
108
110
  "transcript_path": transcript_path,
109
111
  "cwd": cwd,
@@ -348,6 +350,7 @@ def main():
348
350
  cwd=cwd,
349
351
  project_dir=project_dir,
350
352
  source="Stop",
353
+ agent_id=agent_id if agent_id else None,
351
354
  )
352
355
  except Exception:
353
356
  pass
@@ -41,7 +41,18 @@ def _get_db():
41
41
 
42
42
  return get_database(read_only=False)
43
43
  except Exception:
44
- return None
44
+ try:
45
+ import sys
46
+
47
+ root = Path(__file__).resolve().parents[2]
48
+ root_str = str(root)
49
+ if root_str not in sys.path:
50
+ sys.path.insert(0, root_str)
51
+ from realign.db import get_database # type: ignore
52
+
53
+ return get_database(read_only=False)
54
+ except Exception:
55
+ return None
45
56
 
46
57
 
47
58
  def _write_to_db(
@@ -56,6 +67,7 @@ def _write_to_db(
56
67
  source: str = "",
57
68
  context_id: Optional[str] = None,
58
69
  attention: Optional[str] = None,
70
+ agent_id: Optional[str] = None,
59
71
  ) -> bool:
60
72
  """Write terminal mapping to database (best-effort).
61
73
 
@@ -66,6 +78,10 @@ def _write_to_db(
66
78
  if not db:
67
79
  return False
68
80
 
81
+ # Force source to agent mapping when agent_id is known
82
+ if agent_id:
83
+ source = f"agent:{agent_id}"
84
+
69
85
  # Check if agent exists
70
86
  existing = db.get_agent_by_id(terminal_id)
71
87
  if existing:
@@ -96,6 +112,27 @@ def _write_to_db(
96
112
  source=source if source else None,
97
113
  attention=attention,
98
114
  )
115
+
116
+ # Link session to agent if both are available (V19+)
117
+ if session_id and agent_id:
118
+ try:
119
+ db.update_session_agent_id(session_id, agent_id)
120
+ except Exception:
121
+ pass
122
+
123
+ # WindowLink: record terminal/session association (V23)
124
+ try:
125
+ db.insert_window_link(
126
+ terminal_id=terminal_id,
127
+ agent_id=agent_id,
128
+ session_id=session_id,
129
+ provider=provider,
130
+ source=source,
131
+ ts=time.time(),
132
+ )
133
+ except Exception:
134
+ pass
135
+
99
136
  # Note: Don't close - get_database() returns a singleton
100
137
  return True
101
138
  except Exception:
@@ -114,6 +151,7 @@ def update_terminal_mapping(
114
151
  source: str = "",
115
152
  context_id: Optional[str] = None,
116
153
  attention: Optional[str] = None,
154
+ agent_id: Optional[str] = None,
117
155
  ) -> None:
118
156
  """Update terminal->session binding.
119
157
 
@@ -124,6 +162,9 @@ def update_terminal_mapping(
124
162
  Concurrency: uses a simple fcntl lock file for JSON; last writer wins, but updates are atomic.
125
163
  """
126
164
  # Phase 1: Write to database (best-effort, don't fail if DB unavailable)
165
+ if agent_id:
166
+ source = f"agent:{agent_id}"
167
+
127
168
  _write_to_db(
128
169
  terminal_id=terminal_id,
129
170
  provider=provider,
@@ -135,6 +176,7 @@ def update_terminal_mapping(
135
176
  source=source,
136
177
  context_id=context_id,
137
178
  attention=attention,
179
+ agent_id=agent_id,
138
180
  )
139
181
 
140
182
  # Phase 2: Write to JSON (backward compatibility)
@@ -52,6 +52,7 @@ def main() -> None:
52
52
  terminal_id = os.environ.get("ALINE_TERMINAL_ID", "")
53
53
  inner_socket = os.environ.get("ALINE_INNER_TMUX_SOCKET", "")
54
54
  inner_session = os.environ.get("ALINE_INNER_TMUX_SESSION", "")
55
+ agent_id = os.environ.get("ALINE_AGENT_ID", "")
55
56
 
56
57
  if not terminal_id:
57
58
  try:
@@ -86,6 +87,7 @@ def main() -> None:
86
87
  signal_data = {
87
88
  "session_id": session_id,
88
89
  "terminal_id": terminal_id,
90
+ "agent_id": agent_id,
89
91
  "prompt": prompt,
90
92
  "transcript_path": transcript_path,
91
93
  "cwd": cwd,
@@ -274,6 +276,7 @@ def main() -> None:
274
276
  cwd=cwd,
275
277
  project_dir=project_dir,
276
278
  source="UserPromptSubmit",
279
+ agent_id=agent_id if agent_id else None,
277
280
  )
278
281
  except Exception:
279
282
  pass
realign/cli.py CHANGED
@@ -19,6 +19,7 @@ from .commands import (
19
19
  add,
20
20
  auth,
21
21
  doctor,
22
+ agent,
22
23
  )
23
24
 
24
25
  app = typer.Typer(
@@ -248,6 +249,67 @@ app.add_typer(context_app, name="context")
248
249
  add_app = typer.Typer(help="Install optional local tooling")
249
250
  app.add_typer(add_app, name="add")
250
251
 
252
+ # Create agent subcommand group
253
+ agent_app = typer.Typer(help="Manage agents")
254
+ app.add_typer(agent_app, name="agent")
255
+
256
+
257
+ @agent_app.command(name="new")
258
+ def agent_new_cli(
259
+ name: Optional[str] = typer.Option(None, "--name", "-n", help="Agent name"),
260
+ desc: str = typer.Option("", "--desc", "-d", help="Agent description"),
261
+ ):
262
+ """Create a new agent with a random name (or specify one)."""
263
+ exit_code = agent.agent_new_command(name=name, desc=desc)
264
+ raise typer.Exit(code=exit_code)
265
+
266
+
267
+ @agent_app.command(name="list")
268
+ def agent_list_cli(
269
+ all: bool = typer.Option(
270
+ False, "--all", "-a", help="Include invisible agents"
271
+ ),
272
+ ):
273
+ """List all agents."""
274
+ exit_code = agent.agent_list_command(include_invisible=all)
275
+ raise typer.Exit(code=exit_code)
276
+
277
+
278
+ @agent_app.command(name="share")
279
+ def agent_share_cli(
280
+ agent_id: str = typer.Argument(..., help="Agent ID to share"),
281
+ password: Optional[str] = typer.Option(
282
+ None, "--password", "-p", help="Password for encrypted share"
283
+ ),
284
+ expiry_days: int = typer.Option(7, "--expiry", help="Number of days before share expires"),
285
+ max_views: int = typer.Option(100, "--max-views", help="Maximum number of views allowed"),
286
+ mcp: bool = typer.Option(
287
+ True,
288
+ "--mcp/--no-mcp",
289
+ help="Include MCP usage instructions (default: enabled)",
290
+ ),
291
+ json_output: bool = typer.Option(False, "--json", help="Output results in JSON format"),
292
+ ):
293
+ """Share all sessions for an agent.
294
+
295
+ Creates a shareable link for all sessions associated with the specified agent.
296
+ The share includes a generated Slack message for easy sharing.
297
+
298
+ Examples:
299
+ aline agent share abc123de
300
+ aline agent share abc123de --json
301
+ aline agent share abc123de --password mypass
302
+ """
303
+ exit_code = export_shares.export_agent_shares_command(
304
+ agent_id=agent_id,
305
+ password=password,
306
+ expiry_days=expiry_days,
307
+ max_views=max_views,
308
+ enable_mcp=mcp,
309
+ json_output=json_output,
310
+ )
311
+ raise typer.Exit(code=exit_code)
312
+
251
313
 
252
314
  @add_app.command(name="tmux")
253
315
  def add_tmux_cli():
realign/codex_detector.py CHANGED
@@ -14,15 +14,30 @@ def _codex_session_roots() -> list[Path]:
14
14
  # Default Codex home: ~/.codex/sessions
15
15
  roots.append(Path.home() / ".codex" / "sessions")
16
16
 
17
- # Aline-managed per-terminal CODEX_HOME isolation: ~/.aline/codex_homes/*/sessions
17
+ # Aline-managed per-terminal or per-agent CODEX_HOME isolation: ~/.aline/codex_homes/*/sessions
18
18
  try:
19
19
  from .codex_home import aline_codex_homes_dir, codex_sessions_dir_for_home
20
20
 
21
21
  homes = aline_codex_homes_dir()
22
22
  if homes.exists():
23
23
  for child in homes.iterdir():
24
- if child.is_dir():
25
- roots.append(codex_sessions_dir_for_home(child))
24
+ if not child.is_dir():
25
+ continue
26
+ if child.name.startswith("agent-"):
27
+ # New layout: agent-<id>/<terminal_id>/sessions
28
+ try:
29
+ for grandchild in child.iterdir():
30
+ if grandchild.is_dir():
31
+ nested_sessions = codex_sessions_dir_for_home(grandchild)
32
+ if nested_sessions.exists():
33
+ roots.append(nested_sessions)
34
+ except Exception:
35
+ continue
36
+ else:
37
+ # Terminal layout: <terminal_id>/sessions
38
+ direct_sessions = codex_sessions_dir_for_home(child)
39
+ if direct_sessions.exists():
40
+ roots.append(direct_sessions)
26
41
  except Exception:
27
42
  pass
28
43
 
realign/codex_home.py CHANGED
@@ -1,10 +1,8 @@
1
1
  """Codex home/session path helpers.
2
2
 
3
- To guarantee terminal↔session binding even when multiple Codex instances run in the same cwd,
4
- we can isolate Codex storage per dashboard terminal via the `CODEX_HOME` environment variable.
5
-
6
- We choose deterministic paths under `~/.aline/` so the watcher (a separate process) can
7
- derive the owning terminal_id purely from the session file path.
3
+ We isolate Codex storage via `CODEX_HOME` so the watcher can infer ownership
4
+ from the session file path. By default it's per-terminal, but when an
5
+ ALINE_AGENT_ID is present we can scope CODEX_HOME per agent.
8
6
  """
9
7
 
10
8
  from __future__ import annotations
@@ -15,6 +13,7 @@ from typing import Optional
15
13
 
16
14
 
17
15
  ENV_CODEX_HOME = "CODEX_HOME"
16
+ AGENT_HOME_PREFIX = "agent-"
18
17
 
19
18
 
20
19
  def aline_codex_homes_dir() -> Path:
@@ -24,11 +23,26 @@ def aline_codex_homes_dir() -> Path:
24
23
  return Path.home() / ".aline" / "codex_homes"
25
24
 
26
25
 
26
+ def _safe_id(raw_id: str) -> str:
27
+ return (raw_id or "").strip().replace("/", "_").replace("\\", "_")
28
+
29
+
27
30
  def codex_home_for_terminal(terminal_id: str) -> Path:
28
- tid = (terminal_id or "").strip()
31
+ tid = _safe_id(terminal_id)
29
32
  return aline_codex_homes_dir() / tid
30
33
 
31
34
 
35
+ def codex_home_for_agent(agent_id: str) -> Path:
36
+ aid = _safe_id(agent_id)
37
+ return aline_codex_homes_dir() / f"{AGENT_HOME_PREFIX}{aid}"
38
+
39
+
40
+ def codex_home_for_terminal_or_agent(terminal_id: str, agent_id: Optional[str]) -> Path:
41
+ if agent_id:
42
+ return codex_home_for_agent(agent_id) / _safe_id(terminal_id)
43
+ return codex_home_for_terminal(terminal_id)
44
+
45
+
32
46
  def codex_sessions_dir_for_home(codex_home: Path) -> Path:
33
47
  return codex_home / "sessions"
34
48
 
@@ -37,8 +51,14 @@ def codex_sessions_dir_for_terminal(terminal_id: str) -> Path:
37
51
  return codex_sessions_dir_for_home(codex_home_for_terminal(terminal_id))
38
52
 
39
53
 
40
- def terminal_id_from_codex_session_file(session_file: Path) -> Optional[str]:
41
- """If session_file is under an Aline-managed CODEX_HOME, return terminal_id."""
54
+ def codex_sessions_dir_for_terminal_or_agent(
55
+ terminal_id: str, agent_id: Optional[str]
56
+ ) -> Path:
57
+ return codex_sessions_dir_for_home(codex_home_for_terminal_or_agent(terminal_id, agent_id))
58
+
59
+
60
+ def codex_home_owner_from_session_file(session_file: Path) -> Optional[tuple[str, str]]:
61
+ """Return ("terminal", id) or ("agent", id) if session_file is under Aline-managed homes."""
42
62
  try:
43
63
  homes = aline_codex_homes_dir().resolve()
44
64
  p = session_file.resolve()
@@ -53,17 +73,35 @@ def terminal_id_from_codex_session_file(session_file: Path) -> Optional[str]:
53
73
  parts = rel.parts
54
74
  if len(parts) < 3:
55
75
  return None
56
- terminal_id = (parts[0] or "").strip()
57
- if not terminal_id:
76
+ owner = (parts[0] or "").strip()
77
+ if not owner:
58
78
  return None
59
- if parts[1] != "sessions":
79
+ # Terminal layout: <homes>/<terminal_id>/sessions/...
80
+ if parts[1] == "sessions":
81
+ if owner.startswith(AGENT_HOME_PREFIX):
82
+ return ("agent", owner[len(AGENT_HOME_PREFIX):])
83
+ return ("terminal", owner)
84
+ # Agent/terminal layout: <homes>/agent-<agent_id>/<terminal_id>/sessions/...
85
+ if owner.startswith(AGENT_HOME_PREFIX) and len(parts) >= 4 and parts[2] == "sessions":
86
+ terminal_id = (parts[1] or "").strip()
87
+ if terminal_id:
88
+ return ("terminal", terminal_id)
89
+ return None
90
+
91
+
92
+ def terminal_id_from_codex_session_file(session_file: Path) -> Optional[str]:
93
+ """If session_file is under an Aline-managed CODEX_HOME, return terminal_id."""
94
+ owner = codex_home_owner_from_session_file(session_file)
95
+ if not owner:
96
+ return None
97
+ if owner[0] != "terminal":
60
98
  return None
61
- return terminal_id
99
+ return owner[1]
62
100
 
63
101
 
64
- def prepare_codex_home(terminal_id: str) -> Path:
65
- """Create/prepare an isolated CODEX_HOME for a terminal (best-effort)."""
66
- home = codex_home_for_terminal(terminal_id)
102
+ def prepare_codex_home(terminal_id: str, *, agent_id: Optional[str] = None) -> Path:
103
+ """Create/prepare an isolated CODEX_HOME (per-agent if agent_id is provided)."""
104
+ home = codex_home_for_terminal_or_agent(terminal_id, agent_id)
67
105
  sessions = codex_sessions_dir_for_home(home)
68
106
  try:
69
107
  sessions.mkdir(parents=True, exist_ok=True)
@@ -81,5 +119,16 @@ def prepare_codex_home(terminal_id: str) -> Path:
81
119
  except Exception:
82
120
  pass
83
121
 
84
- return home
122
+ # Reuse global auth/config to avoid re-login for per-terminal homes.
123
+ try:
124
+ global_home = Path.home() / ".codex"
125
+ for name in ("auth.json", "config.toml"):
126
+ src = global_home / name
127
+ dst = home / name
128
+ if src.exists() and not dst.exists():
129
+ dst.parent.mkdir(parents=True, exist_ok=True)
130
+ dst.symlink_to(src)
131
+ except Exception:
132
+ pass
85
133
 
134
+ return home