@chrysb/alphaclaw 0.5.1-beta.0 → 0.5.1

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/bin/alphaclaw.js CHANGED
@@ -481,6 +481,8 @@ if (!kSetupPassword) {
481
481
 
482
482
  process.env.OPENCLAW_HOME = rootDir;
483
483
  process.env.OPENCLAW_CONFIG_PATH = path.join(openclawDir, "openclaw.json");
484
+ process.env.GOG_KEYRING_PASSWORD =
485
+ process.env.GOG_KEYRING_PASSWORD || "alphaclaw";
484
486
 
485
487
  // ---------------------------------------------------------------------------
486
488
  // 8. Install gog (Google Workspace CLI) if not present
@@ -516,7 +518,7 @@ if (!gogInstalled) {
516
518
  }
517
519
 
518
520
  // ---------------------------------------------------------------------------
519
- // 7. Install/reconcile system cron entry
521
+ // 9. Install/reconcile system cron entry
520
522
  // ---------------------------------------------------------------------------
521
523
 
522
524
  const packagedHourlyGitSyncPath = path.join(setupDir, "hourly-git-sync.sh");
@@ -246,6 +246,45 @@ textarea:focus {
246
246
  background: rgba(99, 235, 255, 0.08);
247
247
  }
248
248
 
249
+ .ac-path-card {
250
+ border: 1px solid var(--panel-border-contrast);
251
+ background: rgba(0, 0, 0, 0.2);
252
+ transition:
253
+ border-color 0.15s ease,
254
+ background 0.15s ease,
255
+ box-shadow 0.15s ease,
256
+ transform 0.15s ease;
257
+ }
258
+
259
+ .ac-path-card:hover {
260
+ border-color: rgba(99, 235, 255, 0.5);
261
+ background: rgba(99, 235, 255, 0.04);
262
+ box-shadow:
263
+ inset 0 0 0 1px rgba(99, 235, 255, 0.1),
264
+ 0 0 12px rgba(99, 235, 255, 0.08);
265
+ }
266
+
267
+ .ac-path-card:hover .ac-path-icon {
268
+ color: var(--accent);
269
+ border-color: rgba(99, 235, 255, 0.3);
270
+ background: rgba(99, 235, 255, 0.1);
271
+ }
272
+
273
+ .ac-path-card:hover .ac-path-title {
274
+ color: #b9f8ff;
275
+ }
276
+
277
+ .ac-path-card:hover .ac-path-desc {
278
+ color: #94a3b8;
279
+ }
280
+
281
+ .ac-path-icon {
282
+ transition:
283
+ color 0.15s ease,
284
+ border-color 0.15s ease,
285
+ background 0.15s ease;
286
+ }
287
+
249
288
  .ac-btn-secondary {
250
289
  border: 1px solid var(--panel-border-contrast);
251
290
  color: #d1d5db;
@@ -426,6 +465,24 @@ textarea:focus {
426
465
  }
427
466
  }
428
467
 
468
+ @keyframes acStepPillPulse {
469
+ 0%,
470
+ 100% {
471
+ box-shadow:
472
+ 0 0 0 0 rgba(99, 235, 255, 0.14),
473
+ 0 0 5px rgba(99, 235, 255, 0.18);
474
+ }
475
+ 50% {
476
+ box-shadow:
477
+ 0 0 0 3px rgba(99, 235, 255, 0.08),
478
+ 0 0 9px rgba(99, 235, 255, 0.32);
479
+ }
480
+ }
481
+
482
+ .ac-step-pill-pulse {
483
+ animation: acStepPillPulse 2.6s ease-in-out infinite;
484
+ }
485
+
429
486
  .ac-status-dot {
430
487
  width: 8px;
431
488
  height: 8px;
@@ -1,7 +1,12 @@
1
1
  import { h, render } from "https://esm.sh/preact";
2
2
  import { useState, useEffect } from "https://esm.sh/preact/hooks";
3
3
  import htm from "https://esm.sh/htm";
4
- import { Router, Route, Switch, useLocation } from "https://esm.sh/wouter-preact";
4
+ import {
5
+ Router,
6
+ Route,
7
+ Switch,
8
+ useLocation,
9
+ } from "https://esm.sh/wouter-preact";
5
10
  import { logout } from "./lib/api.js";
6
11
  import { Welcome } from "./components/welcome/index.js";
7
12
  import { ToastContainer } from "./components/toast.js";
@@ -14,7 +19,6 @@ import {
14
19
  EnvarsRoute,
15
20
  GeneralRoute,
16
21
  ModelsRoute,
17
- ProvidersRoute,
18
22
  RouteRedirect,
19
23
  TelegramRoute,
20
24
  UsageRoute,
@@ -24,34 +28,48 @@ import {
24
28
  import { useAppShellController } from "./hooks/use-app-shell-controller.js";
25
29
  import { useAppShellUi } from "./hooks/use-app-shell-ui.js";
26
30
  import { useBrowseNavigation } from "./hooks/use-browse-navigation.js";
27
- import { getHashRouterPath, useHashLocation } from "./hooks/use-hash-location.js";
31
+ import {
32
+ getHashRouterPath,
33
+ useHashLocation,
34
+ } from "./hooks/use-hash-location.js";
28
35
  import { readUiSettings, writeUiSettings } from "./lib/ui-settings.js";
29
36
 
30
37
  const html = htm.bind(h);
31
- const kDoctorWarningDismissedUntilUiSettingKey = "doctorWarningDismissedUntilMs";
38
+ const kDoctorWarningDismissedUntilUiSettingKey =
39
+ "doctorWarningDismissedUntilMs";
32
40
  const kOneWeekMs = 7 * 24 * 60 * 60 * 1000;
33
41
 
34
42
  const App = () => {
35
43
  const [location, setLocation] = useLocation();
36
- const [doctorWarningDismissedUntilMs, setDoctorWarningDismissedUntilMs] = useState(() => {
37
- const settings = readUiSettings();
38
- return Number(settings[kDoctorWarningDismissedUntilUiSettingKey] || 0);
39
- });
44
+ const [doctorWarningDismissedUntilMs, setDoctorWarningDismissedUntilMs] =
45
+ useState(() => {
46
+ const settings = readUiSettings();
47
+ return Number(settings[kDoctorWarningDismissedUntilUiSettingKey] || 0);
48
+ });
40
49
 
41
- const { state: controllerState, actions: controllerActions } = useAppShellController({
42
- location,
43
- });
44
- const { refs: shellRefs, state: shellState, actions: shellActions } = useAppShellUi();
45
- const { state: browseState, actions: browseActions, constants: browseConstants } =
46
- useBrowseNavigation({
50
+ const { state: controllerState, actions: controllerActions } =
51
+ useAppShellController({
47
52
  location,
48
- setLocation,
49
- onCloseMobileSidebar: shellActions.closeMobileSidebar,
50
53
  });
54
+ const {
55
+ refs: shellRefs,
56
+ state: shellState,
57
+ actions: shellActions,
58
+ } = useAppShellUi();
59
+ const {
60
+ state: browseState,
61
+ actions: browseActions,
62
+ constants: browseConstants,
63
+ } = useBrowseNavigation({
64
+ location,
65
+ setLocation,
66
+ onCloseMobileSidebar: shellActions.closeMobileSidebar,
67
+ });
51
68
 
52
69
  useEffect(() => {
53
70
  const settings = readUiSettings();
54
- settings[kDoctorWarningDismissedUntilUiSettingKey] = doctorWarningDismissedUntilMs;
71
+ settings[kDoctorWarningDismissedUntilUiSettingKey] =
72
+ doctorWarningDismissedUntilMs;
55
73
  writeUiSettings(settings);
56
74
  }, [doctorWarningDismissedUntilMs]);
57
75
 
@@ -83,10 +101,13 @@ const App = () => {
83
101
  if (!controllerState.onboarded) {
84
102
  return html`
85
103
  <div
86
- class="min-h-screen flex justify-center pt-12 pb-8 px-4"
104
+ class="min-h-screen flex flex-col items-center pt-12 pb-8 px-4"
87
105
  style="position: relative; z-index: 1"
88
106
  >
89
- <${Welcome} onComplete=${controllerActions.handleOnboardingComplete} />
107
+ <${Welcome}
108
+ onComplete=${controllerActions.handleOnboardingComplete}
109
+ acVersion=${controllerState.acVersion}
110
+ />
90
111
  </div>
91
112
  <${ToastContainer} />
92
113
  `;
@@ -150,7 +171,9 @@ const App = () => {
150
171
  onNavigateToBrowseFile=${browseActions.navigateToBrowseFile}
151
172
  onEditSelectedBrowseFile=${() =>
152
173
  setLocation(
153
- browseActions.buildBrowseRoute(browseState.selectedBrowsePath, { view: "edit" }),
174
+ browseActions.buildBrowseRoute(browseState.selectedBrowsePath, {
175
+ view: "edit",
176
+ }),
154
177
  )}
155
178
  onClearSelection=${() => {
156
179
  browseActions.clearBrowsePreview();
@@ -163,14 +186,22 @@ const App = () => {
163
186
  onscroll=${shellActions.handlePaneScroll}
164
187
  style=${{ display: browseState.isBrowseRoute ? "none" : "block" }}
165
188
  >
166
- <div class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}>
189
+ <div
190
+ class=${`mobile-topbar ${shellState.mobileTopbarScrolled ? "is-scrolled" : ""}`}
191
+ >
167
192
  <button
168
193
  class="mobile-topbar-menu"
169
- onclick=${() => shellActions.setMobileSidebarOpen((open) => !open)}
194
+ onclick=${() =>
195
+ shellActions.setMobileSidebarOpen((open) => !open)}
170
196
  aria-label="Open menu"
171
197
  aria-expanded=${shellState.mobileSidebarOpen ? "true" : "false"}
172
198
  >
173
- <svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor">
199
+ <svg
200
+ width="18"
201
+ height="18"
202
+ viewBox="0 0 16 16"
203
+ fill="currentColor"
204
+ >
174
205
  <path
175
206
  d="M2 3.75a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 3.75zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 8zm0 4.25a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75a.75.75 0 01-.75-.75z"
176
207
  />
@@ -201,7 +232,9 @@ const App = () => {
201
232
  onOpenclawUpdate=${controllerActions.handleOpenclawUpdate}
202
233
  onRestartRequired=${controllerActions.setRestartRequired}
203
234
  onDismissDoctorWarning=${() =>
204
- setDoctorWarningDismissedUntilMs(Date.now() + kOneWeekMs)}
235
+ setDoctorWarningDismissedUntilMs(
236
+ Date.now() + kOneWeekMs,
237
+ )}
205
238
  />
206
239
  </${Route}>
207
240
  <${Route} path="/doctor">
@@ -232,7 +265,9 @@ const App = () => {
232
265
  <${Route} path="/usage/:sessionId">
233
266
  ${(params) => html`
234
267
  <${UsageRoute}
235
- sessionId=${decodeURIComponent(params.sessionId || "")}
268
+ sessionId=${decodeURIComponent(
269
+ params.sessionId || "",
270
+ )}
236
271
  onSetLocation=${setLocation}
237
272
  />
238
273
  `}
@@ -280,7 +315,9 @@ const App = () => {
280
315
  <div class="app-statusbar">
281
316
  <div class="statusbar-left">
282
317
  ${controllerState.acVersion
283
- ? html`<span style="color: var(--text-muted)">v${controllerState.acVersion}</span>`
318
+ ? html`<span style="color: var(--text-muted)"
319
+ >v${controllerState.acVersion}</span
320
+ >`
284
321
  : null}
285
322
  </div>
286
323
  <div class="statusbar-right">
@@ -30,8 +30,8 @@ export const useWelcomeStorage = ({
30
30
  String(initialSetupState?.[kOnboardingStepKey] || ""),
31
31
  10,
32
32
  );
33
- if (!Number.isFinite(parsedStep)) return 0;
34
- const clampedStep = Math.max(0, Math.min(kPairingStepIndex, parsedStep));
33
+ if (!Number.isFinite(parsedStep)) return -1;
34
+ const clampedStep = Math.max(-1, Math.min(kPairingStepIndex, parsedStep));
35
35
  if (clampedStep === kSetupStepIndex && shouldRecoverFromSetupState) return 0;
36
36
  return clampedStep;
37
37
  });
@@ -29,7 +29,7 @@ export const kWelcomeGroups = [
29
29
  {
30
30
  id: "github",
31
31
  title: "GitHub",
32
- description: "Backs up your agent's config and workspace",
32
+ description: "Auto-backup your config and workspace",
33
33
  fields: [
34
34
  {
35
35
  key: "_GITHUB_SOURCE_REPO",
@@ -6,7 +6,6 @@ import { ActionButton } from "../action-button.js";
6
6
  import { Badge } from "../badge.js";
7
7
  import { SegmentedControl } from "../segmented-control.js";
8
8
  import {
9
- isValidGithubRepoInput,
10
9
  kGithubFlowFresh,
11
10
  kGithubFlowImport,
12
11
  kGithubTargetRepoModeCreate,
@@ -195,29 +194,9 @@ export const WelcomeFormStep = ({
195
194
  ${activeGroup.id === "github" &&
196
195
  html`
197
196
  <div class="space-y-3">
198
- <div class="space-y-1 pt-1">
199
- <div>
200
- <label class="text-xs font-medium text-gray-400">Setup mode</label>
201
- </div>
202
- <${SegmentedControl}
203
- options=${[
204
- { label: "Start fresh", value: kGithubFlowFresh },
205
- { label: "Import existing setup", value: kGithubFlowImport },
206
- ]}
207
- value=${githubFlow}
208
- onChange=${(value) => setValue("_GITHUB_FLOW", value)}
209
- size="md"
210
- fullWidth=${true}
211
- />
212
- </div>
213
197
  ${githubFlow === kGithubFlowFresh
214
198
  ? html`
215
199
  <div class="space-y-1">
216
- <div>
217
- <label class="text-xs font-medium text-gray-400"
218
- >Repository setup</label
219
- >
220
- </div>
221
200
  <${SegmentedControl}
222
201
  options=${[
223
202
  {
@@ -366,7 +345,7 @@ export const WelcomeFormStep = ({
366
345
  <div class="grid grid-cols-2 gap-2 pt-3">
367
346
  ${step < totalGroups - 1
368
347
  ? html`
369
- ${step > 0
348
+ ${step >= 0
370
349
  ? html`<${ActionButton}
371
350
  onClick=${goBack}
372
351
  tone="secondary"
@@ -390,7 +369,7 @@ export const WelcomeFormStep = ({
390
369
  />
391
370
  `
392
371
  : html`
393
- ${step > 0
372
+ ${step >= 0
394
373
  ? html`<${ActionButton}
395
374
  onClick=${goBack}
396
375
  tone="secondary"
@@ -6,6 +6,7 @@ const html = htm.bind(h);
6
6
  export const WelcomeHeader = ({
7
7
  groups,
8
8
  step,
9
+ isPreStep,
9
10
  isSetupStep,
10
11
  isPairingStep,
11
12
  stepNumber,
@@ -30,12 +31,14 @@ export const WelcomeHeader = ({
30
31
  <p style="color: var(--text-muted)" class="text-sm">
31
32
  Let's get your agent running
32
33
  </p>
33
- <div class="mt-4 mb-2 flex items-center justify-center">
34
+ <div class="mt-4 mb-2 flex items-center justify-center">
34
35
  <span
35
36
  class="text-[11px] px-2.5 py-1 rounded-full border border-border font-medium"
36
37
  style="background: rgba(0, 0, 0, 0.3); color: var(--text-muted)"
37
38
  >
38
- Step ${stepNumber} of ${progressSteps.length} - ${activeStepLabel}
39
+ ${isPreStep
40
+ ? "Choose your destiny"
41
+ : `Step ${stepNumber} of ${progressSteps.length} - ${activeStepLabel}`}
39
42
  </span>
40
43
  </div>
41
44
  </div>
@@ -43,21 +46,24 @@ export const WelcomeHeader = ({
43
46
  <div class="flex items-center gap-2">
44
47
  ${progressSteps.map((group, idx) => {
45
48
  const isActive = idx === step;
46
- const isComplete = idx < step || (isSetupStep && group.id === "setup");
49
+ const isComplete =
50
+ idx < step || (isSetupStep && group.id === "setup");
47
51
  const isPairingComplete =
48
52
  idx < step || (isPairingStep && group.id === "pairing");
49
- const bg = isActive
50
- ? "rgba(99, 235, 255, 0.9)"
51
- : group.id === "pairing"
52
- ? isPairingComplete
53
- ? "rgba(99, 235, 255, 0.55)"
54
- : "rgba(82, 94, 122, 0.45)"
55
- : isComplete
56
- ? "rgba(99, 235, 255, 0.55)"
57
- : "rgba(82, 94, 122, 0.45)";
53
+ const bg = isPreStep
54
+ ? "rgba(82, 94, 122, 0.45)"
55
+ : isActive
56
+ ? "rgba(99, 235, 255, 0.9)"
57
+ : group.id === "pairing"
58
+ ? isPairingComplete
59
+ ? "rgba(99, 235, 255, 0.55)"
60
+ : "rgba(82, 94, 122, 0.45)"
61
+ : isComplete
62
+ ? "rgba(99, 235, 255, 0.55)"
63
+ : "rgba(82, 94, 122, 0.45)";
58
64
  return html`
59
65
  <div
60
- class="h-1 flex-1 rounded-full transition-colors"
66
+ class="h-1 flex-1 rounded-full transition-colors ${isActive ? "ac-step-pill-pulse" : ""}"
61
67
  style=${{ background: bg }}
62
68
  title=${group.title}
63
69
  ></div>
@@ -0,0 +1,81 @@
1
+ import { h } from "https://esm.sh/preact";
2
+ import htm from "https://esm.sh/htm";
3
+ import { kGithubFlowFresh, kGithubFlowImport } from "./welcome-config.js";
4
+
5
+ const html = htm.bind(h);
6
+
7
+ export const WelcomePreStep = ({ onSelectFlow }) => {
8
+ return html`
9
+ <div class="space-y-3">
10
+ <button
11
+ type="button"
12
+ onclick=${() => onSelectFlow(kGithubFlowFresh)}
13
+ class="w-full flex items-center gap-4 text-left p-4 rounded-xl ac-path-card"
14
+ >
15
+ <div
16
+ class="ac-path-icon flex-shrink-0 w-10 h-10 flex items-center justify-center bg-black/30 rounded-lg border border-border text-gray-300"
17
+ >
18
+ <svg
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ viewBox="0 0 24 24"
21
+ fill="currentColor"
22
+ class="w-5 h-5"
23
+ >
24
+ <path
25
+ d="M14 4.4375C15.3462 4.4375 16.4375 3.34619 16.4375 2H17.5625C17.5625 3.34619 18.6538 4.4375 20 4.4375V5.5625C18.6538 5.5625 17.5625 6.65381 17.5625 8H16.4375C16.4375 6.65381 15.3462 5.5625 14 5.5625V4.4375ZM1 11C4.31371 11 7 8.31371 7 5H9C9 8.31371 11.6863 11 15 11V13C11.6863 13 9 15.6863 9 19H7C7 15.6863 4.31371 13 1 13V11ZM4.87601 12C6.18717 12.7276 7.27243 13.8128 8 15.124 8.72757 13.8128 9.81283 12.7276 11.124 12 9.81283 11.2724 8.72757 10.1872 8 8.87601 7.27243 10.1872 6.18717 11.2724 4.87601 12ZM17.25 14C17.25 15.7949 15.7949 17.25 14 17.25V18.75C15.7949 18.75 17.25 20.2051 17.25 22H18.75C18.75 20.2051 20.2051 18.75 22 18.75V17.25C20.2051 17.25 18.75 15.7949 18.75 14H17.25Z"
26
+ ></path>
27
+ </svg>
28
+ </div>
29
+ <div>
30
+ <div
31
+ class="ac-path-title text-sm font-medium text-gray-200 mb-0.5 transition-colors duration-150"
32
+ >
33
+ Start fresh
34
+ </div>
35
+ <div
36
+ class="ac-path-desc text-xs text-gray-500 transition-colors duration-150"
37
+ >
38
+ Create a new repository and set up your agent from scratch.
39
+ </div>
40
+ </div>
41
+ </button>
42
+
43
+ <button
44
+ type="button"
45
+ onclick=${() => onSelectFlow(kGithubFlowImport)}
46
+ class="w-full flex items-center gap-4 text-left p-4 rounded-xl ac-path-card"
47
+ >
48
+ <div
49
+ class="ac-path-icon flex-shrink-0 w-10 h-10 flex items-center justify-center bg-black/30 rounded-lg border border-border text-gray-300"
50
+ >
51
+ <svg
52
+ xmlns="http://www.w3.org/2000/svg"
53
+ viewBox="0 0 24 24"
54
+ fill="none"
55
+ stroke="currentColor"
56
+ stroke-width="2"
57
+ stroke-linecap="round"
58
+ stroke-linejoin="round"
59
+ class="w-5 h-5"
60
+ >
61
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
62
+ <polyline points="7 10 12 15 17 10"></polyline>
63
+ <line x1="12" y1="15" x2="12" y2="3"></line>
64
+ </svg>
65
+ </div>
66
+ <div>
67
+ <div
68
+ class="ac-path-title text-sm font-medium text-gray-200 mb-0.5 transition-colors duration-150"
69
+ >
70
+ Import existing setup
71
+ </div>
72
+ <div
73
+ class="ac-path-desc text-xs text-gray-500 transition-colors duration-150"
74
+ >
75
+ Connect an existing repository that already has an OpenClaw setup.
76
+ </div>
77
+ </div>
78
+ </button>
79
+ </div>
80
+ `;
81
+ };
@@ -2,7 +2,6 @@ import { h } from "https://esm.sh/preact";
2
2
  import htm from "https://esm.sh/htm";
3
3
  import { ActionButton } from "../action-button.js";
4
4
  import { PageHeader } from "../page-header.js";
5
- import { showToast } from "../toast.js";
6
5
  import { OverviewSection } from "./overview-section.js";
7
6
  import { SessionsSection } from "./sessions-section.js";
8
7
  import { useUsageTab } from "./use-usage-tab.js";
@@ -27,20 +26,6 @@ export const UsageTab = ({ sessionId = "" }) => {
27
26
  );
28
27
  };
29
28
 
30
- const handleRunBackfill = async () => {
31
- try {
32
- const result = await actions.triggerBackfill();
33
- const backfilledEvents = Number(result?.backfilledEvents || 0);
34
- const filesScanned = Number(result?.filesScanned || 0);
35
- showToast(
36
- `Imported ${backfilledEvents.toLocaleString()} usage events from ${filesScanned.toLocaleString()} session files`,
37
- "success",
38
- );
39
- } catch (error) {
40
- showToast(error.message || "Could not import historical usage data", "error");
41
- }
42
- };
43
-
44
29
  return html`
45
30
  <div class="space-y-4">
46
31
  <${PageHeader}
@@ -61,34 +46,6 @@ export const UsageTab = ({ sessionId = "" }) => {
61
46
  ${state.error}
62
47
  </div>`
63
48
  : null}
64
- ${state.showBackfillBanner
65
- ? html`
66
- <div class="bg-surface border border-border rounded-xl p-4 space-y-3">
67
- <p class="text-xs text-gray-300 leading-5">
68
- We found historical usage data from
69
- <span class="font-medium text-gray-200"
70
- >${Number(state.estimatedBackfillFiles || 0).toLocaleString()}</span
71
- >
72
- session files. Import it?
73
- </p>
74
- <div class="flex flex-wrap items-center gap-2">
75
- <${ActionButton}
76
- onClick=${handleRunBackfill}
77
- loading=${state.runningBackfill}
78
- disabled=${state.loadingBackfillStatus}
79
- idleLabel="Import historical data"
80
- loadingLabel="Importing..."
81
- />
82
- <${ActionButton}
83
- onClick=${actions.dismissBackfillBanner}
84
- tone="secondary"
85
- disabled=${state.runningBackfill}
86
- idleLabel="Dismiss"
87
- />
88
- </div>
89
- </div>
90
- `
91
- : null}
92
49
  ${state.loadingSummary && !state.summary
93
50
  ? html`<div class="text-sm text-[var(--text-muted)]">Loading usage summary...</div>`
94
51
  : html`
@@ -31,9 +31,8 @@ const getCacheHitRateValueClass = (ratio) => {
31
31
  const getOverviewMetrics = (summary) => {
32
32
  const totals = summary?.totals || {};
33
33
  const cacheReadTokens = Number(totals.cacheReadTokens || 0);
34
- const cacheWriteTokens = Number(totals.cacheWriteTokens || 0);
35
34
  const inputTokens = Number(totals.inputTokens || 0);
36
- const promptTokens = inputTokens + cacheReadTokens + cacheWriteTokens;
35
+ const promptTokens = inputTokens + cacheReadTokens;
37
36
  const turnCount = Number(totals.turnCount || 0);
38
37
  const totalTokens = Number(totals.totalTokens || 0);
39
38
  const totalCost = Number(totals.totalCost || 0);
@@ -6,11 +6,9 @@ import {
6
6
  useState,
7
7
  } from "https://esm.sh/preact/hooks";
8
8
  import {
9
- fetchUsageBackfillStatus,
10
9
  fetchUsageSessionDetail,
11
10
  fetchUsageSessions,
12
11
  fetchUsageSummary,
13
- runUsageBackfill,
14
12
  } from "../../lib/api.js";
15
13
  import { formatInteger, formatUsd } from "../../lib/format.js";
16
14
  import { readUiSettings, writeUiSettings } from "../../lib/ui-settings.js";
@@ -43,10 +41,6 @@ export const useUsageTab = ({ sessionId = "" }) => {
43
41
  const [loadingSummary, setLoadingSummary] = useState(false);
44
42
  const [loadingSessions, setLoadingSessions] = useState(false);
45
43
  const [loadingDetailById, setLoadingDetailById] = useState({});
46
- const [loadingBackfillStatus, setLoadingBackfillStatus] = useState(false);
47
- const [runningBackfill, setRunningBackfill] = useState(false);
48
- const [showBackfillBanner, setShowBackfillBanner] = useState(false);
49
- const [estimatedBackfillFiles, setEstimatedBackfillFiles] = useState(0);
50
44
  const [expandedSessionIds, setExpandedSessionIds] = useState(() =>
51
45
  sessionId ? [String(sessionId)] : [],
52
46
  );
@@ -102,37 +96,6 @@ export const useUsageTab = ({ sessionId = "" }) => {
102
96
  }
103
97
  }, []);
104
98
 
105
- const loadBackfillStatus = useCallback(async () => {
106
- setLoadingBackfillStatus(true);
107
- try {
108
- const data = await fetchUsageBackfillStatus();
109
- const available = !!data?.available;
110
- setShowBackfillBanner(available);
111
- setEstimatedBackfillFiles(Number(data?.estimatedFiles || 0));
112
- } catch {
113
- setShowBackfillBanner(false);
114
- setEstimatedBackfillFiles(0);
115
- } finally {
116
- setLoadingBackfillStatus(false);
117
- }
118
- }, []);
119
-
120
- const triggerBackfill = useCallback(async () => {
121
- setRunningBackfill(true);
122
- try {
123
- const result = await runUsageBackfill();
124
- setShowBackfillBanner(false);
125
- await loadSummary();
126
- await loadSessions();
127
- return result;
128
- } catch (err) {
129
- setError(err.message || "Could not backfill usage data");
130
- throw err;
131
- } finally {
132
- setRunningBackfill(false);
133
- }
134
- }, [loadSessions, loadSummary]);
135
-
136
99
  useEffect(() => {
137
100
  loadSummary();
138
101
  }, [loadSummary]);
@@ -148,10 +111,6 @@ export const useUsageTab = ({ sessionId = "" }) => {
148
111
  loadSessions();
149
112
  }, [loadSessions]);
150
113
 
151
- useEffect(() => {
152
- loadBackfillStatus();
153
- }, [loadBackfillStatus]);
154
-
155
114
  useEffect(() => {
156
115
  const safeSessionId = String(sessionId || "").trim();
157
116
  if (!safeSessionId) return;
@@ -297,10 +256,6 @@ export const useUsageTab = ({ sessionId = "" }) => {
297
256
  loadingSummary,
298
257
  loadingSessions,
299
258
  loadingDetailById,
300
- loadingBackfillStatus,
301
- runningBackfill,
302
- showBackfillBanner,
303
- estimatedBackfillFiles,
304
259
  expandedSessionIds,
305
260
  error,
306
261
  periodSummary,
@@ -310,9 +265,6 @@ export const useUsageTab = ({ sessionId = "" }) => {
310
265
  setDays,
311
266
  setMetric,
312
267
  loadSummary,
313
- loadBackfillStatus,
314
- triggerBackfill,
315
- dismissBackfillBanner: () => setShowBackfillBanner(false),
316
268
  loadSessionDetail,
317
269
  setExpandedSessionIds,
318
270
  },