@zzusp/ccsm 1.0.0 → 1.0.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.
Files changed (58) hide show
  1. package/README.md +7 -3
  2. package/bin/cli.mjs +52 -52
  3. package/dist/assets/DiskUsage-CKhggLs5.js +2 -0
  4. package/dist/assets/DiskUsage-CKhggLs5.js.map +1 -0
  5. package/dist/assets/{ImportPage-b8NORa8b.js → ImportPage-wge4VhZ-.js} +2 -2
  6. package/dist/assets/{ImportPage-b8NORa8b.js.map → ImportPage-wge4VhZ-.js.map} +1 -1
  7. package/dist/assets/{ProjectMemory-aSV8UzQ9.js → ProjectMemory-Q4XX40j_.js} +2 -2
  8. package/dist/assets/{ProjectMemory-aSV8UzQ9.js.map → ProjectMemory-Q4XX40j_.js.map} +1 -1
  9. package/dist/assets/{charts-A5eNHLjX.js → charts-jxJqXXUr.js} +2 -2
  10. package/dist/assets/{charts-A5eNHLjX.js.map → charts-jxJqXXUr.js.map} +1 -1
  11. package/dist/assets/index-7aMrnHJG.js +7 -0
  12. package/dist/assets/index-7aMrnHJG.js.map +1 -0
  13. package/dist/assets/index-BOeI_J4B.css +1 -0
  14. package/dist/assets/{query-C1K1uQRu.js → query-CS7JQ86v.js} +2 -2
  15. package/dist/assets/{query-C1K1uQRu.js.map → query-CS7JQ86v.js.map} +1 -1
  16. package/dist/assets/{react-W0jzChlo.js → react-CPkiFScu.js} +10 -10
  17. package/dist/assets/{react-W0jzChlo.js.map → react-CPkiFScu.js.map} +1 -1
  18. package/dist/assets/{router-DfbutHY3.js → router-DwaHAh1G.js} +2 -2
  19. package/dist/assets/{router-DfbutHY3.js.map → router-DwaHAh1G.js.map} +1 -1
  20. package/dist/assets/vendor-Cs8vYp-N.js +27 -0
  21. package/dist/assets/vendor-Cs8vYp-N.js.map +1 -0
  22. package/dist/favicon.svg +7 -7
  23. package/dist/index.html +6 -6
  24. package/package.json +83 -72
  25. package/server/index.ts +130 -126
  26. package/server/lib/active-sessions.test.ts +119 -0
  27. package/server/lib/bundle.test.ts +182 -0
  28. package/server/lib/claude-paths.test.ts +126 -0
  29. package/server/lib/claude-paths.ts +19 -12
  30. package/server/lib/cleanup-suggestions.ts +131 -0
  31. package/server/lib/constants.ts +1 -0
  32. package/server/lib/delete.test.ts +244 -0
  33. package/server/lib/delete.ts +5 -16
  34. package/server/lib/disk-usage.ts +6 -8
  35. package/server/lib/export-import-bundle.test.ts +337 -0
  36. package/server/lib/modified-files.test.ts +280 -0
  37. package/server/lib/modified-files.ts +228 -0
  38. package/server/lib/open-folder.ts +22 -15
  39. package/server/lib/parse-jsonl.ts +35 -3
  40. package/server/lib/safe-id.test.ts +41 -0
  41. package/server/lib/safe-remove.test.ts +73 -0
  42. package/server/lib/safe-remove.ts +25 -0
  43. package/server/lib/scan.ts +103 -0
  44. package/server/lib/update.ts +67 -0
  45. package/server/lib/version.test.ts +39 -0
  46. package/server/lib/version.ts +117 -0
  47. package/server/routes/disk-cleanup.ts +54 -0
  48. package/server/routes/sessions.ts +49 -0
  49. package/server/routes/version.ts +34 -0
  50. package/shared/constants.ts +5 -0
  51. package/shared/types.ts +152 -0
  52. package/dist/assets/DiskUsage-Bq4VaoUA.js +0 -2
  53. package/dist/assets/DiskUsage-Bq4VaoUA.js.map +0 -1
  54. package/dist/assets/index-DLATR3tZ.js +0 -5
  55. package/dist/assets/index-DLATR3tZ.js.map +0 -1
  56. package/dist/assets/index-DLDtbkux.css +0 -1
  57. package/dist/assets/vendor-CH80ylbS.js +0 -19
  58. package/dist/assets/vendor-CH80ylbS.js.map +0 -1
package/shared/types.ts CHANGED
@@ -31,6 +31,15 @@ export interface SessionSummary {
31
31
  isLivePid: boolean;
32
32
  isRecentlyActive: boolean;
33
33
  livePid: number | null;
34
+ /**
35
+ * Claude is *actively processing this turn* right now (a stricter state than
36
+ * `isLivePid`, which only means a Claude Code process is alive). True when the
37
+ * session has a live PID, was touched recently, and its last conversation turn
38
+ * is unfinished — Claude owes a reply (last record is `user`) or is mid-work
39
+ * (last `assistant` record ends on a `tool_use`). An aborted turn (trailing
40
+ * `[Request interrupted by user]`) counts as finished.
41
+ */
42
+ isWorking: boolean;
34
43
  }
35
44
 
36
45
  export type Block =
@@ -135,6 +144,42 @@ export interface DiskUsage {
135
144
  totalSessions: number;
136
145
  }
137
146
 
147
+ // ── 清理建议:把"可行动"的 cleanup target 显式列出来 ──────────────────────────
148
+ //
149
+ // largeSessions:top 10 最大的会话(按 jsonl + subdir + file-history + session-env 合计)
150
+ // orphanFileHistory / orphanSessionEnv:file-history/<sid>/ 或 session-env/<sid>/ 存在,
151
+ // 但对应 sid 在 projects/*/<sid>.jsonl 全集中找不到——典型情况是会话主体已被手动删
152
+ // 掉但侧 store 没清,纯属浪费磁盘。
153
+
154
+ export interface DiskCleanupLargeSession {
155
+ sessionId: string;
156
+ projectId: string;
157
+ projectPath: string;
158
+ title: string;
159
+ customTitle: string | null;
160
+ sizeBytes: number;
161
+ lastActivity: string | null;
162
+ }
163
+
164
+ export type DiskOrphanKind = 'file-history' | 'session-env';
165
+
166
+ export interface DiskCleanupOrphan {
167
+ sessionId: string;
168
+ sizeBytes: number;
169
+ }
170
+
171
+ export interface DiskCleanupSuggestions {
172
+ largeSessions: DiskCleanupLargeSession[];
173
+ orphanFileHistory: DiskCleanupOrphan[];
174
+ orphanSessionEnv: DiskCleanupOrphan[];
175
+ }
176
+
177
+ export interface DiskOrphanDeleteResult {
178
+ sessionId: string;
179
+ kind: DiskOrphanKind;
180
+ freedBytes: number;
181
+ }
182
+
138
183
  export type MemoryType = 'user' | 'feedback' | 'project' | 'reference';
139
184
 
140
185
  export interface MemoryEntry {
@@ -161,6 +206,42 @@ export interface HealthResponse {
161
206
  pid: number;
162
207
  }
163
208
 
209
+ // ── Version check & self-update ─────────────────────────────────────────────
210
+ //
211
+ // current = package.json version (same source as `ccsm --version`).
212
+ // latest/releaseNotes/releaseUrl come from the GitHub "latest release" API; when
213
+ // that check fails (offline, rate-limited) `checkError` carries the reason and the
214
+ // UI silently degrades to showing just the current version.
215
+
216
+ export interface VersionInfo {
217
+ current: string;
218
+ /** Latest release tag with leading `v` stripped; null if the check failed. */
219
+ latest: string | null;
220
+ hasUpdate: boolean;
221
+ /** Release title (GitHub `name`), falling back to the tag. */
222
+ releaseName: string | null;
223
+ /** Markdown release notes (GitHub `body`). */
224
+ releaseNotes: string | null;
225
+ /** Link to the GitHub release page. */
226
+ releaseUrl: string | null;
227
+ publishedAt: string | null;
228
+ repositoryUrl: string;
229
+ /** Non-null when the latest-release lookup failed. */
230
+ checkError: string | null;
231
+ }
232
+
233
+ export interface VersionUpdateResult {
234
+ /** True when `npm install -g …` exited 0. */
235
+ ok: boolean;
236
+ fromVersion: string;
237
+ /** Target version on success; null on failure. */
238
+ toVersion: string | null;
239
+ /** Tail of the package-manager stdout/stderr. */
240
+ output: string;
241
+ /** True after a successful update — the running process still serves the old code. */
242
+ restartRequired: boolean;
243
+ }
244
+
164
245
  // ── Cross-device share: export/import bundles ───────────────────────────────
165
246
  //
166
247
  // A bundle is a path-INDEPENDENT folder a user copies / commits-to-git / cloud-
@@ -323,6 +404,77 @@ export interface ImportResult {
323
404
  memoryWritten: string[];
324
405
  }
325
406
 
407
+ // ── Session: modified files ─────────────────────────────────────────────────
408
+ //
409
+ // 一个会话里"被修改过的文件" = 该会话 .jsonl 中 tool_use(Edit/Write/MultiEdit/
410
+ // NotebookEdit) 的 input.file_path / notebook_path 聚合。文件快照本身在
411
+ // ~/.claude/file-history/<sid>/<hash>@v<n>,文件名是 hash 反查不出路径,所以
412
+ // 我们以 jsonl 里的 tool_use 记录为单一事实源。
413
+ //
414
+ // errored = 该 tool_use 对应的 tool_result 标了 is_error。
415
+ // pending = 没找到对应 tool_result(截断或仍在进行中)。
416
+ // totalCount/errorCount 把这两种都算在内,UI 区分展示。
417
+
418
+ export type ModifiedFileToolName = 'Edit' | 'Write' | 'MultiEdit' | 'NotebookEdit';
419
+
420
+ /** One hunk of a structured patch, copied verbatim from Claude Code's
421
+ * `toolUseResult.structuredPatch`. Carries the *real* file line numbers so the
422
+ * UI can render a GitHub-style unified diff with accurate gutters + omitted gaps. */
423
+ export interface DiffHunk {
424
+ oldStart: number;
425
+ oldLines: number;
426
+ newStart: number;
427
+ newLines: number;
428
+ /** Each entry prefixed with ' ' (context), '-' (removed), or '+' (added). */
429
+ lines: string[];
430
+ }
431
+
432
+ export interface ModifiedFileOperation {
433
+ toolUseId: string;
434
+ toolName: ModifiedFileToolName;
435
+ ts: string | null;
436
+ /** uuid of the assistant message that issued this tool_use; lets the UI focus it. */
437
+ messageUuid: string | null;
438
+ errored: boolean;
439
+ pending: boolean;
440
+ /** Accurate diff from the tool_result, with real file line numbers. Empty array
441
+ * for a brand-new file (Write/NotebookEdit create — render input content as all-added);
442
+ * null when still pending or the session was truncated before the result. */
443
+ structuredPatch: DiffHunk[] | null;
444
+ }
445
+
446
+ export interface ModifiedFileSummary {
447
+ /** Absolute path as recorded in the tool_use input. */
448
+ filePath: string;
449
+ /** Path relativized against session.cwd when filePath sits under it; else null. */
450
+ relativePath: string | null;
451
+ editCount: number;
452
+ writeCount: number;
453
+ multiEditCount: number;
454
+ notebookEditCount: number;
455
+ totalCount: number;
456
+ errorCount: number;
457
+ firstAt: string | null;
458
+ lastAt: string | null;
459
+ /** Operations sorted by ts asc (null ts last). */
460
+ operations: ModifiedFileOperation[];
461
+ }
462
+
463
+ export interface ModifiedFilesResponse {
464
+ sessionId: string;
465
+ projectId: string;
466
+ /** Session-recorded cwd; used for relative paths and display. */
467
+ cwd: string | null;
468
+ /** Files sorted by lastAt desc (no-ts entries last). */
469
+ files: ModifiedFileSummary[];
470
+ }
471
+
472
+ /** Response of opening a session-modified file in the OS default app. */
473
+ export interface OpenFileResult {
474
+ ok: true;
475
+ path: string;
476
+ }
477
+
326
478
  export type SearchBlockKind = 'text' | 'tool_use' | 'tool_result' | 'thinking';
327
479
 
328
480
  export interface SearchSnippet {
@@ -1,2 +0,0 @@
1
- import{j as e,r as c}from"./react-W0jzChlo.js";import{b as E}from"./query-C1K1uQRu.js";import{u as b,L as K,s as _,f as g,a as n,b as q,M as j,S as B,c as z,q as D}from"./index-DLATR3tZ.js";import{G as h}from"./vendor-CH80ylbS.js";import{R as M,P as U,a as V,C as O,T as A,A as G,X as W,Y as X,b as Y}from"./charts-A5eNHLjX.js";import{L}from"./router-DfbutHY3.js";function y({label:s,value:t,unit:o,trail:r,accent:l}){return e.jsxs("div",{className:"surface-card is-interactive group relative overflow-hidden p-5 "+(l?"border-[var(--color-accent)]/40 hover:border-[var(--color-accent)]/60":""),children:[l&&e.jsx("span",{"aria-hidden":!0,className:"pointer-events-none absolute -right-12 -top-12 h-32 w-32 rounded-full bg-[var(--color-accent-soft)] opacity-70 blur-2xl"}),e.jsx("div",{className:"eyebrow",children:s}),e.jsxs("div",{className:"mt-3 flex items-baseline gap-1.5",children:[e.jsx("span",{className:"font-mono text-4xl font-light leading-none tracking-[-0.02em] tabular-nums text-[var(--color-fg-primary)]",children:t}),o&&e.jsx("span",{className:"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]",children:o})]}),r&&e.jsx("div",{className:"mt-3 font-mono text-[11px] text-[var(--color-fg-muted)]",children:r})]})}const P=["--color-accent","--color-moss","--color-iris","--color-fg-secondary","--color-accent-ink","--color-fg-muted"],H=["--color-accent","--color-fg-muted","--color-hairline","--color-surface","--color-fg-primary"];function R(s){const[t,o]=c.useState(()=>F(s));return c.useEffect(()=>{const r=new MutationObserver(()=>o(F(s)));return r.observe(document.documentElement,{attributes:!0,attributeFilter:["class"]}),()=>r.disconnect()},[s]),t}function F(s){const t=getComputedStyle(document.documentElement),o={};for(const r of s)o[r]=t.getPropertyValue(r).trim()||"#888";return o}function re(){var C;const s=b(),{data:t,isLoading:o,error:r}=E({queryKey:D.diskUsage(),queryFn:()=>z("/api/disk-usage")}),l=R(H),u=l["--color-accent"],N=l["--color-fg-muted"],d=l["--color-hairline"],f=l["--color-surface"],k=l["--color-fg-primary"],w=R(P),m=c.useMemo(()=>P.map(a=>w[a]),[w]),x=c.useMemo(()=>t?t.byProject.map(a=>({name:T(a.decodedCwd),value:a.totalBytes,sessions:a.sessionCount})):[],[t]),S=c.useMemo(()=>t?t.byMonth.map(a=>({month:a.month,MB:+(a.totalBytes/1048576).toFixed(2)})):[],[t]);return e.jsxs("section",{children:[e.jsx("div",{className:"surface-card p-6",children:e.jsx(Q,{title:s("disk.title"),tagline:s("disk.tagline"),stats:t?{totalBytes:t.totalBytes,projectCount:t.byProject.length,totalSessions:t.totalSessions}:null})}),o&&e.jsx(K,{label:s("common.computing"),className:"mt-10"}),r&&e.jsxs("p",{className:"mt-10 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-4 py-3 text-sm text-[var(--color-danger)]",children:[s("common.failed"),": ",r.message]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs(h.div,{initial:"hidden",animate:"show",variants:_,className:"mt-8 grid gap-3 sm:grid-cols-3",children:[e.jsx(h.div,{variants:g,children:e.jsx(y,{accent:!0,label:s("disk.stat.total"),value:n(t.totalBytes).split(" ")[0],unit:n(t.totalBytes).split(" ")[1],trail:s("disk.stat.acrossProjects",{n:t.byProject.length})})}),e.jsx(h.div,{variants:g,children:e.jsx(y,{label:s("disk.stat.sessions"),value:t.totalSessions.toLocaleString(),trail:t.topSessions[0]?s("disk.stat.largest",{size:n(t.topSessions[0].totalBytes)}):void 0})}),e.jsx(h.div,{variants:g,children:e.jsx(y,{label:s("disk.stat.months"),value:t.byMonth.length,trail:t.byMonth[0]?`${t.byMonth[0].month} → ${((C=t.byMonth.at(-1))==null?void 0:C.month)??t.byMonth[0].month}`:void 0})})]}),e.jsxs("div",{className:"mt-12 grid gap-8 lg:grid-cols-5",children:[e.jsx($,{title:s("disk.composition.title"),subtitle:s("disk.composition.subtitle"),className:"lg:col-span-3",children:x.length===0?e.jsx(v,{}):e.jsxs("div",{className:"grid gap-6 md:grid-cols-[minmax(0,1fr)_minmax(0,1.1fr)] md:items-center",children:[e.jsxs("div",{className:"relative mx-auto aspect-square w-full max-w-[260px]",children:[e.jsx(M,{width:"100%",height:"100%",children:e.jsxs(U,{margin:{top:0,right:0,bottom:0,left:0},children:[e.jsx(V,{data:x,dataKey:"value",nameKey:"name",cx:"50%",cy:"50%",innerRadius:"58%",outerRadius:"92%",paddingAngle:1.5,stroke:f,strokeWidth:2,isAnimationActive:!1,children:x.map((a,i)=>e.jsx(O,{fill:m[i%m.length]},i))}),e.jsx(A,{contentStyle:I(f,d,k),formatter:a=>n(a)})]})}),e.jsxs("div",{className:"pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center",children:[e.jsx("span",{className:"eyebrow",children:s("disk.composition.total")}),e.jsx("span",{className:"mt-1 font-mono text-2xl font-light tabular-nums text-[var(--color-fg-primary)]",children:n(t.totalBytes)})]})]}),e.jsx("ol",{className:"space-y-1.5 text-sm",children:x.slice(0,8).map((a,i)=>{const p=(a.value/t.totalBytes*100).toFixed(1);return e.jsxs("li",{className:"grid grid-cols-[14px_1fr_auto] items-baseline gap-2",children:[e.jsx("span",{"aria-hidden":!0,className:"block h-2.5 w-2.5 self-center rounded-sm",style:{background:m[i%m.length]}}),e.jsx("span",{className:"truncate font-mono text-xs text-[var(--color-fg-secondary)]",title:a.name,children:a.name}),e.jsxs("span",{className:"font-mono tabular-nums text-xs text-[var(--color-fg-primary)]",children:[p,"% ",e.jsxs("span",{className:"text-[var(--color-fg-faint)]",children:["· ",n(a.value)]})]})]},i)})})]})}),e.jsx($,{title:s("disk.cadence.title"),subtitle:s("disk.cadence.subtitle"),className:"lg:col-span-2",children:S.length===0?e.jsx(v,{}):e.jsx("div",{className:"h-72",children:e.jsx(M,{width:"100%",height:"100%",children:e.jsxs(G,{data:S,margin:{top:10,right:8,bottom:0,left:-10},children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:"cadenceFill",x1:"0",y1:"0",x2:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:u,stopOpacity:.55}),e.jsx("stop",{offset:"100%",stopColor:u,stopOpacity:0})]})}),e.jsx(W,{dataKey:"month",tick:{fontSize:11,fill:N,fontFamily:"var(--font-mono)"},tickLine:!1,axisLine:{stroke:d}}),e.jsx(X,{tick:{fontSize:11,fill:N,fontFamily:"var(--font-mono)"},tickLine:!1,axisLine:!1,width:36}),e.jsx(A,{contentStyle:I(f,d,k),formatter:a=>`${a.toFixed(2)} MB`,cursor:{stroke:d,strokeDasharray:"2 3"}}),e.jsx(Y,{type:"monotone",dataKey:"MB",stroke:u,strokeWidth:1.6,fill:"url(#cadenceFill)"})]})})})})]}),e.jsxs("div",{className:"surface-card mt-12 p-6",children:[e.jsxs("div",{className:"flex items-baseline justify-between",children:[e.jsx("h2",{className:"font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]",children:s("disk.heaviest.title")}),t.topSessions.length>0&&e.jsx("span",{className:"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]",children:s("disk.heaviest.top",{n:t.topSessions.length})})]}),e.jsx("div",{className:"rule-dotted mt-3","aria-hidden":!0}),t.topSessions.length===0?e.jsx(v,{className:"mt-6"}):e.jsx("div",{className:"mt-4 -mx-6 overflow-x-auto px-6",children:e.jsxs("table",{className:"w-full table-fixed text-sm",children:[e.jsxs("colgroup",{children:[e.jsx("col",{className:"w-10"}),e.jsx("col",{}),e.jsx("col",{className:"w-[22rem]"}),e.jsx("col",{className:"w-24"}),e.jsx("col",{className:"w-24"})]}),e.jsx("thead",{children:e.jsxs("tr",{className:"text-left",children:[e.jsx("th",{className:"px-2 py-3 eyebrow",children:s("disk.col.num")}),e.jsx("th",{className:"px-2 py-3 eyebrow",children:s("disk.col.title")}),e.jsx("th",{className:"px-2 py-3 eyebrow",children:s("disk.col.project")}),e.jsx("th",{className:"px-2 py-3 eyebrow text-right",children:s("disk.col.last")}),e.jsx("th",{className:"px-2 py-3 eyebrow text-right",children:s("disk.col.size")})]})}),e.jsx("tbody",{className:"border-t border-[var(--color-hairline)]",children:t.topSessions.map((a,i)=>{const p=a.customTitle??a.title;return e.jsxs("tr",{className:"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]",children:[e.jsx("td",{className:"px-2 py-3 align-top font-mono text-[11px] text-[var(--color-fg-faint)]",children:String(i+1).padStart(2,"0")}),e.jsx("td",{className:"px-2 py-3 align-top",children:e.jsx(L,{to:`/projects/${encodeURIComponent(a.projectId)}/sessions/${a.sessionId}`,className:"block truncate font-medium text-[var(--color-fg-primary)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]",title:p,children:p})}),e.jsx("td",{className:"px-2 py-3 align-top font-mono text-[12px] text-[var(--color-fg-muted)]",children:e.jsx(L,{to:`/projects/${encodeURIComponent(a.projectId)}`,className:"block truncate hover:text-[var(--color-fg-primary)]",title:a.projectId,children:J(t,a.projectId)})}),e.jsx("td",{className:"px-2 py-3 text-right align-top font-mono text-[12.5px] text-[var(--color-fg-secondary)]",children:q(a.lastAt)}),e.jsx("td",{className:"px-2 py-3 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:n(a.totalBytes)})]},`${a.projectId}/${a.sessionId}`)})})]})})]})]})]})}function Q({title:s,tagline:t,stats:o}){const r=b();return e.jsxs("header",{className:"relative",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline gap-x-4 gap-y-1",children:[e.jsxs("h1",{className:"font-display text-[clamp(1.75rem,3.5vw,2.25rem)] font-light leading-[1.1] tracking-[-0.02em] text-[var(--color-fg-primary)]",children:[s,e.jsx("span",{className:"text-[var(--color-accent)]",children:"."})]}),e.jsx("p",{className:"min-w-0 flex-1 font-display text-[13px] italic leading-snug text-[var(--color-fg-muted)]",children:t})]}),o&&e.jsxs("div",{className:"mt-3 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-xs",children:[e.jsx(j,{label:r("disk.meta.total"),value:n(o.totalBytes)}),e.jsx(B,{}),e.jsx(j,{label:r("disk.meta.projects"),value:o.projectCount}),e.jsx(B,{}),e.jsx(j,{label:r("disk.meta.sessions"),value:o.totalSessions.toLocaleString()})]})]})}function I(s,t,o){return{background:s,border:`1px solid ${t}`,borderRadius:8,fontFamily:"var(--font-mono)",fontSize:11,color:o,boxShadow:"var(--shadow-pop)"}}function J(s,t){const o=s.byProject.find(r=>r.projectId===t);return o?T(o.decodedCwd):t}function T(s){const t=s.split(/[\\/]+/).filter(Boolean);return t.length<=2?s:"…/"+t.slice(-2).join("/")}function $({title:s,subtitle:t,children:o,className:r=""}){return e.jsxs("section",{className:`surface-card p-5 ${r}`,children:[e.jsxs("header",{className:"mb-4 flex items-baseline justify-between gap-3",children:[e.jsx("h3",{className:"font-display text-lg font-light tracking-tight text-[var(--color-fg-primary)]",children:s}),t&&e.jsx("span",{className:"font-mono text-[10px] uppercase tracking-[0.18em] text-[var(--color-fg-muted)]",children:t})]}),o]})}function v({className:s=""}){const t=b();return e.jsx("p",{className:`font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)] ${s}`,children:t("common.noData")})}export{re as default};
2
- //# sourceMappingURL=DiskUsage-Bq4VaoUA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DiskUsage-Bq4VaoUA.js","sources":["../../web/src/components/StatCard.tsx","../../web/src/routes/DiskUsage.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\r\n\r\ninterface Props {\r\n label: string;\r\n value: ReactNode;\r\n unit?: ReactNode;\r\n trail?: ReactNode;\r\n accent?: boolean;\r\n}\r\n\r\nexport default function StatCard({ label, value, unit, trail, accent }: Props) {\r\n return (\r\n <div\r\n className={\r\n 'surface-card is-interactive group relative overflow-hidden p-5 ' +\r\n (accent ? 'border-[var(--color-accent)]/40 hover:border-[var(--color-accent)]/60' : '')\r\n }\r\n >\r\n {accent && (\r\n <span\r\n aria-hidden\r\n className=\"pointer-events-none absolute -right-12 -top-12 h-32 w-32 rounded-full bg-[var(--color-accent-soft)] opacity-70 blur-2xl\"\r\n />\r\n )}\r\n <div className=\"eyebrow\">{label}</div>\r\n <div className=\"mt-3 flex items-baseline gap-1.5\">\r\n <span className=\"font-mono text-4xl font-light leading-none tracking-[-0.02em] tabular-nums text-[var(--color-fg-primary)]\">\r\n {value}\r\n </span>\r\n {unit && (\r\n <span className=\"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]\">\r\n {unit}\r\n </span>\r\n )}\r\n </div>\r\n {trail && (\r\n <div className=\"mt-3 font-mono text-[11px] text-[var(--color-fg-muted)]\">{trail}</div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useQuery } from '@tanstack/react-query';\r\nimport { motion } from 'motion/react';\r\nimport { useEffect, useMemo, useState } from 'react';\r\nimport { Link } from 'react-router-dom';\r\nimport {\r\n Area,\r\n AreaChart,\r\n Cell,\r\n Pie,\r\n PieChart,\r\n ResponsiveContainer,\r\n Tooltip,\r\n XAxis,\r\n YAxis,\r\n} from 'recharts';\r\nimport { Loading } from '../components/Loading.tsx';\r\nimport { MetaItem, Sep } from '../components/PageHeader.tsx';\r\nimport StatCard from '../components/StatCard.tsx';\r\nimport { api, type DiskUsage } from '../lib/api.ts';\r\nimport { formatBytes, formatRelativeTime } from '../lib/format.ts';\r\nimport { useT } from '../lib/i18n.ts';\r\nimport { fadeUpItem, staggerParent } from '../lib/motion.ts';\r\nimport { queryKeys } from '../lib/query-keys.ts';\r\n\r\nconst PALETTE_VARS = [\r\n '--color-accent',\r\n '--color-moss',\r\n '--color-iris',\r\n '--color-fg-secondary',\r\n '--color-accent-ink',\r\n '--color-fg-muted',\r\n];\r\n\r\nconst CHART_VARS = [\r\n '--color-accent',\r\n '--color-fg-muted',\r\n '--color-hairline',\r\n '--color-surface',\r\n '--color-fg-primary',\r\n] as const;\r\n\r\n// Resolve a list of CSS variables on <html> and re-resolve whenever the\r\n// theme class flips. Recharts needs concrete colors; CSS vars don't traverse SVG cleanly.\r\nfunction useThemeColors<T extends readonly string[]>(vars: T): Record<T[number], string> {\r\n const [snapshot, setSnapshot] = useState(() => readVars(vars));\r\n useEffect(() => {\r\n const observer = new MutationObserver(() => setSnapshot(readVars(vars)));\r\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });\r\n return () => observer.disconnect();\r\n }, [vars]);\r\n return snapshot;\r\n}\r\n\r\nfunction readVars<T extends readonly string[]>(vars: T): Record<T[number], string> {\r\n const cs = getComputedStyle(document.documentElement);\r\n const out = {} as Record<T[number], string>;\r\n for (const v of vars) (out as Record<string, string>)[v] = cs.getPropertyValue(v).trim() || '#888';\r\n return out;\r\n}\r\n\r\nexport default function DiskUsageRoute() {\r\n const t = useT();\r\n const { data, isLoading, error } = useQuery({\r\n queryKey: queryKeys.diskUsage(),\r\n queryFn: () => api<DiskUsage>('/api/disk-usage'),\r\n });\r\n\r\n const colors = useThemeColors(CHART_VARS);\r\n const accent = colors['--color-accent'];\r\n const muted = colors['--color-fg-muted'];\r\n const hairline = colors['--color-hairline'];\r\n const surface = colors['--color-surface'];\r\n const fgPrimary = colors['--color-fg-primary'];\r\n\r\n const palette = useThemeColors(PALETTE_VARS);\r\n const resolvedPalette = useMemo(() => PALETTE_VARS.map((v) => palette[v]), [palette]);\r\n\r\n const pieData = useMemo(() => {\r\n if (!data) return [];\r\n return data.byProject.map((p) => ({\r\n name: shortCwd(p.decodedCwd),\r\n value: p.totalBytes,\r\n sessions: p.sessionCount,\r\n }));\r\n }, [data]);\r\n\r\n const monthData = useMemo(() => {\r\n if (!data) return [];\r\n return data.byMonth.map((m) => ({ month: m.month, MB: +(m.totalBytes / 1_048_576).toFixed(2) }));\r\n }, [data]);\r\n\r\n return (\r\n <section>\r\n <div className=\"surface-card p-6\">\r\n <Masthead\r\n title={t('disk.title')}\r\n tagline={t('disk.tagline')}\r\n stats={\r\n data\r\n ? {\r\n totalBytes: data.totalBytes,\r\n projectCount: data.byProject.length,\r\n totalSessions: data.totalSessions,\r\n }\r\n : null\r\n }\r\n />\r\n </div>\r\n\r\n {isLoading && <Loading label={t('common.computing')} className=\"mt-10\" />}\r\n {error && (\r\n <p className=\"mt-10 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-4 py-3 text-sm text-[var(--color-danger)]\">\r\n {t('common.failed')}: {(error as Error).message}\r\n </p>\r\n )}\r\n\r\n {data && (\r\n <>\r\n <motion.div\r\n initial=\"hidden\"\r\n animate=\"show\"\r\n variants={staggerParent}\r\n className=\"mt-8 grid gap-3 sm:grid-cols-3\"\r\n >\r\n <motion.div variants={fadeUpItem}>\r\n <StatCard\r\n accent\r\n label={t('disk.stat.total')}\r\n value={formatBytes(data.totalBytes).split(' ')[0]}\r\n unit={formatBytes(data.totalBytes).split(' ')[1]}\r\n trail={t('disk.stat.acrossProjects', { n: data.byProject.length })}\r\n />\r\n </motion.div>\r\n <motion.div variants={fadeUpItem}>\r\n <StatCard\r\n label={t('disk.stat.sessions')}\r\n value={data.totalSessions.toLocaleString()}\r\n trail={\r\n data.topSessions[0]\r\n ? t('disk.stat.largest', { size: formatBytes(data.topSessions[0].totalBytes) })\r\n : undefined\r\n }\r\n />\r\n </motion.div>\r\n <motion.div variants={fadeUpItem}>\r\n <StatCard\r\n label={t('disk.stat.months')}\r\n value={data.byMonth.length}\r\n trail={\r\n data.byMonth[0]\r\n ? `${data.byMonth[0].month} → ${data.byMonth.at(-1)?.month ?? data.byMonth[0].month}`\r\n : undefined\r\n }\r\n />\r\n </motion.div>\r\n </motion.div>\r\n\r\n <div className=\"mt-12 grid gap-8 lg:grid-cols-5\">\r\n <Card\r\n title={t('disk.composition.title')}\r\n subtitle={t('disk.composition.subtitle')}\r\n className=\"lg:col-span-3\"\r\n >\r\n {pieData.length === 0 ? (\r\n <Empty />\r\n ) : (\r\n <div className=\"grid gap-6 md:grid-cols-[minmax(0,1fr)_minmax(0,1.1fr)] md:items-center\">\r\n <div className=\"relative mx-auto aspect-square w-full max-w-[260px]\">\r\n <ResponsiveContainer width=\"100%\" height=\"100%\">\r\n <PieChart margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>\r\n <Pie\r\n data={pieData}\r\n dataKey=\"value\"\r\n nameKey=\"name\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n innerRadius=\"58%\"\r\n outerRadius=\"92%\"\r\n paddingAngle={1.5}\r\n stroke={surface}\r\n strokeWidth={2}\r\n isAnimationActive={false}\r\n >\r\n {pieData.map((_, i) => (\r\n <Cell key={i} fill={resolvedPalette[i % resolvedPalette.length]} />\r\n ))}\r\n </Pie>\r\n <Tooltip\r\n contentStyle={tooltipStyle(surface, hairline, fgPrimary)}\r\n formatter={(value: number) => formatBytes(value)}\r\n />\r\n </PieChart>\r\n </ResponsiveContainer>\r\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center\">\r\n <span className=\"eyebrow\">{t('disk.composition.total')}</span>\r\n <span className=\"mt-1 font-mono text-2xl font-light tabular-nums text-[var(--color-fg-primary)]\">\r\n {formatBytes(data.totalBytes)}\r\n </span>\r\n </div>\r\n </div>\r\n <ol className=\"space-y-1.5 text-sm\">\r\n {pieData.slice(0, 8).map((p, i) => {\r\n const pct = ((p.value / data.totalBytes) * 100).toFixed(1);\r\n return (\r\n <li key={i} className=\"grid grid-cols-[14px_1fr_auto] items-baseline gap-2\">\r\n <span\r\n aria-hidden\r\n className=\"block h-2.5 w-2.5 self-center rounded-sm\"\r\n style={{ background: resolvedPalette[i % resolvedPalette.length] }}\r\n />\r\n <span className=\"truncate font-mono text-xs text-[var(--color-fg-secondary)]\" title={p.name}>\r\n {p.name}\r\n </span>\r\n <span className=\"font-mono tabular-nums text-xs text-[var(--color-fg-primary)]\">\r\n {pct}% <span className=\"text-[var(--color-fg-faint)]\">· {formatBytes(p.value)}</span>\r\n </span>\r\n </li>\r\n );\r\n })}\r\n </ol>\r\n </div>\r\n )}\r\n </Card>\r\n\r\n <Card\r\n title={t('disk.cadence.title')}\r\n subtitle={t('disk.cadence.subtitle')}\r\n className=\"lg:col-span-2\"\r\n >\r\n {monthData.length === 0 ? (\r\n <Empty />\r\n ) : (\r\n <div className=\"h-72\">\r\n <ResponsiveContainer width=\"100%\" height=\"100%\">\r\n <AreaChart data={monthData} margin={{ top: 10, right: 8, bottom: 0, left: -10 }}>\r\n <defs>\r\n <linearGradient id=\"cadenceFill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\r\n <stop offset=\"0%\" stopColor={accent} stopOpacity={0.55} />\r\n <stop offset=\"100%\" stopColor={accent} stopOpacity={0} />\r\n </linearGradient>\r\n </defs>\r\n <XAxis\r\n dataKey=\"month\"\r\n tick={{ fontSize: 11, fill: muted, fontFamily: 'var(--font-mono)' }}\r\n tickLine={false}\r\n axisLine={{ stroke: hairline }}\r\n />\r\n <YAxis\r\n tick={{ fontSize: 11, fill: muted, fontFamily: 'var(--font-mono)' }}\r\n tickLine={false}\r\n axisLine={false}\r\n width={36}\r\n />\r\n <Tooltip\r\n contentStyle={tooltipStyle(surface, hairline, fgPrimary)}\r\n formatter={(value: number) => `${value.toFixed(2)} MB`}\r\n cursor={{ stroke: hairline, strokeDasharray: '2 3' }}\r\n />\r\n <Area\r\n type=\"monotone\"\r\n dataKey=\"MB\"\r\n stroke={accent}\r\n strokeWidth={1.6}\r\n fill=\"url(#cadenceFill)\"\r\n />\r\n </AreaChart>\r\n </ResponsiveContainer>\r\n </div>\r\n )}\r\n </Card>\r\n </div>\r\n\r\n <div className=\"surface-card mt-12 p-6\">\r\n <div className=\"flex items-baseline justify-between\">\r\n <h2 className=\"font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]\">\r\n {t('disk.heaviest.title')}\r\n </h2>\r\n {data.topSessions.length > 0 && (\r\n <span className=\"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]\">\r\n {t('disk.heaviest.top', { n: data.topSessions.length })}\r\n </span>\r\n )}\r\n </div>\r\n <div className=\"rule-dotted mt-3\" aria-hidden />\r\n {data.topSessions.length === 0 ? (\r\n <Empty className=\"mt-6\" />\r\n ) : (\r\n <div className=\"mt-4 -mx-6 overflow-x-auto px-6\">\r\n <table className=\"w-full table-fixed text-sm\">\r\n <colgroup>\r\n <col className=\"w-10\" />\r\n <col />\r\n <col className=\"w-[22rem]\" />\r\n <col className=\"w-24\" />\r\n <col className=\"w-24\" />\r\n </colgroup>\r\n <thead>\r\n <tr className=\"text-left\">\r\n <th className=\"px-2 py-3 eyebrow\">{t('disk.col.num')}</th>\r\n <th className=\"px-2 py-3 eyebrow\">{t('disk.col.title')}</th>\r\n <th className=\"px-2 py-3 eyebrow\">{t('disk.col.project')}</th>\r\n <th className=\"px-2 py-3 eyebrow text-right\">{t('disk.col.last')}</th>\r\n <th className=\"px-2 py-3 eyebrow text-right\">{t('disk.col.size')}</th>\r\n </tr>\r\n </thead>\r\n <tbody className=\"border-t border-[var(--color-hairline)]\">\r\n {data.topSessions.map((s, i) => {\r\n const displayTitle = s.customTitle ?? s.title;\r\n return (\r\n <tr\r\n key={`${s.projectId}/${s.sessionId}`}\r\n className=\"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]\"\r\n >\r\n <td className=\"px-2 py-3 align-top font-mono text-[11px] text-[var(--color-fg-faint)]\">\r\n {String(i + 1).padStart(2, '0')}\r\n </td>\r\n <td className=\"px-2 py-3 align-top\">\r\n <Link\r\n to={`/projects/${encodeURIComponent(s.projectId)}/sessions/${s.sessionId}`}\r\n className=\"block truncate font-medium text-[var(--color-fg-primary)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]\"\r\n title={displayTitle}\r\n >\r\n {displayTitle}\r\n </Link>\r\n </td>\r\n <td className=\"px-2 py-3 align-top font-mono text-[12px] text-[var(--color-fg-muted)]\">\r\n <Link\r\n to={`/projects/${encodeURIComponent(s.projectId)}`}\r\n className=\"block truncate hover:text-[var(--color-fg-primary)]\"\r\n title={s.projectId}\r\n >\r\n {projectCwdLabel(data, s.projectId)}\r\n </Link>\r\n </td>\r\n <td className=\"px-2 py-3 text-right align-top font-mono text-[12.5px] text-[var(--color-fg-secondary)]\">\r\n {formatRelativeTime(s.lastAt)}\r\n </td>\r\n <td className=\"px-2 py-3 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]\">\r\n {formatBytes(s.totalBytes)}\r\n </td>\r\n </tr>\r\n );\r\n })}\r\n </tbody>\r\n </table>\r\n </div>\r\n )}\r\n </div>\r\n </>\r\n )}\r\n </section>\r\n );\r\n}\r\n\r\nfunction Masthead({\r\n title,\r\n tagline,\r\n stats,\r\n}: {\r\n title: string;\r\n tagline: string;\r\n stats: {\r\n totalBytes: number;\r\n projectCount: number;\r\n totalSessions: number;\r\n } | null;\r\n}) {\r\n const t = useT();\r\n return (\r\n <header className=\"relative\">\r\n <div className=\"flex flex-wrap items-baseline gap-x-4 gap-y-1\">\r\n <h1 className=\"font-display text-[clamp(1.75rem,3.5vw,2.25rem)] font-light leading-[1.1] tracking-[-0.02em] text-[var(--color-fg-primary)]\">\r\n {title}\r\n <span className=\"text-[var(--color-accent)]\">.</span>\r\n </h1>\r\n <p className=\"min-w-0 flex-1 font-display text-[13px] italic leading-snug text-[var(--color-fg-muted)]\">\r\n {tagline}\r\n </p>\r\n </div>\r\n {stats && (\r\n <div className=\"mt-3 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-xs\">\r\n <MetaItem label={t('disk.meta.total')} value={formatBytes(stats.totalBytes)} />\r\n <Sep />\r\n <MetaItem label={t('disk.meta.projects')} value={stats.projectCount} />\r\n <Sep />\r\n <MetaItem label={t('disk.meta.sessions')} value={stats.totalSessions.toLocaleString()} />\r\n </div>\r\n )}\r\n </header>\r\n );\r\n}\r\n\r\nfunction tooltipStyle(surface: string, hairline: string, fg: string): React.CSSProperties {\r\n return {\r\n background: surface,\r\n border: `1px solid ${hairline}`,\r\n borderRadius: 8,\r\n fontFamily: 'var(--font-mono)',\r\n fontSize: 11,\r\n color: fg,\r\n boxShadow: 'var(--shadow-pop)',\r\n };\r\n}\r\n\r\nfunction projectCwdLabel(data: DiskUsage, projectId: string): string {\r\n const p = data.byProject.find((row) => row.projectId === projectId);\r\n return p ? shortCwd(p.decodedCwd) : projectId;\r\n}\r\n\r\nfunction shortCwd(cwd: string): string {\r\n const parts = cwd.split(/[\\\\/]+/).filter(Boolean);\r\n if (parts.length <= 2) return cwd;\r\n return '…/' + parts.slice(-2).join('/');\r\n}\r\n\r\nfunction Card({\r\n title,\r\n subtitle,\r\n children,\r\n className = '',\r\n}: {\r\n title: string;\r\n subtitle?: string;\r\n children: React.ReactNode;\r\n className?: string;\r\n}) {\r\n return (\r\n <section className={`surface-card p-5 ${className}`}>\r\n <header className=\"mb-4 flex items-baseline justify-between gap-3\">\r\n <h3 className=\"font-display text-lg font-light tracking-tight text-[var(--color-fg-primary)]\">\r\n {title}\r\n </h3>\r\n {subtitle && (\r\n <span className=\"font-mono text-[10px] uppercase tracking-[0.18em] text-[var(--color-fg-muted)]\">\r\n {subtitle}\r\n </span>\r\n )}\r\n </header>\r\n {children}\r\n </section>\r\n );\r\n}\r\n\r\nfunction Empty({ className = '' }: { className?: string }) {\r\n const t = useT();\r\n return (\r\n <p className={`font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)] ${className}`}>\r\n {t('common.noData')}\r\n </p>\r\n );\r\n}\r\n"],"names":["StatCard","label","value","unit","trail","accent","jsxs","jsx","PALETTE_VARS","CHART_VARS","useThemeColors","vars","snapshot","setSnapshot","useState","readVars","useEffect","observer","cs","out","v","DiskUsageRoute","t","useT","data","isLoading","error","useQuery","queryKeys","api","colors","muted","hairline","surface","fgPrimary","palette","resolvedPalette","useMemo","pieData","p","shortCwd","monthData","m","Masthead","Loading","Fragment","motion","staggerParent","fadeUpItem","formatBytes","_a","Card","Empty","ResponsiveContainer","PieChart","Pie","_","Cell","Tooltip","tooltipStyle","pct","AreaChart","XAxis","YAxis","Area","s","displayTitle","Link","projectCwdLabel","formatRelativeTime","title","tagline","stats","MetaItem","Sep","fg","projectId","row","cwd","parts","subtitle","children","className"],"mappings":"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"}