aline-ai 0.5.12__py3-none-any.whl → 0.6.0__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.5.12.dist-info → aline_ai-0.6.0.dist-info}/METADATA +1 -1
- {aline_ai-0.5.12.dist-info → aline_ai-0.6.0.dist-info}/RECORD +25 -23
- realign/__init__.py +1 -1
- realign/auth.py +539 -0
- realign/cli.py +272 -1
- realign/commands/auth.py +343 -0
- realign/commands/export_shares.py +44 -21
- realign/commands/import_shares.py +16 -10
- realign/commands/init.py +10 -33
- realign/commands/watcher.py +19 -16
- realign/commands/worker.py +8 -0
- realign/config.py +12 -29
- realign/dashboard/widgets/config_panel.py +177 -1
- realign/dashboard/widgets/events_table.py +44 -5
- realign/dashboard/widgets/sessions_table.py +76 -16
- realign/db/base.py +28 -11
- realign/db/schema.py +102 -15
- realign/db/sqlite_db.py +108 -58
- realign/watcher_core.py +1 -9
- realign/watcher_daemon.py +11 -0
- realign/worker_daemon.py +11 -0
- {aline_ai-0.5.12.dist-info → aline_ai-0.6.0.dist-info}/WHEEL +0 -0
- {aline_ai-0.5.12.dist-info → aline_ai-0.6.0.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.5.12.dist-info → aline_ai-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.5.12.dist-info → aline_ai-0.6.0.dist-info}/top_level.txt +0 -0
realign/db/schema.py
CHANGED
|
@@ -62,9 +62,23 @@ Schema V15: Agents and contexts tables (replaces terminal.json and load.json).
|
|
|
62
62
|
Schema V16: Remove FK constraints from agent_context_sessions/events.
|
|
63
63
|
- Context may reference sessions/events not yet imported to DB
|
|
64
64
|
- Recreate M2M tables without FK constraints on session_id/event_id
|
|
65
|
+
|
|
66
|
+
Schema V17: Rename creator_id/creator_name to uid/user_name.
|
|
67
|
+
- sessions.creator_id -> uid, sessions.creator_name -> user_name
|
|
68
|
+
- turns.creator_id -> uid, turns.creator_name -> user_name
|
|
69
|
+
- events.creator_id -> uid, events.creator_name -> user_name
|
|
70
|
+
- agents.creator_id -> uid, agents.creator_name -> user_name
|
|
71
|
+
- Update indexes accordingly
|
|
72
|
+
|
|
73
|
+
Schema V18: UID refactor - created_by/shared_by with users table.
|
|
74
|
+
- New users table: uid -> user_name mapping
|
|
75
|
+
- sessions/events: uid -> created_by, drop user_name, add shared_by
|
|
76
|
+
- turns: drop uid and user_name (inherit from session)
|
|
77
|
+
- agents: uid -> created_by, drop user_name
|
|
78
|
+
- Update indexes accordingly
|
|
65
79
|
"""
|
|
66
80
|
|
|
67
|
-
SCHEMA_VERSION =
|
|
81
|
+
SCHEMA_VERSION = 18
|
|
68
82
|
|
|
69
83
|
FTS_EVENTS_SCRIPTS = [
|
|
70
84
|
# Full Text Search for Events
|
|
@@ -115,7 +129,7 @@ INIT_SCRIPTS = [
|
|
|
115
129
|
metadata TEXT -- JSON metadata
|
|
116
130
|
);
|
|
117
131
|
""",
|
|
118
|
-
# Sessions table (V2: decoupled from projects, V3: summary fields,
|
|
132
|
+
# Sessions table (V2: decoupled from projects, V3: summary fields, V18: created_by/shared_by, V10: total_turns cache)
|
|
119
133
|
"""
|
|
120
134
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
121
135
|
id TEXT PRIMARY KEY, -- session ID (filename stem)
|
|
@@ -133,13 +147,13 @@ INIT_SCRIPTS = [
|
|
|
133
147
|
summary_status TEXT DEFAULT 'idle', -- V7: 'idle' | 'processing' | 'completed' | 'failed'
|
|
134
148
|
summary_locked_until TEXT, -- V7: lease/TTL to avoid stuck processing
|
|
135
149
|
summary_error TEXT, -- V7: last error message if failed
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
created_by TEXT, -- V18: Creator UID (FK to users.uid)
|
|
151
|
+
shared_by TEXT, -- V18: Sharer UID (who imported this)
|
|
138
152
|
total_turns INTEGER DEFAULT 0, -- V10: Cached total turn count (avoids reading files)
|
|
139
153
|
total_turns_mtime REAL -- V12: File mtime when total_turns was cached (for validation)
|
|
140
154
|
);
|
|
141
155
|
""",
|
|
142
|
-
# Turns table (corresponds to git commits,
|
|
156
|
+
# Turns table (corresponds to git commits, V18: uid/user_name removed)
|
|
143
157
|
"""
|
|
144
158
|
CREATE TABLE IF NOT EXISTS turns (
|
|
145
159
|
id TEXT PRIMARY KEY, -- UUID
|
|
@@ -158,8 +172,6 @@ INIT_SCRIPTS = [
|
|
|
158
172
|
timestamp TEXT NOT NULL,
|
|
159
173
|
created_at TEXT DEFAULT (datetime('now')),
|
|
160
174
|
git_commit_hash TEXT, -- Linked git commit hash
|
|
161
|
-
creator_name TEXT, -- V9: Username who created the turn
|
|
162
|
-
creator_id TEXT, -- V9: User UUID
|
|
163
175
|
UNIQUE(session_id, turn_number)
|
|
164
176
|
);
|
|
165
177
|
""",
|
|
@@ -209,12 +221,11 @@ INIT_SCRIPTS = [
|
|
|
209
221
|
"CREATE INDEX IF NOT EXISTS idx_sessions_workspace ON sessions(workspace_path);",
|
|
210
222
|
"CREATE INDEX IF NOT EXISTS idx_sessions_activity ON sessions(last_activity_at DESC);",
|
|
211
223
|
"CREATE INDEX IF NOT EXISTS idx_sessions_type ON sessions(session_type);",
|
|
212
|
-
"CREATE INDEX IF NOT EXISTS
|
|
224
|
+
"CREATE INDEX IF NOT EXISTS idx_sessions_created_by ON sessions(created_by);", # V18
|
|
213
225
|
"CREATE INDEX IF NOT EXISTS idx_turns_session ON turns(session_id);",
|
|
214
226
|
"CREATE INDEX IF NOT EXISTS idx_turns_timestamp ON turns(timestamp DESC);",
|
|
215
227
|
"CREATE INDEX IF NOT EXISTS idx_turns_hash ON turns(content_hash);",
|
|
216
|
-
|
|
217
|
-
# Events table (V9: creator fields)
|
|
228
|
+
# Events table (V18: created_by/shared_by)
|
|
218
229
|
"""
|
|
219
230
|
CREATE TABLE IF NOT EXISTS events (
|
|
220
231
|
id TEXT PRIMARY KEY, -- UUID
|
|
@@ -233,8 +244,8 @@ INIT_SCRIPTS = [
|
|
|
233
244
|
share_id TEXT, -- V14: Server share ID (for reuse)
|
|
234
245
|
share_admin_token TEXT, -- V14: Server admin token (extend expiry)
|
|
235
246
|
share_expiry_at TEXT, -- V14: Last known expiry timestamp
|
|
236
|
-
|
|
237
|
-
|
|
247
|
+
created_by TEXT, -- V18: Creator UID (FK to users.uid)
|
|
248
|
+
shared_by TEXT -- V18: Sharer UID (who imported this)
|
|
238
249
|
);
|
|
239
250
|
""",
|
|
240
251
|
# Event-Commit relationship (Many-to-Many)
|
|
@@ -256,7 +267,8 @@ INIT_SCRIPTS = [
|
|
|
256
267
|
""",
|
|
257
268
|
"CREATE INDEX IF NOT EXISTS idx_event_sessions_event ON event_sessions(event_id);",
|
|
258
269
|
"CREATE INDEX IF NOT EXISTS idx_event_sessions_session ON event_sessions(session_id);",
|
|
259
|
-
|
|
270
|
+
"CREATE INDEX IF NOT EXISTS idx_events_created_by ON events(created_by);", # V18
|
|
271
|
+
# Agents table (V15: replaces terminal.json, V18: created_by)
|
|
260
272
|
"""
|
|
261
273
|
CREATE TABLE IF NOT EXISTS agents (
|
|
262
274
|
id TEXT PRIMARY KEY, -- terminal_id (UUID)
|
|
@@ -272,8 +284,7 @@ INIT_SCRIPTS = [
|
|
|
272
284
|
source TEXT,
|
|
273
285
|
created_at TEXT DEFAULT (datetime('now')),
|
|
274
286
|
updated_at TEXT DEFAULT (datetime('now')),
|
|
275
|
-
|
|
276
|
-
creator_id TEXT
|
|
287
|
+
created_by TEXT -- V18: Creator UID (FK to users.uid)
|
|
277
288
|
);
|
|
278
289
|
""",
|
|
279
290
|
"CREATE INDEX IF NOT EXISTS idx_agents_session ON agents(session_id);",
|
|
@@ -315,6 +326,15 @@ INIT_SCRIPTS = [
|
|
|
315
326
|
""",
|
|
316
327
|
"CREATE INDEX IF NOT EXISTS idx_agent_context_events_context ON agent_context_events(context_id);",
|
|
317
328
|
"CREATE INDEX IF NOT EXISTS idx_agent_context_events_event ON agent_context_events(event_id);",
|
|
329
|
+
# Users table (V18: UID-to-user-info mapping)
|
|
330
|
+
"""
|
|
331
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
332
|
+
uid TEXT PRIMARY KEY,
|
|
333
|
+
user_name TEXT,
|
|
334
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
335
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
336
|
+
);
|
|
337
|
+
""",
|
|
318
338
|
*FTS_EVENTS_SCRIPTS,
|
|
319
339
|
]
|
|
320
340
|
|
|
@@ -570,6 +590,67 @@ MIGRATION_V15_TO_V16 = [
|
|
|
570
590
|
"CREATE INDEX IF NOT EXISTS idx_agent_context_events_event ON agent_context_events(event_id);",
|
|
571
591
|
]
|
|
572
592
|
|
|
593
|
+
# V16 to V17: Rename creator_id/creator_name to uid/user_name
|
|
594
|
+
MIGRATION_V16_TO_V17 = [
|
|
595
|
+
# Sessions table: rename columns
|
|
596
|
+
"ALTER TABLE sessions RENAME COLUMN creator_id TO uid;",
|
|
597
|
+
"ALTER TABLE sessions RENAME COLUMN creator_name TO user_name;",
|
|
598
|
+
# Turns table: rename columns
|
|
599
|
+
"ALTER TABLE turns RENAME COLUMN creator_id TO uid;",
|
|
600
|
+
"ALTER TABLE turns RENAME COLUMN creator_name TO user_name;",
|
|
601
|
+
# Events table: rename columns
|
|
602
|
+
"ALTER TABLE events RENAME COLUMN creator_id TO uid;",
|
|
603
|
+
"ALTER TABLE events RENAME COLUMN creator_name TO user_name;",
|
|
604
|
+
# Agents table: rename columns
|
|
605
|
+
"ALTER TABLE agents RENAME COLUMN creator_id TO uid;",
|
|
606
|
+
"ALTER TABLE agents RENAME COLUMN creator_name TO user_name;",
|
|
607
|
+
# Update indexes: drop old, create new
|
|
608
|
+
"DROP INDEX IF EXISTS idx_sessions_creator;",
|
|
609
|
+
"DROP INDEX IF EXISTS idx_turns_creator;",
|
|
610
|
+
"DROP INDEX IF EXISTS idx_events_creator;",
|
|
611
|
+
"CREATE INDEX IF NOT EXISTS idx_sessions_uid ON sessions(uid);",
|
|
612
|
+
"CREATE INDEX IF NOT EXISTS idx_turns_uid ON turns(uid);",
|
|
613
|
+
"CREATE INDEX IF NOT EXISTS idx_events_uid ON events(uid);",
|
|
614
|
+
]
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
# V17 to V18: uid/user_name → created_by/shared_by, users table, remove turns uid
|
|
618
|
+
MIGRATION_V17_TO_V18 = [
|
|
619
|
+
# 1. Create users table
|
|
620
|
+
"""
|
|
621
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
622
|
+
uid TEXT PRIMARY KEY,
|
|
623
|
+
user_name TEXT,
|
|
624
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
625
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
626
|
+
);
|
|
627
|
+
""",
|
|
628
|
+
# 2. Extract user info from existing data into users table
|
|
629
|
+
"INSERT OR IGNORE INTO users (uid, user_name) SELECT DISTINCT uid, user_name FROM sessions WHERE uid IS NOT NULL AND uid != '';",
|
|
630
|
+
"INSERT OR IGNORE INTO users (uid, user_name) SELECT DISTINCT uid, user_name FROM events WHERE uid IS NOT NULL AND uid != '' AND uid NOT IN (SELECT uid FROM users);",
|
|
631
|
+
"INSERT OR IGNORE INTO users (uid, user_name) SELECT DISTINCT uid, user_name FROM turns WHERE uid IS NOT NULL AND uid != '' AND uid NOT IN (SELECT uid FROM users);",
|
|
632
|
+
"INSERT OR IGNORE INTO users (uid, user_name) SELECT DISTINCT uid, user_name FROM agents WHERE uid IS NOT NULL AND uid != '' AND uid NOT IN (SELECT uid FROM users);",
|
|
633
|
+
# 3. Sessions: uid → created_by, drop user_name, add shared_by
|
|
634
|
+
"DROP INDEX IF EXISTS idx_sessions_uid;",
|
|
635
|
+
"ALTER TABLE sessions RENAME COLUMN uid TO created_by;",
|
|
636
|
+
"ALTER TABLE sessions DROP COLUMN user_name;",
|
|
637
|
+
"ALTER TABLE sessions ADD COLUMN shared_by TEXT;",
|
|
638
|
+
"CREATE INDEX IF NOT EXISTS idx_sessions_created_by ON sessions(created_by);",
|
|
639
|
+
# 4. Events: uid → created_by, drop user_name, add shared_by
|
|
640
|
+
"DROP INDEX IF EXISTS idx_events_uid;",
|
|
641
|
+
"ALTER TABLE events RENAME COLUMN uid TO created_by;",
|
|
642
|
+
"ALTER TABLE events DROP COLUMN user_name;",
|
|
643
|
+
"ALTER TABLE events ADD COLUMN shared_by TEXT;",
|
|
644
|
+
"CREATE INDEX IF NOT EXISTS idx_events_created_by ON events(created_by);",
|
|
645
|
+
# 5. Turns: drop uid and user_name
|
|
646
|
+
"DROP INDEX IF EXISTS idx_turns_uid;",
|
|
647
|
+
"ALTER TABLE turns DROP COLUMN uid;",
|
|
648
|
+
"ALTER TABLE turns DROP COLUMN user_name;",
|
|
649
|
+
# 6. Agents: uid → created_by, drop user_name (no shared_by needed)
|
|
650
|
+
"ALTER TABLE agents RENAME COLUMN uid TO created_by;",
|
|
651
|
+
"ALTER TABLE agents DROP COLUMN user_name;",
|
|
652
|
+
]
|
|
653
|
+
|
|
573
654
|
|
|
574
655
|
def get_migration_scripts(from_version: int, to_version: int) -> list:
|
|
575
656
|
"""Get migration scripts for upgrading between versions."""
|
|
@@ -629,4 +710,10 @@ def get_migration_scripts(from_version: int, to_version: int) -> list:
|
|
|
629
710
|
if from_version == 15:
|
|
630
711
|
scripts.extend(MIGRATION_V15_TO_V16)
|
|
631
712
|
|
|
713
|
+
if from_version < 17 and to_version >= 17:
|
|
714
|
+
scripts.extend(MIGRATION_V16_TO_V17)
|
|
715
|
+
|
|
716
|
+
if from_version < 18 and to_version >= 18:
|
|
717
|
+
scripts.extend(MIGRATION_V17_TO_V18)
|
|
718
|
+
|
|
632
719
|
return scripts
|
realign/db/sqlite_db.py
CHANGED
|
@@ -22,6 +22,7 @@ from .base import (
|
|
|
22
22
|
LockRecord,
|
|
23
23
|
AgentRecord,
|
|
24
24
|
AgentContextRecord,
|
|
25
|
+
UserRecord,
|
|
25
26
|
)
|
|
26
27
|
from .schema import (
|
|
27
28
|
INIT_SCRIPTS,
|
|
@@ -303,7 +304,7 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
303
304
|
if row:
|
|
304
305
|
return self._row_to_session(row)
|
|
305
306
|
|
|
306
|
-
# Get user identity from config
|
|
307
|
+
# Get user identity from config
|
|
307
308
|
from ..config import ReAlignConfig
|
|
308
309
|
|
|
309
310
|
config = ReAlignConfig.load()
|
|
@@ -316,8 +317,8 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
316
317
|
INSERT INTO sessions (
|
|
317
318
|
id, session_file_path, session_type, workspace_path,
|
|
318
319
|
started_at, last_activity_at, created_at, updated_at, metadata,
|
|
319
|
-
|
|
320
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
320
|
+
created_by
|
|
321
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
321
322
|
""",
|
|
322
323
|
(
|
|
323
324
|
session_id,
|
|
@@ -329,12 +330,18 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
329
330
|
now,
|
|
330
331
|
now,
|
|
331
332
|
metadata_json,
|
|
332
|
-
config.
|
|
333
|
-
config.user_id,
|
|
333
|
+
config.uid,
|
|
334
334
|
),
|
|
335
335
|
)
|
|
336
336
|
conn.commit()
|
|
337
337
|
|
|
338
|
+
# Upsert current user to users table
|
|
339
|
+
if config.uid:
|
|
340
|
+
try:
|
|
341
|
+
self.upsert_user(config.uid, config.user_name)
|
|
342
|
+
except Exception:
|
|
343
|
+
pass
|
|
344
|
+
|
|
338
345
|
return SessionRecord(
|
|
339
346
|
id=session_id,
|
|
340
347
|
session_file_path=session_file_path,
|
|
@@ -345,8 +352,7 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
345
352
|
updated_at=now,
|
|
346
353
|
metadata=metadata or {},
|
|
347
354
|
workspace_path=workspace_path,
|
|
348
|
-
|
|
349
|
-
creator_id=config.user_id,
|
|
355
|
+
created_by=config.uid,
|
|
350
356
|
)
|
|
351
357
|
|
|
352
358
|
def update_session_activity(self, session_id: str, last_activity_at: datetime) -> None:
|
|
@@ -659,15 +665,15 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
659
665
|
# Older schema without temp_title column.
|
|
660
666
|
pass
|
|
661
667
|
|
|
662
|
-
# Insert turn record (
|
|
668
|
+
# Insert turn record (V18: no user identity fields)
|
|
663
669
|
conn.execute(
|
|
664
670
|
"""
|
|
665
671
|
INSERT OR REPLACE INTO turns (
|
|
666
672
|
id, session_id, turn_number, user_message, assistant_summary,
|
|
667
673
|
turn_status, llm_title, temp_title, llm_description, model_name,
|
|
668
674
|
if_last_task, satisfaction, content_hash, timestamp,
|
|
669
|
-
created_at, git_commit_hash
|
|
670
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
675
|
+
created_at, git_commit_hash
|
|
676
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
671
677
|
""",
|
|
672
678
|
(
|
|
673
679
|
turn.id,
|
|
@@ -686,8 +692,6 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
686
692
|
turn.timestamp,
|
|
687
693
|
turn.created_at,
|
|
688
694
|
turn.git_commit_hash,
|
|
689
|
-
turn.creator_name,
|
|
690
|
-
turn.creator_id,
|
|
691
695
|
),
|
|
692
696
|
)
|
|
693
697
|
|
|
@@ -1495,13 +1499,13 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
1495
1499
|
conn = self._get_connection()
|
|
1496
1500
|
try:
|
|
1497
1501
|
for event in events:
|
|
1498
|
-
# Upsert Event (
|
|
1502
|
+
# Upsert Event (V18: created_by/shared_by)
|
|
1499
1503
|
conn.execute(
|
|
1500
1504
|
"""
|
|
1501
1505
|
INSERT INTO events (
|
|
1502
1506
|
id, title, description, event_type, status,
|
|
1503
1507
|
start_timestamp, end_timestamp, created_at, updated_at, metadata,
|
|
1504
|
-
|
|
1508
|
+
created_by, shared_by
|
|
1505
1509
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1506
1510
|
ON CONFLICT(id) DO UPDATE SET
|
|
1507
1511
|
title=excluded.title,
|
|
@@ -1512,8 +1516,8 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
1512
1516
|
end_timestamp=excluded.end_timestamp,
|
|
1513
1517
|
updated_at=excluded.updated_at,
|
|
1514
1518
|
metadata=excluded.metadata,
|
|
1515
|
-
|
|
1516
|
-
|
|
1519
|
+
created_by=excluded.created_by,
|
|
1520
|
+
shared_by=excluded.shared_by
|
|
1517
1521
|
""",
|
|
1518
1522
|
(
|
|
1519
1523
|
event.id,
|
|
@@ -1526,8 +1530,8 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
1526
1530
|
event.created_at,
|
|
1527
1531
|
event.updated_at,
|
|
1528
1532
|
json.dumps(event.metadata),
|
|
1529
|
-
event.
|
|
1530
|
-
event.
|
|
1533
|
+
event.created_by,
|
|
1534
|
+
event.shared_by,
|
|
1531
1535
|
),
|
|
1532
1536
|
)
|
|
1533
1537
|
|
|
@@ -2063,11 +2067,11 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2063
2067
|
from ..config import ReAlignConfig
|
|
2064
2068
|
|
|
2065
2069
|
config = ReAlignConfig.load()
|
|
2066
|
-
|
|
2067
|
-
|
|
2070
|
+
created_by = config.uid
|
|
2071
|
+
user_name_for_upsert = config.user_name
|
|
2068
2072
|
except Exception:
|
|
2069
|
-
|
|
2070
|
-
|
|
2073
|
+
created_by = None
|
|
2074
|
+
user_name_for_upsert = None
|
|
2071
2075
|
|
|
2072
2076
|
now = datetime.now()
|
|
2073
2077
|
cursor.execute(
|
|
@@ -2075,8 +2079,8 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2075
2079
|
INSERT INTO agents (
|
|
2076
2080
|
id, provider, session_type, session_id, context_id,
|
|
2077
2081
|
transcript_path, cwd, project_dir, status, attention, source,
|
|
2078
|
-
created_at, updated_at,
|
|
2079
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
2082
|
+
created_at, updated_at, created_by
|
|
2083
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2080
2084
|
""",
|
|
2081
2085
|
(
|
|
2082
2086
|
agent_id,
|
|
@@ -2092,12 +2096,18 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2092
2096
|
source,
|
|
2093
2097
|
now,
|
|
2094
2098
|
now,
|
|
2095
|
-
|
|
2096
|
-
creator_id,
|
|
2099
|
+
created_by,
|
|
2097
2100
|
),
|
|
2098
2101
|
)
|
|
2099
2102
|
conn.commit()
|
|
2100
2103
|
|
|
2104
|
+
# Upsert current user to users table
|
|
2105
|
+
if created_by:
|
|
2106
|
+
try:
|
|
2107
|
+
self.upsert_user(created_by, user_name_for_upsert)
|
|
2108
|
+
except Exception:
|
|
2109
|
+
pass
|
|
2110
|
+
|
|
2101
2111
|
return AgentRecord(
|
|
2102
2112
|
id=agent_id,
|
|
2103
2113
|
provider=provider,
|
|
@@ -2112,8 +2122,7 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2112
2122
|
source=source,
|
|
2113
2123
|
created_at=now,
|
|
2114
2124
|
updated_at=now,
|
|
2115
|
-
|
|
2116
|
-
creator_id=creator_id,
|
|
2125
|
+
created_by=created_by,
|
|
2117
2126
|
)
|
|
2118
2127
|
|
|
2119
2128
|
def update_agent(
|
|
@@ -2642,12 +2651,15 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2642
2651
|
except (IndexError, KeyError):
|
|
2643
2652
|
pass
|
|
2644
2653
|
|
|
2645
|
-
#
|
|
2646
|
-
|
|
2647
|
-
|
|
2654
|
+
# V18: user identity fields
|
|
2655
|
+
created_by = None
|
|
2656
|
+
shared_by = None
|
|
2657
|
+
try:
|
|
2658
|
+
created_by = row["created_by"]
|
|
2659
|
+
except (IndexError, KeyError):
|
|
2660
|
+
pass
|
|
2648
2661
|
try:
|
|
2649
|
-
|
|
2650
|
-
creator_id = row["creator_id"]
|
|
2662
|
+
shared_by = row["shared_by"]
|
|
2651
2663
|
except (IndexError, KeyError):
|
|
2652
2664
|
pass
|
|
2653
2665
|
|
|
@@ -2681,21 +2693,13 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2681
2693
|
summary_status=summary_status,
|
|
2682
2694
|
summary_locked_until=summary_locked_until,
|
|
2683
2695
|
summary_error=summary_error,
|
|
2684
|
-
|
|
2685
|
-
|
|
2696
|
+
created_by=created_by,
|
|
2697
|
+
shared_by=shared_by,
|
|
2686
2698
|
total_turns=total_turns,
|
|
2687
2699
|
total_turns_mtime=total_turns_mtime,
|
|
2688
2700
|
)
|
|
2689
2701
|
|
|
2690
2702
|
def _row_to_turn(self, row: sqlite3.Row) -> TurnRecord:
|
|
2691
|
-
# V9: creator fields (optional for backward compatibility)
|
|
2692
|
-
creator_name = None
|
|
2693
|
-
creator_id = None
|
|
2694
|
-
try:
|
|
2695
|
-
creator_name = row["creator_name"]
|
|
2696
|
-
creator_id = row["creator_id"]
|
|
2697
|
-
except (IndexError, KeyError):
|
|
2698
|
-
pass
|
|
2699
2703
|
temp_title = None
|
|
2700
2704
|
try:
|
|
2701
2705
|
temp_title = row["temp_title"]
|
|
@@ -2718,8 +2722,6 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2718
2722
|
timestamp=self._parse_datetime(row["timestamp"]),
|
|
2719
2723
|
created_at=self._parse_datetime(row["created_at"]),
|
|
2720
2724
|
git_commit_hash=row["git_commit_hash"],
|
|
2721
|
-
creator_name=creator_name,
|
|
2722
|
-
creator_id=creator_id,
|
|
2723
2725
|
temp_title=temp_title,
|
|
2724
2726
|
)
|
|
2725
2727
|
|
|
@@ -2793,12 +2795,15 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2793
2795
|
share_admin_token = None
|
|
2794
2796
|
share_expiry_at = None
|
|
2795
2797
|
|
|
2796
|
-
#
|
|
2797
|
-
|
|
2798
|
-
|
|
2798
|
+
# V18: user identity fields
|
|
2799
|
+
created_by = None
|
|
2800
|
+
shared_by = None
|
|
2801
|
+
try:
|
|
2802
|
+
created_by = row["created_by"]
|
|
2803
|
+
except KeyError:
|
|
2804
|
+
pass
|
|
2799
2805
|
try:
|
|
2800
|
-
|
|
2801
|
-
creator_id = row["creator_id"]
|
|
2806
|
+
shared_by = row["shared_by"]
|
|
2802
2807
|
except KeyError:
|
|
2803
2808
|
pass
|
|
2804
2809
|
|
|
@@ -2820,17 +2825,16 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2820
2825
|
share_id=share_id,
|
|
2821
2826
|
share_admin_token=share_admin_token,
|
|
2822
2827
|
share_expiry_at=share_expiry_at,
|
|
2823
|
-
|
|
2824
|
-
|
|
2828
|
+
created_by=created_by,
|
|
2829
|
+
shared_by=shared_by,
|
|
2825
2830
|
)
|
|
2826
2831
|
|
|
2827
2832
|
def _row_to_agent(self, row: sqlite3.Row) -> AgentRecord:
|
|
2828
2833
|
"""Convert a database row to an AgentRecord."""
|
|
2829
|
-
|
|
2830
|
-
|
|
2834
|
+
# V18: user identity field
|
|
2835
|
+
created_by = None
|
|
2831
2836
|
try:
|
|
2832
|
-
|
|
2833
|
-
creator_id = row["creator_id"]
|
|
2837
|
+
created_by = row["created_by"]
|
|
2834
2838
|
except (IndexError, KeyError):
|
|
2835
2839
|
pass
|
|
2836
2840
|
|
|
@@ -2848,8 +2852,7 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2848
2852
|
source=row["source"],
|
|
2849
2853
|
created_at=self._parse_datetime(row["created_at"]),
|
|
2850
2854
|
updated_at=self._parse_datetime(row["updated_at"]),
|
|
2851
|
-
|
|
2852
|
-
creator_id=creator_id,
|
|
2855
|
+
created_by=created_by,
|
|
2853
2856
|
)
|
|
2854
2857
|
|
|
2855
2858
|
def _row_to_agent_context(self, row: sqlite3.Row) -> AgentContextRecord:
|
|
@@ -2872,3 +2875,50 @@ class SQLiteDatabase(DatabaseInterface):
|
|
|
2872
2875
|
session_ids=None, # Populated separately
|
|
2873
2876
|
event_ids=None, # Populated separately
|
|
2874
2877
|
)
|
|
2878
|
+
|
|
2879
|
+
# -------------------------------------------------------------------------
|
|
2880
|
+
# Users table methods (Schema V18)
|
|
2881
|
+
# -------------------------------------------------------------------------
|
|
2882
|
+
|
|
2883
|
+
def upsert_user(self, uid: str, user_name: Optional[str] = None) -> None:
|
|
2884
|
+
"""Insert or update a user in the users table."""
|
|
2885
|
+
if not uid:
|
|
2886
|
+
return
|
|
2887
|
+
conn = self._get_connection()
|
|
2888
|
+
try:
|
|
2889
|
+
conn.execute(
|
|
2890
|
+
"""
|
|
2891
|
+
INSERT INTO users (uid, user_name, created_at, updated_at)
|
|
2892
|
+
VALUES (?, ?, datetime('now'), datetime('now'))
|
|
2893
|
+
ON CONFLICT(uid) DO UPDATE SET
|
|
2894
|
+
user_name = COALESCE(excluded.user_name, users.user_name),
|
|
2895
|
+
updated_at = datetime('now')
|
|
2896
|
+
""",
|
|
2897
|
+
(uid, user_name),
|
|
2898
|
+
)
|
|
2899
|
+
conn.commit()
|
|
2900
|
+
except sqlite3.OperationalError:
|
|
2901
|
+
# Older schema without users table
|
|
2902
|
+
try:
|
|
2903
|
+
conn.rollback()
|
|
2904
|
+
except Exception:
|
|
2905
|
+
pass
|
|
2906
|
+
|
|
2907
|
+
def get_user(self, uid: str) -> Optional[UserRecord]:
|
|
2908
|
+
"""Get a user by UID from the users table."""
|
|
2909
|
+
if not uid:
|
|
2910
|
+
return None
|
|
2911
|
+
conn = self._get_connection()
|
|
2912
|
+
try:
|
|
2913
|
+
cursor = conn.execute("SELECT * FROM users WHERE uid = ?", (uid,))
|
|
2914
|
+
row = cursor.fetchone()
|
|
2915
|
+
if row:
|
|
2916
|
+
return UserRecord(
|
|
2917
|
+
uid=row["uid"],
|
|
2918
|
+
user_name=row["user_name"],
|
|
2919
|
+
created_at=self._parse_datetime(row["created_at"]),
|
|
2920
|
+
updated_at=self._parse_datetime(row["updated_at"]),
|
|
2921
|
+
)
|
|
2922
|
+
except sqlite3.OperationalError:
|
|
2923
|
+
pass
|
|
2924
|
+
return None
|
realign/watcher_core.py
CHANGED
|
@@ -1509,8 +1509,6 @@ class DialogueWatcher:
|
|
|
1509
1509
|
timestamp=processing_created_at,
|
|
1510
1510
|
created_at=processing_created_at,
|
|
1511
1511
|
git_commit_hash=None,
|
|
1512
|
-
creator_name=config.user_name,
|
|
1513
|
-
creator_id=config.user_id,
|
|
1514
1512
|
)
|
|
1515
1513
|
try:
|
|
1516
1514
|
db.create_turn(processing_turn, content="")
|
|
@@ -1593,9 +1591,7 @@ class DialogueWatcher:
|
|
|
1593
1591
|
content_hash=turn_hash,
|
|
1594
1592
|
timestamp=datetime.now(),
|
|
1595
1593
|
created_at=datetime.now(),
|
|
1596
|
-
git_commit_hash=None,
|
|
1597
|
-
creator_name=config.user_name,
|
|
1598
|
-
creator_id=config.user_id,
|
|
1594
|
+
git_commit_hash=None,
|
|
1599
1595
|
)
|
|
1600
1596
|
db.create_turn(
|
|
1601
1597
|
new_turn,
|
|
@@ -1628,8 +1624,6 @@ class DialogueWatcher:
|
|
|
1628
1624
|
timestamp=datetime.now(),
|
|
1629
1625
|
created_at=processing_created_at,
|
|
1630
1626
|
git_commit_hash=None,
|
|
1631
|
-
creator_name=config.user_name,
|
|
1632
|
-
creator_id=config.user_id,
|
|
1633
1627
|
)
|
|
1634
1628
|
try:
|
|
1635
1629
|
db.create_turn(
|
|
@@ -1882,8 +1876,6 @@ class DialogueWatcher:
|
|
|
1882
1876
|
timestamp=now,
|
|
1883
1877
|
created_at=now,
|
|
1884
1878
|
git_commit_hash=None,
|
|
1885
|
-
creator_name=config.user_name,
|
|
1886
|
-
creator_id=config.user_id,
|
|
1887
1879
|
)
|
|
1888
1880
|
db.create_turn(temp_turn, content=turn_content or "", skip_session_summary=True)
|
|
1889
1881
|
except Exception as e:
|
realign/watcher_daemon.py
CHANGED
|
@@ -48,6 +48,17 @@ async def run_daemon():
|
|
|
48
48
|
"""Run the watcher daemon."""
|
|
49
49
|
watcher = None
|
|
50
50
|
|
|
51
|
+
# Check login status before starting
|
|
52
|
+
try:
|
|
53
|
+
from .auth import is_logged_in
|
|
54
|
+
except ImportError:
|
|
55
|
+
from realign.auth import is_logged_in
|
|
56
|
+
|
|
57
|
+
if not is_logged_in():
|
|
58
|
+
logger.error("Not logged in. Watcher daemon requires authentication.")
|
|
59
|
+
print("[Watcher Daemon] Error: Not logged in. Run 'aline login' first.", file=sys.stderr)
|
|
60
|
+
sys.exit(1)
|
|
61
|
+
|
|
51
62
|
# Shutdown handler
|
|
52
63
|
def handle_shutdown(signum, frame):
|
|
53
64
|
"""Handle shutdown signals gracefully."""
|
realign/worker_daemon.py
CHANGED
|
@@ -49,6 +49,17 @@ async def run_daemon() -> None:
|
|
|
49
49
|
worker = None
|
|
50
50
|
db = None
|
|
51
51
|
|
|
52
|
+
# Check login status before starting
|
|
53
|
+
try:
|
|
54
|
+
from .auth import is_logged_in
|
|
55
|
+
except ImportError:
|
|
56
|
+
from realign.auth import is_logged_in
|
|
57
|
+
|
|
58
|
+
if not is_logged_in():
|
|
59
|
+
logger.error("Not logged in. Worker daemon requires authentication.")
|
|
60
|
+
print("[Worker Daemon] Error: Not logged in. Run 'aline login' first.", file=sys.stderr)
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
|
|
52
63
|
def handle_shutdown(signum, frame):
|
|
53
64
|
logger.info(f"Received signal {signum}, shutting down...")
|
|
54
65
|
try:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|