aline-ai 0.6.1__py3-none-any.whl → 0.6.2__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.1.dist-info → aline_ai-0.6.2.dist-info}/METADATA +1 -1
- {aline_ai-0.6.1.dist-info → aline_ai-0.6.2.dist-info}/RECORD +18 -18
- realign/__init__.py +1 -1
- realign/claude_hooks/stop_hook.py +35 -0
- realign/claude_hooks/user_prompt_submit_hook.py +5 -0
- realign/cli.py +32 -28
- realign/dashboard/app.py +1 -0
- realign/dashboard/screens/create_agent.py +41 -4
- realign/dashboard/tmux_manager.py +17 -0
- realign/dashboard/widgets/terminal_panel.py +26 -11
- realign/db/sqlite_db.py +18 -0
- realign/events/session_summarizer.py +17 -2
- realign/watcher_core.py +56 -22
- realign/worker_core.py +2 -0
- {aline_ai-0.6.1.dist-info → aline_ai-0.6.2.dist-info}/WHEEL +0 -0
- {aline_ai-0.6.1.dist-info → aline_ai-0.6.2.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.6.1.dist-info → aline_ai-0.6.2.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.6.1.dist-info → aline_ai-0.6.2.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
aline_ai-0.6.
|
|
2
|
-
realign/__init__.py,sha256=
|
|
1
|
+
aline_ai-0.6.2.dist-info/licenses/LICENSE,sha256=H8wTqV5IF1oHw_HbBtS1PSDU8G_q81yblEIL_JfV8Vo,1077
|
|
2
|
+
realign/__init__.py,sha256=WCultxtZIKlfMhrDP35gb3Jtyvc7vOLpx-I1JO6nPAc,1623
|
|
3
3
|
realign/auth.py,sha256=d_1yvCwluN5iIrdgjtuSKpOYAksDzrzNgntKacLVJrw,16583
|
|
4
4
|
realign/claude_detector.py,sha256=ZLSJacMo6zzQclXByABKA70UNpstxqIv3fPGqdpA934,2792
|
|
5
|
-
realign/cli.py,sha256=
|
|
5
|
+
realign/cli.py,sha256=M8lpAkDaE2ZjESzrlksFk8M8cpbFKkIzK3y8qNnZmJo,43793
|
|
6
6
|
realign/codex_detector.py,sha256=N9ulgMgvTzDfXE4s4vLd6OoS0hT7R6h2bDFFXWa-2hE,4183
|
|
7
7
|
realign/config.py,sha256=d8HQ6v1xju6cjNGbR7LlfHaMyvFPcMDofhGbepxpQq8,11634
|
|
8
8
|
realign/context.py,sha256=8hzgNOg-7_eMW22wt7OM5H9IsmMveKXCv0epG7E0G7w,13917
|
|
@@ -13,9 +13,9 @@ realign/logging_config.py,sha256=LCAigKFhTj86PSJm4-kUl3Ag9h_GENh3x2iPnMv7qUI,487
|
|
|
13
13
|
realign/mcp_server.py,sha256=LWiQ2qukYoNLsoV2ID2f0vF9jkJlBvB587HpM5jymgE,10193
|
|
14
14
|
realign/mcp_watcher.py,sha256=aK4jWStv7CoCroS4tXFHgZ_y_-q4QDjrpWgm4DxcEj4,1260
|
|
15
15
|
realign/redactor.py,sha256=Zsoi5HfYak2yPmck20JArhm-1cPSB78IdkBJiNVXfrc,17096
|
|
16
|
-
realign/watcher_core.py,sha256=
|
|
16
|
+
realign/watcher_core.py,sha256=k9esacTBfHpa77MPEXAsiMDiFa4Ml52vWfGGT-IucAM,108135
|
|
17
17
|
realign/watcher_daemon.py,sha256=OHUQ9P1LlagKJHfrf6uRnzO-zDtBRXIxt8ydMFHf5S8,3475
|
|
18
|
-
realign/worker_core.py,sha256
|
|
18
|
+
realign/worker_core.py,sha256=TXioUVJlOO-8EgmKssCTLIyuh0aaupRLb1sh9s3kSuc,10194
|
|
19
19
|
realign/worker_daemon.py,sha256=X7Xyjw_u6m6KG4E84nx0HpDFw4cWMv8ja1G8btc9PiM,3957
|
|
20
20
|
realign/adapters/__init__.py,sha256=bpDm5aBxMdq4OA_beYahoUb4zfNaq3KOG6KghQJruRc,827
|
|
21
21
|
realign/adapters/antigravity.py,sha256=geaYxAEswpgsVtERqsQ1OwvPFsy5tRkyjx2yQ-Uq9nM,5461
|
|
@@ -27,10 +27,10 @@ realign/adapters/registry.py,sha256=yM6nf9nGTJ1vaK2Uixp-VacseK7PmxZkCdKedmWI8MA,
|
|
|
27
27
|
realign/claude_hooks/__init__.py,sha256=MT9c8TWjLO23xDCM-uBBMy_mOThNd7O-AgN_Khn30qs,594
|
|
28
28
|
realign/claude_hooks/permission_request_hook.py,sha256=jMN7UtL6bMqHObUCP5A5ysvFrooDEcd9KxtmF2-3nCw,6448
|
|
29
29
|
realign/claude_hooks/permission_request_hook_installer.py,sha256=_8Wr_L5MES7iGukJzcaj4bqR0BH8kFL44U_X4iKtw2Y,7791
|
|
30
|
-
realign/claude_hooks/stop_hook.py,sha256=
|
|
30
|
+
realign/claude_hooks/stop_hook.py,sha256=GWADlzaTGzV8_BUKLLGhHmwJDIXSLQGVUUBuP_rdJ0o,13431
|
|
31
31
|
realign/claude_hooks/stop_hook_installer.py,sha256=uyqKOqpix7CQP64ERBvvh7viSPp_wx_JVGNAX18rKh0,7228
|
|
32
32
|
realign/claude_hooks/terminal_state.py,sha256=i8B6b_2_9ttPEemp7SrGdFRJSa-vm5lc7YSTRTvAWNg,5397
|
|
33
|
-
realign/claude_hooks/user_prompt_submit_hook.py,sha256=
|
|
33
|
+
realign/claude_hooks/user_prompt_submit_hook.py,sha256=kMrmhAVtfV41oTX7JZcq2HPXjgQQ5gX26iOJoHJkfqA,10474
|
|
34
34
|
realign/claude_hooks/user_prompt_submit_hook_installer.py,sha256=2xLF8yZcE7Iwib9gU-xCkA1NWxNH9Nc5CFKPYK7rtXw,5371
|
|
35
35
|
realign/commands/__init__.py,sha256=sx_ck55oxaoiF4N3LugG0ZXwonUDxeEZ5uHbBKCC7K8,89
|
|
36
36
|
realign/commands/add.py,sha256=njZgg3paUmOw-sb-sWkXr_eUaf5bD-hBEiRectaphPs,24332
|
|
@@ -46,15 +46,15 @@ realign/commands/upgrade.py,sha256=L3PLOUIN5qAQTbkfoVtSsIbbzEezA_xjjk9F1GMVfjw,1
|
|
|
46
46
|
realign/commands/watcher.py,sha256=rB3x2diC7scqghl7wLAeBNgMj4NLXUKbr0ou1_VVUIU,136292
|
|
47
47
|
realign/commands/worker.py,sha256=jTu7Pj60nTnn7SsH3oNCNnO6zl4TIFCJVNSC1OoQ_0o,23363
|
|
48
48
|
realign/dashboard/__init__.py,sha256=QZkHTsGityH8UkF8rmvA3xW7dMXNe0swEWr443qfgCM,128
|
|
49
|
-
realign/dashboard/app.py,sha256=
|
|
49
|
+
realign/dashboard/app.py,sha256=yy2rjMQuAfpukFgrA6udAnAbCXQoAHr9WeeuZ9bCSa4,16064
|
|
50
50
|
realign/dashboard/layout.py,sha256=sZxmFj6QTbkois9MHTvBEMMcnaRVehCDqugdbiFx10k,9072
|
|
51
51
|
realign/dashboard/terminal_backend.py,sha256=MlDfwtqhftyQK6jDNizQGFjAWIo5Bx2TDpSnP3MCZVM,3375
|
|
52
|
-
realign/dashboard/tmux_manager.py,sha256=
|
|
52
|
+
realign/dashboard/tmux_manager.py,sha256=K8sjzSBtISLuWF7s4g4YieJ4oiE5wIgSztFvmhJZd0M,26849
|
|
53
53
|
realign/dashboard/backends/__init__.py,sha256=POROX7YKtukYZcLB1pi_kO0sSEpuO3y-hwmF3WIN1Kk,163
|
|
54
54
|
realign/dashboard/backends/iterm2.py,sha256=XYYJT5lrrp4pW_MyEqPZYkRI0qyKUwJlezwMidgnsHc,21390
|
|
55
55
|
realign/dashboard/backends/kitty.py,sha256=5jdkR1f2PwB8a4SnS3EG6uOQ2XU-PB7-cpKBfIJq3hU,12066
|
|
56
56
|
realign/dashboard/screens/__init__.py,sha256=US6sAmQs5VVkH2tFkH_z0WDT4H8cVhLL-JckfSR1yQY,446
|
|
57
|
-
realign/dashboard/screens/create_agent.py,sha256=
|
|
57
|
+
realign/dashboard/screens/create_agent.py,sha256=06uiQYvz-Xvn4Xm689o3tdhzb2HQ0gdzAA1WHVEwziM,11706
|
|
58
58
|
realign/dashboard/screens/create_event.py,sha256=oiQY1zKpUYnQU-5fQLeuZH9BV5NClE5B5XZIVBYG5A8,5506
|
|
59
59
|
realign/dashboard/screens/event_detail.py,sha256=OLaL3-FgAohDdzVlfuUw5yh2SR49IHIpCtiqXJhBTc0,20992
|
|
60
60
|
realign/dashboard/screens/help_screen.py,sha256=Icrcvbgyz49R2tBiu8vBZ4CLm6iYclv_-FTa2pCFRRQ,3398
|
|
@@ -68,7 +68,7 @@ realign/dashboard/widgets/header.py,sha256=0HHCFXX7F3C6HII-WDwOJwWkJrajmKPWmdoMW
|
|
|
68
68
|
realign/dashboard/widgets/openable_table.py,sha256=GeJPDEYp0kRHShqvmPMzAePpYXRZHUNqcWNnxqsqxjA,1963
|
|
69
69
|
realign/dashboard/widgets/search_panel.py,sha256=ZNJDfwDSxUFnCeltYQYsQsPJ6t4HDeNWpENoTOoBdVM,8951
|
|
70
70
|
realign/dashboard/widgets/sessions_table.py,sha256=GyaWzvt-elKx1iE2YR94CBNPyjqM8B7g0j7zsukiXi0,36517
|
|
71
|
-
realign/dashboard/widgets/terminal_panel.py,sha256=
|
|
71
|
+
realign/dashboard/widgets/terminal_panel.py,sha256=BZgh7lo9rhuJdvSGBhUPlWjS3KjcXDJP7SSnNngmFaY,45805
|
|
72
72
|
realign/dashboard/widgets/watcher_panel.py,sha256=O_mdDacgc87xA-5KEfta53Ik_Xsk_B2OfwenMOTtGw8,19722
|
|
73
73
|
realign/dashboard/widgets/worker_panel.py,sha256=F_jKWABuCNmjQgeeuCr4KnFRKdY4CLTNcEXMYwsNaSk,18691
|
|
74
74
|
realign/db/__init__.py,sha256=65LsNdsq_rkwNC1eg1OAr3HC0ORXtelOh0I8MhNGr-g,3288
|
|
@@ -77,11 +77,11 @@ realign/db/locks.py,sha256=yzCiPJZ4eOQX-Q4mXB6s76U2U7lXAzIBBy1t59w-AVU,1698
|
|
|
77
77
|
realign/db/migrate_agents.py,sha256=cDeVUzKW950dJ0lV74QObHuONqKwErSrXI5akU2vBmQ,9633
|
|
78
78
|
realign/db/migration.py,sha256=af1QFEfIh_qX0pFyXzm5gWFVbQn0sKOUNLSJHlr__FU,13405
|
|
79
79
|
realign/db/schema.py,sha256=YHj5PGZWbCl0VG0epnMF_Ofg3jRiLHq6SLHCi1q34eQ,30181
|
|
80
|
-
realign/db/sqlite_db.py,sha256=
|
|
80
|
+
realign/db/sqlite_db.py,sha256=AJb05gWN8L7K79-f9TJ0UGqGnoHUED1z-yjufGQTyQE,104929
|
|
81
81
|
realign/events/__init__.py,sha256=IM-NxF4Zk2hYFD07k4WrfNRuuiC9ihGjf4GBpJhjd2E,35
|
|
82
82
|
realign/events/debouncer.py,sha256=U3Q7dYpnMsAgWsW_E_IbSC4lrdEoi6H_SFLGLOAazs4,3062
|
|
83
83
|
realign/events/event_summarizer.py,sha256=ZLiwOXWN8eawep3cQs3Wh9QLSypvU1SRbe8GTJXJQaY,8272
|
|
84
|
-
realign/events/session_summarizer.py,sha256=
|
|
84
|
+
realign/events/session_summarizer.py,sha256=W5J1zZs1ZrH0MvWgvPObwB1KFdxXEZMLctAmFQC_rok,10994
|
|
85
85
|
realign/models/event.py,sha256=ypz74D4l6U2U0RhgL8fzEhiq7iQjhHybmAdLUNDY7P4,5521
|
|
86
86
|
realign/prompts/__init__.py,sha256=PpYR7f-T96fd-QyNYJDRS1U6h9O0rIt_SMsREy9i3aA,443
|
|
87
87
|
realign/prompts/presets.py,sha256=h9oEy0XP4JQ4DCnp8HN_FfF0LmI-yOV6xWJLknIghJ8,7256
|
|
@@ -96,8 +96,8 @@ realign/triggers/next_turn_trigger.py,sha256=BpP0PWn4mU1MZd6mv89jWcjs8Jtv0zEWapW
|
|
|
96
96
|
realign/triggers/registry.py,sha256=cb-AVLbYB2pqwfWL3q1DQxLv4kOw7g7m-GshTdfFESc,3827
|
|
97
97
|
realign/triggers/turn_status.py,sha256=wAZEhXDAmDoX5F-ohWfSnZZ0eA6DAJ9svSPiSv_f6sg,6041
|
|
98
98
|
realign/triggers/turn_summary.py,sha256=f3hEUshgv9skJ9AbfWpoYs417lsv_HK2A_vpPjgryO4,4467
|
|
99
|
-
aline_ai-0.6.
|
|
100
|
-
aline_ai-0.6.
|
|
101
|
-
aline_ai-0.6.
|
|
102
|
-
aline_ai-0.6.
|
|
103
|
-
aline_ai-0.6.
|
|
99
|
+
aline_ai-0.6.2.dist-info/METADATA,sha256=KJbwjx2uZdXBhG2HyeVUs77RT72msrkJLRYBlCrldVc,1597
|
|
100
|
+
aline_ai-0.6.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
101
|
+
aline_ai-0.6.2.dist-info/entry_points.txt,sha256=TvYELpMoWsUTcQdMV8tBHxCbEf_LbK4sESqK3r8PM6Y,78
|
|
102
|
+
aline_ai-0.6.2.dist-info/top_level.txt,sha256=yIL3s2xv9nf1GwD5n71Aq_JEIV4AfzCIDNKBzewuRm4,8
|
|
103
|
+
aline_ai-0.6.2.dist-info/RECORD,,
|
realign/__init__.py
CHANGED
|
@@ -98,6 +98,9 @@ def main():
|
|
|
98
98
|
signal_file = signal_dir / f"{session_id}_{timestamp_ms}.signal"
|
|
99
99
|
tmp_file = signal_dir / f"{session_id}_{timestamp_ms}.signal.tmp"
|
|
100
100
|
|
|
101
|
+
# Check for no-track mode
|
|
102
|
+
no_track = os.environ.get("ALINE_NO_TRACK", "") == "1"
|
|
103
|
+
|
|
101
104
|
signal_data = {
|
|
102
105
|
"session_id": session_id,
|
|
103
106
|
"terminal_id": terminal_id,
|
|
@@ -107,6 +110,8 @@ def main():
|
|
|
107
110
|
"timestamp": time.time(),
|
|
108
111
|
"hook_event": "Stop",
|
|
109
112
|
}
|
|
113
|
+
if no_track:
|
|
114
|
+
signal_data["no_track"] = True
|
|
110
115
|
|
|
111
116
|
# Write atomically to avoid watcher reading a partial JSON file.
|
|
112
117
|
tmp_file.write_text(json.dumps(signal_data, indent=2))
|
|
@@ -193,6 +198,22 @@ def main():
|
|
|
193
198
|
],
|
|
194
199
|
check=False,
|
|
195
200
|
)
|
|
201
|
+
# Set no-track flag if applicable
|
|
202
|
+
if no_track:
|
|
203
|
+
subprocess.run(
|
|
204
|
+
[
|
|
205
|
+
"tmux",
|
|
206
|
+
"-L",
|
|
207
|
+
inner_socket,
|
|
208
|
+
"set-option",
|
|
209
|
+
"-w",
|
|
210
|
+
"-t",
|
|
211
|
+
window_id,
|
|
212
|
+
"@aline_no_track",
|
|
213
|
+
"1",
|
|
214
|
+
],
|
|
215
|
+
check=False,
|
|
216
|
+
)
|
|
196
217
|
if transcript_path:
|
|
197
218
|
subprocess.run(
|
|
198
219
|
[
|
|
@@ -285,6 +306,20 @@ def main():
|
|
|
285
306
|
],
|
|
286
307
|
check=False,
|
|
287
308
|
)
|
|
309
|
+
# Set no-track flag if applicable
|
|
310
|
+
if no_track:
|
|
311
|
+
subprocess.run(
|
|
312
|
+
[
|
|
313
|
+
"tmux",
|
|
314
|
+
"set-option",
|
|
315
|
+
"-w",
|
|
316
|
+
"-t",
|
|
317
|
+
window_id,
|
|
318
|
+
"@aline_no_track",
|
|
319
|
+
"1",
|
|
320
|
+
],
|
|
321
|
+
check=False,
|
|
322
|
+
)
|
|
288
323
|
if transcript_path:
|
|
289
324
|
subprocess.run(
|
|
290
325
|
[
|
|
@@ -80,6 +80,9 @@ def main() -> None:
|
|
|
80
80
|
signal_file = signal_dir / f"{session_id}_{timestamp_ms}.signal"
|
|
81
81
|
tmp_file = signal_dir / f"{session_id}_{timestamp_ms}.signal.tmp"
|
|
82
82
|
|
|
83
|
+
# Check for no-track mode
|
|
84
|
+
no_track = os.environ.get("ALINE_NO_TRACK", "") == "1"
|
|
85
|
+
|
|
83
86
|
signal_data = {
|
|
84
87
|
"session_id": session_id,
|
|
85
88
|
"terminal_id": terminal_id,
|
|
@@ -90,6 +93,8 @@ def main() -> None:
|
|
|
90
93
|
"timestamp": time.time(),
|
|
91
94
|
"hook_event": "UserPromptSubmit",
|
|
92
95
|
}
|
|
96
|
+
if no_track:
|
|
97
|
+
signal_data["no_track"] = True
|
|
93
98
|
|
|
94
99
|
tmp_file.write_text(json.dumps(signal_data, indent=2))
|
|
95
100
|
tmp_file.replace(signal_file)
|
realign/cli.py
CHANGED
|
@@ -131,8 +131,8 @@ def doctor_cli(
|
|
|
131
131
|
- Clears Python bytecode cache (.pyc files)
|
|
132
132
|
- Updates Claude Code hooks (Stop, UserPromptSubmit, PermissionRequest)
|
|
133
133
|
- Updates skills to latest version
|
|
134
|
-
-
|
|
135
|
-
-
|
|
134
|
+
- Ensures watcher daemon is running (restarts if running, starts if not)
|
|
135
|
+
- Ensures worker daemon is running (restarts if running, starts if not)
|
|
136
136
|
|
|
137
137
|
Run this after pulling new code to ensure everything uses the latest version.
|
|
138
138
|
"""
|
|
@@ -285,20 +285,22 @@ def doctor_cli(
|
|
|
285
285
|
|
|
286
286
|
if watcher_was_running:
|
|
287
287
|
console.print(" [dim]Starting watcher daemon...[/dim]")
|
|
288
|
-
try:
|
|
289
|
-
subprocess.Popen(
|
|
290
|
-
["python", "-m", "src.realign.watcher_daemon"],
|
|
291
|
-
stdout=subprocess.DEVNULL,
|
|
292
|
-
stderr=subprocess.DEVNULL,
|
|
293
|
-
start_new_session=True,
|
|
294
|
-
cwd=str(project_root),
|
|
295
|
-
)
|
|
296
|
-
time.sleep(2)
|
|
297
|
-
console.print(" [green]✓[/green] Watcher daemon restarted")
|
|
298
|
-
except Exception as e:
|
|
299
|
-
console.print(f" [red]✗[/red] Failed to restart watcher: {e}")
|
|
300
288
|
else:
|
|
301
|
-
console.print(" [dim]Watcher daemon was not running[/dim]")
|
|
289
|
+
console.print(" [dim]Watcher daemon was not running, starting...[/dim]")
|
|
290
|
+
try:
|
|
291
|
+
subprocess.Popen(
|
|
292
|
+
["python", "-m", "src.realign.watcher_daemon"],
|
|
293
|
+
stdout=subprocess.DEVNULL,
|
|
294
|
+
stderr=subprocess.DEVNULL,
|
|
295
|
+
start_new_session=True,
|
|
296
|
+
cwd=str(project_root),
|
|
297
|
+
)
|
|
298
|
+
time.sleep(2)
|
|
299
|
+
action = "restarted" if watcher_was_running else "started"
|
|
300
|
+
console.print(f" [green]✓[/green] Watcher daemon {action}")
|
|
301
|
+
except Exception as e:
|
|
302
|
+
action = "restart" if watcher_was_running else "start"
|
|
303
|
+
console.print(f" [red]✗[/red] Failed to {action} watcher: {e}")
|
|
302
304
|
|
|
303
305
|
# 5. Restart worker daemon
|
|
304
306
|
console.print("\n[bold]5. Checking worker daemon...[/bold]")
|
|
@@ -329,20 +331,22 @@ def doctor_cli(
|
|
|
329
331
|
|
|
330
332
|
if worker_was_running:
|
|
331
333
|
console.print(" [dim]Starting worker daemon...[/dim]")
|
|
332
|
-
try:
|
|
333
|
-
subprocess.Popen(
|
|
334
|
-
["python", "-m", "src.realign.worker_daemon"],
|
|
335
|
-
stdout=subprocess.DEVNULL,
|
|
336
|
-
stderr=subprocess.DEVNULL,
|
|
337
|
-
start_new_session=True,
|
|
338
|
-
cwd=str(project_root),
|
|
339
|
-
)
|
|
340
|
-
time.sleep(2)
|
|
341
|
-
console.print(" [green]✓[/green] Worker daemon restarted")
|
|
342
|
-
except Exception as e:
|
|
343
|
-
console.print(f" [red]✗[/red] Failed to restart worker: {e}")
|
|
344
334
|
else:
|
|
345
|
-
console.print(" [dim]Worker daemon was not running[/dim]")
|
|
335
|
+
console.print(" [dim]Worker daemon was not running, starting...[/dim]")
|
|
336
|
+
try:
|
|
337
|
+
subprocess.Popen(
|
|
338
|
+
["python", "-m", "src.realign.worker_daemon"],
|
|
339
|
+
stdout=subprocess.DEVNULL,
|
|
340
|
+
stderr=subprocess.DEVNULL,
|
|
341
|
+
start_new_session=True,
|
|
342
|
+
cwd=str(project_root),
|
|
343
|
+
)
|
|
344
|
+
time.sleep(2)
|
|
345
|
+
action = "restarted" if worker_was_running else "started"
|
|
346
|
+
console.print(f" [green]✓[/green] Worker daemon {action}")
|
|
347
|
+
except Exception as e:
|
|
348
|
+
action = "restart" if worker_was_running else "start"
|
|
349
|
+
console.print(f" [red]✗[/red] Failed to {action} worker: {e}")
|
|
346
350
|
|
|
347
351
|
console.print("\n[green]Done![/green] Aline is ready with the latest code.")
|
|
348
352
|
raise typer.Exit(code=0)
|
realign/dashboard/app.py
CHANGED
|
@@ -60,6 +60,23 @@ def _save_claude_permission_mode(mode: str) -> None:
|
|
|
60
60
|
_save_state("claude_permission_mode", mode)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
def _load_claude_tracking_mode() -> str:
|
|
64
|
+
"""Load the last used Claude tracking mode from state file."""
|
|
65
|
+
try:
|
|
66
|
+
if DASHBOARD_STATE_FILE.exists():
|
|
67
|
+
with open(DASHBOARD_STATE_FILE, "r", encoding="utf-8") as f:
|
|
68
|
+
state = json.load(f)
|
|
69
|
+
return state.get("claude_tracking_mode", "track")
|
|
70
|
+
except Exception:
|
|
71
|
+
pass
|
|
72
|
+
return "track"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _save_claude_tracking_mode(mode: str) -> None:
|
|
76
|
+
"""Save the Claude tracking mode to state file."""
|
|
77
|
+
_save_state("claude_tracking_mode", mode)
|
|
78
|
+
|
|
79
|
+
|
|
63
80
|
def _save_state(key: str, value: str) -> None:
|
|
64
81
|
"""Save a key-value pair to the state file."""
|
|
65
82
|
try:
|
|
@@ -75,10 +92,10 @@ def _save_state(key: str, value: str) -> None:
|
|
|
75
92
|
pass
|
|
76
93
|
|
|
77
94
|
|
|
78
|
-
class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool]]]):
|
|
95
|
+
class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool, bool]]]):
|
|
79
96
|
"""Modal to create a new agent terminal.
|
|
80
97
|
|
|
81
|
-
Returns a tuple of (agent_type, workspace_path, skip_permissions) on success, None on cancel.
|
|
98
|
+
Returns a tuple of (agent_type, workspace_path, skip_permissions, no_track) on success, None on cancel.
|
|
82
99
|
"""
|
|
83
100
|
|
|
84
101
|
BINDINGS = [
|
|
@@ -175,6 +192,7 @@ class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool]]]):
|
|
|
175
192
|
super().__init__()
|
|
176
193
|
self._workspace_path = _load_last_workspace()
|
|
177
194
|
self._permission_mode = _load_claude_permission_mode()
|
|
195
|
+
self._tracking_mode = _load_claude_tracking_mode()
|
|
178
196
|
|
|
179
197
|
def compose(self) -> ComposeResult:
|
|
180
198
|
with Container(id="create-agent-root"):
|
|
@@ -199,6 +217,11 @@ class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool]]]):
|
|
|
199
217
|
yield RadioButton("Normal", id="perm-normal", value=True)
|
|
200
218
|
yield RadioButton("Skip (--dangerously-skip-permissions)", id="perm-skip")
|
|
201
219
|
|
|
220
|
+
yield Label("Tracking", classes="section-label")
|
|
221
|
+
with RadioSet(id="tracking-mode"):
|
|
222
|
+
yield RadioButton("Track", id="track-track", value=True)
|
|
223
|
+
yield RadioButton("No Track (skip LLM summaries)", id="track-notrack")
|
|
224
|
+
|
|
202
225
|
with Horizontal(id="buttons"):
|
|
203
226
|
yield Button("Cancel", id="cancel")
|
|
204
227
|
yield Button("Create", id="create", variant="primary")
|
|
@@ -209,6 +232,11 @@ class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool]]]):
|
|
|
209
232
|
self.query_one("#perm-skip", RadioButton).value = True
|
|
210
233
|
else:
|
|
211
234
|
self.query_one("#perm-normal", RadioButton).value = True
|
|
235
|
+
# Set the saved tracking mode
|
|
236
|
+
if self._tracking_mode == "notrack":
|
|
237
|
+
self.query_one("#track-notrack", RadioButton).value = True
|
|
238
|
+
else:
|
|
239
|
+
self.query_one("#track-track", RadioButton).value = True
|
|
212
240
|
self.query_one("#create", Button).focus()
|
|
213
241
|
|
|
214
242
|
def action_close(self) -> None:
|
|
@@ -292,8 +320,9 @@ class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool]]]):
|
|
|
292
320
|
}
|
|
293
321
|
agent_type = agent_type_map.get(pressed_button.id or "", "claude")
|
|
294
322
|
|
|
295
|
-
# Get permission mode (only relevant for Claude)
|
|
323
|
+
# Get permission mode and tracking mode (only relevant for Claude)
|
|
296
324
|
skip_permissions = False
|
|
325
|
+
no_track = False
|
|
297
326
|
if agent_type == "claude":
|
|
298
327
|
perm_radio_set = self.query_one("#permission-mode", RadioSet)
|
|
299
328
|
perm_pressed = perm_radio_set.pressed_button
|
|
@@ -302,8 +331,16 @@ class CreateAgentScreen(ModalScreen[Optional[tuple[str, str, bool]]]):
|
|
|
302
331
|
permission_mode = "skip" if skip_permissions else "normal"
|
|
303
332
|
_save_claude_permission_mode(permission_mode)
|
|
304
333
|
|
|
334
|
+
# Get tracking mode
|
|
335
|
+
track_radio_set = self.query_one("#tracking-mode", RadioSet)
|
|
336
|
+
track_pressed = track_radio_set.pressed_button
|
|
337
|
+
no_track = track_pressed is not None and track_pressed.id == "track-notrack"
|
|
338
|
+
# Save the tracking mode for next time
|
|
339
|
+
tracking_mode = "notrack" if no_track else "track"
|
|
340
|
+
_save_claude_tracking_mode(tracking_mode)
|
|
341
|
+
|
|
305
342
|
# Save the workspace path for next time
|
|
306
343
|
_save_last_workspace(self._workspace_path)
|
|
307
344
|
|
|
308
345
|
# Return the result
|
|
309
|
-
self.dismiss((agent_type, self._workspace_path, skip_permissions))
|
|
346
|
+
self.dismiss((agent_type, self._workspace_path, skip_permissions, no_track))
|
|
@@ -45,6 +45,7 @@ OPT_TRANSCRIPT_PATH = "@aline_transcript_path"
|
|
|
45
45
|
OPT_CONTEXT_ID = "@aline_context_id"
|
|
46
46
|
OPT_ATTENTION = "@aline_attention"
|
|
47
47
|
OPT_CREATED_AT = "@aline_created_at"
|
|
48
|
+
OPT_NO_TRACK = "@aline_no_track"
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
@dataclass(frozen=True)
|
|
@@ -60,6 +61,7 @@ class InnerWindow:
|
|
|
60
61
|
context_id: str | None = None
|
|
61
62
|
attention: str | None = None # "permission_request", "stop", or None
|
|
62
63
|
created_at: float | None = None # Unix timestamp when window was created
|
|
64
|
+
no_track: bool = False # Whether tracking is disabled for this terminal
|
|
63
65
|
|
|
64
66
|
|
|
65
67
|
def tmux_available() -> bool:
|
|
@@ -604,6 +606,8 @@ def list_inner_windows() -> list[InnerWindow]:
|
|
|
604
606
|
+ OPT_ATTENTION
|
|
605
607
|
+ "}\t#{"
|
|
606
608
|
+ OPT_CREATED_AT
|
|
609
|
+
+ "}\t#{"
|
|
610
|
+
+ OPT_NO_TRACK
|
|
607
611
|
+ "}",
|
|
608
612
|
],
|
|
609
613
|
capture=True,
|
|
@@ -632,6 +636,8 @@ def list_inner_windows() -> list[InnerWindow]:
|
|
|
632
636
|
created_at = float(created_at_str)
|
|
633
637
|
except ValueError:
|
|
634
638
|
pass
|
|
639
|
+
no_track_str = parts[11] if len(parts) > 11 and parts[11] else None
|
|
640
|
+
no_track = no_track_str == "1"
|
|
635
641
|
|
|
636
642
|
if terminal_id:
|
|
637
643
|
persisted = state.get(terminal_id) or {}
|
|
@@ -663,6 +669,7 @@ def list_inner_windows() -> list[InnerWindow]:
|
|
|
663
669
|
context_id=context_id,
|
|
664
670
|
attention=attention,
|
|
665
671
|
created_at=created_at,
|
|
672
|
+
no_track=no_track,
|
|
666
673
|
)
|
|
667
674
|
)
|
|
668
675
|
# Sort by creation time (newest first). Windows without created_at go to the bottom.
|
|
@@ -758,6 +765,16 @@ def select_inner_window(window_id: str) -> bool:
|
|
|
758
765
|
return _run_inner_tmux(["select-window", "-t", window_id]).returncode == 0
|
|
759
766
|
|
|
760
767
|
|
|
768
|
+
def focus_right_pane() -> bool:
|
|
769
|
+
"""Focus the right pane (terminal area) in the outer tmux layout."""
|
|
770
|
+
return (
|
|
771
|
+
_run_outer_tmux(
|
|
772
|
+
["select-pane", "-t", f"{OUTER_SESSION}:{OUTER_WINDOW}.1"]
|
|
773
|
+
).returncode
|
|
774
|
+
== 0
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
|
|
761
778
|
def clear_attention(window_id: str) -> bool:
|
|
762
779
|
"""Clear the attention state for a window (e.g., after user acknowledges permission request)."""
|
|
763
780
|
if not ensure_inner_session():
|
|
@@ -888,6 +888,9 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
888
888
|
detail_line = (
|
|
889
889
|
f"{detail_line} · {self._format_context_summary(raw_sessions, raw_events)}"
|
|
890
890
|
)
|
|
891
|
+
# Show no-track indicator
|
|
892
|
+
if w.metadata.get("no_track") == "1":
|
|
893
|
+
detail_line = f"{detail_line} [NT]"
|
|
891
894
|
details.append(detail_line, style="dim not bold")
|
|
892
895
|
return details
|
|
893
896
|
|
|
@@ -919,6 +922,9 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
919
922
|
detail_line = (
|
|
920
923
|
f"{detail_line} · {self._format_context_summary(raw_sessions, raw_events)}"
|
|
921
924
|
)
|
|
925
|
+
# Show no-track indicator
|
|
926
|
+
if w.no_track:
|
|
927
|
+
detail_line = f"{detail_line} [NT]"
|
|
922
928
|
details.append(detail_line, style="dim not bold")
|
|
923
929
|
return details
|
|
924
930
|
|
|
@@ -944,24 +950,26 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
944
950
|
"""Wrap a command to run in a specific directory."""
|
|
945
951
|
return f"cd {shlex.quote(directory)} && {command}"
|
|
946
952
|
|
|
947
|
-
def _on_create_agent_result(self, result: tuple[str, str, bool] | None) -> None:
|
|
953
|
+
def _on_create_agent_result(self, result: tuple[str, str, bool, bool] | None) -> None:
|
|
948
954
|
"""Handle the result from CreateAgentScreen modal."""
|
|
949
955
|
if result is None:
|
|
950
956
|
return
|
|
951
957
|
|
|
952
|
-
agent_type, workspace, skip_permissions = result
|
|
958
|
+
agent_type, workspace, skip_permissions, no_track = result
|
|
953
959
|
self.run_worker(
|
|
954
|
-
self._create_agent(
|
|
960
|
+
self._create_agent(
|
|
961
|
+
agent_type, workspace, skip_permissions=skip_permissions, no_track=no_track
|
|
962
|
+
),
|
|
955
963
|
group="terminal-panel-create",
|
|
956
964
|
exclusive=True,
|
|
957
965
|
)
|
|
958
966
|
|
|
959
967
|
async def _create_agent(
|
|
960
|
-
self, agent_type: str, workspace: str, *, skip_permissions: bool = False
|
|
968
|
+
self, agent_type: str, workspace: str, *, skip_permissions: bool = False, no_track: bool = False
|
|
961
969
|
) -> None:
|
|
962
970
|
"""Create a new agent terminal based on the selected type and workspace."""
|
|
963
971
|
if agent_type == "claude":
|
|
964
|
-
await self._create_claude_terminal(workspace, skip_permissions=skip_permissions)
|
|
972
|
+
await self._create_claude_terminal(workspace, skip_permissions=skip_permissions, no_track=no_track)
|
|
965
973
|
elif agent_type == "codex":
|
|
966
974
|
await self._create_codex_terminal(workspace)
|
|
967
975
|
elif agent_type == "opencode":
|
|
@@ -971,16 +979,16 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
971
979
|
await self.refresh_data()
|
|
972
980
|
|
|
973
981
|
async def _create_claude_terminal(
|
|
974
|
-
self, workspace: str, *, skip_permissions: bool = False
|
|
982
|
+
self, workspace: str, *, skip_permissions: bool = False, no_track: bool = False
|
|
975
983
|
) -> None:
|
|
976
984
|
"""Create a new Claude terminal."""
|
|
977
985
|
if self._is_native_mode():
|
|
978
|
-
await self._create_claude_terminal_native(workspace, skip_permissions=skip_permissions)
|
|
986
|
+
await self._create_claude_terminal_native(workspace, skip_permissions=skip_permissions, no_track=no_track)
|
|
979
987
|
else:
|
|
980
|
-
await self._create_claude_terminal_tmux(workspace, skip_permissions=skip_permissions)
|
|
988
|
+
await self._create_claude_terminal_tmux(workspace, skip_permissions=skip_permissions, no_track=no_track)
|
|
981
989
|
|
|
982
990
|
async def _create_claude_terminal_native(
|
|
983
|
-
self, workspace: str, *, skip_permissions: bool = False
|
|
991
|
+
self, workspace: str, *, skip_permissions: bool = False, no_track: bool = False
|
|
984
992
|
) -> None:
|
|
985
993
|
"""Create a new Claude terminal using native backend."""
|
|
986
994
|
backend = await self._ensure_native_backend()
|
|
@@ -1000,6 +1008,8 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
1000
1008
|
tmux_manager.ENV_TERMINAL_PROVIDER: "claude",
|
|
1001
1009
|
tmux_manager.ENV_CONTEXT_ID: context_id,
|
|
1002
1010
|
}
|
|
1011
|
+
if no_track:
|
|
1012
|
+
env["ALINE_NO_TRACK"] = "1"
|
|
1003
1013
|
|
|
1004
1014
|
# Install hooks
|
|
1005
1015
|
self._install_claude_hooks(workspace)
|
|
@@ -1024,7 +1034,7 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
1024
1034
|
)
|
|
1025
1035
|
|
|
1026
1036
|
async def _create_claude_terminal_tmux(
|
|
1027
|
-
self, workspace: str, *, skip_permissions: bool = False
|
|
1037
|
+
self, workspace: str, *, skip_permissions: bool = False, no_track: bool = False
|
|
1028
1038
|
) -> None:
|
|
1029
1039
|
"""Create a new Claude terminal using tmux backend."""
|
|
1030
1040
|
terminal_id = tmux_manager.new_terminal_id()
|
|
@@ -1036,6 +1046,8 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
1036
1046
|
tmux_manager.ENV_INNER_SESSION: tmux_manager.INNER_SESSION,
|
|
1037
1047
|
tmux_manager.ENV_CONTEXT_ID: context_id,
|
|
1038
1048
|
}
|
|
1049
|
+
if no_track:
|
|
1050
|
+
env["ALINE_NO_TRACK"] = "1"
|
|
1039
1051
|
|
|
1040
1052
|
# Install hooks
|
|
1041
1053
|
self._install_claude_hooks(workspace)
|
|
@@ -1239,7 +1251,7 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
1239
1251
|
if self._is_native_mode():
|
|
1240
1252
|
backend = await self._ensure_native_backend()
|
|
1241
1253
|
if backend:
|
|
1242
|
-
success = await backend.focus_tab(window_id, steal_focus=
|
|
1254
|
+
success = await backend.focus_tab(window_id, steal_focus=True)
|
|
1243
1255
|
if not success:
|
|
1244
1256
|
self.app.notify(
|
|
1245
1257
|
"Failed to switch terminal", title="Terminal", severity="error"
|
|
@@ -1247,6 +1259,9 @@ class TerminalPanel(Container, can_focus=True):
|
|
|
1247
1259
|
else:
|
|
1248
1260
|
if not tmux_manager.select_inner_window(window_id):
|
|
1249
1261
|
self.app.notify("Failed to switch terminal", title="Terminal", severity="error")
|
|
1262
|
+
else:
|
|
1263
|
+
# Move cursor focus to the right pane (terminal area)
|
|
1264
|
+
tmux_manager.focus_right_pane()
|
|
1250
1265
|
# Clear attention when user clicks on terminal
|
|
1251
1266
|
tmux_manager.clear_attention(window_id)
|
|
1252
1267
|
|
realign/db/sqlite_db.py
CHANGED
|
@@ -442,6 +442,21 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
442
442
|
)
|
|
443
443
|
conn.commit()
|
|
444
444
|
|
|
445
|
+
def update_session_metadata_flag(self, session_id: str, key: str, value: Any) -> None:
|
|
446
|
+
"""Update a single key in session metadata JSON."""
|
|
447
|
+
conn = self._get_connection()
|
|
448
|
+
row = conn.execute(
|
|
449
|
+
"SELECT metadata FROM sessions WHERE id = ?", (session_id,)
|
|
450
|
+
).fetchone()
|
|
451
|
+
if row:
|
|
452
|
+
meta = json.loads(row[0] or "{}")
|
|
453
|
+
meta[key] = value
|
|
454
|
+
conn.execute(
|
|
455
|
+
"UPDATE sessions SET metadata = ?, updated_at = datetime('now') WHERE id = ?",
|
|
456
|
+
(json.dumps(meta), session_id),
|
|
457
|
+
)
|
|
458
|
+
conn.commit()
|
|
459
|
+
|
|
445
460
|
def backfill_session_total_turns(self) -> int:
|
|
446
461
|
"""Backfill total_turns for all sessions from turns table (V10 migration).
|
|
447
462
|
|
|
@@ -957,6 +972,7 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
957
972
|
skip_session_summary: bool = False,
|
|
958
973
|
expected_turns: Optional[int] = None,
|
|
959
974
|
skip_dedup: bool = False,
|
|
975
|
+
no_track: bool = False,
|
|
960
976
|
) -> str:
|
|
961
977
|
session_id = session_file_path.stem
|
|
962
978
|
dedupe_key = f"turn:{session_id}:{int(turn_number)}"
|
|
@@ -973,6 +989,8 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
973
989
|
payload["expected_turns"] = int(expected_turns)
|
|
974
990
|
if skip_dedup:
|
|
975
991
|
payload["skip_dedup"] = True
|
|
992
|
+
if no_track:
|
|
993
|
+
payload["no_track"] = True
|
|
976
994
|
|
|
977
995
|
# For append-only session formats (Claude/Codex/Gemini), a turn is immutable once completed.
|
|
978
996
|
# Avoid re-running already-done turn jobs on repeated enqueue attempts.
|
|
@@ -97,9 +97,24 @@ def update_session_summary_now(db: SQLiteDatabase, session_id: str) -> bool:
|
|
|
97
97
|
pass
|
|
98
98
|
return True
|
|
99
99
|
|
|
100
|
+
# Check session metadata for no_track mode
|
|
101
|
+
is_no_track = False
|
|
100
102
|
try:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
session = db.get_session_by_id(session_id)
|
|
104
|
+
if session:
|
|
105
|
+
session_meta = getattr(session, "metadata", None) or {}
|
|
106
|
+
is_no_track = bool(session_meta.get("no_track", False))
|
|
107
|
+
except Exception:
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
# Skip LLM call for no-track mode
|
|
112
|
+
if is_no_track:
|
|
113
|
+
title, summary = "No Track", "No Track"
|
|
114
|
+
logger.info(f"No-track mode: skipping LLM for session summary {session_id}")
|
|
115
|
+
else:
|
|
116
|
+
# Generate title and summary using LLM
|
|
117
|
+
title, summary = _generate_session_summary_llm(turns)
|
|
103
118
|
|
|
104
119
|
# Update database
|
|
105
120
|
db.update_session_summary(session_id, title, summary)
|
realign/watcher_core.py
CHANGED
|
@@ -368,6 +368,7 @@ class DialogueWatcher:
|
|
|
368
368
|
session_id = signal_data.get("session_id", "")
|
|
369
369
|
project_dir = signal_data.get("project_dir", "")
|
|
370
370
|
transcript_path = signal_data.get("transcript_path", "")
|
|
371
|
+
no_track = bool(signal_data.get("no_track", False))
|
|
371
372
|
|
|
372
373
|
logger.info(f"Stop signal received for session {session_id}")
|
|
373
374
|
print(f"[Watcher] Stop signal received for {session_id}", file=sys.stderr)
|
|
@@ -402,6 +403,7 @@ class DialogueWatcher:
|
|
|
402
403
|
workspace_path=project_path,
|
|
403
404
|
turn_number=target_turn,
|
|
404
405
|
session_type=self._detect_session_type(session_file),
|
|
406
|
+
no_track=no_track,
|
|
405
407
|
)
|
|
406
408
|
except Exception as e:
|
|
407
409
|
logger.warning(
|
|
@@ -462,6 +464,7 @@ class DialogueWatcher:
|
|
|
462
464
|
prompt = str(signal_data.get("prompt") or "")
|
|
463
465
|
transcript_path = str(signal_data.get("transcript_path") or "")
|
|
464
466
|
project_dir = str(signal_data.get("project_dir") or "")
|
|
467
|
+
no_track = bool(signal_data.get("no_track", False))
|
|
465
468
|
|
|
466
469
|
session_file = None
|
|
467
470
|
if transcript_path and Path(transcript_path).exists():
|
|
@@ -488,6 +491,7 @@ class DialogueWatcher:
|
|
|
488
491
|
session_id,
|
|
489
492
|
prompt,
|
|
490
493
|
project_dir,
|
|
494
|
+
no_track,
|
|
491
495
|
)
|
|
492
496
|
|
|
493
497
|
signal_file.unlink(missing_ok=True)
|
|
@@ -1318,6 +1322,7 @@ class DialogueWatcher:
|
|
|
1318
1322
|
debug_callback: Optional[Callable[[Dict[str, Any]], None]] = None,
|
|
1319
1323
|
skip_dedup: bool = False,
|
|
1320
1324
|
skip_session_summary: bool = False,
|
|
1325
|
+
no_track: bool = False,
|
|
1321
1326
|
) -> bool:
|
|
1322
1327
|
"""
|
|
1323
1328
|
Execute commit with DB-backed lease locking to prevent cross-process races.
|
|
@@ -1365,6 +1370,7 @@ class DialogueWatcher:
|
|
|
1365
1370
|
debug_callback=debug_callback,
|
|
1366
1371
|
skip_dedup=skip_dedup,
|
|
1367
1372
|
skip_session_summary=skip_session_summary,
|
|
1373
|
+
no_track=no_track,
|
|
1368
1374
|
)
|
|
1369
1375
|
except Exception as e:
|
|
1370
1376
|
print(f"[Watcher] Commit error: {e}", file=sys.stderr)
|
|
@@ -1381,6 +1387,7 @@ class DialogueWatcher:
|
|
|
1381
1387
|
debug_callback: Optional[Callable[[Dict[str, Any]], None]] = None,
|
|
1382
1388
|
skip_dedup: bool = False,
|
|
1383
1389
|
skip_session_summary: bool = False,
|
|
1390
|
+
no_track: bool = False,
|
|
1384
1391
|
) -> bool:
|
|
1385
1392
|
"""
|
|
1386
1393
|
Perform the actual commit operation to SQLite database.
|
|
@@ -1443,7 +1450,7 @@ class DialogueWatcher:
|
|
|
1443
1450
|
file_created = datetime.fromtimestamp(
|
|
1444
1451
|
getattr(file_stat, "st_birthtime", file_stat.st_ctime)
|
|
1445
1452
|
)
|
|
1446
|
-
db.get_or_create_session(
|
|
1453
|
+
session = db.get_or_create_session(
|
|
1447
1454
|
session_id=session_id,
|
|
1448
1455
|
session_file_path=session_file,
|
|
1449
1456
|
session_type=self._detect_session_type(session_file),
|
|
@@ -1451,6 +1458,19 @@ class DialogueWatcher:
|
|
|
1451
1458
|
workspace_path=str(project_path) if project_path else None,
|
|
1452
1459
|
)
|
|
1453
1460
|
|
|
1461
|
+
# Check no_track from parameter or existing session metadata (polling path)
|
|
1462
|
+
is_no_track = no_track
|
|
1463
|
+
if not is_no_track and session:
|
|
1464
|
+
session_meta = getattr(session, "metadata", None) or {}
|
|
1465
|
+
is_no_track = bool(session_meta.get("no_track", False))
|
|
1466
|
+
|
|
1467
|
+
# Store no_track flag in session metadata if applicable
|
|
1468
|
+
if is_no_track:
|
|
1469
|
+
try:
|
|
1470
|
+
db.update_session_metadata_flag(session_id, "no_track", True)
|
|
1471
|
+
except Exception:
|
|
1472
|
+
pass
|
|
1473
|
+
|
|
1454
1474
|
takeover_attempt = False
|
|
1455
1475
|
existing_turn = db.get_turn_by_number(session_id, turn_number)
|
|
1456
1476
|
if existing_turn and not skip_dedup:
|
|
@@ -1517,14 +1537,19 @@ class DialogueWatcher:
|
|
|
1517
1537
|
logger.debug(f"Failed to write processing placeholder: {e}")
|
|
1518
1538
|
|
|
1519
1539
|
try:
|
|
1520
|
-
#
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
turn_number
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1540
|
+
# Skip LLM call for no-track mode
|
|
1541
|
+
if is_no_track:
|
|
1542
|
+
llm_result = ("No Track", None, "No Track", "no", "fine")
|
|
1543
|
+
logger.info(f"No-track mode: skipping LLM for {session_id} turn {turn_number}")
|
|
1544
|
+
else:
|
|
1545
|
+
# Generate LLM summary with fallback for errors
|
|
1546
|
+
llm_result = self._generate_llm_summary(
|
|
1547
|
+
session_file,
|
|
1548
|
+
turn_number=turn_number,
|
|
1549
|
+
turn_content=turn_content,
|
|
1550
|
+
user_message=user_message,
|
|
1551
|
+
debug_callback=debug_callback,
|
|
1552
|
+
)
|
|
1528
1553
|
|
|
1529
1554
|
if not llm_result:
|
|
1530
1555
|
# LLM summary failed, use error marker to continue commit
|
|
@@ -1774,6 +1799,7 @@ class DialogueWatcher:
|
|
|
1774
1799
|
session_id: str,
|
|
1775
1800
|
prompt: str,
|
|
1776
1801
|
project_dir: str,
|
|
1802
|
+
no_track: bool = False,
|
|
1777
1803
|
) -> None:
|
|
1778
1804
|
"""Generate and store a temporary turn title for a newly submitted user prompt."""
|
|
1779
1805
|
try:
|
|
@@ -1802,20 +1828,28 @@ class DialogueWatcher:
|
|
|
1802
1828
|
if not user_message:
|
|
1803
1829
|
user_message = str(group.get("user_message") or "")
|
|
1804
1830
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1831
|
+
# Skip LLM call for no-track mode
|
|
1832
|
+
if no_track:
|
|
1833
|
+
title = "No Track"
|
|
1834
|
+
model_name = None
|
|
1835
|
+
description = "No Track"
|
|
1836
|
+
if_last_task = "no"
|
|
1837
|
+
satisfaction = "fine"
|
|
1838
|
+
else:
|
|
1839
|
+
turn_content = self._extract_turn_content_by_number(session_file, turn_number)
|
|
1840
|
+
result = self._generate_llm_summary(
|
|
1841
|
+
session_file,
|
|
1842
|
+
turn_number=turn_number,
|
|
1843
|
+
turn_content=turn_content,
|
|
1844
|
+
user_message=user_message or None,
|
|
1845
|
+
session_id=session_id or session_file.stem,
|
|
1846
|
+
)
|
|
1847
|
+
if not result:
|
|
1848
|
+
return
|
|
1815
1849
|
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1850
|
+
title, model_name, description, if_last_task, satisfaction = result
|
|
1851
|
+
if not title:
|
|
1852
|
+
return
|
|
1819
1853
|
|
|
1820
1854
|
from .db import get_database
|
|
1821
1855
|
from .db.base import TurnRecord
|
realign/worker_core.py
CHANGED
|
@@ -186,6 +186,7 @@ class AlineWorker:
|
|
|
186
186
|
expected_turns_raw = payload.get("expected_turns")
|
|
187
187
|
expected_turns = int(expected_turns_raw) if expected_turns_raw is not None else None
|
|
188
188
|
skip_dedup = bool(payload.get("skip_dedup") or False)
|
|
189
|
+
no_track = bool(payload.get("no_track") or False)
|
|
189
190
|
|
|
190
191
|
if not session_id or turn_number <= 0 or not session_file_path:
|
|
191
192
|
raise ValueError(f"Invalid turn_summary payload: {payload}")
|
|
@@ -212,6 +213,7 @@ class AlineWorker:
|
|
|
212
213
|
quiet=True,
|
|
213
214
|
skip_session_summary=skip_session_summary,
|
|
214
215
|
skip_dedup=skip_dedup,
|
|
216
|
+
no_track=no_track,
|
|
215
217
|
)
|
|
216
218
|
|
|
217
219
|
if created:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|