@chrysb/alphaclaw 0.8.1 → 0.8.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.
Files changed (209) hide show
  1. package/README.md +32 -24
  2. package/bin/alphaclaw.js +13 -2
  3. package/lib/public/css/tailwind.generated.css +1 -0
  4. package/lib/public/css/tailwind.input.css +3 -0
  5. package/lib/public/css/theme.css +28 -0
  6. package/lib/public/css/vendor/xterm.css +218 -0
  7. package/lib/public/dist/app.bundle.js +10514 -0
  8. package/lib/public/dist/chunks/addon-fit-W4YZGRNV.js +1 -0
  9. package/lib/public/dist/chunks/chunk-72ZECFVW.js +1 -0
  10. package/lib/public/dist/chunks/xterm-KOX4YMOF.js +9 -0
  11. package/lib/public/js/app.js +4 -4
  12. package/lib/public/js/components/action-button.js +8 -8
  13. package/lib/public/js/components/add-channel-menu.js +2 -2
  14. package/lib/public/js/components/agent-send-modal.js +6 -6
  15. package/lib/public/js/components/agents-tab/agent-bindings-section/channel-item-trailing.js +7 -7
  16. package/lib/public/js/components/agents-tab/agent-bindings-section/index.js +3 -3
  17. package/lib/public/js/components/agents-tab/agent-bindings-section/use-agent-bindings.js +1 -1
  18. package/lib/public/js/components/agents-tab/agent-bindings-section/use-channel-items.js +4 -4
  19. package/lib/public/js/components/agents-tab/agent-detail-panel.js +5 -5
  20. package/lib/public/js/components/agents-tab/agent-identity-section.js +18 -18
  21. package/lib/public/js/components/agents-tab/agent-overview/index.js +2 -2
  22. package/lib/public/js/components/agents-tab/agent-overview/manage-card.js +2 -2
  23. package/lib/public/js/components/agents-tab/agent-overview/model-card.js +8 -8
  24. package/lib/public/js/components/agents-tab/agent-overview/tools-card.js +5 -5
  25. package/lib/public/js/components/agents-tab/agent-overview/use-model-card.js +1 -1
  26. package/lib/public/js/components/agents-tab/agent-overview/use-workspace-card.js +1 -1
  27. package/lib/public/js/components/agents-tab/agent-overview/workspace-card.js +4 -4
  28. package/lib/public/js/components/agents-tab/agent-pairing-section.js +4 -4
  29. package/lib/public/js/components/agents-tab/agent-tools/index.js +5 -5
  30. package/lib/public/js/components/agents-tab/agent-tools/use-agent-tools.js +1 -1
  31. package/lib/public/js/components/agents-tab/create-agent-modal.js +13 -13
  32. package/lib/public/js/components/agents-tab/create-channel-modal.js +34 -34
  33. package/lib/public/js/components/agents-tab/delete-agent-dialog.js +3 -3
  34. package/lib/public/js/components/agents-tab/edit-agent-modal.js +9 -9
  35. package/lib/public/js/components/agents-tab/index.js +3 -3
  36. package/lib/public/js/components/agents-tab/use-agents.js +1 -1
  37. package/lib/public/js/components/badge.js +6 -6
  38. package/lib/public/js/components/channel-account-status-badge.js +2 -2
  39. package/lib/public/js/components/channel-operations-panel.js +2 -2
  40. package/lib/public/js/components/channels.js +9 -9
  41. package/lib/public/js/components/confirm-dialog.js +5 -5
  42. package/lib/public/js/components/credentials-modal.js +22 -22
  43. package/lib/public/js/components/cron-tab/cron-calendar.js +6 -6
  44. package/lib/public/js/components/cron-tab/cron-insights-panel.js +10 -10
  45. package/lib/public/js/components/cron-tab/cron-job-detail.js +4 -4
  46. package/lib/public/js/components/cron-tab/cron-job-list.js +4 -4
  47. package/lib/public/js/components/cron-tab/cron-job-settings-card.js +15 -15
  48. package/lib/public/js/components/cron-tab/cron-job-trends-panel.js +5 -5
  49. package/lib/public/js/components/cron-tab/cron-job-usage.js +16 -16
  50. package/lib/public/js/components/cron-tab/cron-overview.js +10 -10
  51. package/lib/public/js/components/cron-tab/cron-prompt-editor.js +3 -3
  52. package/lib/public/js/components/cron-tab/cron-run-history-panel.js +39 -39
  53. package/lib/public/js/components/cron-tab/cron-runs-trend-card.js +4 -4
  54. package/lib/public/js/components/cron-tab/index.js +5 -5
  55. package/lib/public/js/components/cron-tab/use-cron-tab.js +1 -1
  56. package/lib/public/js/components/device-pairings.js +12 -12
  57. package/lib/public/js/components/doctor/findings-list.js +22 -22
  58. package/lib/public/js/components/doctor/fix-card-modal.js +2 -2
  59. package/lib/public/js/components/doctor/general-warning.js +5 -5
  60. package/lib/public/js/components/doctor/index.js +26 -26
  61. package/lib/public/js/components/doctor/summary-cards.js +5 -5
  62. package/lib/public/js/components/envars.js +16 -16
  63. package/lib/public/js/components/features.js +4 -4
  64. package/lib/public/js/components/file-tree.js +4 -4
  65. package/lib/public/js/components/file-viewer/diff-viewer.js +2 -2
  66. package/lib/public/js/components/file-viewer/editor-surface.js +2 -2
  67. package/lib/public/js/components/file-viewer/frontmatter-panel.js +2 -2
  68. package/lib/public/js/components/file-viewer/index.js +3 -3
  69. package/lib/public/js/components/file-viewer/markdown-split-view.js +2 -2
  70. package/lib/public/js/components/file-viewer/media-preview.js +2 -2
  71. package/lib/public/js/components/file-viewer/scroll-sync.js +1 -1
  72. package/lib/public/js/components/file-viewer/sqlite-viewer.js +2 -2
  73. package/lib/public/js/components/file-viewer/status-banners.js +2 -2
  74. package/lib/public/js/components/file-viewer/toolbar.js +2 -2
  75. package/lib/public/js/components/file-viewer/use-editor-line-number-sync.js +1 -1
  76. package/lib/public/js/components/file-viewer/use-editor-selection-restore.js +1 -1
  77. package/lib/public/js/components/file-viewer/use-file-diff.js +1 -1
  78. package/lib/public/js/components/file-viewer/use-file-loader.js +1 -1
  79. package/lib/public/js/components/file-viewer/use-file-viewer-draft-sync.js +1 -1
  80. package/lib/public/js/components/file-viewer/use-file-viewer-hotkeys.js +1 -1
  81. package/lib/public/js/components/file-viewer/use-file-viewer.js +2 -2
  82. package/lib/public/js/components/gateway.js +12 -12
  83. package/lib/public/js/components/general/index.js +7 -7
  84. package/lib/public/js/components/general/use-general-tab.js +1 -1
  85. package/lib/public/js/components/global-restart-banner.js +2 -2
  86. package/lib/public/js/components/google/account-row.js +7 -7
  87. package/lib/public/js/components/google/add-account-modal.js +8 -8
  88. package/lib/public/js/components/google/gmail-setup-wizard.js +24 -24
  89. package/lib/public/js/components/google/gmail-watch-toggle.js +5 -5
  90. package/lib/public/js/components/google/index.js +6 -6
  91. package/lib/public/js/components/google/use-gmail-watch.js +1 -1
  92. package/lib/public/js/components/google/use-google-accounts.js +1 -1
  93. package/lib/public/js/components/icons.js +2 -2
  94. package/lib/public/js/components/info-tooltip.js +3 -3
  95. package/lib/public/js/components/loading-spinner.js +2 -2
  96. package/lib/public/js/components/modal-shell.js +5 -5
  97. package/lib/public/js/components/models-tab/index.js +11 -11
  98. package/lib/public/js/components/models-tab/model-picker.js +9 -9
  99. package/lib/public/js/components/models-tab/provider-auth-card.js +12 -12
  100. package/lib/public/js/components/models-tab/use-models.js +1 -1
  101. package/lib/public/js/components/models.js +18 -18
  102. package/lib/public/js/components/nodes-tab/browser-attach/index.js +5 -5
  103. package/lib/public/js/components/nodes-tab/connected-nodes/index.js +32 -32
  104. package/lib/public/js/components/nodes-tab/connected-nodes/use-connected-nodes-card.js +18 -3
  105. package/lib/public/js/components/nodes-tab/exec-allowlist/index.js +10 -10
  106. package/lib/public/js/components/nodes-tab/exec-allowlist/use-exec-allowlist.js +1 -1
  107. package/lib/public/js/components/nodes-tab/exec-config/index.js +13 -13
  108. package/lib/public/js/components/nodes-tab/exec-config/use-exec-config.js +1 -1
  109. package/lib/public/js/components/nodes-tab/index.js +2 -2
  110. package/lib/public/js/components/nodes-tab/setup-wizard/index.js +14 -14
  111. package/lib/public/js/components/nodes-tab/setup-wizard/use-setup-wizard.js +1 -1
  112. package/lib/public/js/components/nodes-tab/use-nodes-tab.js +1 -1
  113. package/lib/public/js/components/onboarding/use-welcome-codex.js +1 -1
  114. package/lib/public/js/components/onboarding/use-welcome-pairing.js +1 -1
  115. package/lib/public/js/components/onboarding/use-welcome-storage.js +1 -1
  116. package/lib/public/js/components/onboarding/welcome-config.js +3 -3
  117. package/lib/public/js/components/onboarding/welcome-form-step.js +34 -34
  118. package/lib/public/js/components/onboarding/welcome-header.js +2 -2
  119. package/lib/public/js/components/onboarding/welcome-import-step.js +22 -22
  120. package/lib/public/js/components/onboarding/welcome-pairing-step.js +15 -15
  121. package/lib/public/js/components/onboarding/welcome-placeholder-review-step.js +7 -7
  122. package/lib/public/js/components/onboarding/welcome-pre-step.js +9 -9
  123. package/lib/public/js/components/onboarding/welcome-secret-review-step.js +15 -15
  124. package/lib/public/js/components/onboarding/welcome-setup-step.js +8 -8
  125. package/lib/public/js/components/overflow-menu.js +3 -3
  126. package/lib/public/js/components/page-header.js +2 -2
  127. package/lib/public/js/components/pairings.js +14 -14
  128. package/lib/public/js/components/pane-shell.js +2 -2
  129. package/lib/public/js/components/pill-tabs.js +4 -4
  130. package/lib/public/js/components/pop-actions.js +3 -3
  131. package/lib/public/js/components/providers.js +17 -17
  132. package/lib/public/js/components/routes/agents-route.js +2 -2
  133. package/lib/public/js/components/routes/browse-route.js +2 -2
  134. package/lib/public/js/components/routes/cron-route.js +2 -2
  135. package/lib/public/js/components/routes/doctor-route.js +2 -2
  136. package/lib/public/js/components/routes/envars-route.js +2 -2
  137. package/lib/public/js/components/routes/general-route.js +2 -2
  138. package/lib/public/js/components/routes/models-route.js +2 -2
  139. package/lib/public/js/components/routes/nodes-route.js +2 -2
  140. package/lib/public/js/components/routes/providers-route.js +2 -2
  141. package/lib/public/js/components/routes/route-redirect.js +2 -2
  142. package/lib/public/js/components/routes/telegram-route.js +2 -2
  143. package/lib/public/js/components/routes/usage-route.js +2 -2
  144. package/lib/public/js/components/routes/watchdog-route.js +2 -2
  145. package/lib/public/js/components/routes/webhooks-route.js +2 -2
  146. package/lib/public/js/components/scope-picker.js +9 -9
  147. package/lib/public/js/components/secret-input.js +5 -5
  148. package/lib/public/js/components/segmented-control.js +2 -2
  149. package/lib/public/js/components/session-select-field.js +7 -7
  150. package/lib/public/js/components/sidebar-git-panel.js +3 -3
  151. package/lib/public/js/components/sidebar.js +3 -3
  152. package/lib/public/js/components/summary-stat-card.js +3 -3
  153. package/lib/public/js/components/telegram-workspace/index.js +10 -10
  154. package/lib/public/js/components/telegram-workspace/manage.js +36 -36
  155. package/lib/public/js/components/telegram-workspace/onboarding.js +73 -73
  156. package/lib/public/js/components/toast.js +8 -8
  157. package/lib/public/js/components/toggle-switch.js +2 -2
  158. package/lib/public/js/components/tooltip.js +5 -5
  159. package/lib/public/js/components/update-action-button.js +2 -2
  160. package/lib/public/js/components/update-modal.js +9 -9
  161. package/lib/public/js/components/usage-tab/constants.js +2 -2
  162. package/lib/public/js/components/usage-tab/index.js +3 -3
  163. package/lib/public/js/components/usage-tab/overview-section.js +15 -15
  164. package/lib/public/js/components/usage-tab/sessions-section.js +19 -19
  165. package/lib/public/js/components/usage-tab/use-usage-tab.js +2 -2
  166. package/lib/public/js/components/watchdog-tab/console/index.js +22 -8
  167. package/lib/public/js/components/watchdog-tab/console/use-console.js +28 -2
  168. package/lib/public/js/components/watchdog-tab/helpers.js +35 -6
  169. package/lib/public/js/components/watchdog-tab/incidents/index.js +6 -6
  170. package/lib/public/js/components/watchdog-tab/incidents/use-incidents.js +1 -1
  171. package/lib/public/js/components/watchdog-tab/index.js +4 -2
  172. package/lib/public/js/components/watchdog-tab/resource-bar.js +5 -5
  173. package/lib/public/js/components/watchdog-tab/resources/index.js +14 -3
  174. package/lib/public/js/components/watchdog-tab/resources/use-resources.js +1 -1
  175. package/lib/public/js/components/watchdog-tab/settings/index.js +97 -30
  176. package/lib/public/js/components/watchdog-tab/settings/use-settings.js +1 -1
  177. package/lib/public/js/components/watchdog-tab/terminal/index.js +3 -3
  178. package/lib/public/js/components/watchdog-tab/terminal/use-terminal.js +41 -5
  179. package/lib/public/js/components/watchdog-tab/use-watchdog-tab.js +2 -0
  180. package/lib/public/js/components/webhooks/create-webhook-modal/index.js +17 -17
  181. package/lib/public/js/components/webhooks/helpers.js +3 -3
  182. package/lib/public/js/components/webhooks/index.js +4 -4
  183. package/lib/public/js/components/webhooks/request-history/index.js +14 -14
  184. package/lib/public/js/components/webhooks/request-history/use-request-history.js +1 -1
  185. package/lib/public/js/components/webhooks/webhook-detail/index.js +41 -41
  186. package/lib/public/js/components/webhooks/webhook-detail/use-webhook-detail.js +1 -1
  187. package/lib/public/js/components/webhooks/webhook-list/index.js +11 -11
  188. package/lib/public/js/components/webhooks/webhook-list/use-webhook-list.js +1 -1
  189. package/lib/public/js/components/welcome/index.js +3 -3
  190. package/lib/public/js/components/welcome/use-welcome.js +10 -10
  191. package/lib/public/js/hooks/use-app-shell-controller.js +1 -1
  192. package/lib/public/js/hooks/use-app-shell-ui.js +1 -1
  193. package/lib/public/js/hooks/use-browse-navigation.js +1 -1
  194. package/lib/public/js/hooks/use-cached-fetch.js +1 -1
  195. package/lib/public/js/hooks/use-destination-session-selection.js +1 -1
  196. package/lib/public/js/hooks/use-hash-location.js +1 -1
  197. package/lib/public/js/hooks/useAgentSessions.js +1 -1
  198. package/lib/public/js/hooks/usePolling.js +1 -1
  199. package/lib/public/js/tailwind-config.js +39 -0
  200. package/lib/public/login.html +3 -18
  201. package/lib/public/setup.html +2 -18
  202. package/lib/server/init/register-server-routes.js +2 -0
  203. package/lib/server/routes/nodes.js +10 -2
  204. package/lib/server/routes/pairings.js +5 -1
  205. package/lib/server/routes/system.js +5 -0
  206. package/lib/server/routes/watchdog.js +15 -0
  207. package/lib/server/watchdog.js +137 -51
  208. package/lib/server.js +2 -0
  209. package/package.json +14 -3
@@ -1,7 +1,7 @@
1
- import { h } from "https://esm.sh/preact";
2
- import { useEffect, useRef, useState } from "https://esm.sh/preact/hooks";
3
- import { createPortal } from "https://esm.sh/preact/compat";
4
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import { useEffect, useRef, useState } from "preact/hooks";
3
+ import { createPortal } from "preact/compat";
4
+ import htm from "htm";
5
5
 
6
6
  const html = htm.bind(h);
7
7
 
@@ -138,7 +138,7 @@ export const Tooltip = ({
138
138
  <span
139
139
  ref=${tooltipRef}
140
140
  role="tooltip"
141
- class=${`pointer-events-none fixed left-0 top-0 z-[80] -translate-x-1/2 rounded-md border border-border bg-modal px-2 py-1 text-[11px] text-gray-300 shadow-lg ${widthClass} ${tooltipClassName}`.trim()}
141
+ class=${`pointer-events-none fixed left-0 top-0 z-[80] -translate-x-1/2 rounded-md border border-border bg-modal px-2 py-1 text-[11px] text-body shadow-lg ${widthClass} ${tooltipClassName}`.trim()}
142
142
  style=${positionStyle || { visibility: "hidden" }}
143
143
  >
144
144
  ${text}
@@ -1,5 +1,5 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
3
  import { ActionButton } from "./action-button.js";
4
4
 
5
5
  const html = htm.bind(h);
@@ -1,7 +1,7 @@
1
- import { h } from "https://esm.sh/preact";
2
- import { useEffect, useMemo, useState } from "https://esm.sh/preact/hooks";
3
- import htm from "https://esm.sh/htm";
4
- import { marked } from "https://esm.sh/marked";
1
+ import { h } from "preact";
2
+ import { useEffect, useMemo, useState } from "preact/hooks";
3
+ import htm from "htm";
4
+ import { marked } from "marked";
5
5
  import { fetchAlphaclawReleaseNotes } from "../lib/api.js";
6
6
  import { ModalShell } from "./modal-shell.js";
7
7
  import { ActionButton } from "./action-button.js";
@@ -103,18 +103,18 @@ export const UpdateModal = ({
103
103
  class="absolute top-5 right-5 h-8 w-8 inline-flex items-center justify-center rounded-lg ac-btn-secondary"
104
104
  aria-label="Close modal"
105
105
  >
106
- <${CloseIcon} className="w-3.5 h-3.5 text-gray-300" />
106
+ <${CloseIcon} className="w-3.5 h-3.5 text-body" />
107
107
  </button>
108
108
  <div class="space-y-1 pr-10">
109
109
  <h3 class="text-sm font-semibold">AlphaClaw release notes</h3>
110
110
  ${publishedAtLabel
111
- ? html`<p class="text-xs text-gray-500">Published ${publishedAtLabel}</p>`
111
+ ? html`<p class="text-xs text-fg-muted">Published ${publishedAtLabel}</p>`
112
112
  : null}
113
113
  </div>
114
114
  <div class="ac-surface-inset border border-border rounded-lg p-2 overflow-auto min-h-[220px] max-h-[66vh]">
115
115
  ${loadingNotes
116
116
  ? html`
117
- <div class="min-h-[200px] flex items-center justify-center text-gray-400">
117
+ <div class="min-h-[200px] flex items-center justify-center text-fg-muted">
118
118
  <span class="inline-flex items-center gap-2 text-sm">
119
119
  <${LoadingSpinner} className="h-4 w-4" />
120
120
  Loading release notes...
@@ -124,7 +124,7 @@ export const UpdateModal = ({
124
124
  : notesError
125
125
  ? html`
126
126
  <div class="space-y-2">
127
- <p class="text-sm text-red-300">${notesError}</p>
127
+ <p class="text-sm text-status-error">${notesError}</p>
128
128
  <a
129
129
  class="ac-tip-link text-xs"
130
130
  href=${effectiveReleaseUrl}
@@ -141,7 +141,7 @@ export const UpdateModal = ({
141
141
  ></div>`
142
142
  : html`
143
143
  <div class="space-y-2">
144
- <p class="text-sm text-gray-300">No release notes were published for this tag.</p>
144
+ <p class="text-sm text-body">No release notes were published for this tag.</p>
145
145
  <a
146
146
  class="ac-tip-link text-xs"
147
147
  href=${effectiveReleaseUrl}
@@ -12,10 +12,10 @@ export const kColorPalette = [
12
12
  ];
13
13
 
14
14
  export const kBadgeToneClass = {
15
- cyan: "border-cyan-400/30 text-cyan-300 bg-cyan-400/10",
15
+ cyan: "border-cyan-400/30 text-status-info bg-cyan-400/10",
16
16
  blue: "border-blue-400/30 text-blue-300 bg-blue-400/10",
17
17
  purple: "border-purple-400/30 text-purple-300 bg-purple-400/10",
18
- gray: "border-gray-400/30 text-gray-400 bg-gray-400/10",
18
+ gray: "border-gray-400/30 text-fg-muted bg-gray-400/10",
19
19
  };
20
20
 
21
21
  export const kRangeOptions = [
@@ -1,5 +1,5 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
3
  import { ActionButton } from "../action-button.js";
4
4
  import { PageHeader } from "../page-header.js";
5
5
  import { OverviewSection } from "./overview-section.js";
@@ -42,7 +42,7 @@ export const UsageTab = ({ sessionId = "" }) => {
42
42
  `}
43
43
  />
44
44
  ${state.error
45
- ? html`<div class="text-xs text-red-300 bg-red-950/30 border border-red-900 rounded px-3 py-2">
45
+ ? html`<div class="text-xs text-status-error bg-status-error-bg border border-status-error-border rounded px-3 py-2">
46
46
  ${state.error}
47
47
  </div>`
48
48
  : null}
@@ -1,6 +1,6 @@
1
- import { h } from "https://esm.sh/preact";
2
- import { useEffect, useState } from "https://esm.sh/preact/hooks";
3
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import { useEffect, useState } from "preact/hooks";
3
+ import htm from "htm";
4
4
  import {
5
5
  formatCompactNumber,
6
6
  formatInteger,
@@ -26,10 +26,10 @@ const formatPercent = (ratio) => `${(Number(ratio || 0) * 100).toFixed(1)}%`;
26
26
 
27
27
  const getCacheHitRateValueClass = (ratio) => {
28
28
  const percent = Number(ratio || 0) * 100;
29
- if (percent <= 0) return "text-gray-300";
30
- if (percent >= 70) return "text-green-400";
29
+ if (percent <= 0) return "text-body";
30
+ if (percent >= 70) return "text-status-success";
31
31
  if (percent >= 40) return "text-amber-300";
32
- return "text-red-400";
32
+ return "text-status-error-muted";
33
33
  };
34
34
 
35
35
  const getOverviewMetrics = (summary) => {
@@ -133,7 +133,7 @@ const AgentCostDistribution = ({ summary }) => {
133
133
  >
134
134
  <h2 class="card-label text-xs">Estimated cost breakdown</h2>
135
135
  </div>
136
- <p class="text-xs text-gray-500">
136
+ <p class="text-xs text-fg-muted">
137
137
  No agent usage recorded for this range.
138
138
  </p>
139
139
  `
@@ -144,13 +144,13 @@ const AgentCostDistribution = ({ summary }) => {
144
144
  >
145
145
  <h2 class="card-label text-xs">Estimated cost breakdown</h2>
146
146
  <div
147
- class="inline-flex flex-wrap items-center gap-3 text-xs text-gray-500"
147
+ class="inline-flex flex-wrap items-center gap-3 text-xs text-fg-muted"
148
148
  >
149
149
  <label
150
- class="inline-flex items-center gap-2 text-xs text-gray-500"
150
+ class="inline-flex items-center gap-2 text-xs text-fg-muted"
151
151
  >
152
152
  <select
153
- class="bg-black/30 border border-border rounded-lg text-xs px-2.5 py-1.5 text-gray-200 focus:border-gray-500"
153
+ class="bg-field border border-border rounded-lg text-xs px-2.5 py-1.5 text-body focus:border-fg-muted"
154
154
  value=${String(selectedAgentRow?.agent || "")}
155
155
  onChange=${(e) =>
156
156
  setSelectedAgent(String(e.currentTarget?.value || ""))}
@@ -178,13 +178,13 @@ const AgentCostDistribution = ({ summary }) => {
178
178
  };
179
179
  return html`
180
180
  <div class="ac-surface-inset px-2.5 py-2">
181
- <p class="text-[11px] text-gray-500">
181
+ <p class="text-[11px] text-fg-muted">
182
182
  ${renderSourceLabel(sourceRow.source)}
183
183
  </p>
184
- <p class="text-xs text-gray-300 mt-0.5">
184
+ <p class="text-xs text-body mt-0.5">
185
185
  ${formatUsd(sourceRow.totalCost)}
186
186
  </p>
187
- <p class="text-[11px] text-gray-500 mt-0.5">
187
+ <p class="text-[11px] text-fg-muted mt-0.5">
188
188
  ${formatInteger(sourceRow.totalTokens)} tok ·
189
189
  ${formatCountLabel(
190
190
  sourceRow.turnCount,
@@ -201,7 +201,7 @@ const AgentCostDistribution = ({ summary }) => {
201
201
  ${missingPricingModels.length
202
202
  ? html`
203
203
  <div class="mt-3">
204
- <p class="text-[11px] text-gray-500">
204
+ <p class="text-[11px] text-fg-muted">
205
205
  <span>
206
206
  . Missing model pricing for ${missingPricingModels.length}
207
207
  ${missingPricingModels.length === 1 ? "model" : "models"}:
@@ -272,7 +272,7 @@ export const OverviewSection = ({
272
272
  >
273
273
  <label class="inline-flex items-center gap-2">
274
274
  <select
275
- class="bg-black/30 border border-border rounded-lg text-xs px-2.5 py-1.5 text-gray-200 focus:border-gray-500"
275
+ class="bg-field border border-border rounded-lg text-xs px-2.5 py-1.5 text-body focus:border-fg-muted"
276
276
  value=${breakdown}
277
277
  onChange=${(event) =>
278
278
  onBreakdownChange(String(event.currentTarget?.value || "model"))}
@@ -1,5 +1,5 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
3
  import {
4
4
  formatDurationCompactMs,
5
5
  formatInteger,
@@ -51,14 +51,14 @@ const SessionInlineDetail = ({
51
51
  if (loadingDetail) {
52
52
  return html`
53
53
  <div class="ac-history-body">
54
- <p class="text-xs text-gray-500">Loading session detail...</p>
54
+ <p class="text-xs text-fg-muted">Loading session detail...</p>
55
55
  </div>
56
56
  `;
57
57
  }
58
58
  if (!detail) {
59
59
  return html`
60
60
  <div class="ac-history-body">
61
- <p class="text-xs text-gray-500">Session detail not available.</p>
61
+ <p class="text-xs text-fg-muted">Session detail not available.</p>
62
62
  </div>
63
63
  `;
64
64
  }
@@ -68,20 +68,20 @@ const SessionInlineDetail = ({
68
68
  return html`
69
69
  <div class="ac-history-body space-y-3 border-0 pt-0 mt-0">
70
70
  <div>
71
- <p class="text-[11px] text-gray-500 mb-1">Session key</p>
72
- <p class="text-xs text-gray-300 font-mono break-all">${sessionKeyValue || "n/a"}</p>
71
+ <p class="text-[11px] text-fg-muted mb-1">Session key</p>
72
+ <p class="text-xs text-body font-mono break-all">${sessionKeyValue || "n/a"}</p>
73
73
  </div>
74
74
  <div class="mt-1.5">
75
- <p class="text-[11px] text-gray-500 mb-1">Model breakdown</p>
75
+ <p class="text-[11px] text-fg-muted mb-1">Model breakdown</p>
76
76
  ${(detail.modelBreakdown || []).length === 0
77
- ? html`<p class="text-xs text-gray-500">No model usage recorded.</p>`
77
+ ? html`<p class="text-xs text-fg-muted">No model usage recorded.</p>`
78
78
  : html`
79
79
  <div class="space-y-1.5">
80
80
  ${(detail.modelBreakdown || []).map(
81
81
  (row) => html`
82
- <div class="flex items-center justify-between gap-3 text-xs px-1 py-0.5 rounded hover:bg-white/5 transition-colors">
83
- <span class="text-gray-300 truncate">${row.model || "unknown"}</span>
84
- <span class="inline-flex items-center gap-3 text-gray-500 shrink-0">
82
+ <div class="flex items-center justify-between gap-3 text-xs px-1 py-0.5 rounded hover:bg-surface transition-colors">
83
+ <span class="text-body truncate">${row.model || "unknown"}</span>
84
+ <span class="inline-flex items-center gap-3 text-fg-muted shrink-0">
85
85
  <span>${formatInteger(row.totalTokens)} tok</span>
86
86
  <span>${formatUsd(row.totalCost)}</span>
87
87
  <span>${formatCountLabel(row.turnCount, "turn", "turns")}</span>
@@ -93,16 +93,16 @@ const SessionInlineDetail = ({
93
93
  `}
94
94
  </div>
95
95
  <div>
96
- <p class="text-[11px] text-gray-500 mb-1">Tool usage</p>
96
+ <p class="text-[11px] text-fg-muted mb-1">Tool usage</p>
97
97
  ${(detail.toolUsage || []).length === 0
98
- ? html`<p class="text-xs text-gray-500">No tool calls recorded.</p>`
98
+ ? html`<p class="text-xs text-fg-muted">No tool calls recorded.</p>`
99
99
  : html`
100
100
  <div class="space-y-1.5">
101
101
  ${(detail.toolUsage || []).map(
102
102
  (row) => html`
103
- <div class="flex items-center justify-between gap-3 text-xs px-1 py-0.5 rounded hover:bg-white/5 transition-colors">
104
- <span class="text-gray-300 truncate">${row.toolName}</span>
105
- <span class="inline-flex items-center gap-3 text-gray-500 shrink-0">
103
+ <div class="flex items-center justify-between gap-3 text-xs px-1 py-0.5 rounded hover:bg-surface transition-colors">
104
+ <span class="text-body truncate">${row.toolName}</span>
105
+ <span class="inline-flex items-center gap-3 text-fg-muted shrink-0">
106
106
  <span>${formatCountLabel(row.callCount, "call", "calls")}</span>
107
107
  <span>${(Number(row.errorRate || 0) * 100).toFixed(1)}% err</span>
108
108
  <span>${formatDurationCompactMs(row.avgDurationMs)}</span>
@@ -129,7 +129,7 @@ export const SessionsSection = ({
129
129
  <h2 class="card-label text-xs mb-3">Sessions</h2>
130
130
  <div class="ac-history-list">
131
131
  ${sessions.length === 0
132
- ? html`<p class="text-xs text-gray-500">
132
+ ? html`<p class="text-xs text-fg-muted">
133
133
  ${loadingSessions ? "Loading sessions..." : "No sessions recorded yet."}
134
134
  </p>`
135
135
  : sessions.map(
@@ -143,13 +143,13 @@ export const SessionsSection = ({
143
143
  onToggleSession(itemSessionId, isOpen);
144
144
  }}
145
145
  >
146
- <summary class="ac-history-summary hover:bg-white/5 transition-colors">
146
+ <summary class="ac-history-summary hover:bg-surface transition-colors">
147
147
  <div class="ac-history-summary-row">
148
148
  <span class="inline-flex items-center gap-2 min-w-0">
149
149
  <span class="ac-history-toggle shrink-0" aria-hidden="true">▸</span>
150
150
  <${SessionBadges} session=${item} />
151
151
  </span>
152
- <span class="inline-flex items-center gap-3 shrink-0 text-xs text-gray-500">
152
+ <span class="inline-flex items-center gap-3 shrink-0 text-xs text-fg-muted">
153
153
  <span>${formatInteger(item.totalTokens)} tok</span>
154
154
  <span>${formatUsd(item.totalCost)}</span>
155
155
  <span>
@@ -4,7 +4,8 @@ import {
4
4
  useMemo,
5
5
  useRef,
6
6
  useState,
7
- } from "https://esm.sh/preact/hooks";
7
+ } from "preact/hooks";
8
+ import Chart from "chart.js/auto";
8
9
  import {
9
10
  fetchUsageSessionDetail,
10
11
  fetchUsageSessions,
@@ -233,7 +234,6 @@ export const useUsageTab = ({ sessionId = "" }) => {
233
234
 
234
235
  useEffect(() => {
235
236
  const canvas = overviewCanvasRef.current;
236
- const Chart = window.Chart;
237
237
  if (!canvas || !Chart) return;
238
238
  if (overviewChartRef.current) {
239
239
  overviewChartRef.current.destroy();
@@ -1,5 +1,6 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
+ import { FileCopyLineIcon } from "../../icons.js";
3
4
  import {
4
5
  kWatchdogConsoleTabLogs,
5
6
  kWatchdogConsoleTabTerminal,
@@ -22,26 +23,28 @@ export const WatchdogConsoleCard = ({
22
23
  logsRef = null,
23
24
  logs = "",
24
25
  loadingLogs = true,
26
+ copyingAll = false,
25
27
  terminalPanelRef = null,
26
28
  terminalHostRef = null,
27
29
  terminalInstanceRef = null,
28
30
  logsPanelHeightPx = 320,
31
+ onCopyAll = () => {},
29
32
  }) => html`
30
33
  <div class="bg-surface border border-border rounded-xl p-4">
31
34
  <div class="flex items-center justify-between gap-2 mb-3">
32
35
  <div
33
- class="inline-flex items-center rounded-lg border border-border bg-black/20 p-0.5"
36
+ class="inline-flex items-center rounded-lg border border-border bg-field p-0.5"
34
37
  >
35
38
  <button
36
39
  type="button"
37
- class=${`px-2.5 py-1 text-xs rounded-md ${activeConsoleTab === kWatchdogConsoleTabLogs ? "bg-surface text-gray-100" : "text-gray-400 hover:text-gray-200"}`}
40
+ class=${`px-2.5 py-1 text-xs rounded-md ${activeConsoleTab === kWatchdogConsoleTabLogs ? "bg-surface text-bright" : "text-fg-muted hover:text-body"}`}
38
41
  onClick=${() => onSelectConsoleTab(kWatchdogConsoleTabLogs)}
39
42
  >
40
43
  Logs
41
44
  </button>
42
45
  <button
43
46
  type="button"
44
- class=${`px-2.5 py-1 text-xs rounded-md ${activeConsoleTab === kWatchdogConsoleTabTerminal ? "bg-surface text-gray-100" : "text-gray-400 hover:text-gray-200"}`}
47
+ class=${`px-2.5 py-1 text-xs rounded-md ${activeConsoleTab === kWatchdogConsoleTabTerminal ? "bg-surface text-bright" : "text-fg-muted hover:text-body"}`}
45
48
  onClick=${() => onSelectConsoleTab(kWatchdogConsoleTabTerminal)}
46
49
  >
47
50
  Terminal
@@ -50,7 +53,7 @@ export const WatchdogConsoleCard = ({
50
53
  <div class="flex items-center gap-2">
51
54
  ${activeConsoleTab === kWatchdogConsoleTabLogs
52
55
  ? html`
53
- <label class="inline-flex items-center gap-2 text-xs text-gray-400">
56
+ <label class="inline-flex items-center gap-2 text-xs text-fg-muted">
54
57
  <input
55
58
  type="checkbox"
56
59
  checked=${stickToBottom}
@@ -65,7 +68,7 @@ export const WatchdogConsoleCard = ({
65
68
  ${terminalUiSettling
66
69
  ? null
67
70
  : html`
68
- <span class="text-xs text-gray-500">
71
+ <span class="text-xs text-fg-muted">
69
72
  ${connectingTerminal
70
73
  ? "Connecting..."
71
74
  : terminalEnded
@@ -93,11 +96,22 @@ export const WatchdogConsoleCard = ({
93
96
  <div class=${activeConsoleTab === kWatchdogConsoleTabLogs ? "" : "hidden"}>
94
97
  <pre
95
98
  ref=${logsRef}
96
- class="watchdog-logs-panel bg-black/40 border border-border rounded-lg p-3 overflow-auto text-xs text-gray-300 whitespace-pre-wrap break-words"
99
+ class="watchdog-logs-panel bg-field border border-border rounded-lg p-3 overflow-auto text-xs text-body whitespace-pre-wrap break-words"
97
100
  style=${{ height: `${logsPanelHeightPx}px` }}
98
101
  >
99
102
  ${loadingLogs ? "Loading logs..." : logs || "No logs yet."}</pre
100
103
  >
104
+ <div class="mt-3 flex justify-end">
105
+ <button
106
+ type="button"
107
+ class=${`ac-btn-secondary text-xs px-2.5 py-1 rounded-lg inline-flex items-center gap-1.5 ${copyingAll ? "opacity-50 cursor-not-allowed" : ""}`}
108
+ onClick=${onCopyAll}
109
+ disabled=${copyingAll}
110
+ >
111
+ <${FileCopyLineIcon} className="w-3.5 h-3.5" />
112
+ ${copyingAll ? "Copying..." : "Copy all"}
113
+ </button>
114
+ </div>
101
115
  </div>
102
116
  <div
103
117
  class=${activeConsoleTab === kWatchdogConsoleTabTerminal
@@ -1,8 +1,11 @@
1
- import { useEffect, useRef, useState } from "https://esm.sh/preact/hooks";
1
+ import { useEffect, useRef, useState } from "preact/hooks";
2
2
  import { fetchWatchdogLogs } from "../../../lib/api.js";
3
+ import { copyTextToClipboard } from "../../../lib/clipboard.js";
3
4
  import { readUiSettings, writeUiSettings } from "../../../lib/ui-settings.js";
5
+ import { showToast } from "../../toast.js";
4
6
  import {
5
7
  clampWatchdogLogsPanelHeight,
8
+ formatWatchdogCopyAllText,
6
9
  kWatchdogConsoleTabLogs,
7
10
  kWatchdogConsoleTabTerminal,
8
11
  kWatchdogConsoleTabUiSettingKey,
@@ -12,9 +15,11 @@ import {
12
15
  } from "../helpers.js";
13
16
  import { useWatchdogTerminal } from "../terminal/use-terminal.js";
14
17
 
15
- export const useWatchdogConsole = () => {
18
+ export const useWatchdogConsole = ({
19
+ } = {}) => {
16
20
  const [logs, setLogs] = useState("");
17
21
  const [loadingLogs, setLoadingLogs] = useState(true);
22
+ const [copyingAll, setCopyingAll] = useState(false);
18
23
  const [stickToBottom, setStickToBottom] = useState(true);
19
24
  const [activeConsoleTab, setActiveConsoleTab] = useState(() => {
20
25
  const settings = readUiSettings();
@@ -120,9 +125,29 @@ export const useWatchdogConsole = () => {
120
125
  setActiveConsoleTab(kWatchdogConsoleTabTerminal);
121
126
  };
122
127
 
128
+ const handleCopyAll = async () => {
129
+ if (copyingAll) return;
130
+ setCopyingAll(true);
131
+ try {
132
+ const text = formatWatchdogCopyAllText({
133
+ logs,
134
+ });
135
+ const copied = await copyTextToClipboard(text);
136
+ if (!copied) {
137
+ throw new Error("Could not copy watchdog export");
138
+ }
139
+ showToast("Copied watchdog logs", "success");
140
+ } catch (error) {
141
+ showToast(error.message || "Could not copy watchdog export", "error");
142
+ } finally {
143
+ setCopyingAll(false);
144
+ }
145
+ };
146
+
123
147
  return {
124
148
  logs,
125
149
  loadingLogs,
150
+ copyingAll,
126
151
  stickToBottom,
127
152
  setStickToBottom,
128
153
  activeConsoleTab,
@@ -132,6 +157,7 @@ export const useWatchdogConsole = () => {
132
157
  terminalPanelRef,
133
158
  terminalHostRef,
134
159
  onRestartTerminalSession,
160
+ onCopyAll: handleCopyAll,
135
161
  ...terminal,
136
162
  };
137
163
  };
@@ -4,18 +4,28 @@ export const kWatchdogConsoleTabUiSettingKey = "watchdogConsoleTab";
4
4
  export const kWatchdogLogsPanelHeightUiSettingKey = "watchdogLogsPanelHeightPx";
5
5
  export const kWatchdogLogsPanelDefaultHeightPx = 320;
6
6
  export const kWatchdogLogsPanelMinHeightPx = 160;
7
- export const kXtermCssUrl =
8
- "https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.css";
7
+ export const kXtermCssUrl = "/css/vendor/xterm.css";
9
8
  export const kWatchdogTerminalWsPath = "/api/watchdog/terminal/ws";
10
9
 
11
10
  let xtermModulesPromise = null;
12
11
 
13
12
  export const loadXtermModules = () => {
14
13
  if (!xtermModulesPromise) {
15
- xtermModulesPromise = Promise.all([
16
- import("https://esm.sh/@xterm/xterm@5.5.0"),
17
- import("https://esm.sh/@xterm/addon-fit@0.10.0"),
18
- ]);
14
+ xtermModulesPromise = Promise.all([import("@xterm/xterm"), import("@xterm/addon-fit")]).then(
15
+ ([xtermModule, fitAddonModule]) => {
16
+ const Terminal =
17
+ xtermModule?.Terminal || xtermModule?.default?.Terminal || null;
18
+ const FitAddon =
19
+ fitAddonModule?.FitAddon || fitAddonModule?.default?.FitAddon || null;
20
+ if (typeof Terminal !== "function") {
21
+ throw new Error("Xterm Terminal export not found");
22
+ }
23
+ if (typeof FitAddon !== "function") {
24
+ throw new Error("Xterm FitAddon export not found");
25
+ }
26
+ return { Terminal, FitAddon };
27
+ },
28
+ );
19
29
  }
20
30
  return xtermModulesPromise;
21
31
  };
@@ -104,3 +114,22 @@ export const getIncidentStatusTone = (event) => {
104
114
  label: "Unknown",
105
115
  };
106
116
  };
117
+
118
+ export const formatWatchdogCopyAllText = ({
119
+ logs = "",
120
+ generatedAt = null,
121
+ } = {}) => {
122
+ const sections = [];
123
+ const generatedAtLabel =
124
+ generatedAt instanceof Date && !Number.isNaN(generatedAt.getTime())
125
+ ? generatedAt.toISOString()
126
+ : new Date().toISOString();
127
+
128
+ sections.push(`# AlphaClaw Watchdog Export`);
129
+ sections.push(`Generated at: ${generatedAtLabel}`);
130
+
131
+ sections.push(`## Gateway Logs`);
132
+ sections.push(String(logs || "").trim() || "No logs yet.");
133
+
134
+ return sections.join("\n\n").trim();
135
+ };
@@ -1,5 +1,5 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
3
  import { getIncidentStatusTone } from "../helpers.js";
4
4
 
5
5
  const html = htm.bind(h);
@@ -11,13 +11,13 @@ export const WatchdogIncidentsCard = ({
11
11
  <div class="bg-surface border border-border rounded-xl p-4">
12
12
  <div class="flex items-center justify-between gap-2 mb-3">
13
13
  <h2 class="card-label">Recent incidents</h2>
14
- <button class="text-xs text-gray-400 hover:text-gray-200" onclick=${onRefresh}>
14
+ <button class="text-xs text-fg-muted hover:text-body" onclick=${onRefresh}>
15
15
  Refresh
16
16
  </button>
17
17
  </div>
18
18
  <div class="ac-history-list">
19
19
  ${events.length === 0 &&
20
- html`<p class="text-xs text-gray-500">No incidents recorded.</p>`}
20
+ html`<p class="text-xs text-fg-muted">No incidents recorded.</p>`}
21
21
  ${events.map((event) => {
22
22
  const tone = getIncidentStatusTone(event);
23
23
  return html`
@@ -40,9 +40,9 @@ export const WatchdogIncidentsCard = ({
40
40
  ></span>
41
41
  </div>
42
42
  </summary>
43
- <div class="ac-history-body text-xs text-gray-400">
43
+ <div class="ac-history-body text-xs text-fg-muted">
44
44
  <div>Source: ${event.source || "unknown"}</div>
45
- <pre class="mt-2 bg-black/30 rounded p-2 whitespace-pre-wrap break-words">
45
+ <pre class="mt-2 bg-field rounded p-2 whitespace-pre-wrap break-words">
46
46
  ${typeof event.details === "string"
47
47
  ? event.details
48
48
  : JSON.stringify(event.details || {}, null, 2)}</pre
@@ -1,4 +1,4 @@
1
- import { useEffect } from "https://esm.sh/preact/hooks";
1
+ import { useEffect } from "preact/hooks";
2
2
  import { usePolling } from "../../../hooks/usePolling.js";
3
3
  import { fetchWatchdogEvents } from "../../../lib/api.js";
4
4
 
@@ -1,5 +1,5 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
3
  import { Gateway } from "../gateway.js";
4
4
  import { useWatchdogTab } from "./use-watchdog-tab.js";
5
5
  import { WatchdogResourcesCard } from "./resources/index.js";
@@ -69,10 +69,12 @@ export const WatchdogTab = ({
69
69
  logsRef=${state.logsRef}
70
70
  logs=${state.logs}
71
71
  loadingLogs=${state.loadingLogs}
72
+ copyingAll=${state.copyingAll}
72
73
  terminalPanelRef=${state.terminalPanelRef}
73
74
  terminalHostRef=${state.terminalHostRef}
74
75
  terminalInstanceRef=${state.terminalInstanceRef}
75
76
  logsPanelHeightPx=${state.logsPanelHeightPx}
77
+ onCopyAll=${state.onCopyAll}
76
78
  />
77
79
 
78
80
  <${WatchdogIncidentsCard}
@@ -1,5 +1,5 @@
1
- import { h } from "https://esm.sh/preact";
2
- import htm from "https://esm.sh/htm";
1
+ import { h } from "preact";
2
+ import htm from "htm";
3
3
 
4
4
  const html = htm.bind(h);
5
5
 
@@ -21,7 +21,7 @@ export const ResourceBar = ({
21
21
  onclick=${onToggle || undefined}
22
22
  >
23
23
  <span
24
- class=${`text-xs text-gray-400 ${onToggle ? "group-hover:text-gray-200 transition-colors" : ""}`}
24
+ class=${`text-xs text-fg-muted ${onToggle ? "group-hover:text-body transition-colors" : ""}`}
25
25
  >${label}</span
26
26
  >
27
27
  <div
@@ -53,7 +53,7 @@ export const ResourceBar = ({
53
53
  `}
54
54
  </div>
55
55
  <div class="flex flex-wrap items-center gap-x-3 mt-2.5">
56
- <span class="text-xs text-gray-500 font-mono flex-1">${detail}</span>
56
+ <span class="text-xs text-fg-muted font-mono flex-1">${detail}</span>
57
57
  ${expanded &&
58
58
  segments &&
59
59
  segments
@@ -61,7 +61,7 @@ export const ResourceBar = ({
61
61
  .map(
62
62
  (segment) => html`
63
63
  <span
64
- class="inline-flex items-center gap-1 text-xs text-gray-500 font-mono"
64
+ class="inline-flex items-center gap-1 text-xs text-fg-muted font-mono"
65
65
  >
66
66
  <span
67
67
  class="inline-block w-1.5 h-1.5 rounded-full"