@action-llama/action-llama 0.17.0 → 0.17.2
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.
- package/dist/agents/container-runner.d.ts.map +1 -1
- package/dist/agents/container-runner.js +42 -49
- package/dist/agents/container-runner.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/cli/commands/status.js +1 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cloud/vps/nginx.d.ts +4 -1
- package/dist/cloud/vps/nginx.d.ts.map +1 -1
- package/dist/cloud/vps/nginx.js +48 -12
- package/dist/cloud/vps/nginx.js.map +1 -1
- package/dist/control/index.d.ts +1 -1
- package/dist/control/index.d.ts.map +1 -1
- package/dist/control/index.js +1 -1
- package/dist/control/index.js.map +1 -1
- package/dist/control/routes/dashboard-api.d.ts +20 -0
- package/dist/control/routes/dashboard-api.d.ts.map +1 -0
- package/dist/control/routes/dashboard-api.js +168 -0
- package/dist/control/routes/dashboard-api.js.map +1 -0
- package/dist/control/routes/dashboard.d.ts +3 -11
- package/dist/control/routes/dashboard.d.ts.map +1 -1
- package/dist/control/routes/dashboard.js +3 -218
- package/dist/control/routes/dashboard.js.map +1 -1
- package/dist/execution/routes/locks.d.ts.map +1 -1
- package/dist/execution/routes/locks.js +1 -0
- package/dist/execution/routes/locks.js.map +1 -1
- package/dist/extensions/loader.d.ts +1 -1
- package/dist/extensions/loader.d.ts.map +1 -1
- package/dist/extensions/loader.js +17 -13
- package/dist/extensions/loader.js.map +1 -1
- package/dist/frontend/assets/index-heXAA4Ev.js +13 -0
- package/dist/frontend/assets/index-tjVM5-7N.css +2 -0
- package/dist/frontend/index.html +13 -0
- package/dist/gateway/index.d.ts +7 -0
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +84 -7
- package/dist/gateway/index.js.map +1 -1
- package/dist/models/providers/anthropic.d.ts.map +1 -1
- package/dist/models/providers/anthropic.js +2 -3
- package/dist/models/providers/anthropic.js.map +1 -1
- package/dist/models/providers/openai.d.ts.map +1 -1
- package/dist/models/providers/openai.js +2 -8
- package/dist/models/providers/openai.js.map +1 -1
- package/dist/remote/push.d.ts.map +1 -1
- package/dist/remote/push.js +43 -6
- package/dist/remote/push.js.map +1 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +6 -3
- package/dist/scheduler/index.js.map +1 -1
- package/dist/shared/usage.d.ts.map +1 -1
- package/dist/shared/usage.js +14 -9
- package/dist/shared/usage.js.map +1 -1
- package/dist/tui/App.js +3 -3
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/status-tracker.d.ts.map +1 -1
- package/dist/tui/status-tracker.js +6 -21
- package/dist/tui/status-tracker.js.map +1 -1
- package/package.json +5 -3
- package/dist/control/views/agent-detail-page.d.ts +0 -14
- package/dist/control/views/agent-detail-page.d.ts.map +0 -1
- package/dist/control/views/agent-detail-page.js +0 -501
- package/dist/control/views/agent-detail-page.js.map +0 -1
- package/dist/control/views/agent-skill-page.d.ts +0 -2
- package/dist/control/views/agent-skill-page.d.ts.map +0 -1
- package/dist/control/views/agent-skill-page.js +0 -32
- package/dist/control/views/agent-skill-page.js.map +0 -1
- package/dist/control/views/dashboard-page.d.ts +0 -4
- package/dist/control/views/dashboard-page.d.ts.map +0 -1
- package/dist/control/views/dashboard-page.js +0 -364
- package/dist/control/views/dashboard-page.js.map +0 -1
- package/dist/control/views/instance-detail-page.d.ts +0 -39
- package/dist/control/views/instance-detail-page.d.ts.map +0 -1
- package/dist/control/views/instance-detail-page.js +0 -387
- package/dist/control/views/instance-detail-page.js.map +0 -1
- package/dist/control/views/layout.d.ts +0 -17
- package/dist/control/views/layout.d.ts.map +0 -1
- package/dist/control/views/layout.js +0 -153
- package/dist/control/views/layout.js.map +0 -1
- package/dist/control/views/login-page.d.ts +0 -2
- package/dist/control/views/login-page.d.ts.map +0 -1
- package/dist/control/views/login-page.js +0 -41
- package/dist/control/views/login-page.js.map +0 -1
- package/dist/control/views/markdown.d.ts +0 -6
- package/dist/control/views/markdown.d.ts.map +0 -1
- package/dist/control/views/markdown.js +0 -119
- package/dist/control/views/markdown.js.map +0 -1
- package/dist/control/views/project-config-page.d.ts +0 -8
- package/dist/control/views/project-config-page.d.ts.map +0 -1
- package/dist/control/views/project-config-page.js +0 -117
- package/dist/control/views/project-config-page.js.map +0 -1
- package/dist/control/views/trigger-history-page.d.ts +0 -10
- package/dist/control/views/trigger-history-page.d.ts.map +0 -1
- package/dist/control/views/trigger-history-page.js +0 -89
- package/dist/control/views/trigger-history-page.js.map +0 -1
|
@@ -1,387 +0,0 @@
|
|
|
1
|
-
import { escapeHtml, formatDuration, formatCost, formatTokens, renderLayout } from "./layout.js";
|
|
2
|
-
function resultBadge(result) {
|
|
3
|
-
switch (result) {
|
|
4
|
-
case "completed":
|
|
5
|
-
case "rerun":
|
|
6
|
-
return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-400">${escapeHtml(result)}</span>`;
|
|
7
|
-
case "error":
|
|
8
|
-
return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-400">error</span>`;
|
|
9
|
-
default:
|
|
10
|
-
return `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400">${escapeHtml(result)}</span>`;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function statRow(label, value) {
|
|
14
|
-
return `<div class="flex justify-between py-2 border-b border-slate-100 dark:border-slate-800">
|
|
15
|
-
<span class="text-sm text-slate-500 dark:text-slate-400">${escapeHtml(label)}</span>
|
|
16
|
-
<span class="text-sm font-medium text-slate-900 dark:text-white">${value}</span>
|
|
17
|
-
</div>`;
|
|
18
|
-
}
|
|
19
|
-
function renderTriggerDetail(data) {
|
|
20
|
-
const run = data.run;
|
|
21
|
-
if (!run)
|
|
22
|
-
return "";
|
|
23
|
-
if (run.trigger_type === "agent") {
|
|
24
|
-
if (data.parentEdge) {
|
|
25
|
-
const parentUrl = `/dashboard/agents/${encodeURIComponent(data.parentEdge.caller_agent)}/instances/${encodeURIComponent(data.parentEdge.caller_instance)}`;
|
|
26
|
-
return `Agent — triggered by <a href="${parentUrl}" class="text-blue-500 hover:underline">${escapeHtml(data.parentEdge.caller_agent)}/${escapeHtml(data.parentEdge.caller_instance)}</a>`;
|
|
27
|
-
}
|
|
28
|
-
return "Agent" + (run.trigger_source ? ` (${escapeHtml(run.trigger_source)})` : "");
|
|
29
|
-
}
|
|
30
|
-
if (run.trigger_type === "webhook") {
|
|
31
|
-
if (data.webhookReceipt) {
|
|
32
|
-
const parts = [`Webhook from ${escapeHtml(data.webhookReceipt.source)}`];
|
|
33
|
-
if (data.webhookReceipt.eventSummary)
|
|
34
|
-
parts.push(escapeHtml(data.webhookReceipt.eventSummary));
|
|
35
|
-
if (data.webhookReceipt.deliveryId)
|
|
36
|
-
parts.push(`<span class="text-slate-400 text-xs font-mono">${escapeHtml(data.webhookReceipt.deliveryId)}</span>`);
|
|
37
|
-
return parts.join(" · ");
|
|
38
|
-
}
|
|
39
|
-
return "Webhook" + (run.trigger_source ? ` (${escapeHtml(run.trigger_source)})` : "");
|
|
40
|
-
}
|
|
41
|
-
if (run.trigger_type === "schedule") {
|
|
42
|
-
return "Scheduled";
|
|
43
|
-
}
|
|
44
|
-
return escapeHtml(run.trigger_type) + (run.trigger_source ? ` (${escapeHtml(run.trigger_source)})` : "");
|
|
45
|
-
}
|
|
46
|
-
export function renderInstanceDetailPage(data) {
|
|
47
|
-
const { agentName, instanceId, run, runningInstance } = data;
|
|
48
|
-
let notFoundContent;
|
|
49
|
-
if (!run && runningInstance) {
|
|
50
|
-
notFoundContent = `
|
|
51
|
-
<div class="text-center py-12">
|
|
52
|
-
<div class="text-slate-400 text-lg mb-2">Telemetry data will be available once the run completes</div>
|
|
53
|
-
<p class="text-sm text-slate-500">Instance <code class="font-mono">${escapeHtml(instanceId)}</code> is currently running. Stats and telemetry data will be shown here after the run finishes.</p>
|
|
54
|
-
</div>`;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
notFoundContent = `
|
|
58
|
-
<div class="text-center py-12">
|
|
59
|
-
<div class="text-slate-400 text-lg mb-2">Instance not found or data has been pruned</div>
|
|
60
|
-
<p class="text-sm text-slate-500">The instance <code class="font-mono">${escapeHtml(instanceId)}</code> was not found in the stats database. The data may have been pruned or the instance never existed.</p>
|
|
61
|
-
</div>`;
|
|
62
|
-
}
|
|
63
|
-
if (!run) {
|
|
64
|
-
// Even without stats data, show the log viewer — the instance may be running
|
|
65
|
-
let headerContent;
|
|
66
|
-
if (runningInstance) {
|
|
67
|
-
const startedAt = runningInstance.startedAt.toLocaleString();
|
|
68
|
-
headerContent = `
|
|
69
|
-
<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
|
|
70
|
-
<h1 class="text-xl sm:text-2xl font-bold text-slate-900 dark:text-white font-mono">${escapeHtml(instanceId)}</h1>
|
|
71
|
-
<div class="flex items-center gap-2">
|
|
72
|
-
<button class="px-3 py-1.5 text-sm rounded-md font-bold bg-red-600 hover:bg-red-700 text-white transition-colors" onclick="killThisInstance()">Kill</button>
|
|
73
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-400">running</span>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
<div class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-4 mb-6">
|
|
77
|
-
<h3 class="text-sm font-semibold text-slate-900 dark:text-white mb-3 uppercase tracking-wide">Running Instance</h3>
|
|
78
|
-
${statRow("Instance ID", instanceId)}
|
|
79
|
-
${statRow("Status", runningInstance.status)}
|
|
80
|
-
${statRow("Started", startedAt)}
|
|
81
|
-
${statRow("Trigger", runningInstance.trigger)}
|
|
82
|
-
</div>`;
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
headerContent = `
|
|
86
|
-
<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
|
|
87
|
-
<h1 class="text-xl sm:text-2xl font-bold text-slate-900 dark:text-white font-mono">${escapeHtml(instanceId)}</h1>
|
|
88
|
-
<div class="flex items-center gap-2">
|
|
89
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 dark:bg-gray-900/40 text-gray-700 dark:text-gray-400">unknown</span>
|
|
90
|
-
</div>
|
|
91
|
-
</div>`;
|
|
92
|
-
}
|
|
93
|
-
const content = `
|
|
94
|
-
${headerContent}
|
|
95
|
-
${notFoundContent}
|
|
96
|
-
<div id="locks-section" class="mt-6">
|
|
97
|
-
<h3 class="text-base font-semibold text-slate-900 dark:text-white mb-3">Resource Locks</h3>
|
|
98
|
-
<div id="locks-container" class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-4">
|
|
99
|
-
<div class="text-sm text-slate-400 italic">Loading...</div>
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
<h2 class="text-base font-semibold text-slate-900 dark:text-white mb-3 mt-8">Logs</h2>
|
|
103
|
-
${logViewerHtml(agentName, instanceId)}`;
|
|
104
|
-
return renderLayout({
|
|
105
|
-
title: instanceId,
|
|
106
|
-
breadcrumbs: [
|
|
107
|
-
{ label: "Dashboard", href: "/dashboard" },
|
|
108
|
-
{ label: agentName, href: `/dashboard/agents/${encodeURIComponent(agentName)}` },
|
|
109
|
-
{ label: instanceId },
|
|
110
|
-
],
|
|
111
|
-
content,
|
|
112
|
-
scripts: logViewerScript(agentName, instanceId),
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const startedAt = new Date(run.started_at);
|
|
116
|
-
const endedAt = new Date(run.started_at + run.duration_ms);
|
|
117
|
-
const content = `
|
|
118
|
-
<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
|
|
119
|
-
<h1 class="text-xl sm:text-2xl font-bold text-slate-900 dark:text-white font-mono">${escapeHtml(run.instance_id)}</h1>
|
|
120
|
-
<div class="flex items-center gap-2">
|
|
121
|
-
${run.result === "running" ? `<button class="px-3 py-1.5 text-sm rounded-md font-bold bg-red-600 hover:bg-red-700 text-white transition-colors" onclick="killThisInstance()">Kill</button>` : ""}
|
|
122
|
-
${resultBadge(run.result)}
|
|
123
|
-
</div>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
|
-
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|
127
|
-
<div class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-4">
|
|
128
|
-
<h3 class="text-sm font-semibold text-slate-900 dark:text-white mb-3 uppercase tracking-wide">Run Info</h3>
|
|
129
|
-
${statRow("Trigger", renderTriggerDetail(data))}
|
|
130
|
-
${statRow("Status", run.result)}
|
|
131
|
-
${run.exit_code != null ? statRow("Exit Code", `${run.exit_code}`) : ""}
|
|
132
|
-
${statRow("Started", startedAt.toLocaleString())}
|
|
133
|
-
${statRow("Ended", endedAt.toLocaleString())}
|
|
134
|
-
${statRow("Duration", formatDuration(run.duration_ms))}
|
|
135
|
-
${statRow("Turns", `${run.turn_count}`)}
|
|
136
|
-
${run.error_message ? `<div class="mt-3 p-2 bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-900 rounded text-sm text-red-700 dark:text-red-400 break-words">${escapeHtml(run.error_message)}</div>` : ""}
|
|
137
|
-
</div>
|
|
138
|
-
|
|
139
|
-
<div class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-4">
|
|
140
|
-
<h3 class="text-sm font-semibold text-slate-900 dark:text-white mb-3 uppercase tracking-wide">Token Usage</h3>
|
|
141
|
-
${statRow("Input Tokens", formatTokens(run.input_tokens))}
|
|
142
|
-
${statRow("Output Tokens", formatTokens(run.output_tokens))}
|
|
143
|
-
${statRow("Cache Read", formatTokens(run.cache_read_tokens))}
|
|
144
|
-
${statRow("Cache Write", formatTokens(run.cache_write_tokens))}
|
|
145
|
-
${statRow("Total Tokens", formatTokens(run.total_tokens))}
|
|
146
|
-
${statRow("Cost", formatCost(run.cost_usd))}
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div id="locks-section" class="mt-6">
|
|
151
|
-
<h3 class="text-base font-semibold text-slate-900 dark:text-white mb-3">Resource Locks</h3>
|
|
152
|
-
<div id="locks-container" class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-4">
|
|
153
|
-
<div class="text-sm text-slate-400 italic">Loading...</div>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<h2 class="text-base font-semibold text-slate-900 dark:text-white mb-3">Logs</h2>
|
|
158
|
-
${logViewerHtml(agentName, instanceId)}`;
|
|
159
|
-
return renderLayout({
|
|
160
|
-
title: instanceId,
|
|
161
|
-
breadcrumbs: [
|
|
162
|
-
{ label: "Dashboard", href: "/dashboard" },
|
|
163
|
-
{ label: agentName, href: `/dashboard/agents/${encodeURIComponent(agentName)}` },
|
|
164
|
-
{ label: instanceId },
|
|
165
|
-
],
|
|
166
|
-
content,
|
|
167
|
-
scripts: logViewerScript(agentName, instanceId),
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
function logViewerHtml(agentName, instanceId) {
|
|
171
|
-
return `
|
|
172
|
-
<div class="flex items-center gap-3 mb-2">
|
|
173
|
-
<button id="follow-btn" class="px-3 py-1 text-xs rounded-md font-bold border border-blue-500 bg-blue-500 text-white hover:bg-blue-600 transition-colors" onclick="toggleFollow()">Follow</button>
|
|
174
|
-
<button class="px-3 py-1 text-xs rounded-md font-bold border border-orange-500 bg-orange-500 text-white hover:bg-orange-600 transition-colors" onclick="clearLogs()">Clear</button>
|
|
175
|
-
<span id="line-count" class="text-xs text-slate-400">0 lines</span>
|
|
176
|
-
<span id="conn-status" class="text-xs text-green-500">connected</span>
|
|
177
|
-
</div>
|
|
178
|
-
<div id="log-container" class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-3 sm:p-4 font-mono text-xs sm:text-sm leading-relaxed overflow-y-auto scrollbar-thin" style="height: 500px;">
|
|
179
|
-
<div id="empty-msg" class="text-slate-400 italic">Waiting for logs...</div>
|
|
180
|
-
</div>`;
|
|
181
|
-
}
|
|
182
|
-
function logViewerScript(agentName, instanceId) {
|
|
183
|
-
return `<script>
|
|
184
|
-
var agentName = ${JSON.stringify(agentName)};
|
|
185
|
-
var instanceId = ${JSON.stringify(instanceId)};
|
|
186
|
-
var container = document.getElementById("log-container");
|
|
187
|
-
var emptyMsg = document.getElementById("empty-msg");
|
|
188
|
-
var followBtn = document.getElementById("follow-btn");
|
|
189
|
-
var lineCountEl = document.getElementById("line-count");
|
|
190
|
-
var connStatus = document.getElementById("conn-status");
|
|
191
|
-
|
|
192
|
-
var follow = true;
|
|
193
|
-
var lineCount = 0;
|
|
194
|
-
|
|
195
|
-
function toggleFollow() {
|
|
196
|
-
follow = !follow;
|
|
197
|
-
if (follow) {
|
|
198
|
-
followBtn.className = "px-3 py-1 text-xs rounded-md border border-blue-500 bg-blue-500 text-white hover:bg-blue-600 transition-colors";
|
|
199
|
-
container.scrollTop = container.scrollHeight;
|
|
200
|
-
} else {
|
|
201
|
-
followBtn.className = "px-3 py-1 text-xs rounded-md border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 hover:bg-slate-50 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 transition-colors";
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function clearLogs() {
|
|
206
|
-
container.innerHTML = "";
|
|
207
|
-
lineCount = 0;
|
|
208
|
-
lineCountEl.textContent = "0 lines";
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
var SKIP_MSGS = { "event": 1, "tool done": 1 };
|
|
212
|
-
|
|
213
|
-
function formatEntry(p) {
|
|
214
|
-
var time = '<span class="text-slate-400">' + esc(new Date(p.time).toLocaleTimeString("en-US", { hour12: false })) + '</span> ';
|
|
215
|
-
var msg = p.msg || "";
|
|
216
|
-
var lvl = p.level || 30;
|
|
217
|
-
|
|
218
|
-
if (SKIP_MSGS[msg]) return null;
|
|
219
|
-
if (lvl <= 20 && msg !== "tool start") return null;
|
|
220
|
-
|
|
221
|
-
if (msg === "assistant") {
|
|
222
|
-
var text = p.text || "";
|
|
223
|
-
if (!text) return null;
|
|
224
|
-
var lines = text.split("\\n");
|
|
225
|
-
var out = time + '<span class="text-slate-900 dark:text-white font-medium">' + esc(lines[0]) + '</span>';
|
|
226
|
-
for (var i = 1; i < lines.length; i++) {
|
|
227
|
-
out += '<span class="text-slate-900 dark:text-white block pl-[7.5em]">' + esc(lines[i]) + '</span>';
|
|
228
|
-
}
|
|
229
|
-
return out;
|
|
230
|
-
}
|
|
231
|
-
if (msg === "bash") return time + '<span class="text-cyan-500">$ ' + esc(p.cmd || "") + '</span>';
|
|
232
|
-
if (msg === "tool start") return time + '<span class="text-blue-500">\\u25b8 ' + esc(p.tool || "unknown") + '</span>';
|
|
233
|
-
if (msg === "tool error") {
|
|
234
|
-
var out = time + '<span class="text-red-500">\\u2717 ' + esc(p.tool || "unknown") + ' failed</span>';
|
|
235
|
-
if (p.cmd) out += '<span class="block pl-[7.5em] text-slate-400 text-[0.9em]">$ ' + esc(String(p.cmd)) + '</span>';
|
|
236
|
-
if (p.result) out += '<span class="block pl-[7.5em] text-slate-400 text-[0.9em]">' + esc(String(p.result).slice(0, 300)) + '</span>';
|
|
237
|
-
return out;
|
|
238
|
-
}
|
|
239
|
-
if (msg.startsWith && msg.startsWith("Starting ")) {
|
|
240
|
-
var ctr = p.container ? ' <span class="text-slate-400">(' + esc(p.container) + ')</span>' : "";
|
|
241
|
-
return time + '<span class="text-purple-500 font-semibold">' + esc(msg) + '</span>' + ctr;
|
|
242
|
-
}
|
|
243
|
-
if (msg === "run completed" || msg === "run completed, rerun requested") {
|
|
244
|
-
var suffix = msg.includes("rerun") ? ' <span class="text-yellow-500">(rerun requested)</span>' : "";
|
|
245
|
-
return time + '<span class="text-green-500 font-semibold">Run completed</span>' + suffix;
|
|
246
|
-
}
|
|
247
|
-
if (msg === "container launched" || msg === "container finished" || msg.includes("container")) {
|
|
248
|
-
return time + '<span class="text-slate-400">' + esc(msg) + '</span>';
|
|
249
|
-
}
|
|
250
|
-
if (lvl >= 50) {
|
|
251
|
-
var detail = p.err ? '<span class="block pl-[7.5em] text-slate-400 text-[0.9em]">' + esc(JSON.stringify(p.err).slice(0, 300)) + '</span>' : "";
|
|
252
|
-
return time + '<span class="text-red-500 font-semibold">ERROR: ' + esc(msg) + '</span>' + detail;
|
|
253
|
-
}
|
|
254
|
-
if (lvl >= 40) return time + '<span class="text-yellow-500">WARN: ' + esc(msg) + '</span>';
|
|
255
|
-
return time + '<span class="text-slate-400">' + esc(msg) + '</span>';
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function maybeRunHeader(p) {
|
|
259
|
-
var msg = p.msg || "";
|
|
260
|
-
if (msg.startsWith && msg.startsWith("Starting ") && (msg.includes(" run") || msg.includes(" container run"))) {
|
|
261
|
-
var name = p.name || "agent";
|
|
262
|
-
var ctr = p.container ? " " + p.container : "";
|
|
263
|
-
return '<div class="whitespace-pre-wrap break-all border-t border-slate-200 dark:border-slate-700 mt-2 pt-1.5 text-purple-500 font-semibold">\\u2500\\u2500 ' + esc(name + ctr) + ' ' + "\\u2500".repeat(50) + '</div>';
|
|
264
|
-
}
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function appendEntry(p) {
|
|
269
|
-
if (emptyMsg && emptyMsg.parentNode) emptyMsg.remove();
|
|
270
|
-
var header = maybeRunHeader(p);
|
|
271
|
-
if (header) {
|
|
272
|
-
var hdiv = document.createElement("div");
|
|
273
|
-
hdiv.innerHTML = header;
|
|
274
|
-
container.appendChild(hdiv.firstChild);
|
|
275
|
-
}
|
|
276
|
-
var html = formatEntry(p);
|
|
277
|
-
if (!html) return;
|
|
278
|
-
var div = document.createElement("div");
|
|
279
|
-
div.className = "whitespace-pre-wrap break-all py-px";
|
|
280
|
-
div.innerHTML = html;
|
|
281
|
-
container.appendChild(div);
|
|
282
|
-
lineCount++;
|
|
283
|
-
lineCountEl.textContent = lineCount + " line" + (lineCount !== 1 ? "s" : "");
|
|
284
|
-
if (follow) container.scrollTop = container.scrollHeight;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
container.addEventListener("scroll", function() {
|
|
288
|
-
var atBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 50;
|
|
289
|
-
if (!atBottom && follow) { follow = false; followBtn.className = "px-3 py-1 text-xs rounded-md border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 hover:bg-slate-50 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-200 transition-colors"; }
|
|
290
|
-
else if (atBottom && !follow) { follow = true; followBtn.className = "px-3 py-1 text-xs rounded-md border border-blue-500 bg-blue-500 text-white hover:bg-blue-600 transition-colors"; }
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
function killThisInstance() {
|
|
294
|
-
if (!confirm("Kill instance " + instanceId + "?")) return;
|
|
295
|
-
ctrlPost("/control/kill/" + encodeURIComponent(instanceId));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Log polling
|
|
299
|
-
var logCursor = null;
|
|
300
|
-
async function fetchLogs(initial) {
|
|
301
|
-
try {
|
|
302
|
-
var params = new URLSearchParams();
|
|
303
|
-
if (initial) params.set("lines", "500");
|
|
304
|
-
if (logCursor) params.set("cursor", logCursor);
|
|
305
|
-
var res = await fetch("/api/logs/agents/" + encodeURIComponent(agentName) + "/" + encodeURIComponent(instanceId) + "?" + params, { credentials: "same-origin" });
|
|
306
|
-
if (!res.ok) throw new Error(res.status);
|
|
307
|
-
var data = await res.json();
|
|
308
|
-
for (var i = 0; i < data.entries.length; i++) appendEntry(data.entries[i]);
|
|
309
|
-
if (data.cursor) logCursor = data.cursor;
|
|
310
|
-
connStatus.textContent = "connected";
|
|
311
|
-
connStatus.className = "text-xs text-green-500";
|
|
312
|
-
} catch(e) {
|
|
313
|
-
connStatus.textContent = "disconnected";
|
|
314
|
-
connStatus.className = "text-xs text-red-500";
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
fetchLogs(true);
|
|
318
|
-
setInterval(function() { fetchLogs(false); }, 1500);
|
|
319
|
-
|
|
320
|
-
// Fetch locks for this instance
|
|
321
|
-
async function fetchInstanceLocks() {
|
|
322
|
-
try {
|
|
323
|
-
var res = await fetch("/dashboard/api/locks");
|
|
324
|
-
if (res.ok) {
|
|
325
|
-
var data = await res.json();
|
|
326
|
-
var instanceLocks = [];
|
|
327
|
-
if (data.locks) {
|
|
328
|
-
for (var i = 0; i < data.locks.length; i++) {
|
|
329
|
-
var lock = data.locks[i];
|
|
330
|
-
// Check if holder matches this instance
|
|
331
|
-
if (lock.holder && lock.holder.includes(instanceId)) {
|
|
332
|
-
instanceLocks.push(lock);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
// Update locks display
|
|
337
|
-
var container = document.getElementById("locks-container");
|
|
338
|
-
if (instanceLocks.length > 0) {
|
|
339
|
-
var html = "<div class='space-y-2'>";
|
|
340
|
-
for (var j = 0; j < instanceLocks.length; j++) {
|
|
341
|
-
var l = instanceLocks[j];
|
|
342
|
-
var since = new Date(l.heldSince).toLocaleString();
|
|
343
|
-
html += "<div class='flex justify-between py-2 border-b border-slate-100 dark:border-slate-800'>" +
|
|
344
|
-
"<span class='text-sm font-mono text-slate-700 dark:text-slate-300'>" + esc(l.resourceKey) + "</span>" +
|
|
345
|
-
"<span class='text-xs text-slate-500'>Since " + since + "</span></div>";
|
|
346
|
-
}
|
|
347
|
-
html += "</div>";
|
|
348
|
-
container.innerHTML = html;
|
|
349
|
-
} else {
|
|
350
|
-
container.innerHTML = "<div class='text-sm text-slate-400 italic'>No locks held</div>";
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
} catch(e) {}
|
|
354
|
-
}
|
|
355
|
-
setInterval(fetchInstanceLocks, 2000);
|
|
356
|
-
fetchInstanceLocks(); // Initial fetch
|
|
357
|
-
|
|
358
|
-
// Scroll up to load older logs
|
|
359
|
-
var loadingOlder = false;
|
|
360
|
-
var oldestTime = null;
|
|
361
|
-
container.addEventListener("scroll", async function() {
|
|
362
|
-
if (container.scrollTop < 100 && !loadingOlder && lineCount > 0) {
|
|
363
|
-
loadingOlder = true;
|
|
364
|
-
try {
|
|
365
|
-
// Find oldest entry time
|
|
366
|
-
var firstEntry = container.querySelector(".whitespace-pre-wrap");
|
|
367
|
-
// Use a before param to load older entries
|
|
368
|
-
if (oldestTime === null) {
|
|
369
|
-
// Get time from the first visible log entry's data
|
|
370
|
-
var params = new URLSearchParams();
|
|
371
|
-
params.set("lines", "50");
|
|
372
|
-
if (oldestTime) params.set("before", String(oldestTime));
|
|
373
|
-
var res = await fetch("/api/logs/agents/" + encodeURIComponent(agentName) + "/" + encodeURIComponent(instanceId) + "?" + params, { credentials: "same-origin" });
|
|
374
|
-
if (res.ok) {
|
|
375
|
-
var data = await res.json();
|
|
376
|
-
if (data.entries.length > 0) {
|
|
377
|
-
oldestTime = data.entries[0].time;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
} catch(e) {}
|
|
382
|
-
loadingOlder = false;
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
</script>`;
|
|
386
|
-
}
|
|
387
|
-
//# sourceMappingURL=instance-detail-page.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"instance-detail-page.js","sourceRoot":"","sources":["../../../src/control/views/instance-detail-page.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export declare function escapeHtml(str: string): string;
|
|
2
|
-
export declare function formatDuration(ms: number): string;
|
|
3
|
-
export declare function formatTime(date: Date | null): string;
|
|
4
|
-
export declare function formatCost(usd: number): string;
|
|
5
|
-
export declare function formatTokens(n: number): string;
|
|
6
|
-
export interface Breadcrumb {
|
|
7
|
-
label: string;
|
|
8
|
-
href?: string;
|
|
9
|
-
}
|
|
10
|
-
export interface LayoutOptions {
|
|
11
|
-
title: string;
|
|
12
|
-
breadcrumbs?: Breadcrumb[];
|
|
13
|
-
content: string;
|
|
14
|
-
scripts?: string;
|
|
15
|
-
}
|
|
16
|
-
export declare function renderLayout(opts: LayoutOptions): string;
|
|
17
|
-
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/control/views/layout.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAGpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9C;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAgHxD"}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
export function escapeHtml(str) {
|
|
2
|
-
return str
|
|
3
|
-
.replace(/&/g, "&")
|
|
4
|
-
.replace(/</g, "<")
|
|
5
|
-
.replace(/>/g, ">")
|
|
6
|
-
.replace(/"/g, """);
|
|
7
|
-
}
|
|
8
|
-
export function formatDuration(ms) {
|
|
9
|
-
if (ms < 1000)
|
|
10
|
-
return `${ms}ms`;
|
|
11
|
-
const s = Math.floor(ms / 1000);
|
|
12
|
-
if (s < 60)
|
|
13
|
-
return `${s}s`;
|
|
14
|
-
const m = Math.floor(s / 60);
|
|
15
|
-
if (m < 60)
|
|
16
|
-
return `${m}m ${s % 60}s`;
|
|
17
|
-
const h = Math.floor(m / 60);
|
|
18
|
-
return `${h}h ${m % 60}m`;
|
|
19
|
-
}
|
|
20
|
-
export function formatTime(date) {
|
|
21
|
-
if (!date)
|
|
22
|
-
return "\u2014";
|
|
23
|
-
return date.toLocaleTimeString();
|
|
24
|
-
}
|
|
25
|
-
export function formatCost(usd) {
|
|
26
|
-
if (usd === 0)
|
|
27
|
-
return "$0.00";
|
|
28
|
-
if (usd < 0.01)
|
|
29
|
-
return `$${usd.toFixed(4)}`;
|
|
30
|
-
return `$${usd.toFixed(2)}`;
|
|
31
|
-
}
|
|
32
|
-
export function formatTokens(n) {
|
|
33
|
-
if (n === 0)
|
|
34
|
-
return "0";
|
|
35
|
-
if (n < 1000)
|
|
36
|
-
return `${n}`;
|
|
37
|
-
if (n < 1_000_000)
|
|
38
|
-
return `${(n / 1000).toFixed(1)}k`;
|
|
39
|
-
return `${(n / 1_000_000).toFixed(2)}M`;
|
|
40
|
-
}
|
|
41
|
-
export function renderLayout(opts) {
|
|
42
|
-
const { title, breadcrumbs, content, scripts } = opts;
|
|
43
|
-
const breadcrumbHtml = breadcrumbs?.length
|
|
44
|
-
? `<nav class="flex items-center gap-1.5 text-sm text-slate-400 mb-4">
|
|
45
|
-
${breadcrumbs
|
|
46
|
-
.map((b, i) => {
|
|
47
|
-
const isLast = i === breadcrumbs.length - 1;
|
|
48
|
-
if (isLast)
|
|
49
|
-
return `<span class="text-slate-200 font-medium">${escapeHtml(b.label)}</span>`;
|
|
50
|
-
return `<a href="${b.href || "#"}" class="hover:text-slate-200 transition-colors">${escapeHtml(b.label)}</a><span class="text-slate-600">/</span>`;
|
|
51
|
-
})
|
|
52
|
-
.join("\n ")}
|
|
53
|
-
</nav>`
|
|
54
|
-
: "";
|
|
55
|
-
return `<!DOCTYPE html>
|
|
56
|
-
<html lang="en" class="dark">
|
|
57
|
-
<head>
|
|
58
|
-
<meta charset="utf-8">
|
|
59
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
60
|
-
<title>${escapeHtml(title)} \u2014 Action Llama</title>
|
|
61
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
62
|
-
<script>
|
|
63
|
-
tailwind.config = {
|
|
64
|
-
darkMode: 'class',
|
|
65
|
-
theme: {
|
|
66
|
-
extend: {
|
|
67
|
-
fontFamily: {
|
|
68
|
-
mono: ['SF Mono', 'Fira Code', 'monospace'],
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
</script>
|
|
74
|
-
<style>
|
|
75
|
-
.state-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; }
|
|
76
|
-
.scrollbar-thin::-webkit-scrollbar { width: 6px; }
|
|
77
|
-
.scrollbar-thin::-webkit-scrollbar-track { background: transparent; }
|
|
78
|
-
.scrollbar-thin::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }
|
|
79
|
-
</style>
|
|
80
|
-
</head>
|
|
81
|
-
<body class="bg-white dark:bg-slate-950 text-slate-800 dark:text-slate-200 min-h-screen">
|
|
82
|
-
<header class="border-b border-slate-200 dark:border-slate-800 px-4 sm:px-6 py-3">
|
|
83
|
-
<div class="flex items-center justify-between">
|
|
84
|
-
<a href="/dashboard" class="text-lg font-bold text-slate-900 dark:text-white hover:text-blue-600 dark:hover:text-blue-400 transition-colors">Action Llama</a>
|
|
85
|
-
<div class="flex items-center gap-3">
|
|
86
|
-
<button id="theme-toggle" onclick="toggleTheme()" class="p-1.5 rounded-md text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors" title="Toggle theme">
|
|
87
|
-
<svg id="theme-icon-dark" class="w-4 h-4 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" /></svg>
|
|
88
|
-
<svg id="theme-icon-light" class="w-4 h-4 block dark:hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" /></svg>
|
|
89
|
-
</button>
|
|
90
|
-
<a href="#" onclick="doLogout(); return false;" class="text-sm text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 transition-colors">Logout</a>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
</header>
|
|
94
|
-
|
|
95
|
-
<main class="px-4 sm:px-6 py-4 max-w-7xl mx-auto">
|
|
96
|
-
${breadcrumbHtml}
|
|
97
|
-
${content}
|
|
98
|
-
</main>
|
|
99
|
-
|
|
100
|
-
<script>
|
|
101
|
-
// Theme management
|
|
102
|
-
function getTheme() {
|
|
103
|
-
return localStorage.getItem('al-theme') || 'dark';
|
|
104
|
-
}
|
|
105
|
-
function applyTheme(theme) {
|
|
106
|
-
document.documentElement.classList.toggle('dark', theme === 'dark');
|
|
107
|
-
localStorage.setItem('al-theme', theme);
|
|
108
|
-
}
|
|
109
|
-
function toggleTheme() {
|
|
110
|
-
applyTheme(getTheme() === 'dark' ? 'light' : 'dark');
|
|
111
|
-
}
|
|
112
|
-
applyTheme(getTheme());
|
|
113
|
-
|
|
114
|
-
// Shared helpers
|
|
115
|
-
function esc(s) { var d = document.createElement("div"); d.textContent = s; return d.innerHTML; }
|
|
116
|
-
function fmtDur(ms) {
|
|
117
|
-
if (ms < 1000) return ms + "ms";
|
|
118
|
-
var s = Math.floor(ms / 1000);
|
|
119
|
-
if (s < 60) return s + "s";
|
|
120
|
-
var m = Math.floor(s / 60);
|
|
121
|
-
if (m < 60) return m + "m " + (s % 60) + "s";
|
|
122
|
-
var h = Math.floor(m / 60);
|
|
123
|
-
return h + "h " + (m % 60) + "m";
|
|
124
|
-
}
|
|
125
|
-
function fmtTime(iso) {
|
|
126
|
-
if (!iso) return "\\u2014";
|
|
127
|
-
return new Date(iso).toLocaleTimeString();
|
|
128
|
-
}
|
|
129
|
-
function fmtCost(usd) {
|
|
130
|
-
if (!usd || usd === 0) return "$0.00";
|
|
131
|
-
if (usd < 0.01) return "$" + usd.toFixed(4);
|
|
132
|
-
return "$" + usd.toFixed(2);
|
|
133
|
-
}
|
|
134
|
-
function fmtTokens(n) {
|
|
135
|
-
if (!n || n === 0) return "0";
|
|
136
|
-
if (n < 1000) return "" + n;
|
|
137
|
-
if (n < 1000000) return (n / 1000).toFixed(1) + "k";
|
|
138
|
-
return (n / 1000000).toFixed(2) + "M";
|
|
139
|
-
}
|
|
140
|
-
function ctrlPost(path) {
|
|
141
|
-
return fetch(path, { method: "POST", credentials: "same-origin" }).then(function(r) { return r.json(); });
|
|
142
|
-
}
|
|
143
|
-
function doLogout() {
|
|
144
|
-
fetch("/logout", { method: "POST", credentials: "same-origin" }).then(function() {
|
|
145
|
-
window.location.href = "/login";
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
</script>
|
|
149
|
-
${scripts || ""}
|
|
150
|
-
</body>
|
|
151
|
-
</html>`;
|
|
152
|
-
}
|
|
153
|
-
//# sourceMappingURL=layout.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/control/views/layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-page.d.ts","sourceRoot":"","sources":["../../../src/control/views/login-page.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCtD"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { escapeHtml } from "./layout.js";
|
|
2
|
-
export function renderLoginPage(error) {
|
|
3
|
-
const errorHtml = error
|
|
4
|
-
? `<div class="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-3 mb-4 text-sm text-red-700 dark:text-red-400 text-center">${escapeHtml(error)}</div>`
|
|
5
|
-
: "";
|
|
6
|
-
return `<!DOCTYPE html>
|
|
7
|
-
<html lang="en" class="dark">
|
|
8
|
-
<head>
|
|
9
|
-
<meta charset="utf-8">
|
|
10
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
11
|
-
<title>Login \u2014 Action Llama</title>
|
|
12
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
13
|
-
<script>
|
|
14
|
-
tailwind.config = { darkMode: 'class' };
|
|
15
|
-
</script>
|
|
16
|
-
</head>
|
|
17
|
-
<body class="bg-white dark:bg-slate-950 text-slate-800 dark:text-slate-200 flex items-center justify-center min-h-screen">
|
|
18
|
-
<div class="bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl p-8 w-full max-w-sm mx-4">
|
|
19
|
-
<h1 class="text-2xl font-bold text-slate-900 dark:text-white text-center mb-2">Action Llama</h1>
|
|
20
|
-
<p class="text-slate-500 dark:text-slate-400 text-sm text-center mb-6">Enter your API key to access the dashboard</p>
|
|
21
|
-
${errorHtml}
|
|
22
|
-
<form method="POST" action="/login">
|
|
23
|
-
<label for="key" class="block text-sm text-slate-500 dark:text-slate-400 mb-1.5">API Key</label>
|
|
24
|
-
<input type="password" id="key" name="key" placeholder="Paste your gateway API key" autofocus required
|
|
25
|
-
class="w-full px-3 py-2.5 bg-white dark:bg-slate-950 border border-slate-300 dark:border-slate-700 rounded-lg text-slate-900 dark:text-slate-200 text-sm outline-none focus:border-blue-500 dark:focus:border-blue-400 transition-colors">
|
|
26
|
-
<button type="submit"
|
|
27
|
-
class="w-full mt-4 px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm font-medium transition-colors">
|
|
28
|
-
Log in
|
|
29
|
-
</button>
|
|
30
|
-
</form>
|
|
31
|
-
<p class="text-slate-400 dark:text-slate-500 text-xs text-center mt-4">Key is stored at ~/.action-llama/credentials/gateway_api_key/default/key</p>
|
|
32
|
-
</div>
|
|
33
|
-
<script>
|
|
34
|
-
// Apply saved theme
|
|
35
|
-
var theme = localStorage.getItem('al-theme') || 'dark';
|
|
36
|
-
document.documentElement.classList.toggle('dark', theme === 'dark');
|
|
37
|
-
</script>
|
|
38
|
-
</body>
|
|
39
|
-
</html>`;
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=login-page.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"login-page.js","sourceRoot":"","sources":["../../../src/control/views/login-page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,MAAM,SAAS,GAAG,KAAK;QACrB,CAAC,CAAC,8JAA8J,UAAU,CAAC,KAAK,CAAC,QAAQ;QACzL,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;;;;;;;;;MAeH,SAAS;;;;;;;;;;;;;;;;;;QAkBP,CAAC;AACT,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/control/views/markdown.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA4GtD"}
|