@action-llama/action-llama 0.13.7 → 0.15.0

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.
Files changed (249) hide show
  1. package/agent-docs/AGENTS.md +123 -207
  2. package/dist/agents/container-entry.d.ts +1 -3
  3. package/dist/agents/container-entry.d.ts.map +1 -1
  4. package/dist/agents/container-entry.js +208 -154
  5. package/dist/agents/container-entry.js.map +1 -1
  6. package/dist/agents/container-runner.d.ts.map +1 -1
  7. package/dist/agents/container-runner.js +19 -8
  8. package/dist/agents/container-runner.js.map +1 -1
  9. package/dist/agents/context-injection.d.ts +7 -0
  10. package/dist/agents/context-injection.d.ts.map +1 -0
  11. package/dist/agents/context-injection.js +27 -0
  12. package/dist/agents/context-injection.js.map +1 -0
  13. package/dist/agents/execution-engine.d.ts.map +1 -1
  14. package/dist/agents/execution-engine.js +99 -109
  15. package/dist/agents/execution-engine.js.map +1 -1
  16. package/dist/agents/feedback-monitor.d.ts +56 -0
  17. package/dist/agents/feedback-monitor.d.ts.map +1 -0
  18. package/dist/agents/feedback-monitor.js +176 -0
  19. package/dist/agents/feedback-monitor.js.map +1 -0
  20. package/dist/agents/feedback-runner.d.ts +28 -0
  21. package/dist/agents/feedback-runner.d.ts.map +1 -0
  22. package/dist/agents/feedback-runner.js +138 -0
  23. package/dist/agents/feedback-runner.js.map +1 -0
  24. package/dist/agents/model-fallback.d.ts +18 -0
  25. package/dist/agents/model-fallback.d.ts.map +1 -0
  26. package/dist/agents/model-fallback.js +40 -0
  27. package/dist/agents/model-fallback.js.map +1 -0
  28. package/dist/agents/prompt.d.ts +9 -2
  29. package/dist/agents/prompt.d.ts.map +1 -1
  30. package/dist/agents/prompt.js +21 -49
  31. package/dist/agents/prompt.js.map +1 -1
  32. package/dist/agents/runner.d.ts +6 -0
  33. package/dist/agents/runner.d.ts.map +1 -1
  34. package/dist/agents/runner.js +153 -124
  35. package/dist/agents/runner.js.map +1 -1
  36. package/dist/agents/session-factory.d.ts +13 -0
  37. package/dist/agents/session-factory.d.ts.map +1 -0
  38. package/dist/agents/session-factory.js +27 -0
  39. package/dist/agents/session-factory.js.map +1 -0
  40. package/dist/build-info.json +1 -1
  41. package/dist/cli/commands/agent.d.ts.map +1 -1
  42. package/dist/cli/commands/agent.js +89 -23
  43. package/dist/cli/commands/agent.js.map +1 -1
  44. package/dist/cli/commands/chat.d.ts.map +1 -1
  45. package/dist/cli/commands/chat.js +26 -43
  46. package/dist/cli/commands/chat.js.map +1 -1
  47. package/dist/cli/commands/claude.d.ts +4 -0
  48. package/dist/cli/commands/claude.d.ts.map +1 -0
  49. package/dist/cli/commands/claude.js +8 -0
  50. package/dist/cli/commands/claude.js.map +1 -0
  51. package/dist/cli/commands/doctor.d.ts.map +1 -1
  52. package/dist/cli/commands/doctor.js +24 -6
  53. package/dist/cli/commands/doctor.js.map +1 -1
  54. package/dist/cli/commands/mcp.d.ts +8 -0
  55. package/dist/cli/commands/mcp.d.ts.map +1 -0
  56. package/dist/cli/commands/mcp.js +31 -0
  57. package/dist/cli/commands/mcp.js.map +1 -0
  58. package/dist/cli/commands/new.d.ts.map +1 -1
  59. package/dist/cli/commands/new.js +15 -6
  60. package/dist/cli/commands/new.js.map +1 -1
  61. package/dist/cli/commands/run.js +1 -1
  62. package/dist/cli/commands/run.js.map +1 -1
  63. package/dist/cli/commands/start.js +3 -3
  64. package/dist/cli/commands/start.js.map +1 -1
  65. package/dist/cli/commands/stats.d.ts +9 -0
  66. package/dist/cli/commands/stats.d.ts.map +1 -0
  67. package/dist/cli/commands/stats.js +149 -0
  68. package/dist/cli/commands/stats.js.map +1 -0
  69. package/dist/cli/commands/status.d.ts.map +1 -1
  70. package/dist/cli/commands/status.js +3 -0
  71. package/dist/cli/commands/status.js.map +1 -1
  72. package/dist/cli/main.js +50 -3
  73. package/dist/cli/main.js.map +1 -1
  74. package/dist/gateway/index.d.ts +3 -0
  75. package/dist/gateway/index.d.ts.map +1 -1
  76. package/dist/gateway/index.js +7 -1
  77. package/dist/gateway/index.js.map +1 -1
  78. package/dist/gateway/lock-store.d.ts +10 -0
  79. package/dist/gateway/lock-store.d.ts.map +1 -1
  80. package/dist/gateway/lock-store.js +38 -0
  81. package/dist/gateway/lock-store.js.map +1 -1
  82. package/dist/gateway/routes/control.d.ts +2 -0
  83. package/dist/gateway/routes/control.d.ts.map +1 -1
  84. package/dist/gateway/routes/control.js +56 -0
  85. package/dist/gateway/routes/control.js.map +1 -1
  86. package/dist/gateway/routes/dashboard.d.ts +2 -1
  87. package/dist/gateway/routes/dashboard.d.ts.map +1 -1
  88. package/dist/gateway/routes/dashboard.js +112 -6
  89. package/dist/gateway/routes/dashboard.js.map +1 -1
  90. package/dist/gateway/routes/locks.d.ts.map +1 -1
  91. package/dist/gateway/routes/locks.js +39 -0
  92. package/dist/gateway/routes/locks.js.map +1 -1
  93. package/dist/gateway/routes/logs.d.ts.map +1 -1
  94. package/dist/gateway/routes/logs.js +4 -5
  95. package/dist/gateway/routes/logs.js.map +1 -1
  96. package/dist/gateway/routes/stats.d.ts +4 -0
  97. package/dist/gateway/routes/stats.d.ts.map +1 -0
  98. package/dist/gateway/routes/stats.js +25 -0
  99. package/dist/gateway/routes/stats.js.map +1 -0
  100. package/dist/gateway/views/agent-detail-page.d.ts +14 -0
  101. package/dist/gateway/views/agent-detail-page.d.ts.map +1 -0
  102. package/dist/gateway/views/agent-detail-page.js +416 -0
  103. package/dist/gateway/views/agent-detail-page.js.map +1 -0
  104. package/dist/gateway/views/dashboard-page.d.ts.map +1 -1
  105. package/dist/gateway/views/dashboard-page.js +213 -245
  106. package/dist/gateway/views/dashboard-page.js.map +1 -1
  107. package/dist/gateway/views/instance-detail-page.d.ts +30 -0
  108. package/dist/gateway/views/instance-detail-page.d.ts.map +1 -0
  109. package/dist/gateway/views/instance-detail-page.js +360 -0
  110. package/dist/gateway/views/instance-detail-page.js.map +1 -0
  111. package/dist/gateway/views/layout.d.ts +17 -0
  112. package/dist/gateway/views/layout.d.ts.map +1 -0
  113. package/dist/gateway/views/layout.js +153 -0
  114. package/dist/gateway/views/layout.js.map +1 -0
  115. package/dist/gateway/views/login-page.d.ts.map +1 -1
  116. package/dist/gateway/views/login-page.js +24 -37
  117. package/dist/gateway/views/login-page.js.map +1 -1
  118. package/dist/gateway/views/project-config-page.d.ts +12 -0
  119. package/dist/gateway/views/project-config-page.d.ts.map +1 -0
  120. package/dist/gateway/views/project-config-page.js +199 -0
  121. package/dist/gateway/views/project-config-page.js.map +1 -0
  122. package/dist/hooks/runner.d.ts +12 -0
  123. package/dist/hooks/runner.d.ts.map +1 -0
  124. package/dist/hooks/runner.js +32 -0
  125. package/dist/hooks/runner.js.map +1 -0
  126. package/dist/mcp/server.d.ts +5 -0
  127. package/dist/mcp/server.d.ts.map +1 -0
  128. package/dist/mcp/server.js +336 -0
  129. package/dist/mcp/server.js.map +1 -0
  130. package/dist/scheduler/call-dispatcher.d.ts +2 -2
  131. package/dist/scheduler/call-dispatcher.js +3 -3
  132. package/dist/scheduler/call-dispatcher.js.map +1 -1
  133. package/dist/scheduler/execution.d.ts +5 -2
  134. package/dist/scheduler/execution.d.ts.map +1 -1
  135. package/dist/scheduler/execution.js +75 -4
  136. package/dist/scheduler/execution.js.map +1 -1
  137. package/dist/scheduler/gateway-setup.d.ts +2 -0
  138. package/dist/scheduler/gateway-setup.d.ts.map +1 -1
  139. package/dist/scheduler/gateway-setup.js +21 -2
  140. package/dist/scheduler/gateway-setup.js.map +1 -1
  141. package/dist/scheduler/image-builder.js +3 -3
  142. package/dist/scheduler/image-builder.js.map +1 -1
  143. package/dist/scheduler/index.d.ts.map +1 -1
  144. package/dist/scheduler/index.js +90 -3
  145. package/dist/scheduler/index.js.map +1 -1
  146. package/dist/scheduler/shutdown.d.ts +2 -0
  147. package/dist/scheduler/shutdown.d.ts.map +1 -1
  148. package/dist/scheduler/shutdown.js +4 -1
  149. package/dist/scheduler/shutdown.js.map +1 -1
  150. package/dist/scheduler/validation.d.ts.map +1 -1
  151. package/dist/scheduler/validation.js +5 -3
  152. package/dist/scheduler/validation.js.map +1 -1
  153. package/dist/scheduler/watcher.d.ts +1 -1
  154. package/dist/scheduler/watcher.js +1 -1
  155. package/dist/scheduler/webhook-setup.d.ts +2 -0
  156. package/dist/scheduler/webhook-setup.d.ts.map +1 -1
  157. package/dist/scheduler/webhook-setup.js +2 -0
  158. package/dist/scheduler/webhook-setup.js.map +1 -1
  159. package/dist/setup/prompts.d.ts.map +1 -1
  160. package/dist/setup/prompts.js +35 -6
  161. package/dist/setup/prompts.js.map +1 -1
  162. package/dist/setup/scaffold.d.ts +6 -0
  163. package/dist/setup/scaffold.d.ts.map +1 -1
  164. package/dist/setup/scaffold.js +185 -7
  165. package/dist/setup/scaffold.js.map +1 -1
  166. package/dist/shared/config.d.ts +42 -5
  167. package/dist/shared/config.d.ts.map +1 -1
  168. package/dist/shared/config.js +126 -20
  169. package/dist/shared/config.js.map +1 -1
  170. package/dist/shared/credential-refs.d.ts.map +1 -1
  171. package/dist/shared/credential-refs.js +8 -0
  172. package/dist/shared/credential-refs.js.map +1 -1
  173. package/dist/shared/default-feedback-agent.d.ts +10 -0
  174. package/dist/shared/default-feedback-agent.d.ts.map +1 -0
  175. package/dist/shared/default-feedback-agent.js +114 -0
  176. package/dist/shared/default-feedback-agent.js.map +1 -0
  177. package/dist/shared/environment.d.ts +0 -1
  178. package/dist/shared/environment.d.ts.map +1 -1
  179. package/dist/shared/environment.js +19 -3
  180. package/dist/shared/environment.js.map +1 -1
  181. package/dist/shared/frontmatter.d.ts +11 -0
  182. package/dist/shared/frontmatter.d.ts.map +1 -0
  183. package/dist/shared/frontmatter.js +30 -0
  184. package/dist/shared/frontmatter.js.map +1 -0
  185. package/dist/shared/paths.d.ts +1 -0
  186. package/dist/shared/paths.d.ts.map +1 -1
  187. package/dist/shared/paths.js +3 -0
  188. package/dist/shared/paths.js.map +1 -1
  189. package/dist/shared/usage.d.ts.map +1 -1
  190. package/dist/shared/usage.js +52 -7
  191. package/dist/shared/usage.js.map +1 -1
  192. package/dist/stats/index.d.ts +3 -0
  193. package/dist/stats/index.d.ts.map +1 -0
  194. package/dist/stats/index.js +2 -0
  195. package/dist/stats/index.js.map +1 -0
  196. package/dist/stats/store.d.ts +89 -0
  197. package/dist/stats/store.d.ts.map +1 -0
  198. package/dist/stats/store.js +242 -0
  199. package/dist/stats/store.js.map +1 -0
  200. package/dist/tui/App.d.ts +2 -1
  201. package/dist/tui/App.d.ts.map +1 -1
  202. package/dist/tui/App.js +132 -5
  203. package/dist/tui/App.js.map +1 -1
  204. package/dist/tui/render.d.ts +1 -1
  205. package/dist/tui/render.d.ts.map +1 -1
  206. package/dist/tui/render.js +2 -2
  207. package/dist/tui/render.js.map +1 -1
  208. package/dist/tui/status-tracker.d.ts +18 -1
  209. package/dist/tui/status-tracker.d.ts.map +1 -1
  210. package/dist/tui/status-tracker.js +32 -1
  211. package/dist/tui/status-tracker.js.map +1 -1
  212. package/docker/bin/{al-call → al-subagent} +2 -2
  213. package/docker/bin/{al-check → al-subagent-check} +2 -2
  214. package/docker/bin/{al-wait → al-subagent-wait} +2 -2
  215. package/package.json +8 -21
  216. package/LICENSE +0 -21
  217. package/README.md +0 -192
  218. package/dist/gateway/views/logs-page.d.ts +0 -2
  219. package/dist/gateway/views/logs-page.d.ts.map +0 -1
  220. package/dist/gateway/views/logs-page.js +0 -280
  221. package/dist/gateway/views/logs-page.js.map +0 -1
  222. package/dist/preflight/interpolate.d.ts +0 -10
  223. package/dist/preflight/interpolate.d.ts.map +0 -1
  224. package/dist/preflight/interpolate.js +0 -33
  225. package/dist/preflight/interpolate.js.map +0 -1
  226. package/dist/preflight/providers/git-clone.d.ts +0 -3
  227. package/dist/preflight/providers/git-clone.d.ts.map +0 -1
  228. package/dist/preflight/providers/git-clone.js +0 -36
  229. package/dist/preflight/providers/git-clone.js.map +0 -1
  230. package/dist/preflight/providers/http.d.ts +0 -3
  231. package/dist/preflight/providers/http.d.ts.map +0 -1
  232. package/dist/preflight/providers/http.js +0 -36
  233. package/dist/preflight/providers/http.js.map +0 -1
  234. package/dist/preflight/providers/shell.d.ts +0 -3
  235. package/dist/preflight/providers/shell.d.ts.map +0 -1
  236. package/dist/preflight/providers/shell.js +0 -28
  237. package/dist/preflight/providers/shell.js.map +0 -1
  238. package/dist/preflight/registry.d.ts +0 -4
  239. package/dist/preflight/registry.d.ts.map +0 -1
  240. package/dist/preflight/registry.js +0 -20
  241. package/dist/preflight/registry.js.map +0 -1
  242. package/dist/preflight/runner.d.ts +0 -7
  243. package/dist/preflight/runner.d.ts.map +0 -1
  244. package/dist/preflight/runner.js +0 -28
  245. package/dist/preflight/runner.js.map +0 -1
  246. package/dist/preflight/schema.d.ts +0 -21
  247. package/dist/preflight/schema.d.ts.map +0 -1
  248. package/dist/preflight/schema.js +0 -9
  249. package/dist/preflight/schema.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-page.d.ts","sourceRoot":"","sources":["../../../src/gateway/views/dashboard-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAuFvF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,CAyP7H"}
1
+ {"version":3,"file":"dashboard-page.d.ts","sourceRoot":"","sources":["../../../src/gateway/views/dashboard-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAqGvF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,CAoN7H"}
@@ -1,36 +1,12 @@
1
- function escapeHtml(str) {
2
- return str
3
- .replace(/&/g, "&")
4
- .replace(/</g, "&lt;")
5
- .replace(/>/g, "&gt;")
6
- .replace(/"/g, "&quot;");
7
- }
1
+ import { escapeHtml, formatDuration, formatTime, formatCost, formatTokens, renderLayout } from "./layout.js";
8
2
  function stateColor(state) {
9
3
  switch (state) {
10
- case "running": return "#22c55e";
11
- case "building": return "#eab308";
12
- case "error": return "#ef4444";
13
- case "idle": return "#6b7280";
4
+ case "running": return { dot: "bg-green-500", text: "text-green-600 dark:text-green-400" };
5
+ case "building": return { dot: "bg-yellow-500", text: "text-yellow-600 dark:text-yellow-400" };
6
+ case "error": return { dot: "bg-red-500", text: "text-red-600 dark:text-red-400" };
7
+ case "idle": return { dot: "bg-slate-400", text: "text-slate-500 dark:text-slate-400" };
14
8
  }
15
9
  }
16
- function formatDuration(ms) {
17
- if (ms < 1000)
18
- return `${ms}ms`;
19
- const s = Math.floor(ms / 1000);
20
- if (s < 60)
21
- return `${s}s`;
22
- const m = Math.floor(s / 60);
23
- return `${m}m ${s % 60}s`;
24
- }
25
- function formatTime(date) {
26
- if (!date)
27
- return "\u2014";
28
- return date.toLocaleTimeString();
29
- }
30
- function formatLogLine(log) {
31
- const time = log.timestamp.toLocaleTimeString();
32
- return `<span class="log-time">${escapeHtml(time)}</span> <span class="log-agent">[${escapeHtml(log.agent)}]</span> ${escapeHtml(log.message)}`;
33
- }
34
10
  function formatScale(agent) {
35
11
  if (agent.state === "running" && agent.scale > 1)
36
12
  return `running ${agent.runningCount}/${agent.scale}`;
@@ -38,262 +14,233 @@ function formatScale(agent) {
38
14
  return `${agent.state} (\u00d7${agent.scale})`;
39
15
  return agent.state;
40
16
  }
41
- function renderAgentRow(agent) {
42
- const color = stateColor(agent.state);
43
- const statusText = agent.statusText || agent.lastError || "\u2014";
17
+ function renderStatCard(label, value, id) {
18
+ const idAttr = id ? ` id="${id}"` : "";
19
+ return `<div class="bg-slate-50 dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-3 sm:p-4">
20
+ <div class="text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wide mb-1">${escapeHtml(label)}</div>
21
+ <div class="text-lg sm:text-xl font-semibold text-slate-900 dark:text-white"${idAttr}>${value}</div>
22
+ </div>`;
23
+ }
24
+ function renderTokenBar(agent, totalSessionTokens) {
25
+ const tokens = agent.cumulativeUsage?.totalTokens ?? 0;
26
+ const pct = totalSessionTokens > 0 ? Math.round((tokens / totalSessionTokens) * 100) : 0;
27
+ return `<div class="flex items-center gap-2">
28
+ <div class="flex-1 h-2 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="min-width:60px">
29
+ <div class="h-full bg-blue-500 rounded-full" style="width:${pct}%"></div>
30
+ </div>
31
+ <span class="text-xs text-slate-500 dark:text-slate-400 whitespace-nowrap">${formatTokens(tokens)}</span>
32
+ </div>`;
33
+ }
34
+ function renderAgentRow(agent, totalSessionTokens) {
35
+ const colors = stateColor(agent.state);
44
36
  const toggleLabel = agent.enabled ? "Disable" : "Enable";
45
37
  const toggleAction = agent.enabled ? "disable" : "enable";
46
- return `<tr data-agent="${escapeHtml(agent.name)}">
47
- <td><a href="/dashboard/agents/${escapeHtml(agent.name)}/logs">${escapeHtml(agent.name)}</a></td>
48
- <td><span class="state-dot" style="background:${color}"></span> ${escapeHtml(formatScale(agent))}</td>
49
- <td class="status-text">${escapeHtml(statusText)}</td>
50
- <td>${formatTime(agent.lastRunAt)}</td>
51
- <td>${agent.lastRunDuration != null ? formatDuration(agent.lastRunDuration) : "\u2014"}</td>
52
- <td>${formatTime(agent.nextRunAt)}</td>
53
- <td class="actions">
54
- <button class="btn btn-sm" onclick="triggerAgent('${escapeHtml(agent.name)}')">Run</button>
55
- <button class="btn btn-sm btn-outline" onclick="toggleAgent('${escapeHtml(agent.name)}','${toggleAction}')">${toggleLabel}</button>
38
+ const descHtml = agent.description
39
+ ? `<div class="text-xs text-slate-400 mt-0.5">${escapeHtml(agent.description)}</div>`
40
+ : "";
41
+ return `<tr data-agent="${escapeHtml(agent.name)}" class="hover:bg-slate-50 dark:hover:bg-slate-900/50 transition-colors">
42
+ <td class="px-3 py-2.5">
43
+ <a href="/dashboard/agents/${escapeHtml(agent.name)}" class="text-blue-600 dark:text-blue-400 hover:underline font-medium">${escapeHtml(agent.name)}</a>
44
+ ${descHtml}
45
+ </td>
46
+ <td class="px-3 py-2.5"><span class="state-dot ${colors.dot} mr-1.5 inline-block"></span><span class="${colors.text} text-sm">${escapeHtml(formatScale(agent))}</span></td>
47
+ <td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">${formatTime(agent.lastRunAt)}</td>
48
+ <td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">${agent.lastRunDuration != null ? formatDuration(agent.lastRunDuration) : "\u2014"}</td>
49
+ <td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">${formatTime(agent.nextRunAt)}</td>
50
+ <td class="px-3 py-2.5" style="min-width:120px">${renderTokenBar(agent, totalSessionTokens)}</td>
51
+ <td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">${agent.locks && agent.locks.length > 0 ? agent.locks.map(l => escapeHtml(l.resourceKey.replace(/^[^:]+:\/\//, ""))).join(", ") : "\u2014"}</td>
52
+ <td class="px-3 py-2.5 whitespace-nowrap">
53
+ <button class="px-2 py-1 text-xs rounded font-bold bg-green-600 hover:bg-green-700 text-white transition-colors mr-1" onclick="triggerAgent('${escapeHtml(agent.name)}')">Run</button>
54
+ <button class="px-2 py-1 text-xs rounded font-bold bg-red-600 hover:bg-red-700 text-white transition-colors mr-1" onclick="killAgent('${escapeHtml(agent.name)}')">Kill</button>
55
+ <button class="px-2 py-1 text-xs rounded font-bold 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" onclick="toggleAgent('${escapeHtml(agent.name)}','${toggleAction}')">${toggleLabel}</button>
56
56
  </td>
57
57
  </tr>`;
58
58
  }
59
59
  function renderAgentCard(agent) {
60
- const color = stateColor(agent.state);
61
- const statusText = agent.statusText || agent.lastError || "\u2014";
60
+ const colors = stateColor(agent.state);
62
61
  const toggleLabel = agent.enabled ? "Disable" : "Enable";
63
62
  const toggleAction = agent.enabled ? "disable" : "enable";
64
- return `<div class="agent-card">
65
- <a href="/dashboard/agents/${escapeHtml(agent.name)}/logs" class="card-link">
66
- <div class="card-header">
67
- <span class="card-name">${escapeHtml(agent.name)}</span>
68
- <span><span class="state-dot" style="background:${color}"></span>${escapeHtml(formatScale(agent))}</span>
63
+ const descHtml = agent.description
64
+ ? `<div class="text-xs text-slate-400 mb-1">${escapeHtml(agent.description)}</div>`
65
+ : "";
66
+ return `<div class="bg-white dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-3 mb-2">
67
+ <a href="/dashboard/agents/${escapeHtml(agent.name)}" class="block">
68
+ <div class="flex justify-between items-center mb-1">
69
+ <span class="text-blue-600 dark:text-blue-400 font-semibold text-sm">${escapeHtml(agent.name)}</span>
70
+ <span class="text-xs ${colors.text}"><span class="state-dot ${colors.dot} mr-1 inline-block"></span>${escapeHtml(formatScale(agent))}</span>
69
71
  </div>
70
- <div class="card-status">${escapeHtml(statusText)}</div>
71
- <div class="card-meta">
72
+ ${descHtml}
73
+ <div class="flex gap-3 text-xs text-slate-400">
72
74
  <span>Last: ${formatTime(agent.lastRunAt)}</span>
73
75
  <span>${agent.lastRunDuration != null ? formatDuration(agent.lastRunDuration) : ""}</span>
74
76
  <span>Next: ${formatTime(agent.nextRunAt)}</span>
75
77
  </div>
76
78
  </a>
77
- <div class="card-actions">
78
- <button class="btn btn-sm" onclick="triggerAgent('${escapeHtml(agent.name)}')">Run</button>
79
- <button class="btn btn-sm btn-outline" onclick="toggleAgent('${escapeHtml(agent.name)}','${toggleAction}')">${toggleLabel}</button>
79
+ <div class="flex gap-2 mt-2 pt-2 border-t border-slate-100 dark:border-slate-800">
80
+ <button class="px-2.5 py-1 text-xs rounded font-bold bg-green-600 hover:bg-green-700 text-white transition-colors" onclick="triggerAgent('${escapeHtml(agent.name)}')">Run</button>
81
+ <button class="px-2.5 py-1 text-xs rounded font-bold bg-red-600 hover:bg-red-700 text-white transition-colors" onclick="killAgent('${escapeHtml(agent.name)}')">Kill</button>
82
+ <button class="px-2.5 py-1 text-xs rounded font-bold 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" onclick="toggleAgent('${escapeHtml(agent.name)}','${toggleAction}')">${toggleLabel}</button>
80
83
  </div>
81
84
  </div>`;
82
85
  }
86
+ function formatLogLine(log) {
87
+ const time = log.timestamp.toLocaleTimeString();
88
+ return `<span class="text-slate-400">${escapeHtml(time)}</span> <span class="text-indigo-400">[${escapeHtml(log.agent)}]</span> ${escapeHtml(log.message)}`;
89
+ }
83
90
  export function renderDashboardPage(agents, schedulerInfo, recentLogs) {
84
- const mode = schedulerInfo?.mode || "host";
85
- const runtime = schedulerInfo?.runtime || "\u2014";
86
- const uptime = schedulerInfo ? formatDuration(Date.now() - schedulerInfo.startedAt.getTime()) : "\u2014";
87
- const cronCount = schedulerInfo?.cronJobCount || 0;
88
- const webhooks = schedulerInfo?.webhooksActive ? "active" : "inactive";
89
- return `<!DOCTYPE html>
90
- <html lang="en">
91
- <head>
92
- <meta charset="utf-8">
93
- <meta name="viewport" content="width=device-width, initial-scale=1">
94
- <title>Action Llama Dashboard</title>
95
- <style>
96
- * { margin: 0; padding: 0; box-sizing: border-box; }
97
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: #0f172a; color: #e2e8f0; padding: 16px; }
98
- h1 { font-size: 1.5rem; margin-bottom: 8px; color: #f8fafc; }
99
- .header { display: flex; align-items: baseline; gap: 12px 20px; margin-bottom: 24px; flex-wrap: wrap; }
100
- .header-stat { font-size: 0.85rem; color: #94a3b8; white-space: nowrap; }
101
- .header-stat strong { color: #cbd5e1; }
102
-
103
- /* Desktop table */
104
- .agent-table { width: 100%; border-collapse: collapse; margin-bottom: 32px; }
105
- .agent-table th { text-align: left; padding: 8px 12px; border-bottom: 2px solid #334155; color: #94a3b8; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
106
- .agent-table td { padding: 8px 12px; border-bottom: 1px solid #1e293b; font-size: 0.9rem; }
107
- .agent-table td a { color: #60a5fa; text-decoration: none; }
108
- .agent-table td a:hover { text-decoration: underline; }
109
- .agent-table tr:hover { background: #1e293b; }
110
- .status-text { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #94a3b8; }
111
-
112
- /* Mobile cards (hidden on desktop) */
113
- .agent-cards { display: none; margin-bottom: 24px; }
114
- .agent-card { display: block; background: #1e293b; border-radius: 8px; padding: 12px 16px; margin-bottom: 8px; text-decoration: none; color: #e2e8f0; border: 1px solid #334155; }
115
- .agent-card:active { background: #334155; }
116
- .card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
117
- .card-name { color: #60a5fa; font-weight: 600; font-size: 0.95rem; }
118
- .card-status { color: #94a3b8; font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 6px; }
119
- .card-meta { display: flex; gap: 12px; font-size: 0.75rem; color: #64748b; flex-wrap: wrap; }
120
-
121
- .state-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
122
-
123
- h2 { font-size: 1.1rem; margin-bottom: 12px; color: #f8fafc; }
124
- .logs { background: #1e293b; border-radius: 8px; padding: 12px; font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.75rem; line-height: 1.6; max-height: 300px; overflow-y: auto; }
125
- .log-line { white-space: pre-wrap; word-break: break-all; }
126
- .log-time { color: #64748b; }
127
- .log-agent { color: #818cf8; }
128
- .empty { color: #475569; font-style: italic; }
129
-
130
- .btn { background: #334155; color: #e2e8f0; border: 1px solid #475569; border-radius: 4px; padding: 4px 10px; font-size: 0.75rem; cursor: pointer; transition: background 0.15s; }
131
- .btn:hover { background: #475569; }
132
- .btn-sm { padding: 3px 8px; font-size: 0.7rem; }
133
- .btn-outline { background: transparent; }
134
- .btn-outline:hover { background: #1e293b; }
135
- .btn-primary { background: #3b82f6; border-color: #3b82f6; color: #fff; }
136
- .btn-primary:hover { background: #2563eb; }
137
- .actions { white-space: nowrap; }
138
- .actions button { margin-right: 4px; }
139
- .card-actions { display: flex; gap: 6px; margin-top: 8px; }
140
- .card-link { display: block; text-decoration: none; color: #e2e8f0; }
141
- .header-actions { display: flex; gap: 8px; align-items: center; margin-left: auto; }
142
- .header-actions a { color: #94a3b8; font-size: 0.85rem; text-decoration: none; }
143
- .header-actions a:hover { color: #e2e8f0; }
144
-
145
- @media (max-width: 640px) {
146
- body { padding: 12px; }
147
- h1 { font-size: 1.25rem; }
148
- .header { gap: 6px 14px; margin-bottom: 16px; }
149
- .header-stat { font-size: 0.75rem; }
150
- .agent-table { display: none; }
151
- .agent-cards { display: block; }
152
- .logs { font-size: 0.7rem; padding: 10px; max-height: 250px; }
153
- }
154
-
155
- @media (min-width: 641px) {
156
- body { padding: 24px; }
157
- .logs { font-size: 0.8rem; padding: 16px; }
158
- }
159
- </style>
160
- </head>
161
- <body>
162
- <div class="header">
163
- <h1>Action Llama</h1>
164
- <span class="header-stat">Mode: <strong>${escapeHtml(mode)}</strong></span>
165
- <span class="header-stat">Runtime: <strong>${escapeHtml(runtime)}</strong></span>
166
- <span class="header-stat">Agents: <strong>${agents.length}</strong></span>
167
- <span class="header-stat">Cron: <strong>${cronCount}</strong></span>
168
- <span class="header-stat">Webhooks: <strong>${escapeHtml(webhooks)}</strong></span>
169
- <span class="header-stat">Uptime: <strong id="uptime">${escapeHtml(uptime)}</strong></span>
170
- <span class="header-actions">
171
- <button id="pause-btn" class="btn btn-sm" onclick="togglePause()">${schedulerInfo?.paused ? "Resume" : "Pause"}</button>
172
- <a href="#" onclick="doLogout(); return false;">Logout</a>
173
- </span>
174
- </div>
91
+ const sessionTokens = agents.reduce((sum, a) => sum + (a.cumulativeUsage?.totalTokens ?? 0), 0);
92
+ const sessionCost = agents.reduce((sum, a) => sum + (a.cumulativeUsage?.cost ?? 0), 0);
93
+ const content = `
94
+ <div class="flex flex-wrap items-center justify-between gap-3 mb-6">
95
+ <h1 class="text-xl sm:text-2xl font-bold text-slate-900 dark:text-white">Dashboard</h1>
96
+ <div class="flex items-center gap-2">
97
+ <a href="/dashboard/config" class="px-3 py-1.5 text-sm rounded-md font-bold 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">Config</a>
98
+ <button id="pause-btn" class="px-3 py-1.5 text-sm rounded-md font-bold border border-yellow-500 bg-yellow-500 hover:bg-yellow-600 text-white transition-colors" onclick="togglePause()">${schedulerInfo?.paused ? "Resume" : "Pause"}</button>
99
+ </div>
100
+ </div>
175
101
 
176
- <table class="agent-table">
177
- <thead>
178
- <tr>
179
- <th>Agent</th>
180
- <th>State</th>
181
- <th>Status</th>
182
- <th>Last Run</th>
183
- <th>Duration</th>
184
- <th>Next Run</th>
185
- <th>Actions</th>
186
- </tr>
187
- </thead>
188
- <tbody id="agent-table-body">
189
- ${agents.length > 0 ? agents.map(renderAgentRow).join("\n ") : '<tr><td colspan="7" class="empty">No agents registered</td></tr>'}
190
- </tbody>
191
- </table>
102
+ <div class="grid grid-cols-2 gap-3 mb-6">
103
+ ${renderStatCard("Session Tokens", formatTokens(sessionTokens), "stat-tokens")}
104
+ ${renderStatCard("Session Cost", formatCost(sessionCost), "stat-cost")}
105
+ </div>
192
106
 
193
- <div class="agent-cards" id="agent-cards">
194
- ${agents.length > 0 ? agents.map(renderAgentCard).join("\n ") : '<div class="empty">No agents registered</div>'}
195
- </div>
107
+ <!-- Desktop table -->
108
+ <div class="hidden sm:block mb-8">
109
+ <table class="w-full">
110
+ <thead>
111
+ <tr class="border-b-2 border-slate-200 dark:border-slate-700">
112
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Agent</th>
113
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">State</th>
114
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Last Run</th>
115
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Duration</th>
116
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Next Run</th>
117
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Tokens Used</th>
118
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Locks</th>
119
+ <th class="text-left px-3 py-2 text-xs text-slate-500 dark:text-slate-400 uppercase tracking-wider font-medium">Actions</th>
120
+ </tr>
121
+ </thead>
122
+ <tbody id="agent-table-body" class="divide-y divide-slate-100 dark:divide-slate-800">
123
+ ${agents.length > 0 ? agents.map((a) => renderAgentRow(a, sessionTokens)).join("\n") : '<tr><td colspan="8" class="px-3 py-8 text-center text-slate-400 italic">No agents registered</td></tr>'}
124
+ </tbody>
125
+ </table>
126
+ </div>
196
127
 
197
- <h2>Recent Activity</h2>
198
- <div class="logs" id="recent-logs">
199
- ${recentLogs.length > 0 ? recentLogs.map((l) => `<div class="log-line">${formatLogLine(l)}</div>`).join("\n ") : '<div class="empty">No recent activity</div>'}
200
- </div>
128
+ <!-- Mobile cards -->
129
+ <div class="sm:hidden mb-6" id="agent-cards">
130
+ ${agents.length > 0 ? agents.map(renderAgentCard).join("\n") : '<div class="text-slate-400 italic text-center py-6">No agents registered</div>'}
131
+ </div>
201
132
 
202
- <script>
203
- const stateColors = { running: "#22c55e", building: "#eab308", error: "#ef4444", idle: "#6b7280" };
133
+ <h2 class="text-base font-semibold text-slate-900 dark:text-white mb-3">Recent Activity</h2>
134
+ <div 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 max-h-72 overflow-y-auto scrollbar-thin" id="recent-logs">
135
+ ${recentLogs.length > 0 ? recentLogs.map((l) => `<div class="whitespace-pre-wrap break-all">${formatLogLine(l)}</div>`).join("\n") : '<div class="text-slate-400 italic">No recent activity</div>'}
136
+ </div>`;
137
+ const scripts = `<script>
138
+ var stateColors = { running: "bg-green-500", building: "bg-yellow-500", error: "bg-red-500", idle: "bg-slate-400" };
139
+ var stateTextColors = { running: "text-green-600 dark:text-green-400", building: "text-yellow-600 dark:text-yellow-400", error: "text-red-600 dark:text-red-400", idle: "text-slate-500 dark:text-slate-400" };
204
140
 
205
- function esc(s) { const d = document.createElement("div"); d.textContent = s; return d.innerHTML; }
141
+ function fmtScale(a) {
142
+ if (a.state === "running" && a.scale > 1) return "running " + a.runningCount + "/" + a.scale;
143
+ if (a.scale > 1) return a.state + " (\\u00d7" + a.scale + ")";
144
+ return a.state;
145
+ }
206
146
 
207
- function fmtDur(ms) {
208
- if (ms < 1000) return ms + "ms";
209
- const s = Math.floor(ms / 1000);
210
- if (s < 60) return s + "s";
211
- return Math.floor(s / 60) + "m " + (s % 60) + "s";
147
+ function sessionTotalTokens(agents) {
148
+ var total = 0;
149
+ for (var i = 0; i < agents.length; i++) {
150
+ if (agents[i].cumulativeUsage) total += agents[i].cumulativeUsage.totalTokens || 0;
151
+ }
152
+ return total;
212
153
  }
213
154
 
214
- function fmtTime(iso) {
215
- if (!iso) return "\\u2014";
216
- return new Date(iso).toLocaleTimeString();
155
+ function sessionTotalCost(agents) {
156
+ var total = 0;
157
+ for (var i = 0; i < agents.length; i++) {
158
+ if (agents[i].cumulativeUsage) total += agents[i].cumulativeUsage.cost || 0;
159
+ }
160
+ return total;
217
161
  }
218
162
 
219
- function fmtScale(a) {
220
- if (a.state === "running" && a.scale > 1) return "running " + a.runningCount + "/" + a.scale;
221
- if (a.scale > 1) return a.state + " (\\u00d7" + a.scale + ")";
222
- return a.state;
163
+ function tokenBar(a, totalTokens) {
164
+ var tokens = (a.cumulativeUsage && a.cumulativeUsage.totalTokens) || 0;
165
+ var pct = totalTokens > 0 ? Math.round((tokens / totalTokens) * 100) : 0;
166
+ return '<div class="flex items-center gap-2">' +
167
+ '<div class="flex-1 h-2 bg-slate-200 dark:bg-slate-700 rounded-full overflow-hidden" style="min-width:60px">' +
168
+ '<div class="h-full bg-blue-500 rounded-full" style="width:' + pct + '%"></div></div>' +
169
+ '<span class="text-xs text-slate-500 dark:text-slate-400 whitespace-nowrap">' + fmtTokens(tokens) + '</span></div>';
223
170
  }
224
171
 
172
+ var _cachedAgents = null;
173
+
225
174
  function renderRow(a) {
226
- const color = stateColors[a.state] || "#6b7280";
227
- const status = a.statusText || a.lastError || "\\u2014";
228
- const toggleLabel = a.enabled ? "Disable" : "Enable";
229
- const toggleAction = a.enabled ? "disable" : "enable";
230
- return '<tr data-agent="' + esc(a.name) + '">' +
231
- '<td><a href="/dashboard/agents/' + esc(a.name) + '/logs">' + esc(a.name) + '</a></td>' +
232
- '<td><span class="state-dot" style="background:' + color + '"></span> ' + esc(fmtScale(a)) + '</td>' +
233
- '<td class="status-text">' + esc(status) + '</td>' +
234
- '<td>' + fmtTime(a.lastRunAt) + '</td>' +
235
- '<td>' + (a.lastRunDuration != null ? fmtDur(a.lastRunDuration) : "\\u2014") + '</td>' +
236
- '<td>' + fmtTime(a.nextRunAt) + '</td>' +
237
- '<td class="actions"><button class="btn btn-sm" onclick="triggerAgent(\\'' + esc(a.name) + '\\')">Run</button>' +
238
- '<button class="btn btn-sm btn-outline" onclick="toggleAgent(\\'' + esc(a.name) + '\\',\\'' + toggleAction + '\\')">' + toggleLabel + '</button></td>' +
239
- '</tr>';
175
+ var dotClass = stateColors[a.state] || "bg-slate-400";
176
+ var textClass = stateTextColors[a.state] || "text-slate-400";
177
+ var toggleLabel = a.enabled ? "Disable" : "Enable";
178
+ var toggleAction = a.enabled ? "disable" : "enable";
179
+ var totalTok = _cachedAgents ? sessionTotalTokens(_cachedAgents) : 0;
180
+ return '<tr data-agent="' + esc(a.name) + '" class="hover:bg-slate-50 dark:hover:bg-slate-900/50 transition-colors">' +
181
+ '<td class="px-3 py-2.5"><a href="/dashboard/agents/' + esc(a.name) + '" class="text-blue-600 dark:text-blue-400 hover:underline font-medium">' + esc(a.name) + '</a></td>' +
182
+ '<td class="px-3 py-2.5"><span class="state-dot ' + dotClass + ' mr-1.5 inline-block"></span><span class="' + textClass + ' text-sm">' + esc(fmtScale(a)) + '</span></td>' +
183
+ '<td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">' + fmtTime(a.lastRunAt) + '</td>' +
184
+ '<td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">' + (a.lastRunDuration != null ? fmtDur(a.lastRunDuration) : "\\u2014") + '</td>' +
185
+ '<td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">' + fmtTime(a.nextRunAt) + '</td>' +
186
+ '<td class="px-3 py-2.5" style="min-width:120px">' + tokenBar(a, totalTok) + '</td>' +
187
+ '<td class="px-3 py-2.5 text-sm text-slate-600 dark:text-slate-300">' + (a.locks && a.locks.length > 0 ? a.locks.map(function(l) { return esc(l.resourceKey.replace(/^[^:]+:\\/\\//, "")); }).join(", ") : "\\u2014") + '</td>' +
188
+ '<td class="px-3 py-2.5 whitespace-nowrap">' +
189
+ '<button class="px-2 py-1 text-xs rounded font-bold bg-green-600 hover:bg-green-700 text-white transition-colors mr-1" onclick="triggerAgent(\\'' + esc(a.name) + '\\')">Run</button>' +
190
+ '<button class="px-2 py-1 text-xs rounded font-bold bg-red-600 hover:bg-red-700 text-white transition-colors mr-1" onclick="killAgent(\\'' + esc(a.name) + '\\')">Kill</button>' +
191
+ '<button class="px-2 py-1 text-xs rounded font-bold 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" onclick="toggleAgent(\\'' + esc(a.name) + '\\',\\'' + toggleAction + '\\')">' + toggleLabel + '</button></td></tr>';
240
192
  }
241
193
 
242
194
  function renderCard(a) {
243
- const color = stateColors[a.state] || "#6b7280";
244
- const status = a.statusText || a.lastError || "\\u2014";
245
- const toggleLabel = a.enabled ? "Disable" : "Enable";
246
- const toggleAction = a.enabled ? "disable" : "enable";
247
- return '<div class="agent-card"><a href="/dashboard/agents/' + esc(a.name) + '/logs" class="card-link">' +
248
- '<div class="card-header"><span class="card-name">' + esc(a.name) + '</span>' +
249
- '<span><span class="state-dot" style="background:' + color + '"></span>' + esc(fmtScale(a)) + '</span></div>' +
250
- '<div class="card-status">' + esc(status) + '</div>' +
251
- '<div class="card-meta"><span>Last: ' + fmtTime(a.lastRunAt) + '</span>' +
252
- '<span>' + (a.lastRunDuration != null ? fmtDur(a.lastRunDuration) : "") + '</span>' +
253
- '<span>Next: ' + fmtTime(a.nextRunAt) + '</span></div></a>' +
254
- '<div class="card-actions"><button class="btn btn-sm" onclick="triggerAgent(\\'' + esc(a.name) + '\\')">Run</button>' +
255
- '<button class="btn btn-sm btn-outline" onclick="toggleAgent(\\'' + esc(a.name) + '\\',\\'' + toggleAction + '\\')">' + toggleLabel + '</button></div></div>';
195
+ var dotClass = stateColors[a.state] || "bg-slate-400";
196
+ var textClass = stateTextColors[a.state] || "text-slate-400";
197
+ var toggleLabel = a.enabled ? "Disable" : "Enable";
198
+ var toggleAction = a.enabled ? "disable" : "enable";
199
+ return '<div class="bg-white dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 p-3 mb-2">' +
200
+ '<a href="/dashboard/agents/' + esc(a.name) + '" class="block">' +
201
+ '<div class="flex justify-between items-center mb-1"><span class="text-blue-600 dark:text-blue-400 font-semibold text-sm">' + esc(a.name) + '</span>' +
202
+ '<span class="text-xs ' + textClass + '"><span class="state-dot ' + dotClass + ' mr-1 inline-block"></span>' + esc(fmtScale(a)) + '</span></div>' +
203
+ '<div class="flex gap-3 text-xs text-slate-400"><span>Last: ' + fmtTime(a.lastRunAt) + '</span><span>' + (a.lastRunDuration != null ? fmtDur(a.lastRunDuration) : "") + '</span><span>Next: ' + fmtTime(a.nextRunAt) + '</span></div></a>' +
204
+ '<div class="flex gap-2 mt-2 pt-2 border-t border-slate-100 dark:border-slate-800">' +
205
+ '<button class="px-2.5 py-1 text-xs rounded font-bold bg-green-600 hover:bg-green-700 text-white transition-colors" onclick="triggerAgent(\\'' + esc(a.name) + '\\')">Run</button>' +
206
+ '<button class="px-2.5 py-1 text-xs rounded font-bold bg-red-600 hover:bg-red-700 text-white transition-colors" onclick="killAgent(\\'' + esc(a.name) + '\\')">Kill</button>' +
207
+ '<button class="px-2.5 py-1 text-xs rounded font-bold 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" onclick="toggleAgent(\\'' + esc(a.name) + '\\',\\'' + toggleAction + '\\')">' + toggleLabel + '</button></div></div>';
256
208
  }
257
209
 
258
210
  function renderLog(l) {
259
- const t = new Date(l.timestamp).toLocaleTimeString();
260
- return '<div class="log-line"><span class="log-time">' + esc(t) + '</span> <span class="log-agent">[' + esc(l.agent) + ']</span> ' + esc(l.message) + '</div>';
211
+ var t = new Date(l.timestamp).toLocaleTimeString();
212
+ return '<div class="whitespace-pre-wrap break-all"><span class="text-slate-400">' + esc(t) + '</span> <span class="text-indigo-400">[' + esc(l.agent) + ']</span> ' + esc(l.message) + '</div>';
261
213
  }
262
214
 
263
- const es = new EventSource("/dashboard/api/status-stream");
215
+ var es = new EventSource("/dashboard/api/status-stream");
264
216
  es.onmessage = function(e) {
265
- const data = JSON.parse(e.data);
266
-
217
+ var data = JSON.parse(e.data);
267
218
  if (data.agents) {
268
- // Update desktop table
269
- const tbody = document.getElementById("agent-table-body");
219
+ _cachedAgents = data.agents;
220
+ var tbody = document.getElementById("agent-table-body");
270
221
  if (data.agents.length > 0) {
271
222
  tbody.innerHTML = data.agents.map(renderRow).join("");
272
223
  } else {
273
- tbody.innerHTML = '<tr><td colspan="7" class="empty">No agents registered</td></tr>';
224
+ tbody.innerHTML = '<tr><td colspan="8" class="px-3 py-8 text-center text-slate-400 italic">No agents registered</td></tr>';
274
225
  }
275
-
276
- // Update mobile cards
277
- const cards = document.getElementById("agent-cards");
226
+ var cards = document.getElementById("agent-cards");
278
227
  if (data.agents.length > 0) {
279
228
  cards.innerHTML = data.agents.map(renderCard).join("");
280
229
  } else {
281
- cards.innerHTML = '<div class="empty">No agents registered</div>';
230
+ cards.innerHTML = '<div class="text-slate-400 italic text-center py-6">No agents registered</div>';
282
231
  }
232
+ // Update session stats
233
+ var tokEl = document.getElementById("stat-tokens");
234
+ var costEl = document.getElementById("stat-cost");
235
+ if (tokEl) tokEl.textContent = fmtTokens(sessionTotalTokens(data.agents));
236
+ if (costEl) costEl.textContent = fmtCost(sessionTotalCost(data.agents));
283
237
  }
284
-
285
- // Update recent logs
286
- const logsDiv = document.getElementById("recent-logs");
287
238
  if (data.recentLogs && data.recentLogs.length > 0) {
239
+ var logsDiv = document.getElementById("recent-logs");
288
240
  logsDiv.innerHTML = data.recentLogs.map(renderLog).join("");
289
241
  logsDiv.scrollTop = logsDiv.scrollHeight;
290
242
  }
291
-
292
- // Update uptime and pause button
293
243
  if (data.schedulerInfo) {
294
- if (data.schedulerInfo.startedAt) {
295
- document.getElementById("uptime").textContent = fmtDur(Date.now() - new Date(data.schedulerInfo.startedAt).getTime());
296
- }
297
244
  var btn = document.getElementById("pause-btn");
298
245
  if (btn) {
299
246
  schedulerPaused = !!data.schedulerInfo.paused;
@@ -302,31 +249,52 @@ export function renderDashboardPage(agents, schedulerInfo, recentLogs) {
302
249
  }
303
250
  };
304
251
 
305
- var schedulerPaused = ${schedulerInfo?.paused ? "true" : "false"};
306
-
307
- function ctrlPost(path) {
308
- return fetch(path, { method: "POST", credentials: "same-origin" }).then(function(r) { return r.json(); });
252
+ // Fetch locks periodically
253
+ async function fetchLocks() {
254
+ try {
255
+ var res = await fetch("/dashboard/api/locks");
256
+ if (res.ok) {
257
+ var data = await res.json();
258
+ if (data.locks && _cachedAgents) {
259
+ // Group locks by agent
260
+ var locksByAgent = {};
261
+ for (var i = 0; i < data.locks.length; i++) {
262
+ var lock = data.locks[i];
263
+ if (!locksByAgent[lock.agentName]) locksByAgent[lock.agentName] = [];
264
+ locksByAgent[lock.agentName].push(lock);
265
+ }
266
+ // Update agent locks
267
+ for (var j = 0; j < _cachedAgents.length; j++) {
268
+ _cachedAgents[j].locks = locksByAgent[_cachedAgents[j].name] || [];
269
+ }
270
+ // Re-render table
271
+ var tbody = document.getElementById("agent-table-body");
272
+ if (_cachedAgents.length > 0) {
273
+ tbody.innerHTML = _cachedAgents.map(renderRow).join("");
274
+ }
275
+ }
276
+ }
277
+ } catch(e) {}
309
278
  }
279
+ setInterval(fetchLocks, 2000);
280
+ fetchLocks(); // Initial fetch
281
+
282
+ var schedulerPaused = ${schedulerInfo?.paused ? "true" : "false"};
310
283
 
311
284
  function triggerAgent(name) {
312
285
  ctrlPost("/control/trigger/" + encodeURIComponent(name));
313
286
  }
314
-
315
287
  function toggleAgent(name, action) {
316
288
  ctrlPost("/control/agents/" + encodeURIComponent(name) + "/" + action);
317
289
  }
318
-
290
+ function killAgent(name) {
291
+ if (!confirm("Kill all instances of agent '" + name + "'?")) return;
292
+ ctrlPost("/control/agents/" + encodeURIComponent(name) + "/kill");
293
+ }
319
294
  function togglePause() {
320
295
  ctrlPost(schedulerPaused ? "/control/resume" : "/control/pause");
321
296
  }
322
-
323
- function doLogout() {
324
- fetch("/logout", { method: "POST", credentials: "same-origin" }).then(function() {
325
- window.location.href = "/login";
326
- });
327
- }
328
- </script>
329
- </body>
330
- </html>`;
297
+ </script>`;
298
+ return renderLayout({ title: "Dashboard", content, scripts });
331
299
  }
332
300
  //# sourceMappingURL=dashboard-page.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-page.js","sourceRoot":"","sources":["../../../src/gateway/views/dashboard-page.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashboard-page.js","sourceRoot":"","sources":["../../../src/gateway/views/dashboard-page.ts"],"names":[],"mappings":"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"}