aline-ai 0.6.4__py3-none-any.whl → 0.6.6__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.6.4.dist-info → aline_ai-0.6.6.dist-info}/METADATA +1 -1
- {aline_ai-0.6.4.dist-info → aline_ai-0.6.6.dist-info}/RECORD +41 -34
- realign/__init__.py +1 -1
- realign/agent_names.py +79 -0
- realign/claude_hooks/stop_hook.py +3 -0
- realign/claude_hooks/terminal_state.py +11 -0
- realign/claude_hooks/user_prompt_submit_hook.py +3 -0
- realign/cli.py +62 -0
- realign/codex_detector.py +1 -1
- realign/codex_home.py +46 -15
- realign/codex_terminal_linker.py +18 -7
- realign/commands/agent.py +109 -0
- realign/commands/doctor.py +3 -1
- realign/commands/export_shares.py +297 -0
- realign/commands/search.py +58 -29
- realign/dashboard/app.py +9 -158
- realign/dashboard/clipboard.py +54 -0
- realign/dashboard/screens/__init__.py +4 -0
- realign/dashboard/screens/agent_detail.py +333 -0
- realign/dashboard/screens/create_agent_info.py +133 -0
- realign/dashboard/screens/event_detail.py +6 -27
- realign/dashboard/styles/dashboard.tcss +67 -0
- realign/dashboard/tmux_manager.py +49 -8
- realign/dashboard/widgets/__init__.py +2 -0
- realign/dashboard/widgets/agents_panel.py +1129 -0
- realign/dashboard/widgets/config_panel.py +17 -11
- realign/dashboard/widgets/events_table.py +4 -27
- realign/dashboard/widgets/sessions_table.py +4 -27
- realign/dashboard/widgets/terminal_panel.py +109 -31
- realign/db/base.py +27 -0
- realign/db/locks.py +4 -0
- realign/db/schema.py +53 -2
- realign/db/sqlite_db.py +185 -2
- realign/events/agent_summarizer.py +157 -0
- realign/events/session_summarizer.py +25 -0
- realign/watcher_core.py +60 -3
- realign/worker_core.py +24 -1
- {aline_ai-0.6.4.dist-info → aline_ai-0.6.6.dist-info}/WHEEL +0 -0
- {aline_ai-0.6.4.dist-info → aline_ai-0.6.6.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.6.4.dist-info → aline_ai-0.6.6.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.6.4.dist-info → aline_ai-0.6.6.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
aline_ai-0.6.
|
|
2
|
-
realign/__init__.py,sha256=
|
|
1
|
+
aline_ai-0.6.6.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
|
|
2
|
+
realign/__init__.py,sha256=0jG4gYJd6Zmf7o7WaFAwx0d2VJ0amHPKJ8u3BqkhG6A,1623
|
|
3
|
+
realign/agent_names.py,sha256=ml6Jc1B_nRRr-FcW1tIFMyqxw-90RBLcfzj6fwJRB4U,1158
|
|
3
4
|
realign/auth.py,sha256=d_1yvCwluN5iIrdgjtuSKpOYAksDzrzNgntKacLVJrw,16583
|
|
4
5
|
realign/claude_detector.py,sha256=ZLSJacMo6zzQclXByABKA70UNpstxqIv3fPGqdpA934,2792
|
|
5
|
-
realign/cli.py,sha256=
|
|
6
|
-
realign/codex_detector.py,sha256=
|
|
7
|
-
realign/codex_home.py,sha256=
|
|
8
|
-
realign/codex_terminal_linker.py,sha256=
|
|
6
|
+
realign/cli.py,sha256=IctmQ0OTb6kLlWRFRQumdhY6-CpcpFtocdc68KiwxvM,37748
|
|
7
|
+
realign/codex_detector.py,sha256=t_34CkvxP4x9CxuHmbk8YhEhu8RKLRG-CDr_FaRMQYY,5536
|
|
8
|
+
realign/codex_home.py,sha256=9cfO_kF-WYKAJXdSnceTB1PaRPBpZjAWyDtO0_U_BvA,3569
|
|
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=
|
|
19
|
+
realign/watcher_core.py,sha256=CeHY6PN8vzn4cNezjCWNr3yLEuNsRsshfI5W3HfsXQk,110978
|
|
19
20
|
realign/watcher_daemon.py,sha256=OHUQ9P1LlagKJHfrf6uRnzO-zDtBRXIxt8ydMFHf5S8,3475
|
|
20
|
-
realign/worker_core.py,sha256=
|
|
21
|
+
realign/worker_core.py,sha256=TrFvqlElpa3Vnz7yumVfYaw4h9GcOLhuLhumPkeNCTg,11195
|
|
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=
|
|
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=
|
|
34
|
-
realign/claude_hooks/user_prompt_submit_hook.py,sha256=
|
|
34
|
+
realign/claude_hooks/terminal_state.py,sha256=Ywl173lD9-eUTXvYFaCczkQXNIqzzKL1zXAJPNpMiW8,5728
|
|
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=
|
|
42
|
-
realign/commands/export_shares.py,sha256=
|
|
43
|
+
realign/commands/doctor.py,sha256=q5UOrUR5Uai4AxgaeOnK1Hig5I5UX7m3Vt00tPnUllg,18289
|
|
44
|
+
realign/commands/export_shares.py,sha256=oQHKSBQKr0PmyjuZibBdO8bmZ1arODRNclws3U9Z0Js,142253
|
|
43
45
|
realign/commands/import_shares.py,sha256=HiswLlYHqR0dR3wgB7Rs54_WownqahIs5IdyJOHuot8,25572
|
|
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=
|
|
48
|
+
realign/commands/search.py,sha256=QlUDzRDD6ebq21LTtLe5-OZM62iwDrDqfbnXbuxfklU,27516
|
|
47
49
|
realign/commands/upgrade.py,sha256=L3PLOUIN5qAQTbkfoVtSsIbbzEezA_xjjk9F1GMVfjw,12781
|
|
48
50
|
realign/commands/watcher.py,sha256=4WTThIgr-Z5guKh_JqGDcPmerr97XiHrVaaijmckHsA,134350
|
|
49
51
|
realign/commands/worker.py,sha256=jTu7Pj60nTnn7SsH3oNCNnO6zl4TIFCJVNSC1OoQ_0o,23363
|
|
50
52
|
realign/dashboard/__init__.py,sha256=QZkHTsGityH8UkF8rmvA3xW7dMXNe0swEWr443qfgCM,128
|
|
51
|
-
realign/dashboard/app.py,sha256=
|
|
53
|
+
realign/dashboard/app.py,sha256=e257euP0gR9nA0w1susuLkG9tnYQk1IJJdgAICnIYxs,10398
|
|
54
|
+
realign/dashboard/clipboard.py,sha256=81frq83E_urqLkwuCvtl0hiTEjavtdQn8kCi72jJWcs,1207
|
|
52
55
|
realign/dashboard/layout.py,sha256=sZxmFj6QTbkois9MHTvBEMMcnaRVehCDqugdbiFx10k,9072
|
|
53
56
|
realign/dashboard/terminal_backend.py,sha256=MlDfwtqhftyQK6jDNizQGFjAWIo5Bx2TDpSnP3MCZVM,3375
|
|
54
|
-
realign/dashboard/tmux_manager.py,sha256=
|
|
57
|
+
realign/dashboard/tmux_manager.py,sha256=Fc6OQbnOO4YV47BnrIkcr0SHnQuSFwUSqhepNkpqKLs,32942
|
|
55
58
|
realign/dashboard/backends/__init__.py,sha256=POROX7YKtukYZcLB1pi_kO0sSEpuO3y-hwmF3WIN1Kk,163
|
|
56
59
|
realign/dashboard/backends/iterm2.py,sha256=XYYJT5lrrp4pW_MyEqPZYkRI0qyKUwJlezwMidgnsHc,21390
|
|
57
60
|
realign/dashboard/backends/kitty.py,sha256=5jdkR1f2PwB8a4SnS3EG6uOQ2XU-PB7-cpKBfIJq3hU,12066
|
|
58
|
-
realign/dashboard/screens/__init__.py,sha256=
|
|
61
|
+
realign/dashboard/screens/__init__.py,sha256=MiefFamCYRrzTwQXiCUdybaJaFxlK5XKtLHaSQmqDv0,597
|
|
62
|
+
realign/dashboard/screens/agent_detail.py,sha256=N-iUC4434C91OcDu4dkQaxS_NXQ5Yl5sqNBb2mTmoBw,10490
|
|
59
63
|
realign/dashboard/screens/create_agent.py,sha256=06uiQYvz-Xvn4Xm689o3tdhzb2HQ0gdzAA1WHVEwziM,11706
|
|
64
|
+
realign/dashboard/screens/create_agent_info.py,sha256=B5rGTb5WPREZPbfopQaXZviXz0lZZHV9l0gmNyGhNII,3914
|
|
60
65
|
realign/dashboard/screens/create_event.py,sha256=oiQY1zKpUYnQU-5fQLeuZH9BV5NClE5B5XZIVBYG5A8,5506
|
|
61
|
-
realign/dashboard/screens/event_detail.py,sha256
|
|
66
|
+
realign/dashboard/screens/event_detail.py,sha256=-pqt3NBoeTXGJKtbndZy-msklwXTeNWMS4H12oMG5ks,20175
|
|
62
67
|
realign/dashboard/screens/help_screen.py,sha256=Icrcvbgyz49R2tBiu8vBZ4CLm6iYclv_-FTa2pCFRRQ,3398
|
|
63
68
|
realign/dashboard/screens/session_detail.py,sha256=TBkHqSHyMxsLB2QdZq9m1EoiH8oRVDbPrjt-a8I9sHs,9561
|
|
64
69
|
realign/dashboard/screens/share_import.py,sha256=hl2x0yGVycsoUI76AmdZTAV-br3Q6191g5xHHrZ8hOA,6318
|
|
65
|
-
realign/dashboard/styles/dashboard.tcss,sha256=
|
|
66
|
-
realign/dashboard/widgets/__init__.py,sha256=
|
|
67
|
-
realign/dashboard/widgets/
|
|
68
|
-
realign/dashboard/widgets/
|
|
70
|
+
realign/dashboard/styles/dashboard.tcss,sha256=AhYhvm1hBZee0Gzv0C8qsx_-6DqLw4Gg-h_XiOGQHJ0,4557
|
|
71
|
+
realign/dashboard/widgets/__init__.py,sha256=1FBQzar5Jd4hBZtANVKb_dNxFAqVqrwJJkBpeLmCq-Q,640
|
|
72
|
+
realign/dashboard/widgets/agents_panel.py,sha256=GxnOrg6C1dPw0lhOfrjIHJAk04MMwhYJwMUY1SfMuCs,38875
|
|
73
|
+
realign/dashboard/widgets/config_panel.py,sha256=eRJRuqImQ8eJIKCEj4O8EvYxI-ht_anrcYbT5JskWyU,15972
|
|
74
|
+
realign/dashboard/widgets/events_table.py,sha256=0cMvE0KdZFBZyvywv7vlt005qsR0aLQnQiMf3ZzK7RY,30218
|
|
69
75
|
realign/dashboard/widgets/header.py,sha256=0HHCFXX7F3C6HII-WDwOJwWkJrajmKPWmdoMWyOkn9E,1587
|
|
70
76
|
realign/dashboard/widgets/openable_table.py,sha256=GeJPDEYp0kRHShqvmPMzAePpYXRZHUNqcWNnxqsqxjA,1963
|
|
71
77
|
realign/dashboard/widgets/search_panel.py,sha256=ZNJDfwDSxUFnCeltYQYsQsPJ6t4HDeNWpENoTOoBdVM,8951
|
|
72
|
-
realign/dashboard/widgets/sessions_table.py,sha256=
|
|
73
|
-
realign/dashboard/widgets/terminal_panel.py,sha256=
|
|
78
|
+
realign/dashboard/widgets/sessions_table.py,sha256=6y78pEkyAmNsU4_o46PbwXRFW17fc5khgheBi4LjBNg,33374
|
|
79
|
+
realign/dashboard/widgets/terminal_panel.py,sha256=at8whXa8Bsn_icbyerHG21tb2BsnQikAMlf4NfIpTGw,61504
|
|
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=
|
|
78
|
-
realign/db/locks.py,sha256=
|
|
83
|
+
realign/db/base.py,sha256=XIW25zh8UD2AC4zJaGXWmRkcZxk59nVwqDFysk_vfZw,14370
|
|
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=
|
|
82
|
-
realign/db/sqlite_db.py,sha256=
|
|
87
|
+
realign/db/schema.py,sha256=uOp8B7-zq5nsdyw5aNpwhhAr5lnoYAWNES6Mr1GCh7Y,31803
|
|
88
|
+
realign/db/sqlite_db.py,sha256=Ixcym-aUtVkgpav0FQ3whCp6PblwBtMGrHmvK8GHvMY,113707
|
|
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=
|
|
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.
|
|
101
|
-
aline_ai-0.6.
|
|
102
|
-
aline_ai-0.6.
|
|
103
|
-
aline_ai-0.6.
|
|
104
|
-
aline_ai-0.6.
|
|
107
|
+
aline_ai-0.6.6.dist-info/METADATA,sha256=_RwRrqtSa3O_Rt0sXdK18VX8fHbYtz9gtE-tkVfGe5w,1597
|
|
108
|
+
aline_ai-0.6.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
109
|
+
aline_ai-0.6.6.dist-info/entry_points.txt,sha256=TvYELpMoWsUTcQdMV8tBHxCbEf_LbK4sESqK3r8PM6Y,78
|
|
110
|
+
aline_ai-0.6.6.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
|
|
111
|
+
aline_ai-0.6.6.dist-info/RECORD,,
|
realign/__init__.py
CHANGED
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 Docker-style name, e.g. 'bold-turing'."""
|
|
79
|
+
return f"{_rng.choice(ADJECTIVES)}-{_rng.choice(SURNAMES)}"
|
|
@@ -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
|
|
@@ -56,6 +56,7 @@ def _write_to_db(
|
|
|
56
56
|
source: str = "",
|
|
57
57
|
context_id: Optional[str] = None,
|
|
58
58
|
attention: Optional[str] = None,
|
|
59
|
+
agent_id: Optional[str] = None,
|
|
59
60
|
) -> bool:
|
|
60
61
|
"""Write terminal mapping to database (best-effort).
|
|
61
62
|
|
|
@@ -96,6 +97,14 @@ def _write_to_db(
|
|
|
96
97
|
source=source if source else None,
|
|
97
98
|
attention=attention,
|
|
98
99
|
)
|
|
100
|
+
|
|
101
|
+
# Link session to agent if both are available (V19+)
|
|
102
|
+
if session_id and agent_id:
|
|
103
|
+
try:
|
|
104
|
+
db.update_session_agent_id(session_id, agent_id)
|
|
105
|
+
except Exception:
|
|
106
|
+
pass
|
|
107
|
+
|
|
99
108
|
# Note: Don't close - get_database() returns a singleton
|
|
100
109
|
return True
|
|
101
110
|
except Exception:
|
|
@@ -114,6 +123,7 @@ def update_terminal_mapping(
|
|
|
114
123
|
source: str = "",
|
|
115
124
|
context_id: Optional[str] = None,
|
|
116
125
|
attention: Optional[str] = None,
|
|
126
|
+
agent_id: Optional[str] = None,
|
|
117
127
|
) -> None:
|
|
118
128
|
"""Update terminal->session binding.
|
|
119
129
|
|
|
@@ -135,6 +145,7 @@ def update_terminal_mapping(
|
|
|
135
145
|
source=source,
|
|
136
146
|
context_id=context_id,
|
|
137
147
|
attention=attention,
|
|
148
|
+
agent_id=agent_id,
|
|
138
149
|
)
|
|
139
150
|
|
|
140
151
|
# 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,7 +14,7 @@ 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
|
|
realign/codex_home.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"""Codex home/session path helpers.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
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)
|
|
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
|
|
41
|
-
|
|
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,29 @@ 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
|
-
|
|
57
|
-
if not
|
|
76
|
+
owner = (parts[0] or "").strip()
|
|
77
|
+
if not owner:
|
|
58
78
|
return None
|
|
59
79
|
if parts[1] != "sessions":
|
|
60
80
|
return None
|
|
61
|
-
|
|
81
|
+
if owner.startswith(AGENT_HOME_PREFIX):
|
|
82
|
+
return ("agent", owner[len(AGENT_HOME_PREFIX) :])
|
|
83
|
+
return ("terminal", owner)
|
|
62
84
|
|
|
63
85
|
|
|
64
|
-
def
|
|
65
|
-
"""
|
|
66
|
-
|
|
86
|
+
def terminal_id_from_codex_session_file(session_file: Path) -> Optional[str]:
|
|
87
|
+
"""If session_file is under an Aline-managed CODEX_HOME, return terminal_id."""
|
|
88
|
+
owner = codex_home_owner_from_session_file(session_file)
|
|
89
|
+
if not owner:
|
|
90
|
+
return None
|
|
91
|
+
if owner[0] != "terminal":
|
|
92
|
+
return None
|
|
93
|
+
return owner[1]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def prepare_codex_home(terminal_id: str, *, agent_id: Optional[str] = None) -> Path:
|
|
97
|
+
"""Create/prepare an isolated CODEX_HOME (per-agent if agent_id is provided)."""
|
|
98
|
+
home = codex_home_for_terminal_or_agent(terminal_id, agent_id)
|
|
67
99
|
sessions = codex_sessions_dir_for_home(home)
|
|
68
100
|
try:
|
|
69
101
|
sessions.mkdir(parents=True, exist_ok=True)
|
|
@@ -82,4 +114,3 @@ def prepare_codex_home(terminal_id: str) -> Path:
|
|
|
82
114
|
pass
|
|
83
115
|
|
|
84
116
|
return home
|
|
85
|
-
|
realign/codex_terminal_linker.py
CHANGED
|
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
import json
|
|
14
14
|
from dataclasses import dataclass
|
|
15
15
|
from datetime import datetime, timezone
|
|
16
|
+
import os
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from typing import Iterable, Optional, Protocol
|
|
18
19
|
|
|
@@ -42,6 +43,16 @@ def _parse_iso8601(ts: str) -> Optional[datetime]:
|
|
|
42
43
|
return dt
|
|
43
44
|
|
|
44
45
|
|
|
46
|
+
def _normalize_cwd(cwd: str | None) -> str:
|
|
47
|
+
raw = (cwd or "").strip()
|
|
48
|
+
if not raw:
|
|
49
|
+
return ""
|
|
50
|
+
try:
|
|
51
|
+
return os.path.normpath(raw)
|
|
52
|
+
except Exception:
|
|
53
|
+
return raw.rstrip("/\\")
|
|
54
|
+
|
|
55
|
+
|
|
45
56
|
def read_codex_session_meta(session_file: Path) -> Optional[CodexSessionMeta]:
|
|
46
57
|
"""Extract Codex session metadata from a session file (best-effort)."""
|
|
47
58
|
try:
|
|
@@ -108,10 +119,10 @@ def select_agent_for_codex_session(
|
|
|
108
119
|
agents: Iterable[_AgentLike],
|
|
109
120
|
*,
|
|
110
121
|
session: CodexSessionMeta,
|
|
111
|
-
max_time_delta_seconds: int = 6 * 60 * 60,
|
|
122
|
+
max_time_delta_seconds: Optional[int] = 6 * 60 * 60,
|
|
112
123
|
) -> Optional[str]:
|
|
113
124
|
"""Pick the best active Codex terminal for a Codex session file (best-effort)."""
|
|
114
|
-
cwd = (session.cwd
|
|
125
|
+
cwd = _normalize_cwd(session.cwd)
|
|
115
126
|
if not cwd:
|
|
116
127
|
return None
|
|
117
128
|
|
|
@@ -122,7 +133,7 @@ def select_agent_for_codex_session(
|
|
|
122
133
|
continue
|
|
123
134
|
if getattr(a, "provider", "") != "codex":
|
|
124
135
|
continue
|
|
125
|
-
if (getattr(a, "cwd", None)
|
|
136
|
+
if _normalize_cwd(getattr(a, "cwd", None)) != cwd:
|
|
126
137
|
continue
|
|
127
138
|
# Avoid clobbering an existing binding to a different session.
|
|
128
139
|
existing_sid = (getattr(a, "session_id", None) or "").strip()
|
|
@@ -165,8 +176,8 @@ def select_agent_for_codex_session(
|
|
|
165
176
|
|
|
166
177
|
if best_id is None:
|
|
167
178
|
return None
|
|
168
|
-
if
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
if max_time_delta_seconds is not None and best_delta is not None:
|
|
180
|
+
if best_delta > max_time_delta_seconds:
|
|
181
|
+
# Ambiguous: don't bind if terminals are too far from the session start.
|
|
182
|
+
return None
|
|
171
183
|
return best_id
|
|
172
|
-
|