aline-ai 0.7.2__py3-none-any.whl → 0.7.4__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.7.2.dist-info → aline_ai-0.7.4.dist-info}/METADATA +1 -1
- {aline_ai-0.7.2.dist-info → aline_ai-0.7.4.dist-info}/RECORD +32 -27
- realign/__init__.py +1 -1
- realign/adapters/codex.py +30 -2
- realign/claude_hooks/stop_hook.py +176 -21
- realign/codex_home.py +71 -0
- realign/codex_hooks/__init__.py +16 -0
- realign/codex_hooks/notify_hook.py +511 -0
- realign/codex_hooks/notify_hook_installer.py +247 -0
- realign/commands/doctor.py +125 -0
- realign/commands/export_shares.py +188 -65
- realign/commands/import_shares.py +30 -10
- realign/commands/init.py +16 -0
- realign/commands/sync_agent.py +274 -44
- realign/commit_pipeline.py +1024 -0
- realign/config.py +3 -11
- realign/dashboard/app.py +151 -2
- realign/dashboard/diagnostics.py +274 -0
- realign/dashboard/screens/create_agent.py +2 -1
- realign/dashboard/screens/create_agent_info.py +40 -77
- realign/dashboard/tmux_manager.py +348 -33
- realign/dashboard/widgets/agents_panel.py +942 -314
- realign/dashboard/widgets/config_panel.py +34 -121
- realign/dashboard/widgets/header.py +1 -1
- realign/db/sqlite_db.py +59 -1
- realign/logging_config.py +51 -6
- realign/watcher_core.py +742 -393
- realign/worker_core.py +206 -15
- {aline_ai-0.7.2.dist-info → aline_ai-0.7.4.dist-info}/WHEEL +0 -0
- {aline_ai-0.7.2.dist-info → aline_ai-0.7.4.dist-info}/entry_points.txt +0 -0
- {aline_ai-0.7.2.dist-info → aline_ai-0.7.4.dist-info}/licenses/LICENSE +0 -0
- {aline_ai-0.7.2.dist-info → aline_ai-0.7.4.dist-info}/top_level.txt +0 -0
|
@@ -7,7 +7,7 @@ from typing import Optional
|
|
|
7
7
|
|
|
8
8
|
from textual.app import ComposeResult
|
|
9
9
|
from textual.binding import Binding
|
|
10
|
-
from textual.containers import Container, Horizontal
|
|
10
|
+
from textual.containers import Container, Horizontal
|
|
11
11
|
from textual.screen import ModalScreen
|
|
12
12
|
from textual.widgets import Button, Input, Label, Static
|
|
13
13
|
from textual.worker import Worker, WorkerState
|
|
@@ -34,7 +34,8 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
CreateAgentInfoScreen #create-agent-info-root {
|
|
37
|
-
width:
|
|
37
|
+
width: 100%;
|
|
38
|
+
max-width: 65;
|
|
38
39
|
height: auto;
|
|
39
40
|
max-height: 80%;
|
|
40
41
|
padding: 1 2;
|
|
@@ -57,15 +58,6 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
57
58
|
|
|
58
59
|
CreateAgentInfoScreen Input {
|
|
59
60
|
margin-top: 0;
|
|
60
|
-
border: none;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
CreateAgentInfoScreen #or-separator {
|
|
64
|
-
height: auto;
|
|
65
|
-
margin-top: 1;
|
|
66
|
-
margin-bottom: 0;
|
|
67
|
-
text-align: center;
|
|
68
|
-
color: $text-muted;
|
|
69
61
|
}
|
|
70
62
|
|
|
71
63
|
CreateAgentInfoScreen #import-status {
|
|
@@ -74,23 +66,13 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
74
66
|
color: $text-muted;
|
|
75
67
|
}
|
|
76
68
|
|
|
77
|
-
CreateAgentInfoScreen #
|
|
69
|
+
CreateAgentInfoScreen #add-buttons {
|
|
78
70
|
height: auto;
|
|
79
71
|
margin-top: 1;
|
|
80
72
|
align: right middle;
|
|
81
73
|
}
|
|
82
74
|
|
|
83
|
-
CreateAgentInfoScreen #
|
|
84
|
-
height: auto;
|
|
85
|
-
margin-top: 1;
|
|
86
|
-
align: right middle;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
CreateAgentInfoScreen #create-buttons Button {
|
|
90
|
-
margin-left: 1;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
CreateAgentInfoScreen #import-buttons Button {
|
|
75
|
+
CreateAgentInfoScreen #add-buttons Button {
|
|
94
76
|
margin-left: 1;
|
|
95
77
|
}
|
|
96
78
|
"""
|
|
@@ -103,44 +85,37 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
103
85
|
|
|
104
86
|
def compose(self) -> ComposeResult:
|
|
105
87
|
with Container(id="create-agent-info-root"):
|
|
106
|
-
yield Static("
|
|
107
|
-
|
|
108
|
-
# --- Create New section ---
|
|
109
|
-
yield Label("Name", classes="section-label")
|
|
110
|
-
yield Input(placeholder=self._default_name, id="agent-name")
|
|
88
|
+
yield Static("Add Agent", id="create-agent-info-title")
|
|
111
89
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
yield Button("Create", id="create", variant="primary")
|
|
115
|
-
|
|
116
|
-
# --- Separator ---
|
|
117
|
-
yield Static("-- Or --", id="or-separator")
|
|
118
|
-
|
|
119
|
-
# --- Import from Link section ---
|
|
120
|
-
yield Label("Import from Link", classes="section-label")
|
|
121
|
-
yield Input(placeholder="https://realign-server.vercel.app/share/...", id="share-url")
|
|
122
|
-
|
|
123
|
-
yield Label("Password (optional)", classes="section-label")
|
|
124
|
-
yield Input(placeholder="Leave blank if not password-protected", id="share-password", password=True)
|
|
90
|
+
yield Label("Name or Share Link", classes="section-label")
|
|
91
|
+
yield Input(placeholder=self._default_name, id="agent-input")
|
|
125
92
|
|
|
126
93
|
yield Static("", id="import-status")
|
|
127
94
|
|
|
128
|
-
with Horizontal(id="
|
|
129
|
-
yield Button("
|
|
95
|
+
with Horizontal(id="add-buttons"):
|
|
96
|
+
yield Button("Cancel", id="cancel")
|
|
97
|
+
yield Button("Add", id="add", variant="primary")
|
|
130
98
|
|
|
131
99
|
def on_mount(self) -> None:
|
|
132
|
-
self.query_one("#agent-
|
|
100
|
+
agent_input = self.query_one("#agent-input", Input)
|
|
101
|
+
agent_input.styles.border = ("round", "black")
|
|
102
|
+
agent_input.focus()
|
|
103
|
+
for btn in (self.query_one("#cancel", Button), self.query_one("#add", Button)):
|
|
104
|
+
btn.styles.border = ("round", "black")
|
|
105
|
+
btn.styles.text_align = "center"
|
|
106
|
+
btn.styles.content_align = ("center", "middle")
|
|
133
107
|
|
|
134
108
|
def action_close(self) -> None:
|
|
135
109
|
self.dismiss(None)
|
|
136
110
|
|
|
137
111
|
def _set_busy(self, busy: bool) -> None:
|
|
138
|
-
self.query_one("#agent-
|
|
139
|
-
self.query_one("#
|
|
140
|
-
self.query_one("#share-password", Input).disabled = busy
|
|
141
|
-
self.query_one("#create", Button).disabled = busy
|
|
112
|
+
self.query_one("#agent-input", Input).disabled = busy
|
|
113
|
+
self.query_one("#add", Button).disabled = busy
|
|
142
114
|
self.query_one("#cancel", Button).disabled = busy
|
|
143
|
-
|
|
115
|
+
|
|
116
|
+
def _is_share_link(self, value: str) -> bool:
|
|
117
|
+
"""Check if the input looks like a share link."""
|
|
118
|
+
return "/share/" in value
|
|
144
119
|
|
|
145
120
|
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
146
121
|
button_id = event.button.id or ""
|
|
@@ -149,28 +124,29 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
149
124
|
self.dismiss(None)
|
|
150
125
|
return
|
|
151
126
|
|
|
152
|
-
if button_id == "
|
|
153
|
-
await self.
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
if button_id == "import":
|
|
157
|
-
await self._import_agent()
|
|
127
|
+
if button_id == "add":
|
|
128
|
+
await self._add_agent()
|
|
158
129
|
return
|
|
159
130
|
|
|
160
131
|
async def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
161
132
|
"""Handle enter key in input fields."""
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
await self._create_agent()
|
|
165
|
-
elif input_id in ("share-url", "share-password"):
|
|
166
|
-
await self._import_agent()
|
|
133
|
+
if event.input.id == "agent-input":
|
|
134
|
+
await self._add_agent()
|
|
167
135
|
|
|
168
|
-
async def
|
|
136
|
+
async def _add_agent(self) -> None:
|
|
137
|
+
"""Create a new agent or import from link based on input content."""
|
|
138
|
+
value = self.query_one("#agent-input", Input).value.strip()
|
|
139
|
+
|
|
140
|
+
if self._is_share_link(value):
|
|
141
|
+
await self._import_agent(value)
|
|
142
|
+
else:
|
|
143
|
+
await self._create_agent(value)
|
|
144
|
+
|
|
145
|
+
async def _create_agent(self, name_input: str) -> None:
|
|
169
146
|
"""Create the agent profile."""
|
|
170
147
|
try:
|
|
171
148
|
from ...db import get_database
|
|
172
149
|
|
|
173
|
-
name_input = self.query_one("#agent-name", Input).value.strip()
|
|
174
150
|
name = name_input or self._default_name
|
|
175
151
|
|
|
176
152
|
agent_id = str(uuid.uuid4())
|
|
@@ -187,21 +163,8 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
187
163
|
logger.error(f"Failed to create agent: {e}")
|
|
188
164
|
self.app.notify(f"Failed to create agent: {e}", severity="error")
|
|
189
165
|
|
|
190
|
-
async def _import_agent(self) -> None:
|
|
166
|
+
async def _import_agent(self, share_url: str) -> None:
|
|
191
167
|
"""Import an agent from a share link."""
|
|
192
|
-
share_url = self.query_one("#share-url", Input).value.strip()
|
|
193
|
-
password = self.query_one("#share-password", Input).value.strip() or None
|
|
194
|
-
|
|
195
|
-
if not share_url:
|
|
196
|
-
self.app.notify("Please enter a share URL", severity="warning")
|
|
197
|
-
self.query_one("#share-url", Input).focus()
|
|
198
|
-
return
|
|
199
|
-
|
|
200
|
-
if "/share/" not in share_url:
|
|
201
|
-
self.app.notify("Invalid share URL format", severity="warning")
|
|
202
|
-
self.query_one("#share-url", Input).focus()
|
|
203
|
-
return
|
|
204
|
-
|
|
205
168
|
status = self.query_one("#import-status", Static)
|
|
206
169
|
status.update("Importing...")
|
|
207
170
|
self._set_busy(True)
|
|
@@ -209,7 +172,7 @@ class CreateAgentInfoScreen(ModalScreen[Optional[dict]]):
|
|
|
209
172
|
def do_import() -> dict:
|
|
210
173
|
from ...commands.import_shares import import_agent_from_share
|
|
211
174
|
|
|
212
|
-
return import_agent_from_share(share_url, password=
|
|
175
|
+
return import_agent_from_share(share_url, password=None)
|
|
213
176
|
|
|
214
177
|
self._import_worker = self.run_worker(do_import, thread=True, exit_on_error=False)
|
|
215
178
|
|