@zzusp/ccsm 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +236 -236
- package/bin/cli.mjs +52 -52
- package/dist/assets/{DiskUsage-CKhggLs5.js → DiskUsage-BY6XwffG.js} +2 -2
- package/dist/assets/DiskUsage-BY6XwffG.js.map +1 -0
- package/dist/assets/{ImportPage-wge4VhZ-.js → ImportPage-Cwq5bx7G.js} +2 -2
- package/dist/assets/ImportPage-Cwq5bx7G.js.map +1 -0
- package/dist/assets/MarkdownContent-BFu7Nkk_.js +2 -0
- package/dist/assets/MarkdownContent-BFu7Nkk_.js.map +1 -0
- package/dist/assets/{ProjectMemory-Q4XX40j_.js → ProjectMemory-CcE3KbUK.js} +2 -2
- package/dist/assets/ProjectMemory-CcE3KbUK.js.map +1 -0
- package/dist/assets/index-CrWxV6sb.css +1 -0
- package/dist/assets/index-DTbWl1jb.js +11 -0
- package/dist/assets/index-DTbWl1jb.js.map +1 -0
- package/dist/assets/markdown-Bag5rX3T.js +30 -0
- package/dist/assets/markdown-Bag5rX3T.js.map +1 -0
- package/dist/index.html +26 -26
- package/package.json +85 -83
- package/server/index.ts +130 -130
- package/server/lib/active-sessions.test.ts +119 -119
- package/server/lib/active-sessions.ts +95 -95
- package/server/lib/bundle.test.ts +182 -182
- package/server/lib/bundle.ts +86 -86
- package/server/lib/claude-paths.test.ts +126 -126
- package/server/lib/claude-paths.ts +43 -43
- package/server/lib/cleanup-suggestions.ts +131 -131
- package/server/lib/constants.ts +8 -8
- package/server/lib/delete-project.ts +100 -100
- package/server/lib/delete.test.ts +244 -244
- package/server/lib/delete.ts +192 -192
- package/server/lib/disk-usage.ts +81 -81
- package/server/lib/encode-cwd.ts +24 -24
- package/server/lib/export-bundle.ts +236 -236
- package/server/lib/export-import-bundle.test.ts +337 -337
- package/server/lib/fs-size.ts +38 -38
- package/server/lib/import-bundle.ts +488 -488
- package/server/lib/load-memory.ts +120 -120
- package/server/lib/load-session.ts +209 -209
- package/server/lib/modified-files.test.ts +280 -280
- package/server/lib/modified-files.ts +228 -228
- package/server/lib/open-folder.ts +47 -47
- package/server/lib/parse-jsonl.ts +160 -139
- package/server/lib/port.ts +23 -23
- package/server/lib/safe-id.test.ts +41 -41
- package/server/lib/safe-id.ts +6 -6
- package/server/lib/safe-remove.test.ts +73 -73
- package/server/lib/safe-remove.ts +25 -25
- package/server/lib/scan.ts +289 -286
- package/server/lib/search-all.ts +130 -130
- package/server/lib/search-session.ts +203 -203
- package/server/lib/system-tags.ts +20 -20
- package/server/lib/update.ts +67 -67
- package/server/lib/version.test.ts +39 -39
- package/server/lib/version.ts +117 -117
- package/server/routes/disk-cleanup.ts +54 -54
- package/server/routes/disk.ts +9 -9
- package/server/routes/import.ts +87 -87
- package/server/routes/projects.ts +104 -104
- package/server/routes/search.ts +79 -79
- package/server/routes/sessions.ts +130 -130
- package/server/routes/version.ts +34 -34
- package/server/types.ts +1 -1
- package/shared/constants.ts +7 -7
- package/shared/types.ts +513 -511
- package/dist/assets/DiskUsage-CKhggLs5.js.map +0 -1
- package/dist/assets/ImportPage-wge4VhZ-.js.map +0 -1
- package/dist/assets/ProjectMemory-Q4XX40j_.js.map +0 -1
- package/dist/assets/index-7aMrnHJG.js +0 -7
- package/dist/assets/index-7aMrnHJG.js.map +0 -1
- package/dist/assets/index-BOeI_J4B.css +0 -1
package/bin/cli.mjs
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// ccsm — Claude Code Session Manager CLI launcher.
|
|
3
|
-
//
|
|
4
|
-
// Plain JS so it runs under a bare `node` (global install / npx) with no build
|
|
5
|
-
// step. --help/--version are answered here without loading the server. For the
|
|
6
|
-
// real thing we register tsx's ESM loader (resolved from THIS package, so it
|
|
7
|
-
// works regardless of the user's cwd) and import the TypeScript server entry —
|
|
8
|
-
// the same path `npm run start` (`tsx server/index.ts`) takes.
|
|
9
|
-
import { readFileSync } from 'node:fs';
|
|
10
|
-
import { dirname, join } from 'node:path';
|
|
11
|
-
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
12
|
-
|
|
13
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
-
const pkgRoot = join(__dirname, '..');
|
|
15
|
-
const args = process.argv.slice(2);
|
|
16
|
-
|
|
17
|
-
if (args.includes('-v') || args.includes('--version')) {
|
|
18
|
-
const { version } = JSON.parse(readFileSync(join(pkgRoot, 'package.json'), 'utf8'));
|
|
19
|
-
console.log(version);
|
|
20
|
-
process.exit(0);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (args.includes('-h') || args.includes('--help')) {
|
|
24
|
-
printHelp();
|
|
25
|
-
process.exit(0);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { register } = await import('tsx/esm/api');
|
|
29
|
-
register();
|
|
30
|
-
await import(pathToFileURL(join(pkgRoot, 'server', 'index.ts')).href);
|
|
31
|
-
|
|
32
|
-
function printHelp() {
|
|
33
|
-
console.log(`ccsm — Claude Code Session Manager
|
|
34
|
-
|
|
35
|
-
A local web UI to browse and clean up your Claude Code session history (~/.claude/).
|
|
36
|
-
|
|
37
|
-
Usage:
|
|
38
|
-
ccsm [options]
|
|
39
|
-
|
|
40
|
-
Options:
|
|
41
|
-
-p, --port <number> Port to listen on. Default: first free port in 3131-3140.
|
|
42
|
-
If the given port is busy, ccsm exits (it won't pick another).
|
|
43
|
-
--host <host> Host to bind. Default: 127.0.0.1 (loopback only).
|
|
44
|
-
Pass 0.0.0.0 to expose the UI on your LAN. There is NO
|
|
45
|
-
authentication, so only do this on a network you trust.
|
|
46
|
-
-o, --open Open the UI in your default browser once it's listening.
|
|
47
|
-
-h, --help Show this help and exit.
|
|
48
|
-
-v, --version Print the version and exit.
|
|
49
|
-
|
|
50
|
-
The server binds to 127.0.0.1 by default and is unreachable from the network.
|
|
51
|
-
Once it's up, open http://127.0.0.1:<port> in your browser.`);
|
|
52
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ccsm — Claude Code Session Manager CLI launcher.
|
|
3
|
+
//
|
|
4
|
+
// Plain JS so it runs under a bare `node` (global install / npx) with no build
|
|
5
|
+
// step. --help/--version are answered here without loading the server. For the
|
|
6
|
+
// real thing we register tsx's ESM loader (resolved from THIS package, so it
|
|
7
|
+
// works regardless of the user's cwd) and import the TypeScript server entry —
|
|
8
|
+
// the same path `npm run start` (`tsx server/index.ts`) takes.
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { dirname, join } from 'node:path';
|
|
11
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const pkgRoot = join(__dirname, '..');
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
|
|
17
|
+
if (args.includes('-v') || args.includes('--version')) {
|
|
18
|
+
const { version } = JSON.parse(readFileSync(join(pkgRoot, 'package.json'), 'utf8'));
|
|
19
|
+
console.log(version);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
24
|
+
printHelp();
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { register } = await import('tsx/esm/api');
|
|
29
|
+
register();
|
|
30
|
+
await import(pathToFileURL(join(pkgRoot, 'server', 'index.ts')).href);
|
|
31
|
+
|
|
32
|
+
function printHelp() {
|
|
33
|
+
console.log(`ccsm — Claude Code Session Manager
|
|
34
|
+
|
|
35
|
+
A local web UI to browse and clean up your Claude Code session history (~/.claude/).
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
ccsm [options]
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
-p, --port <number> Port to listen on. Default: first free port in 3131-3140.
|
|
42
|
+
If the given port is busy, ccsm exits (it won't pick another).
|
|
43
|
+
--host <host> Host to bind. Default: 127.0.0.1 (loopback only).
|
|
44
|
+
Pass 0.0.0.0 to expose the UI on your LAN. There is NO
|
|
45
|
+
authentication, so only do this on a network you trust.
|
|
46
|
+
-o, --open Open the UI in your default browser once it's listening.
|
|
47
|
+
-h, --help Show this help and exit.
|
|
48
|
+
-v, --version Print the version and exit.
|
|
49
|
+
|
|
50
|
+
The server binds to 127.0.0.1 by default and is unreachable from the network.
|
|
51
|
+
Once it's up, open http://127.0.0.1:<port> in your browser.`);
|
|
52
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e,r as x}from"./react-CPkiFScu.js";import{u as q,b as H,a as O}from"./query-CS7JQ86v.js";import{u as p,L as K,f as _,a as c,q as y,b as S,s as Q,c as b,M as N,S as $}from"./index-7aMrnHJG.js";import{L as v}from"./router-DwaHAh1G.js";import{H as h}from"./vendor-Cs8vYp-N.js";import{R as E,P as V,a as W,C as X,T as L,A as Y,X as G,Y as J,b as Z}from"./charts-jxJqXXUr.js";function ee(){const s=p(),{data:t,isLoading:a,error:o}=q({queryKey:y.diskCleanupSuggestions(),queryFn:()=>S("/api/disk-cleanup/suggestions")});return e.jsxs("section",{className:"surface-card mt-12 p-6",children:[e.jsxs("header",{className:"flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",children:[e.jsx("h2",{className:"font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]",children:s("cleanup.title")}),e.jsx("p",{className:"min-w-0 flex-1 font-display text-[13px] italic leading-snug text-[var(--color-fg-muted)]",children:s("cleanup.tagline")})]}),e.jsx("div",{className:"rule-dotted mt-3","aria-hidden":!0}),a&&e.jsx(K,{label:s("common.computing"),className:"mt-6"}),o&&e.jsx("p",{className:"mt-6 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("cleanup.failed",{msg:o.message})}),t&&e.jsxs("div",{className:"mt-6 space-y-8",children:[e.jsx(te,{data:t.largeSessions}),e.jsx(R,{kind:"file-history",title:s("cleanup.section.orphanFileHistory"),hint:s("cleanup.section.orphanFileHistory.hint"),rows:t.orphanFileHistory}),e.jsx(R,{kind:"session-env",title:s("cleanup.section.orphanSessionEnv"),hint:s("cleanup.section.orphanSessionEnv.hint"),rows:t.orphanSessionEnv})]})]})}function U({title:s,hint:t}){return e.jsxs("div",{className:"flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1 rounded-[var(--radius-input)] bg-[var(--color-sunken)] px-3 py-2",children:[e.jsx("h3",{className:"font-display text-[15px] font-light tracking-tight text-[var(--color-fg-primary)]",children:s}),e.jsx("span",{className:"font-mono text-[10.5px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]",children:t})]})}function te({data:s}){const t=p();return e.jsxs("div",{children:[e.jsx(U,{title:t("cleanup.section.largeSessions"),hint:t("cleanup.section.largeSessions.hint",{n:s.length||10})}),s.length===0?e.jsx("p",{className:"mt-3 font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)]",children:t("cleanup.empty.largeSessions")}):e.jsx("div",{className:"mt-3 -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",{}),e.jsx("col",{className:"w-[20rem]"}),e.jsx("col",{className:"w-24"}),e.jsx("col",{className:"w-24"}),e.jsx("col",{className:"w-20"})]}),e.jsx("thead",{children:e.jsxs("tr",{className:"text-left",children:[e.jsx("th",{className:"px-2 py-2 eyebrow",children:t("cleanup.col.session")}),e.jsx("th",{className:"px-2 py-2 eyebrow",children:t("cleanup.col.project")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:t("cleanup.col.last")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:t("cleanup.col.size")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:t("cleanup.col.actions")})]})}),e.jsx("tbody",{className:"border-t border-[var(--color-hairline)]",children:s.map(a=>{const o=a.customTitle??a.title;return e.jsxs("tr",{className:"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]",children:[e.jsxs("td",{className:"px-2 py-2.5 align-top",children:[e.jsx("div",{className:"truncate font-medium text-[var(--color-fg-primary)]",title:o,children:o}),e.jsx("div",{className:"mt-0.5 truncate font-mono text-[10.5px] text-[var(--color-fg-faint)]",title:a.sessionId,children:a.sessionId})]}),e.jsx("td",{className:"px-2 py-2.5 align-top font-mono text-[12px] text-[var(--color-fg-muted)]",children:e.jsx(v,{to:`/projects/${encodeURIComponent(a.projectId)}`,className:"block truncate hover:text-[var(--color-fg-primary)]",title:a.projectPath,children:ae(a.projectPath)})}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top font-mono text-[12px] text-[var(--color-fg-secondary)]",children:_(a.lastActivity)}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:c(a.sizeBytes)}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top",children:e.jsx(v,{to:`/projects/${encodeURIComponent(a.projectId)}/sessions/${a.sessionId}`,className:"inline-block rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-2.5 py-1 text-[11.5px] font-medium text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] hover:text-[var(--color-fg-primary)]",children:t("cleanup.action.view")})})]},`${a.projectId}/${a.sessionId}`)})})]})})]})}function R({kind:s,title:t,hint:a,rows:o}){const n=p(),[l,d]=x.useState(null);return e.jsxs("div",{children:[e.jsx(U,{title:t,hint:a}),o.length===0?e.jsx("p",{className:"mt-3 font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)]",children:n("cleanup.empty.orphan")}):e.jsx("div",{className:"mt-3 -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",{}),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-2 eyebrow",children:n("cleanup.col.sid")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:n("cleanup.col.size")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:n("cleanup.col.actions")})]})}),e.jsx("tbody",{className:"border-t border-[var(--color-hairline)]",children:o.map(i=>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-2.5 align-top font-mono text-[12px] text-[var(--color-fg-secondary)]",title:i.sessionId,children:e.jsx("span",{className:"block truncate",children:i.sessionId})}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:c(i.sizeBytes)}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top",children:e.jsx("button",{type:"button",onClick:()=>d(i),className:"inline-block rounded-[var(--radius-control)] border border-[var(--color-danger)]/40 px-2.5 py-1 text-[11.5px] font-medium text-[var(--color-danger)] hover:bg-[var(--color-danger-soft)]",children:n("cleanup.action.delete")})})]},i.sessionId))})]})}),l&&e.jsx(se,{kind:s,orphan:l,onClose:()=>d(null)})]})}function se({kind:s,orphan:t,onClose:a}){const o=p(),n=H(),l=O({mutationFn:()=>S(`/api/disk-cleanup/orphan/${s}/${encodeURIComponent(t.sessionId)}`,{method:"DELETE"}),onSuccess:()=>{n.invalidateQueries({queryKey:y.diskCleanupSuggestions()}),n.invalidateQueries({queryKey:y.diskUsage()}),a()}}),d=x.useRef(l.isPending);return d.current=l.isPending,x.useEffect(()=>{function i(u){u.key==="Escape"&&!d.current&&a()}return window.addEventListener("keydown",i),()=>window.removeEventListener("keydown",i)},[a]),e.jsx(h.div,{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.18},className:"fixed inset-0 z-[60] flex items-start justify-center bg-[oklch(0.16_0.006_85_/_0.55)] backdrop-blur-[2px] px-4 py-12",onClick:()=>!l.isPending&&a(),children:e.jsxs(h.div,{initial:{y:8,opacity:0},animate:{y:0,opacity:1},transition:{duration:.24,ease:[.16,1,.3,1]},className:"w-full max-w-md overflow-hidden rounded-[var(--radius-panel)] border border-[var(--color-hairline)] bg-[var(--color-surface)] shadow-[var(--shadow-pop)]",onClick:i=>i.stopPropagation(),children:[e.jsxs("header",{className:"border-b border-[var(--color-hairline)] px-6 py-5",children:[e.jsx("p",{className:"eyebrow text-[var(--color-danger)]",children:o("delete.eyebrow.confirm")}),e.jsx("h2",{className:"mt-1 font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]",children:o("cleanup.confirm.title")}),e.jsx("p",{className:"mt-2 text-sm text-[var(--color-fg-muted)]",children:o("cleanup.confirm.body",{kind:s,sid:t.sessionId,size:c(t.sizeBytes)})})]}),l.error&&e.jsx("p",{className:"mx-6 mt-3 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]",children:l.error.message}),e.jsxs("footer",{className:"flex justify-end gap-2 border-t border-[var(--color-hairline)] px-6 py-4",children:[e.jsx("button",{type:"button",onClick:a,disabled:l.isPending,className:"rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-4 py-1.5 text-sm text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] disabled:opacity-50",children:o("cleanup.confirm.cancel")}),e.jsx("button",{type:"button",onClick:()=>l.mutate(),disabled:l.isPending,className:"rounded-[var(--radius-control)] bg-[var(--color-danger)] px-4 py-1.5 text-sm font-medium text-white shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",children:l.isPending?o("cleanup.action.deleting"):o("cleanup.confirm.confirm")})]})]})})}function ae(s){const t=s.split(/[\\/]+/).filter(Boolean);return t.length<=2?s:"…/"+t.slice(-2).join("/")}function k({label:s,value:t,unit:a,trail:o,accent:n}){return e.jsxs("div",{className:"surface-card is-interactive group relative overflow-hidden p-5 "+(n?"border-[var(--color-accent)]/40 hover:border-[var(--color-accent)]/60":""),children:[n&&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}),a&&e.jsx("span",{className:"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]",children:a})]}),o&&e.jsx("div",{className:"mt-3 font-mono text-[11px] text-[var(--color-fg-muted)]",children:o})]})}const M=["--color-accent","--color-moss","--color-iris","--color-fg-secondary","--color-accent-ink","--color-fg-muted"],oe=["--color-accent","--color-fg-muted","--color-hairline","--color-surface","--color-fg-primary"];function F(s){const[t,a]=x.useState(()=>A(s));return x.useEffect(()=>{const o=new MutationObserver(()=>a(A(s)));return o.observe(document.documentElement,{attributes:!0,attributeFilter:["class"]}),()=>o.disconnect()},[s]),t}function A(s){const t=getComputedStyle(document.documentElement),a={};for(const o of s)a[o]=t.getPropertyValue(o).trim()||"#888";return a}function pe(){var B;const s=p(),{data:t,isLoading:a,error:o}=q({queryKey:y.diskUsage(),queryFn:()=>S("/api/disk-usage")}),n=F(oe),l=n["--color-accent"],d=n["--color-fg-muted"],i=n["--color-hairline"],u=n["--color-surface"],C=n["--color-fg-primary"],I=F(M),g=x.useMemo(()=>M.map(r=>I[r]),[I]),f=x.useMemo(()=>t?t.byProject.map(r=>({name:D(r.decodedCwd),value:r.totalBytes,sessions:r.sessionCount})):[],[t]),P=x.useMemo(()=>t?t.byMonth.map(r=>({month:r.month,MB:+(r.totalBytes/1048576).toFixed(2)})):[],[t]);return e.jsxs("section",{children:[e.jsx("div",{className:"surface-card p-6",children:e.jsx(re,{title:s("disk.title"),tagline:s("disk.tagline"),stats:t?{totalBytes:t.totalBytes,projectCount:t.byProject.length,totalSessions:t.totalSessions}:null})}),a&&e.jsx(K,{label:s("common.computing"),className:"mt-10"}),o&&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"),": ",o.message]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs(h.div,{initial:"hidden",animate:"show",variants:Q,className:"mt-8 grid gap-3 sm:grid-cols-3",children:[e.jsx(h.div,{variants:b,children:e.jsx(k,{accent:!0,label:s("disk.stat.total"),value:c(t.totalBytes).split(" ")[0],unit:c(t.totalBytes).split(" ")[1],trail:s("disk.stat.acrossProjects",{n:t.byProject.length})})}),e.jsx(h.div,{variants:b,children:e.jsx(k,{label:s("disk.stat.sessions"),value:t.totalSessions.toLocaleString(),trail:t.topSessions[0]?s("disk.stat.largest",{size:c(t.topSessions[0].totalBytes)}):void 0})}),e.jsx(h.div,{variants:b,children:e.jsx(k,{label:s("disk.stat.months"),value:t.byMonth.length,trail:t.byMonth[0]?`${t.byMonth[0].month} → ${((B=t.byMonth.at(-1))==null?void 0:B.month)??t.byMonth[0].month}`:void 0})})]}),e.jsxs("div",{className:"mt-12 grid gap-8 lg:grid-cols-5",children:[e.jsx(z,{title:s("disk.composition.title"),subtitle:s("disk.composition.subtitle"),className:"lg:col-span-3",children:f.length===0?e.jsx(w,{}):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(E,{width:"100%",height:"100%",children:e.jsxs(V,{margin:{top:0,right:0,bottom:0,left:0},children:[e.jsx(W,{data:f,dataKey:"value",nameKey:"name",cx:"50%",cy:"50%",innerRadius:"58%",outerRadius:"92%",paddingAngle:1.5,stroke:u,strokeWidth:2,isAnimationActive:!1,children:f.map((r,m)=>e.jsx(X,{fill:g[m%g.length]},m))}),e.jsx(L,{contentStyle:T(u,i,C),formatter:r=>c(r)})]})}),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:c(t.totalBytes)})]})]}),e.jsx("ol",{className:"space-y-1.5 text-sm",children:f.slice(0,8).map((r,m)=>{const j=(r.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:g[m%g.length]}}),e.jsx("span",{className:"truncate font-mono text-xs text-[var(--color-fg-secondary)]",title:r.name,children:r.name}),e.jsxs("span",{className:"font-mono tabular-nums text-xs text-[var(--color-fg-primary)]",children:[j,"% ",e.jsxs("span",{className:"text-[var(--color-fg-faint)]",children:["· ",c(r.value)]})]})]},m)})})]})}),e.jsx(z,{title:s("disk.cadence.title"),subtitle:s("disk.cadence.subtitle"),className:"lg:col-span-2",children:P.length===0?e.jsx(w,{}):e.jsx("div",{className:"h-72",children:e.jsx(E,{width:"100%",height:"100%",children:e.jsxs(Y,{data:P,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:l,stopOpacity:.55}),e.jsx("stop",{offset:"100%",stopColor:l,stopOpacity:0})]})}),e.jsx(G,{dataKey:"month",tick:{fontSize:11,fill:d,fontFamily:"var(--font-mono)"},tickLine:!1,axisLine:{stroke:i}}),e.jsx(J,{tick:{fontSize:11,fill:d,fontFamily:"var(--font-mono)"},tickLine:!1,axisLine:!1,width:36}),e.jsx(L,{contentStyle:T(u,i,C),formatter:r=>`${r.toFixed(2)} MB`,cursor:{stroke:i,strokeDasharray:"2 3"}}),e.jsx(Z,{type:"monotone",dataKey:"MB",stroke:l,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(w,{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((r,m)=>{const j=r.customTitle??r.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(m+1).padStart(2,"0")}),e.jsx("td",{className:"px-2 py-3 align-top",children:e.jsx(v,{to:`/projects/${encodeURIComponent(r.projectId)}/sessions/${r.sessionId}`,className:"block truncate font-medium text-[var(--color-fg-primary)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]",title:j,children:j})}),e.jsx("td",{className:"px-2 py-3 align-top font-mono text-[12px] text-[var(--color-fg-muted)]",children:e.jsx(v,{to:`/projects/${encodeURIComponent(r.projectId)}`,className:"block truncate hover:text-[var(--color-fg-primary)]",title:r.projectId,children:ne(t,r.projectId)})}),e.jsx("td",{className:"px-2 py-3 text-right align-top font-mono text-[12.5px] text-[var(--color-fg-secondary)]",children:_(r.lastAt)}),e.jsx("td",{className:"px-2 py-3 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:c(r.totalBytes)})]},`${r.projectId}/${r.sessionId}`)})})]})})]}),e.jsx(ee,{})]})]})}function re({title:s,tagline:t,stats:a}){const o=p();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})]}),a&&e.jsxs("div",{className:"mt-3 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-xs",children:[e.jsx(N,{label:o("disk.meta.total"),value:c(a.totalBytes)}),e.jsx($,{}),e.jsx(N,{label:o("disk.meta.projects"),value:a.projectCount}),e.jsx($,{}),e.jsx(N,{label:o("disk.meta.sessions"),value:a.totalSessions.toLocaleString()})]})]})}function T(s,t,a){return{background:s,border:`1px solid ${t}`,borderRadius:8,fontFamily:"var(--font-mono)",fontSize:11,color:a,boxShadow:"var(--shadow-pop)"}}function ne(s,t){const a=s.byProject.find(o=>o.projectId===t);return a?D(a.decodedCwd):t}function D(s){const t=s.split(/[\\/]+/).filter(Boolean);return t.length<=2?s:"…/"+t.slice(-2).join("/")}function z({title:s,subtitle:t,children:a,className:o=""}){return e.jsxs("section",{className:`surface-card p-5 ${o}`,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})]}),a]})}function w({className:s=""}){const t=p();return e.jsx("p",{className:`font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)] ${s}`,children:t("common.noData")})}export{pe as default};
|
|
2
|
-
//# sourceMappingURL=DiskUsage-
|
|
1
|
+
import{j as e,r as x}from"./react-CPkiFScu.js";import{u as q,b as H,a as O}from"./query-CS7JQ86v.js";import{u as p,L as K,f as _,a as c,q as y,b as S,s as Q,c as b,M as N,S as $}from"./index-DTbWl1jb.js";import{L as v}from"./router-DwaHAh1G.js";import{H as h}from"./vendor-Cs8vYp-N.js";import{R as E,P as V,a as W,C as X,T as L,A as Y,X as G,Y as J,b as Z}from"./charts-jxJqXXUr.js";function ee(){const s=p(),{data:t,isLoading:a,error:o}=q({queryKey:y.diskCleanupSuggestions(),queryFn:()=>S("/api/disk-cleanup/suggestions")});return e.jsxs("section",{className:"surface-card mt-12 p-6",children:[e.jsxs("header",{className:"flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",children:[e.jsx("h2",{className:"font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]",children:s("cleanup.title")}),e.jsx("p",{className:"min-w-0 flex-1 font-display text-[13px] italic leading-snug text-[var(--color-fg-muted)]",children:s("cleanup.tagline")})]}),e.jsx("div",{className:"rule-dotted mt-3","aria-hidden":!0}),a&&e.jsx(K,{label:s("common.computing"),className:"mt-6"}),o&&e.jsx("p",{className:"mt-6 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("cleanup.failed",{msg:o.message})}),t&&e.jsxs("div",{className:"mt-6 space-y-8",children:[e.jsx(te,{data:t.largeSessions}),e.jsx(R,{kind:"file-history",title:s("cleanup.section.orphanFileHistory"),hint:s("cleanup.section.orphanFileHistory.hint"),rows:t.orphanFileHistory}),e.jsx(R,{kind:"session-env",title:s("cleanup.section.orphanSessionEnv"),hint:s("cleanup.section.orphanSessionEnv.hint"),rows:t.orphanSessionEnv})]})]})}function U({title:s,hint:t}){return e.jsxs("div",{className:"flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1 rounded-[var(--radius-input)] bg-[var(--color-sunken)] px-3 py-2",children:[e.jsx("h3",{className:"font-display text-[15px] font-light tracking-tight text-[var(--color-fg-primary)]",children:s}),e.jsx("span",{className:"font-mono text-[10.5px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]",children:t})]})}function te({data:s}){const t=p();return e.jsxs("div",{children:[e.jsx(U,{title:t("cleanup.section.largeSessions"),hint:t("cleanup.section.largeSessions.hint",{n:s.length||10})}),s.length===0?e.jsx("p",{className:"mt-3 font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)]",children:t("cleanup.empty.largeSessions")}):e.jsx("div",{className:"mt-3 -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",{}),e.jsx("col",{className:"w-[20rem]"}),e.jsx("col",{className:"w-24"}),e.jsx("col",{className:"w-24"}),e.jsx("col",{className:"w-20"})]}),e.jsx("thead",{children:e.jsxs("tr",{className:"text-left",children:[e.jsx("th",{className:"px-2 py-2 eyebrow",children:t("cleanup.col.session")}),e.jsx("th",{className:"px-2 py-2 eyebrow",children:t("cleanup.col.project")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:t("cleanup.col.last")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:t("cleanup.col.size")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:t("cleanup.col.actions")})]})}),e.jsx("tbody",{className:"border-t border-[var(--color-hairline)]",children:s.map(a=>{const o=a.customTitle??a.title;return e.jsxs("tr",{className:"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]",children:[e.jsxs("td",{className:"px-2 py-2.5 align-top",children:[e.jsx("div",{className:"truncate font-medium text-[var(--color-fg-primary)]",title:o,children:o}),e.jsx("div",{className:"mt-0.5 truncate font-mono text-[10.5px] text-[var(--color-fg-faint)]",title:a.sessionId,children:a.sessionId})]}),e.jsx("td",{className:"px-2 py-2.5 align-top font-mono text-[12px] text-[var(--color-fg-muted)]",children:e.jsx(v,{to:`/projects/${encodeURIComponent(a.projectId)}`,className:"block truncate hover:text-[var(--color-fg-primary)]",title:a.projectPath,children:ae(a.projectPath)})}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top font-mono text-[12px] text-[var(--color-fg-secondary)]",children:_(a.lastActivity)}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:c(a.sizeBytes)}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top",children:e.jsx(v,{to:`/projects/${encodeURIComponent(a.projectId)}/sessions/${a.sessionId}`,className:"inline-block rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-2.5 py-1 text-[11.5px] font-medium text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] hover:text-[var(--color-fg-primary)]",children:t("cleanup.action.view")})})]},`${a.projectId}/${a.sessionId}`)})})]})})]})}function R({kind:s,title:t,hint:a,rows:o}){const n=p(),[l,d]=x.useState(null);return e.jsxs("div",{children:[e.jsx(U,{title:t,hint:a}),o.length===0?e.jsx("p",{className:"mt-3 font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)]",children:n("cleanup.empty.orphan")}):e.jsx("div",{className:"mt-3 -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",{}),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-2 eyebrow",children:n("cleanup.col.sid")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:n("cleanup.col.size")}),e.jsx("th",{className:"px-2 py-2 eyebrow text-right",children:n("cleanup.col.actions")})]})}),e.jsx("tbody",{className:"border-t border-[var(--color-hairline)]",children:o.map(i=>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-2.5 align-top font-mono text-[12px] text-[var(--color-fg-secondary)]",title:i.sessionId,children:e.jsx("span",{className:"block truncate",children:i.sessionId})}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:c(i.sizeBytes)}),e.jsx("td",{className:"px-2 py-2.5 text-right align-top",children:e.jsx("button",{type:"button",onClick:()=>d(i),className:"inline-block rounded-[var(--radius-control)] border border-[var(--color-danger)]/40 px-2.5 py-1 text-[11.5px] font-medium text-[var(--color-danger)] hover:bg-[var(--color-danger-soft)]",children:n("cleanup.action.delete")})})]},i.sessionId))})]})}),l&&e.jsx(se,{kind:s,orphan:l,onClose:()=>d(null)})]})}function se({kind:s,orphan:t,onClose:a}){const o=p(),n=H(),l=O({mutationFn:()=>S(`/api/disk-cleanup/orphan/${s}/${encodeURIComponent(t.sessionId)}`,{method:"DELETE"}),onSuccess:()=>{n.invalidateQueries({queryKey:y.diskCleanupSuggestions()}),n.invalidateQueries({queryKey:y.diskUsage()}),a()}}),d=x.useRef(l.isPending);return d.current=l.isPending,x.useEffect(()=>{function i(u){u.key==="Escape"&&!d.current&&a()}return window.addEventListener("keydown",i),()=>window.removeEventListener("keydown",i)},[a]),e.jsx(h.div,{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},transition:{duration:.18},className:"fixed inset-0 z-[60] flex items-start justify-center bg-[oklch(0.16_0.006_85_/_0.55)] backdrop-blur-[2px] px-4 py-12",onClick:()=>!l.isPending&&a(),children:e.jsxs(h.div,{initial:{y:8,opacity:0},animate:{y:0,opacity:1},transition:{duration:.24,ease:[.16,1,.3,1]},className:"w-full max-w-md overflow-hidden rounded-[var(--radius-panel)] border border-[var(--color-hairline)] bg-[var(--color-surface)] shadow-[var(--shadow-pop)]",onClick:i=>i.stopPropagation(),children:[e.jsxs("header",{className:"border-b border-[var(--color-hairline)] px-6 py-5",children:[e.jsx("p",{className:"eyebrow text-[var(--color-danger)]",children:o("delete.eyebrow.confirm")}),e.jsx("h2",{className:"mt-1 font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]",children:o("cleanup.confirm.title")}),e.jsx("p",{className:"mt-2 text-sm text-[var(--color-fg-muted)]",children:o("cleanup.confirm.body",{kind:s,sid:t.sessionId,size:c(t.sizeBytes)})})]}),l.error&&e.jsx("p",{className:"mx-6 mt-3 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]",children:l.error.message}),e.jsxs("footer",{className:"flex justify-end gap-2 border-t border-[var(--color-hairline)] px-6 py-4",children:[e.jsx("button",{type:"button",onClick:a,disabled:l.isPending,className:"rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-4 py-1.5 text-sm text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] disabled:opacity-50",children:o("cleanup.confirm.cancel")}),e.jsx("button",{type:"button",onClick:()=>l.mutate(),disabled:l.isPending,className:"rounded-[var(--radius-control)] bg-[var(--color-danger)] px-4 py-1.5 text-sm font-medium text-white shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",children:l.isPending?o("cleanup.action.deleting"):o("cleanup.confirm.confirm")})]})]})})}function ae(s){const t=s.split(/[\\/]+/).filter(Boolean);return t.length<=2?s:"…/"+t.slice(-2).join("/")}function k({label:s,value:t,unit:a,trail:o,accent:n}){return e.jsxs("div",{className:"surface-card is-interactive group relative overflow-hidden p-5 "+(n?"border-[var(--color-accent)]/40 hover:border-[var(--color-accent)]/60":""),children:[n&&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}),a&&e.jsx("span",{className:"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]",children:a})]}),o&&e.jsx("div",{className:"mt-3 font-mono text-[11px] text-[var(--color-fg-muted)]",children:o})]})}const M=["--color-accent","--color-moss","--color-iris","--color-fg-secondary","--color-accent-ink","--color-fg-muted"],oe=["--color-accent","--color-fg-muted","--color-hairline","--color-surface","--color-fg-primary"];function F(s){const[t,a]=x.useState(()=>A(s));return x.useEffect(()=>{const o=new MutationObserver(()=>a(A(s)));return o.observe(document.documentElement,{attributes:!0,attributeFilter:["class"]}),()=>o.disconnect()},[s]),t}function A(s){const t=getComputedStyle(document.documentElement),a={};for(const o of s)a[o]=t.getPropertyValue(o).trim()||"#888";return a}function pe(){var B;const s=p(),{data:t,isLoading:a,error:o}=q({queryKey:y.diskUsage(),queryFn:()=>S("/api/disk-usage")}),n=F(oe),l=n["--color-accent"],d=n["--color-fg-muted"],i=n["--color-hairline"],u=n["--color-surface"],C=n["--color-fg-primary"],I=F(M),g=x.useMemo(()=>M.map(r=>I[r]),[I]),f=x.useMemo(()=>t?t.byProject.map(r=>({name:D(r.decodedCwd),value:r.totalBytes,sessions:r.sessionCount})):[],[t]),P=x.useMemo(()=>t?t.byMonth.map(r=>({month:r.month,MB:+(r.totalBytes/1048576).toFixed(2)})):[],[t]);return e.jsxs("section",{children:[e.jsx("div",{className:"surface-card p-6",children:e.jsx(re,{title:s("disk.title"),tagline:s("disk.tagline"),stats:t?{totalBytes:t.totalBytes,projectCount:t.byProject.length,totalSessions:t.totalSessions}:null})}),a&&e.jsx(K,{label:s("common.computing"),className:"mt-10"}),o&&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"),": ",o.message]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs(h.div,{initial:"hidden",animate:"show",variants:Q,className:"mt-8 grid gap-3 sm:grid-cols-3",children:[e.jsx(h.div,{variants:b,children:e.jsx(k,{accent:!0,label:s("disk.stat.total"),value:c(t.totalBytes).split(" ")[0],unit:c(t.totalBytes).split(" ")[1],trail:s("disk.stat.acrossProjects",{n:t.byProject.length})})}),e.jsx(h.div,{variants:b,children:e.jsx(k,{label:s("disk.stat.sessions"),value:t.totalSessions.toLocaleString(),trail:t.topSessions[0]?s("disk.stat.largest",{size:c(t.topSessions[0].totalBytes)}):void 0})}),e.jsx(h.div,{variants:b,children:e.jsx(k,{label:s("disk.stat.months"),value:t.byMonth.length,trail:t.byMonth[0]?`${t.byMonth[0].month} → ${((B=t.byMonth.at(-1))==null?void 0:B.month)??t.byMonth[0].month}`:void 0})})]}),e.jsxs("div",{className:"mt-12 grid gap-8 lg:grid-cols-5",children:[e.jsx(z,{title:s("disk.composition.title"),subtitle:s("disk.composition.subtitle"),className:"lg:col-span-3",children:f.length===0?e.jsx(w,{}):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(E,{width:"100%",height:"100%",children:e.jsxs(V,{margin:{top:0,right:0,bottom:0,left:0},children:[e.jsx(W,{data:f,dataKey:"value",nameKey:"name",cx:"50%",cy:"50%",innerRadius:"58%",outerRadius:"92%",paddingAngle:1.5,stroke:u,strokeWidth:2,isAnimationActive:!1,children:f.map((r,m)=>e.jsx(X,{fill:g[m%g.length]},m))}),e.jsx(L,{contentStyle:T(u,i,C),formatter:r=>c(r)})]})}),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:c(t.totalBytes)})]})]}),e.jsx("ol",{className:"space-y-1.5 text-sm",children:f.slice(0,8).map((r,m)=>{const j=(r.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:g[m%g.length]}}),e.jsx("span",{className:"truncate font-mono text-xs text-[var(--color-fg-secondary)]",title:r.name,children:r.name}),e.jsxs("span",{className:"font-mono tabular-nums text-xs text-[var(--color-fg-primary)]",children:[j,"% ",e.jsxs("span",{className:"text-[var(--color-fg-faint)]",children:["· ",c(r.value)]})]})]},m)})})]})}),e.jsx(z,{title:s("disk.cadence.title"),subtitle:s("disk.cadence.subtitle"),className:"lg:col-span-2",children:P.length===0?e.jsx(w,{}):e.jsx("div",{className:"h-72",children:e.jsx(E,{width:"100%",height:"100%",children:e.jsxs(Y,{data:P,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:l,stopOpacity:.55}),e.jsx("stop",{offset:"100%",stopColor:l,stopOpacity:0})]})}),e.jsx(G,{dataKey:"month",tick:{fontSize:11,fill:d,fontFamily:"var(--font-mono)"},tickLine:!1,axisLine:{stroke:i}}),e.jsx(J,{tick:{fontSize:11,fill:d,fontFamily:"var(--font-mono)"},tickLine:!1,axisLine:!1,width:36}),e.jsx(L,{contentStyle:T(u,i,C),formatter:r=>`${r.toFixed(2)} MB`,cursor:{stroke:i,strokeDasharray:"2 3"}}),e.jsx(Z,{type:"monotone",dataKey:"MB",stroke:l,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(w,{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((r,m)=>{const j=r.customTitle??r.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(m+1).padStart(2,"0")}),e.jsx("td",{className:"px-2 py-3 align-top",children:e.jsx(v,{to:`/projects/${encodeURIComponent(r.projectId)}/sessions/${r.sessionId}`,className:"block truncate font-medium text-[var(--color-fg-primary)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]",title:j,children:j})}),e.jsx("td",{className:"px-2 py-3 align-top font-mono text-[12px] text-[var(--color-fg-muted)]",children:e.jsx(v,{to:`/projects/${encodeURIComponent(r.projectId)}`,className:"block truncate hover:text-[var(--color-fg-primary)]",title:r.projectId,children:ne(t,r.projectId)})}),e.jsx("td",{className:"px-2 py-3 text-right align-top font-mono text-[12.5px] text-[var(--color-fg-secondary)]",children:_(r.lastAt)}),e.jsx("td",{className:"px-2 py-3 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]",children:c(r.totalBytes)})]},`${r.projectId}/${r.sessionId}`)})})]})})]}),e.jsx(ee,{})]})]})}function re({title:s,tagline:t,stats:a}){const o=p();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})]}),a&&e.jsxs("div",{className:"mt-3 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-xs",children:[e.jsx(N,{label:o("disk.meta.total"),value:c(a.totalBytes)}),e.jsx($,{}),e.jsx(N,{label:o("disk.meta.projects"),value:a.projectCount}),e.jsx($,{}),e.jsx(N,{label:o("disk.meta.sessions"),value:a.totalSessions.toLocaleString()})]})]})}function T(s,t,a){return{background:s,border:`1px solid ${t}`,borderRadius:8,fontFamily:"var(--font-mono)",fontSize:11,color:a,boxShadow:"var(--shadow-pop)"}}function ne(s,t){const a=s.byProject.find(o=>o.projectId===t);return a?D(a.decodedCwd):t}function D(s){const t=s.split(/[\\/]+/).filter(Boolean);return t.length<=2?s:"…/"+t.slice(-2).join("/")}function z({title:s,subtitle:t,children:a,className:o=""}){return e.jsxs("section",{className:`surface-card p-5 ${o}`,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})]}),a]})}function w({className:s=""}){const t=p();return e.jsx("p",{className:`font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)] ${s}`,children:t("common.noData")})}export{pe as default};
|
|
2
|
+
//# sourceMappingURL=DiskUsage-BY6XwffG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DiskUsage-BY6XwffG.js","sources":["../../web/src/components/CleanupSuggestions.tsx","../../web/src/components/StatCard.tsx","../../web/src/routes/DiskUsage.tsx"],"sourcesContent":["import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\nimport { motion } from 'motion/react';\nimport { useEffect, useRef, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport {\n api,\n type DiskCleanupOrphan,\n type DiskCleanupSuggestions,\n type DiskOrphanDeleteResult,\n type DiskOrphanKind,\n} from '../lib/api.ts';\nimport { formatBytes, formatRelativeTime } from '../lib/format.ts';\nimport { useT } from '../lib/i18n.ts';\nimport { queryKeys } from '../lib/query-keys.ts';\nimport { Loading } from './Loading.tsx';\n\n/**\n * \"清理建议\" 区块:从 /api/disk-cleanup/suggestions 拉取最大的会话 + 两类孤儿目录,\n * 用户逐条确认后通过 DELETE /api/disk-cleanup/orphan/:kind/:sid 单条清理。\n * 不做批量、不做自动清理。\n */\nexport default function CleanupSuggestions() {\n const t = useT();\n const { data, isLoading, error } = useQuery({\n queryKey: queryKeys.diskCleanupSuggestions(),\n queryFn: () => api<DiskCleanupSuggestions>('/api/disk-cleanup/suggestions'),\n });\n\n return (\n <section className=\"surface-card mt-12 p-6\">\n <header className=\"flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1\">\n <h2 className=\"font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]\">\n {t('cleanup.title')}\n </h2>\n <p className=\"min-w-0 flex-1 font-display text-[13px] italic leading-snug text-[var(--color-fg-muted)]\">\n {t('cleanup.tagline')}\n </p>\n </header>\n <div className=\"rule-dotted mt-3\" aria-hidden />\n\n {isLoading && <Loading label={t('common.computing')} className=\"mt-6\" />}\n {error && (\n <p className=\"mt-6 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-4 py-3 text-sm text-[var(--color-danger)]\">\n {t('cleanup.failed', { msg: (error as Error).message })}\n </p>\n )}\n\n {data && (\n <div className=\"mt-6 space-y-8\">\n <LargeSessionsTable data={data.largeSessions} />\n <OrphanTable\n kind=\"file-history\"\n title={t('cleanup.section.orphanFileHistory')}\n hint={t('cleanup.section.orphanFileHistory.hint')}\n rows={data.orphanFileHistory}\n />\n <OrphanTable\n kind=\"session-env\"\n title={t('cleanup.section.orphanSessionEnv')}\n hint={t('cleanup.section.orphanSessionEnv.hint')}\n rows={data.orphanSessionEnv}\n />\n </div>\n )}\n </section>\n );\n}\n\nfunction SectionHeader({ title, hint }: { title: string; hint: string }) {\n return (\n <div\n className=\"flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1 rounded-[var(--radius-input)] bg-[var(--color-sunken)] px-3 py-2\"\n >\n <h3 className=\"font-display text-[15px] font-light tracking-tight text-[var(--color-fg-primary)]\">\n {title}\n </h3>\n <span className=\"font-mono text-[10.5px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]\">\n {hint}\n </span>\n </div>\n );\n}\n\nfunction LargeSessionsTable({\n data,\n}: {\n data: DiskCleanupSuggestions['largeSessions'];\n}) {\n const t = useT();\n return (\n <div>\n <SectionHeader\n title={t('cleanup.section.largeSessions')}\n hint={t('cleanup.section.largeSessions.hint', { n: data.length || 10 })}\n />\n {data.length === 0 ? (\n <p className=\"mt-3 font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)]\">\n {t('cleanup.empty.largeSessions')}\n </p>\n ) : (\n <div className=\"mt-3 -mx-6 overflow-x-auto px-6\">\n <table className=\"w-full table-fixed text-sm\">\n <colgroup>\n <col />\n <col className=\"w-[20rem]\" />\n <col className=\"w-24\" />\n <col className=\"w-24\" />\n <col className=\"w-20\" />\n </colgroup>\n <thead>\n <tr className=\"text-left\">\n <th className=\"px-2 py-2 eyebrow\">{t('cleanup.col.session')}</th>\n <th className=\"px-2 py-2 eyebrow\">{t('cleanup.col.project')}</th>\n <th className=\"px-2 py-2 eyebrow text-right\">{t('cleanup.col.last')}</th>\n <th className=\"px-2 py-2 eyebrow text-right\">{t('cleanup.col.size')}</th>\n <th className=\"px-2 py-2 eyebrow text-right\">{t('cleanup.col.actions')}</th>\n </tr>\n </thead>\n <tbody className=\"border-t border-[var(--color-hairline)]\">\n {data.map((row) => {\n const display = row.customTitle ?? row.title;\n return (\n <tr\n key={`${row.projectId}/${row.sessionId}`}\n className=\"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]\"\n >\n <td className=\"px-2 py-2.5 align-top\">\n <div\n className=\"truncate font-medium text-[var(--color-fg-primary)]\"\n title={display}\n >\n {display}\n </div>\n <div\n className=\"mt-0.5 truncate font-mono text-[10.5px] text-[var(--color-fg-faint)]\"\n title={row.sessionId}\n >\n {row.sessionId}\n </div>\n </td>\n <td\n className=\"px-2 py-2.5 align-top font-mono text-[12px] text-[var(--color-fg-muted)]\"\n >\n <Link\n to={`/projects/${encodeURIComponent(row.projectId)}`}\n className=\"block truncate hover:text-[var(--color-fg-primary)]\"\n title={row.projectPath}\n >\n {shortCwd(row.projectPath)}\n </Link>\n </td>\n <td className=\"px-2 py-2.5 text-right align-top font-mono text-[12px] text-[var(--color-fg-secondary)]\">\n {formatRelativeTime(row.lastActivity)}\n </td>\n <td className=\"px-2 py-2.5 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]\">\n {formatBytes(row.sizeBytes)}\n </td>\n <td className=\"px-2 py-2.5 text-right align-top\">\n <Link\n to={`/projects/${encodeURIComponent(row.projectId)}/sessions/${row.sessionId}`}\n className=\"inline-block rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-2.5 py-1 text-[11.5px] font-medium text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] hover:text-[var(--color-fg-primary)]\"\n >\n {t('cleanup.action.view')}\n </Link>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n );\n}\n\nfunction OrphanTable({\n kind,\n title,\n hint,\n rows,\n}: {\n kind: DiskOrphanKind;\n title: string;\n hint: string;\n rows: DiskCleanupOrphan[];\n}) {\n const t = useT();\n const [confirming, setConfirming] = useState<DiskCleanupOrphan | null>(null);\n return (\n <div>\n <SectionHeader title={title} hint={hint} />\n {rows.length === 0 ? (\n <p className=\"mt-3 font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)]\">\n {t('cleanup.empty.orphan')}\n </p>\n ) : (\n <div className=\"mt-3 -mx-6 overflow-x-auto px-6\">\n <table className=\"w-full table-fixed text-sm\">\n <colgroup>\n <col />\n <col className=\"w-24\" />\n <col className=\"w-24\" />\n </colgroup>\n <thead>\n <tr className=\"text-left\">\n <th className=\"px-2 py-2 eyebrow\">{t('cleanup.col.sid')}</th>\n <th className=\"px-2 py-2 eyebrow text-right\">{t('cleanup.col.size')}</th>\n <th className=\"px-2 py-2 eyebrow text-right\">{t('cleanup.col.actions')}</th>\n </tr>\n </thead>\n <tbody className=\"border-t border-[var(--color-hairline)]\">\n {rows.map((row) => (\n <tr\n key={row.sessionId}\n className=\"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]\"\n >\n <td\n className=\"px-2 py-2.5 align-top font-mono text-[12px] text-[var(--color-fg-secondary)]\"\n title={row.sessionId}\n >\n <span className=\"block truncate\">{row.sessionId}</span>\n </td>\n <td className=\"px-2 py-2.5 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]\">\n {formatBytes(row.sizeBytes)}\n </td>\n <td className=\"px-2 py-2.5 text-right align-top\">\n <button\n type=\"button\"\n onClick={() => setConfirming(row)}\n className=\"inline-block rounded-[var(--radius-control)] border border-[var(--color-danger)]/40 px-2.5 py-1 text-[11.5px] font-medium text-[var(--color-danger)] hover:bg-[var(--color-danger-soft)]\"\n >\n {t('cleanup.action.delete')}\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n {confirming && (\n <OrphanConfirmDialog\n kind={kind}\n orphan={confirming}\n onClose={() => setConfirming(null)}\n />\n )}\n </div>\n );\n}\n\nfunction OrphanConfirmDialog({\n kind,\n orphan,\n onClose,\n}: {\n kind: DiskOrphanKind;\n orphan: DiskCleanupOrphan;\n onClose: () => void;\n}) {\n const t = useT();\n const queryClient = useQueryClient();\n const mutation = useMutation({\n mutationFn: () =>\n api<DiskOrphanDeleteResult>(\n `/api/disk-cleanup/orphan/${kind}/${encodeURIComponent(orphan.sessionId)}`,\n { method: 'DELETE' },\n ),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: queryKeys.diskCleanupSuggestions() });\n queryClient.invalidateQueries({ queryKey: queryKeys.diskUsage() });\n onClose();\n },\n });\n\n const isPendingRef = useRef(mutation.isPending);\n isPendingRef.current = mutation.isPending;\n useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape' && !isPendingRef.current) onClose();\n }\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose]);\n\n return (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.18 }}\n className=\"fixed inset-0 z-[60] flex items-start justify-center bg-[oklch(0.16_0.006_85_/_0.55)] backdrop-blur-[2px] px-4 py-12\"\n onClick={() => !mutation.isPending && onClose()}\n >\n <motion.div\n initial={{ y: 8, opacity: 0 }}\n animate={{ y: 0, opacity: 1 }}\n transition={{ duration: 0.24, ease: [0.16, 1, 0.3, 1] }}\n className=\"w-full max-w-md overflow-hidden rounded-[var(--radius-panel)] border border-[var(--color-hairline)] bg-[var(--color-surface)] shadow-[var(--shadow-pop)]\"\n onClick={(e) => e.stopPropagation()}\n >\n <header className=\"border-b border-[var(--color-hairline)] px-6 py-5\">\n <p className=\"eyebrow text-[var(--color-danger)]\">{t('delete.eyebrow.confirm')}</p>\n <h2 className=\"mt-1 font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]\">\n {t('cleanup.confirm.title')}\n </h2>\n <p className=\"mt-2 text-sm text-[var(--color-fg-muted)]\">\n {t('cleanup.confirm.body', {\n kind,\n sid: orphan.sessionId,\n size: formatBytes(orphan.sizeBytes),\n })}\n </p>\n </header>\n {mutation.error && (\n <p className=\"mx-6 mt-3 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]\">\n {(mutation.error as Error).message}\n </p>\n )}\n <footer className=\"flex justify-end gap-2 border-t border-[var(--color-hairline)] px-6 py-4\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={mutation.isPending}\n className=\"rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-4 py-1.5 text-sm text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] disabled:opacity-50\"\n >\n {t('cleanup.confirm.cancel')}\n </button>\n <button\n type=\"button\"\n onClick={() => mutation.mutate()}\n disabled={mutation.isPending}\n className=\"rounded-[var(--radius-control)] bg-[var(--color-danger)] px-4 py-1.5 text-sm font-medium text-white shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {mutation.isPending ? t('cleanup.action.deleting') : t('cleanup.confirm.confirm')}\n </button>\n </footer>\n </motion.div>\n </motion.div>\n );\n}\n\nfunction shortCwd(cwd: string): string {\n const parts = cwd.split(/[\\\\/]+/).filter(Boolean);\n if (parts.length <= 2) return cwd;\n return '…/' + parts.slice(-2).join('/');\n}\n","import type { ReactNode } from 'react';\n\ninterface Props {\n label: string;\n value: ReactNode;\n unit?: ReactNode;\n trail?: ReactNode;\n accent?: boolean;\n}\n\nexport default function StatCard({ label, value, unit, trail, accent }: Props) {\n return (\n <div\n className={\n 'surface-card is-interactive group relative overflow-hidden p-5 ' +\n (accent ? 'border-[var(--color-accent)]/40 hover:border-[var(--color-accent)]/60' : '')\n }\n >\n {accent && (\n <span\n aria-hidden\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\"\n />\n )}\n <div className=\"eyebrow\">{label}</div>\n <div className=\"mt-3 flex items-baseline gap-1.5\">\n <span className=\"font-mono text-4xl font-light leading-none tracking-[-0.02em] tabular-nums text-[var(--color-fg-primary)]\">\n {value}\n </span>\n {unit && (\n <span className=\"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]\">\n {unit}\n </span>\n )}\n </div>\n {trail && (\n <div className=\"mt-3 font-mono text-[11px] text-[var(--color-fg-muted)]\">{trail}</div>\n )}\n </div>\n );\n}\n","import { useQuery } from '@tanstack/react-query';\nimport { motion } from 'motion/react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport {\n Area,\n AreaChart,\n Cell,\n Pie,\n PieChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from 'recharts';\nimport CleanupSuggestions from '../components/CleanupSuggestions.tsx';\nimport { Loading } from '../components/Loading.tsx';\nimport { MetaItem, Sep } from '../components/PageHeader.tsx';\nimport StatCard from '../components/StatCard.tsx';\nimport { api, type DiskUsage } from '../lib/api.ts';\nimport { formatBytes, formatRelativeTime } from '../lib/format.ts';\nimport { useT } from '../lib/i18n.ts';\nimport { fadeUpItem, staggerParent } from '../lib/motion.ts';\nimport { queryKeys } from '../lib/query-keys.ts';\n\nconst PALETTE_VARS = [\n '--color-accent',\n '--color-moss',\n '--color-iris',\n '--color-fg-secondary',\n '--color-accent-ink',\n '--color-fg-muted',\n];\n\nconst CHART_VARS = [\n '--color-accent',\n '--color-fg-muted',\n '--color-hairline',\n '--color-surface',\n '--color-fg-primary',\n] as const;\n\n// Resolve a list of CSS variables on <html> and re-resolve whenever the\n// theme class flips. Recharts needs concrete colors; CSS vars don't traverse SVG cleanly.\nfunction useThemeColors<T extends readonly string[]>(vars: T): Record<T[number], string> {\n const [snapshot, setSnapshot] = useState(() => readVars(vars));\n useEffect(() => {\n const observer = new MutationObserver(() => setSnapshot(readVars(vars)));\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });\n return () => observer.disconnect();\n }, [vars]);\n return snapshot;\n}\n\nfunction readVars<T extends readonly string[]>(vars: T): Record<T[number], string> {\n const cs = getComputedStyle(document.documentElement);\n const out = {} as Record<T[number], string>;\n for (const v of vars) (out as Record<string, string>)[v] = cs.getPropertyValue(v).trim() || '#888';\n return out;\n}\n\nexport default function DiskUsageRoute() {\n const t = useT();\n const { data, isLoading, error } = useQuery({\n queryKey: queryKeys.diskUsage(),\n queryFn: () => api<DiskUsage>('/api/disk-usage'),\n });\n\n const colors = useThemeColors(CHART_VARS);\n const accent = colors['--color-accent'];\n const muted = colors['--color-fg-muted'];\n const hairline = colors['--color-hairline'];\n const surface = colors['--color-surface'];\n const fgPrimary = colors['--color-fg-primary'];\n\n const palette = useThemeColors(PALETTE_VARS);\n const resolvedPalette = useMemo(() => PALETTE_VARS.map((v) => palette[v]), [palette]);\n\n const pieData = useMemo(() => {\n if (!data) return [];\n return data.byProject.map((p) => ({\n name: shortCwd(p.decodedCwd),\n value: p.totalBytes,\n sessions: p.sessionCount,\n }));\n }, [data]);\n\n const monthData = useMemo(() => {\n if (!data) return [];\n return data.byMonth.map((m) => ({ month: m.month, MB: +(m.totalBytes / 1_048_576).toFixed(2) }));\n }, [data]);\n\n return (\n <section>\n <div className=\"surface-card p-6\">\n <Masthead\n title={t('disk.title')}\n tagline={t('disk.tagline')}\n stats={\n data\n ? {\n totalBytes: data.totalBytes,\n projectCount: data.byProject.length,\n totalSessions: data.totalSessions,\n }\n : null\n }\n />\n </div>\n\n {isLoading && <Loading label={t('common.computing')} className=\"mt-10\" />}\n {error && (\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)]\">\n {t('common.failed')}: {(error as Error).message}\n </p>\n )}\n\n {data && (\n <>\n <motion.div\n initial=\"hidden\"\n animate=\"show\"\n variants={staggerParent}\n className=\"mt-8 grid gap-3 sm:grid-cols-3\"\n >\n <motion.div variants={fadeUpItem}>\n <StatCard\n accent\n label={t('disk.stat.total')}\n value={formatBytes(data.totalBytes).split(' ')[0]}\n unit={formatBytes(data.totalBytes).split(' ')[1]}\n trail={t('disk.stat.acrossProjects', { n: data.byProject.length })}\n />\n </motion.div>\n <motion.div variants={fadeUpItem}>\n <StatCard\n label={t('disk.stat.sessions')}\n value={data.totalSessions.toLocaleString()}\n trail={\n data.topSessions[0]\n ? t('disk.stat.largest', { size: formatBytes(data.topSessions[0].totalBytes) })\n : undefined\n }\n />\n </motion.div>\n <motion.div variants={fadeUpItem}>\n <StatCard\n label={t('disk.stat.months')}\n value={data.byMonth.length}\n trail={\n data.byMonth[0]\n ? `${data.byMonth[0].month} → ${data.byMonth.at(-1)?.month ?? data.byMonth[0].month}`\n : undefined\n }\n />\n </motion.div>\n </motion.div>\n\n <div className=\"mt-12 grid gap-8 lg:grid-cols-5\">\n <Card\n title={t('disk.composition.title')}\n subtitle={t('disk.composition.subtitle')}\n className=\"lg:col-span-3\"\n >\n {pieData.length === 0 ? (\n <Empty />\n ) : (\n <div className=\"grid gap-6 md:grid-cols-[minmax(0,1fr)_minmax(0,1.1fr)] md:items-center\">\n <div className=\"relative mx-auto aspect-square w-full max-w-[260px]\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <PieChart margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>\n <Pie\n data={pieData}\n dataKey=\"value\"\n nameKey=\"name\"\n cx=\"50%\"\n cy=\"50%\"\n innerRadius=\"58%\"\n outerRadius=\"92%\"\n paddingAngle={1.5}\n stroke={surface}\n strokeWidth={2}\n isAnimationActive={false}\n >\n {pieData.map((_, i) => (\n <Cell key={i} fill={resolvedPalette[i % resolvedPalette.length]} />\n ))}\n </Pie>\n <Tooltip\n contentStyle={tooltipStyle(surface, hairline, fgPrimary)}\n formatter={(value: number) => formatBytes(value)}\n />\n </PieChart>\n </ResponsiveContainer>\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center\">\n <span className=\"eyebrow\">{t('disk.composition.total')}</span>\n <span className=\"mt-1 font-mono text-2xl font-light tabular-nums text-[var(--color-fg-primary)]\">\n {formatBytes(data.totalBytes)}\n </span>\n </div>\n </div>\n <ol className=\"space-y-1.5 text-sm\">\n {pieData.slice(0, 8).map((p, i) => {\n const pct = ((p.value / data.totalBytes) * 100).toFixed(1);\n return (\n <li key={i} className=\"grid grid-cols-[14px_1fr_auto] items-baseline gap-2\">\n <span\n aria-hidden\n className=\"block h-2.5 w-2.5 self-center rounded-sm\"\n style={{ background: resolvedPalette[i % resolvedPalette.length] }}\n />\n <span className=\"truncate font-mono text-xs text-[var(--color-fg-secondary)]\" title={p.name}>\n {p.name}\n </span>\n <span className=\"font-mono tabular-nums text-xs text-[var(--color-fg-primary)]\">\n {pct}% <span className=\"text-[var(--color-fg-faint)]\">· {formatBytes(p.value)}</span>\n </span>\n </li>\n );\n })}\n </ol>\n </div>\n )}\n </Card>\n\n <Card\n title={t('disk.cadence.title')}\n subtitle={t('disk.cadence.subtitle')}\n className=\"lg:col-span-2\"\n >\n {monthData.length === 0 ? (\n <Empty />\n ) : (\n <div className=\"h-72\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={monthData} margin={{ top: 10, right: 8, bottom: 0, left: -10 }}>\n <defs>\n <linearGradient id=\"cadenceFill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={accent} stopOpacity={0.55} />\n <stop offset=\"100%\" stopColor={accent} stopOpacity={0} />\n </linearGradient>\n </defs>\n <XAxis\n dataKey=\"month\"\n tick={{ fontSize: 11, fill: muted, fontFamily: 'var(--font-mono)' }}\n tickLine={false}\n axisLine={{ stroke: hairline }}\n />\n <YAxis\n tick={{ fontSize: 11, fill: muted, fontFamily: 'var(--font-mono)' }}\n tickLine={false}\n axisLine={false}\n width={36}\n />\n <Tooltip\n contentStyle={tooltipStyle(surface, hairline, fgPrimary)}\n formatter={(value: number) => `${value.toFixed(2)} MB`}\n cursor={{ stroke: hairline, strokeDasharray: '2 3' }}\n />\n <Area\n type=\"monotone\"\n dataKey=\"MB\"\n stroke={accent}\n strokeWidth={1.6}\n fill=\"url(#cadenceFill)\"\n />\n </AreaChart>\n </ResponsiveContainer>\n </div>\n )}\n </Card>\n </div>\n\n <div className=\"surface-card mt-12 p-6\">\n <div className=\"flex items-baseline justify-between\">\n <h2 className=\"font-display text-xl font-light tracking-tight text-[var(--color-fg-primary)]\">\n {t('disk.heaviest.title')}\n </h2>\n {data.topSessions.length > 0 && (\n <span className=\"font-mono text-[11px] uppercase tracking-[0.16em] text-[var(--color-fg-muted)]\">\n {t('disk.heaviest.top', { n: data.topSessions.length })}\n </span>\n )}\n </div>\n <div className=\"rule-dotted mt-3\" aria-hidden />\n {data.topSessions.length === 0 ? (\n <Empty className=\"mt-6\" />\n ) : (\n <div className=\"mt-4 -mx-6 overflow-x-auto px-6\">\n <table className=\"w-full table-fixed text-sm\">\n <colgroup>\n <col className=\"w-10\" />\n <col />\n <col className=\"w-[22rem]\" />\n <col className=\"w-24\" />\n <col className=\"w-24\" />\n </colgroup>\n <thead>\n <tr className=\"text-left\">\n <th className=\"px-2 py-3 eyebrow\">{t('disk.col.num')}</th>\n <th className=\"px-2 py-3 eyebrow\">{t('disk.col.title')}</th>\n <th className=\"px-2 py-3 eyebrow\">{t('disk.col.project')}</th>\n <th className=\"px-2 py-3 eyebrow text-right\">{t('disk.col.last')}</th>\n <th className=\"px-2 py-3 eyebrow text-right\">{t('disk.col.size')}</th>\n </tr>\n </thead>\n <tbody className=\"border-t border-[var(--color-hairline)]\">\n {data.topSessions.map((s, i) => {\n const displayTitle = s.customTitle ?? s.title;\n return (\n <tr\n key={`${s.projectId}/${s.sessionId}`}\n className=\"ribbon-row border-b border-[var(--color-hairline)] hover:bg-[var(--color-sunken)]\"\n >\n <td className=\"px-2 py-3 align-top font-mono text-[11px] text-[var(--color-fg-faint)]\">\n {String(i + 1).padStart(2, '0')}\n </td>\n <td className=\"px-2 py-3 align-top\">\n <Link\n to={`/projects/${encodeURIComponent(s.projectId)}/sessions/${s.sessionId}`}\n className=\"block truncate font-medium text-[var(--color-fg-primary)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]\"\n title={displayTitle}\n >\n {displayTitle}\n </Link>\n </td>\n <td className=\"px-2 py-3 align-top font-mono text-[12px] text-[var(--color-fg-muted)]\">\n <Link\n to={`/projects/${encodeURIComponent(s.projectId)}`}\n className=\"block truncate hover:text-[var(--color-fg-primary)]\"\n title={s.projectId}\n >\n {projectCwdLabel(data, s.projectId)}\n </Link>\n </td>\n <td className=\"px-2 py-3 text-right align-top font-mono text-[12.5px] text-[var(--color-fg-secondary)]\">\n {formatRelativeTime(s.lastAt)}\n </td>\n <td className=\"px-2 py-3 text-right align-top font-mono tabular-nums text-[var(--color-fg-primary)]\">\n {formatBytes(s.totalBytes)}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n\n <CleanupSuggestions />\n </>\n )}\n </section>\n );\n}\n\nfunction Masthead({\n title,\n tagline,\n stats,\n}: {\n title: string;\n tagline: string;\n stats: {\n totalBytes: number;\n projectCount: number;\n totalSessions: number;\n } | null;\n}) {\n const t = useT();\n return (\n <header className=\"relative\">\n <div className=\"flex flex-wrap items-baseline gap-x-4 gap-y-1\">\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)]\">\n {title}\n <span className=\"text-[var(--color-accent)]\">.</span>\n </h1>\n <p className=\"min-w-0 flex-1 font-display text-[13px] italic leading-snug text-[var(--color-fg-muted)]\">\n {tagline}\n </p>\n </div>\n {stats && (\n <div className=\"mt-3 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-xs\">\n <MetaItem label={t('disk.meta.total')} value={formatBytes(stats.totalBytes)} />\n <Sep />\n <MetaItem label={t('disk.meta.projects')} value={stats.projectCount} />\n <Sep />\n <MetaItem label={t('disk.meta.sessions')} value={stats.totalSessions.toLocaleString()} />\n </div>\n )}\n </header>\n );\n}\n\nfunction tooltipStyle(surface: string, hairline: string, fg: string): React.CSSProperties {\n return {\n background: surface,\n border: `1px solid ${hairline}`,\n borderRadius: 8,\n fontFamily: 'var(--font-mono)',\n fontSize: 11,\n color: fg,\n boxShadow: 'var(--shadow-pop)',\n };\n}\n\nfunction projectCwdLabel(data: DiskUsage, projectId: string): string {\n const p = data.byProject.find((row) => row.projectId === projectId);\n return p ? shortCwd(p.decodedCwd) : projectId;\n}\n\nfunction shortCwd(cwd: string): string {\n const parts = cwd.split(/[\\\\/]+/).filter(Boolean);\n if (parts.length <= 2) return cwd;\n return '…/' + parts.slice(-2).join('/');\n}\n\nfunction Card({\n title,\n subtitle,\n children,\n className = '',\n}: {\n title: string;\n subtitle?: string;\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <section className={`surface-card p-5 ${className}`}>\n <header className=\"mb-4 flex items-baseline justify-between gap-3\">\n <h3 className=\"font-display text-lg font-light tracking-tight text-[var(--color-fg-primary)]\">\n {title}\n </h3>\n {subtitle && (\n <span className=\"font-mono text-[10px] uppercase tracking-[0.18em] text-[var(--color-fg-muted)]\">\n {subtitle}\n </span>\n )}\n </header>\n {children}\n </section>\n );\n}\n\nfunction Empty({ className = '' }: { className?: string }) {\n const t = useT();\n return (\n <p className={`font-mono text-xs uppercase tracking-[0.18em] text-[var(--color-fg-muted)] ${className}`}>\n {t('common.noData')}\n </p>\n );\n}\n"],"names":["CleanupSuggestions","t","useT","data","isLoading","error","useQuery","queryKeys","api","jsxs","jsx","Loading","LargeSessionsTable","OrphanTable","SectionHeader","title","hint","row","display","Link","shortCwd","formatRelativeTime","formatBytes","kind","rows","confirming","setConfirming","useState","OrphanConfirmDialog","orphan","onClose","queryClient","useQueryClient","mutation","useMutation","isPendingRef","useRef","useEffect","onKey","e","motion","cwd","parts","StatCard","label","value","unit","trail","accent","PALETTE_VARS","CHART_VARS","useThemeColors","vars","snapshot","setSnapshot","readVars","observer","cs","out","v","DiskUsageRoute","colors","muted","hairline","surface","fgPrimary","palette","resolvedPalette","useMemo","pieData","p","monthData","m","Masthead","Fragment","staggerParent","fadeUpItem","_a","Card","Empty","ResponsiveContainer","PieChart","Pie","_","i","Cell","Tooltip","tooltipStyle","pct","AreaChart","XAxis","YAxis","Area","s","displayTitle","projectCwdLabel","tagline","stats","MetaItem","Sep","fg","projectId","subtitle","children","className"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as x,j as e}from"./react-CPkiFScu.js";import{b as P,a as b}from"./query-CS7JQ86v.js";import{u as C,P as I,b as h,q as u}from"./index-
|
|
2
|
-
//# sourceMappingURL=ImportPage-
|
|
1
|
+
import{r as x,j as e}from"./react-CPkiFScu.js";import{b as P,a as b}from"./query-CS7JQ86v.js";import{u as C,P as I,b as h,q as u}from"./index-DTbWl1jb.js";import{L as S}from"./router-DwaHAh1G.js";import"./vendor-Cs8vYp-N.js";const E=["skip","overwrite-if-newer","keep-both"],K={skip:"import.policy.skip","overwrite-if-newer":"import.policy.overwrite-if-newer","keep-both":"import.policy.keep-both"},L={create:"import.action.create",overwrite:"import.action.overwrite","keep-both":"import.action.keep-both",skip:"import.action.skip"},y={"existing-project":"import.suggestion.existing-project","original-path":"import.suggestion.original-path","same-basename":"import.suggestion.same-basename"},T={create:"import.memory.create",skip:"import.memory.skip",conflict:"import.memory.conflict"};function q(o){switch(o){case"create":return"border-[var(--color-moss)]/40 bg-[var(--color-moss-soft)] text-[var(--color-fg-primary)]";case"overwrite":return"border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] text-[var(--color-danger)]";case"keep-both":return"border-[var(--color-accent)]/40 bg-[var(--color-accent-soft)] text-[var(--color-accent-ink)] dark:text-[var(--color-accent)]";default:return"border-[var(--color-hairline-strong)] bg-[var(--color-sunken)] text-[var(--color-fg-muted)]"}}function A(){const o=C(),d=P(),[l,j]=x.useState(""),[i,v]=x.useState(""),[s,w]=x.useState("skip"),[t,g]=x.useState(null),n=b({mutationFn:r=>h("/api/import/preview",{method:"POST",body:JSON.stringify({bundleDir:l.trim(),targetCwd:r.targetCwd,collisionPolicy:r.collisionPolicy})}),onSuccess:r=>{g(r),v(r.remap.targetCwd)}}),a=b({mutationFn:()=>h("/api/import",{method:"POST",body:JSON.stringify({bundleDir:l.trim(),targetCwd:i.trim(),collisionPolicy:s})}),onSuccess:r=>{d.invalidateQueries({queryKey:u.projects()}),d.invalidateQueries({queryKey:u.projectSessions(r.targetProjectId)}),d.invalidateQueries({queryKey:u.projectMemory(r.targetProjectId)}),d.invalidateQueries({queryKey:u.diskUsage()})}});function f(){l.trim()!==""&&(g(null),a.reset(),n.mutate({targetCwd:void 0,collisionPolicy:s}))}function m(r,k){a.reset(),n.mutate({targetCwd:r.trim()||void 0,collisionPolicy:k})}function N(r){w(r),t&&m(i,r)}const c=a.data,p=n.isPending;return e.jsxs("section",{children:[e.jsxs("div",{className:"surface-card p-6",children:[e.jsx(I,{eyebrow:o("nav.import"),title:o("import.title")}),e.jsx("p",{className:"mt-2 max-w-2xl text-sm text-[var(--color-fg-muted)]",children:o("import.tagline")}),e.jsxs("div",{className:"mt-5 flex flex-col gap-2 sm:flex-row",children:[e.jsx("input",{type:"text",value:l,onChange:r=>j(r.target.value),onKeyDown:r=>r.key==="Enter"&&f(),placeholder:o("import.bundlePlaceholder"),spellCheck:!1,"aria-label":o("import.bundleLabel"),className:"min-w-0 flex-1 rounded-[var(--radius-input)] border border-[var(--color-hairline-strong)] bg-[var(--color-canvas)] px-3 py-2 font-mono text-sm text-[var(--color-fg-primary)] outline-none focus:border-[var(--color-accent)]"}),e.jsx("button",{type:"button",onClick:f,disabled:l.trim()===""||p,className:"rounded-[var(--radius-control)] bg-[var(--color-fg-primary)] px-4 py-2 text-sm font-medium text-[var(--color-canvas)] shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",children:o(p?"import.btn.loading":t?"import.btn.recheck":"import.btn.load")})]}),n.error&&e.jsx("p",{className:"mt-3 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]",children:n.error.message}),!t&&!n.error&&e.jsx("p",{className:"mt-4 text-sm text-[var(--color-fg-muted)]",children:o("import.empty")})]}),t&&e.jsxs("div",{className:"surface-card mt-6 space-y-6 p-6",children:[e.jsx("p",{className:"break-all font-mono text-xs text-[var(--color-fg-muted)]",children:o("import.source",{platform:t.source.platform,cwd:t.source.cwd})}),e.jsxs("div",{children:[e.jsx("span",{className:"eyebrow",children:o("import.targetLabel")}),e.jsxs("div",{className:"mt-1.5 flex flex-col gap-2 sm:flex-row",children:[e.jsx("input",{type:"text",value:i,onChange:r=>v(r.target.value),onKeyDown:r=>r.key==="Enter"&&m(i,s),spellCheck:!1,"aria-label":o("import.targetLabel"),className:"min-w-0 flex-1 rounded-[var(--radius-input)] border border-[var(--color-hairline-strong)] bg-[var(--color-canvas)] px-3 py-2 font-mono text-sm text-[var(--color-fg-primary)] outline-none focus:border-[var(--color-accent)]"}),e.jsx("button",{type:"button",onClick:()=>m(i,s),disabled:p,className:"rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-4 py-2 text-sm text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] disabled:opacity-50",children:o("import.btn.recheck")})]}),e.jsx("p",{className:"mt-1.5 text-xs text-[var(--color-fg-muted)]",children:o("import.targetHint")}),e.jsx("p",{className:"mt-1 font-mono text-[11px] text-[var(--color-fg-faint)]",children:o("import.targetId",{id:t.remap.targetProjectId})}),t.suggestions.length>0&&e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-1.5",children:[e.jsx("span",{className:"eyebrow mr-1",children:o("import.suggestions")}),t.suggestions.map(r=>e.jsxs("button",{type:"button",onClick:()=>{v(r.cwd),m(r.cwd,s)},className:"inline-flex items-center gap-1.5 rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] bg-[var(--color-surface)] px-2.5 py-1 font-mono text-[11px] text-[var(--color-fg-secondary)] hover:border-[var(--color-accent)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]",title:o(y[r.reason]),children:[e.jsx("span",{className:"max-w-[20rem] truncate",children:r.cwd}),e.jsxs("span",{className:"text-[var(--color-fg-faint)]",children:["· ",o(y[r.reason])]})]},r.projectId))]})]}),e.jsxs("div",{children:[e.jsx("span",{className:"eyebrow",children:o("import.policyLabel")}),e.jsx("div",{className:"mt-1.5 inline-flex flex-wrap gap-1 rounded-[var(--radius-input)] border border-[var(--color-hairline)] bg-[var(--color-sunken)] p-1",children:E.map(r=>e.jsx("button",{type:"button",onClick:()=>N(r),"aria-pressed":s===r,className:"rounded-[var(--radius-control)] px-3 py-1.5 text-xs font-medium transition "+(s===r?"bg-[var(--color-surface)] text-[var(--color-fg-primary)] shadow-[var(--shadow-rise)]":"text-[var(--color-fg-muted)] hover:text-[var(--color-fg-primary)]"),children:o(K[r])},r))})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-baseline justify-between",children:[e.jsx("span",{className:"eyebrow",children:o("import.sessions.heading")}),e.jsx("span",{className:"font-mono text-[11px] text-[var(--color-fg-faint)]",children:o("import.history",{n:t.historyLinesToAdd})})]}),t.sessions.length===0?e.jsx("p",{className:"mt-2 text-sm text-[var(--color-fg-muted)]",children:o("import.sessions.empty")}):e.jsx("ul",{className:"mt-2 space-y-1.5",children:t.sessions.map(r=>e.jsxs("li",{className:"flex items-center gap-3 rounded-md border border-[var(--color-hairline)] bg-[var(--color-canvas)] px-3 py-2",children:[e.jsx("span",{className:"shrink-0 rounded-[var(--radius-control)] border px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.12em] "+q(r.action),children:o(L[r.action])}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:"block truncate text-sm text-[var(--color-fg-primary)]",children:r.title}),e.jsx("span",{className:"block truncate font-mono text-[10.5px] text-[var(--color-fg-faint)]",children:r.newSessionId??r.sessionId})]}),r.reason&&e.jsx("span",{className:"shrink-0 text-[11px] text-[var(--color-fg-muted)]",children:r.reason})]},r.sessionId))})]}),t.memory.length>0&&e.jsxs("div",{children:[e.jsx("span",{className:"eyebrow",children:o("import.memory.heading")}),e.jsx("ul",{className:"mt-2 flex flex-wrap gap-1.5",children:t.memory.map(r=>e.jsxs("li",{className:"inline-flex items-center gap-1.5 rounded-[var(--radius-control)] border border-[var(--color-hairline)] bg-[var(--color-canvas)] px-2.5 py-1 font-mono text-[11px] text-[var(--color-fg-secondary)]",children:[e.jsx("span",{className:"text-[var(--color-fg-primary)]",children:r.filename}),e.jsxs("span",{className:"text-[var(--color-fg-faint)]",children:["·"," ",r.action==="conflict"?o("import.memory.conflict",{name:r.writtenAs??""}):o(T[r.action])]})]},r.filename))})]}),a.error&&e.jsx("p",{className:"rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]",children:a.error.message}),c?e.jsxs("div",{className:"space-y-3 rounded-[var(--radius-card)] border border-[var(--color-moss)]/40 bg-[var(--color-moss-soft)] px-4 py-3",children:[e.jsx("p",{className:"font-display text-lg font-light text-[var(--color-fg-primary)]",children:o("import.result.title")}),e.jsx("p",{className:"text-sm text-[var(--color-fg-secondary)]",children:o("import.result.summary",{n:c.imported.length,skipped:c.skipped.length,memory:c.memoryWritten.length,lines:c.historyLinesAdded})}),e.jsx(S,{to:`/projects/${encodeURIComponent(c.targetProjectId)}`,className:"inline-flex w-fit items-center gap-2 rounded-[var(--radius-control)] bg-[var(--color-fg-primary)] px-4 py-1.5 text-sm font-medium text-[var(--color-canvas)] hover:opacity-90",children:o("import.result.viewProject")})]}):e.jsx("div",{className:"flex justify-end border-t border-[var(--color-hairline)] pt-4",children:e.jsx("button",{type:"button",onClick:()=>a.mutate(),disabled:i.trim()===""||p||a.isPending,className:"rounded-[var(--radius-control)] bg-[var(--color-fg-primary)] px-5 py-2 text-sm font-medium text-[var(--color-canvas)] shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",children:a.isPending?o("import.btn.committing"):o("import.btn.commit")})})]})]})}export{A as default};
|
|
2
|
+
//# sourceMappingURL=ImportPage-Cwq5bx7G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImportPage-Cwq5bx7G.js","sources":["../../web/src/routes/ImportPage.tsx"],"sourcesContent":["import { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport PageHeader from '../components/PageHeader.tsx';\nimport {\n api,\n type ImportCollisionPolicy,\n type ImportPreviewResult,\n type ImportResult,\n type ImportSessionAction,\n} from '../lib/api.ts';\nimport { useT } from '../lib/i18n.ts';\nimport { queryKeys } from '../lib/query-keys.ts';\n\nconst POLICIES: ImportCollisionPolicy[] = ['skip', 'overwrite-if-newer', 'keep-both'];\n\nconst POLICY_KEY = {\n skip: 'import.policy.skip',\n 'overwrite-if-newer': 'import.policy.overwrite-if-newer',\n 'keep-both': 'import.policy.keep-both',\n} as const;\n\nconst ACTION_KEY = {\n create: 'import.action.create',\n overwrite: 'import.action.overwrite',\n 'keep-both': 'import.action.keep-both',\n skip: 'import.action.skip',\n} as const;\n\nconst SUGGEST_KEY = {\n 'existing-project': 'import.suggestion.existing-project',\n 'original-path': 'import.suggestion.original-path',\n 'same-basename': 'import.suggestion.same-basename',\n} as const;\n\nconst MEM_KEY = {\n create: 'import.memory.create',\n skip: 'import.memory.skip',\n conflict: 'import.memory.conflict',\n} as const;\n\nfunction actionTone(action: ImportSessionAction): string {\n switch (action) {\n case 'create':\n return 'border-[var(--color-moss)]/40 bg-[var(--color-moss-soft)] text-[var(--color-fg-primary)]';\n case 'overwrite':\n return 'border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] text-[var(--color-danger)]';\n case 'keep-both':\n return 'border-[var(--color-accent)]/40 bg-[var(--color-accent-soft)] text-[var(--color-accent-ink)] dark:text-[var(--color-accent)]';\n default:\n return 'border-[var(--color-hairline-strong)] bg-[var(--color-sunken)] text-[var(--color-fg-muted)]';\n }\n}\n\nexport default function ImportPage() {\n const t = useT();\n const queryClient = useQueryClient();\n\n const [bundleDir, setBundleDir] = useState('');\n const [targetCwd, setTargetCwd] = useState('');\n const [policy, setPolicy] = useState<ImportCollisionPolicy>('skip');\n const [preview, setPreview] = useState<ImportPreviewResult | null>(null);\n\n const previewMutation = useMutation({\n mutationFn: (vars: { targetCwd?: string; collisionPolicy: ImportCollisionPolicy }) =>\n api<ImportPreviewResult>('/api/import/preview', {\n method: 'POST',\n body: JSON.stringify({\n bundleDir: bundleDir.trim(),\n targetCwd: vars.targetCwd,\n collisionPolicy: vars.collisionPolicy,\n }),\n }),\n onSuccess: (data) => {\n setPreview(data);\n setTargetCwd(data.remap.targetCwd);\n },\n });\n\n const commitMutation = useMutation({\n mutationFn: () =>\n api<ImportResult>('/api/import', {\n method: 'POST',\n body: JSON.stringify({\n bundleDir: bundleDir.trim(),\n targetCwd: targetCwd.trim(),\n collisionPolicy: policy,\n }),\n }),\n onSuccess: (data) => {\n queryClient.invalidateQueries({ queryKey: queryKeys.projects() });\n queryClient.invalidateQueries({ queryKey: queryKeys.projectSessions(data.targetProjectId) });\n queryClient.invalidateQueries({ queryKey: queryKeys.projectMemory(data.targetProjectId) });\n queryClient.invalidateQueries({ queryKey: queryKeys.diskUsage() });\n },\n });\n\n function loadBundle() {\n if (bundleDir.trim() === '') return;\n setPreview(null);\n commitMutation.reset();\n previewMutation.mutate({ targetCwd: undefined, collisionPolicy: policy });\n }\n\n function recheck(nextTarget: string, nextPolicy: ImportCollisionPolicy) {\n commitMutation.reset();\n previewMutation.mutate({\n targetCwd: nextTarget.trim() || undefined,\n collisionPolicy: nextPolicy,\n });\n }\n\n function changePolicy(p: ImportCollisionPolicy) {\n setPolicy(p);\n if (preview) recheck(targetCwd, p);\n }\n\n const result = commitMutation.data;\n const busy = previewMutation.isPending;\n\n return (\n <section>\n <div className=\"surface-card p-6\">\n <PageHeader eyebrow={t('nav.import')} title={t('import.title')} />\n <p className=\"mt-2 max-w-2xl text-sm text-[var(--color-fg-muted)]\">\n {t('import.tagline')}\n </p>\n\n <div className=\"mt-5 flex flex-col gap-2 sm:flex-row\">\n <input\n type=\"text\"\n value={bundleDir}\n onChange={(e) => setBundleDir(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && loadBundle()}\n placeholder={t('import.bundlePlaceholder')}\n spellCheck={false}\n aria-label={t('import.bundleLabel')}\n className=\"min-w-0 flex-1 rounded-[var(--radius-input)] border border-[var(--color-hairline-strong)] bg-[var(--color-canvas)] px-3 py-2 font-mono text-sm text-[var(--color-fg-primary)] outline-none focus:border-[var(--color-accent)]\"\n />\n <button\n type=\"button\"\n onClick={loadBundle}\n disabled={bundleDir.trim() === '' || busy}\n className=\"rounded-[var(--radius-control)] bg-[var(--color-fg-primary)] px-4 py-2 text-sm font-medium text-[var(--color-canvas)] shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {busy ? t('import.btn.loading') : preview ? t('import.btn.recheck') : t('import.btn.load')}\n </button>\n </div>\n\n {previewMutation.error && (\n <p className=\"mt-3 rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]\">\n {(previewMutation.error as Error).message}\n </p>\n )}\n\n {!preview && !previewMutation.error && (\n <p className=\"mt-4 text-sm text-[var(--color-fg-muted)]\">{t('import.empty')}</p>\n )}\n </div>\n\n {preview && (\n <div className=\"surface-card mt-6 space-y-6 p-6\">\n <p className=\"break-all font-mono text-xs text-[var(--color-fg-muted)]\">\n {t('import.source', { platform: preview.source.platform, cwd: preview.source.cwd })}\n </p>\n\n {/* target */}\n <div>\n <span className=\"eyebrow\">{t('import.targetLabel')}</span>\n <div className=\"mt-1.5 flex flex-col gap-2 sm:flex-row\">\n <input\n type=\"text\"\n value={targetCwd}\n onChange={(e) => setTargetCwd(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && recheck(targetCwd, policy)}\n spellCheck={false}\n aria-label={t('import.targetLabel')}\n className=\"min-w-0 flex-1 rounded-[var(--radius-input)] border border-[var(--color-hairline-strong)] bg-[var(--color-canvas)] px-3 py-2 font-mono text-sm text-[var(--color-fg-primary)] outline-none focus:border-[var(--color-accent)]\"\n />\n <button\n type=\"button\"\n onClick={() => recheck(targetCwd, policy)}\n disabled={busy}\n className=\"rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] px-4 py-2 text-sm text-[var(--color-fg-secondary)] hover:bg-[var(--color-sunken)] disabled:opacity-50\"\n >\n {t('import.btn.recheck')}\n </button>\n </div>\n <p className=\"mt-1.5 text-xs text-[var(--color-fg-muted)]\">{t('import.targetHint')}</p>\n <p className=\"mt-1 font-mono text-[11px] text-[var(--color-fg-faint)]\">\n {t('import.targetId', { id: preview.remap.targetProjectId })}\n </p>\n\n {preview.suggestions.length > 0 && (\n <div className=\"mt-2 flex flex-wrap items-center gap-1.5\">\n <span className=\"eyebrow mr-1\">{t('import.suggestions')}</span>\n {preview.suggestions.map((s) => (\n <button\n key={s.projectId}\n type=\"button\"\n onClick={() => {\n setTargetCwd(s.cwd);\n recheck(s.cwd, policy);\n }}\n className=\"inline-flex items-center gap-1.5 rounded-[var(--radius-control)] border border-[var(--color-hairline-strong)] bg-[var(--color-surface)] px-2.5 py-1 font-mono text-[11px] text-[var(--color-fg-secondary)] hover:border-[var(--color-accent)] hover:text-[var(--color-accent-ink)] dark:hover:text-[var(--color-accent)]\"\n title={t(SUGGEST_KEY[s.reason])}\n >\n <span className=\"max-w-[20rem] truncate\">{s.cwd}</span>\n <span className=\"text-[var(--color-fg-faint)]\">· {t(SUGGEST_KEY[s.reason])}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* policy */}\n <div>\n <span className=\"eyebrow\">{t('import.policyLabel')}</span>\n <div className=\"mt-1.5 inline-flex flex-wrap gap-1 rounded-[var(--radius-input)] border border-[var(--color-hairline)] bg-[var(--color-sunken)] p-1\">\n {POLICIES.map((p) => (\n <button\n key={p}\n type=\"button\"\n onClick={() => changePolicy(p)}\n aria-pressed={policy === p}\n className={\n 'rounded-[var(--radius-control)] px-3 py-1.5 text-xs font-medium transition ' +\n (policy === p\n ? 'bg-[var(--color-surface)] text-[var(--color-fg-primary)] shadow-[var(--shadow-rise)]'\n : 'text-[var(--color-fg-muted)] hover:text-[var(--color-fg-primary)]')\n }\n >\n {t(POLICY_KEY[p])}\n </button>\n ))}\n </div>\n </div>\n\n {/* sessions */}\n <div>\n <div className=\"flex items-baseline justify-between\">\n <span className=\"eyebrow\">{t('import.sessions.heading')}</span>\n <span className=\"font-mono text-[11px] text-[var(--color-fg-faint)]\">\n {t('import.history', { n: preview.historyLinesToAdd })}\n </span>\n </div>\n {preview.sessions.length === 0 ? (\n <p className=\"mt-2 text-sm text-[var(--color-fg-muted)]\">\n {t('import.sessions.empty')}\n </p>\n ) : (\n <ul className=\"mt-2 space-y-1.5\">\n {preview.sessions.map((s) => (\n <li\n key={s.sessionId}\n className=\"flex items-center gap-3 rounded-md border border-[var(--color-hairline)] bg-[var(--color-canvas)] px-3 py-2\"\n >\n <span\n className={\n 'shrink-0 rounded-[var(--radius-control)] border px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.12em] ' +\n actionTone(s.action)\n }\n >\n {t(ACTION_KEY[s.action])}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm text-[var(--color-fg-primary)]\">\n {s.title}\n </span>\n <span className=\"block truncate font-mono text-[10.5px] text-[var(--color-fg-faint)]\">\n {s.newSessionId ?? s.sessionId}\n </span>\n </span>\n {s.reason && (\n <span className=\"shrink-0 text-[11px] text-[var(--color-fg-muted)]\">\n {s.reason}\n </span>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {/* memory */}\n {preview.memory.length > 0 && (\n <div>\n <span className=\"eyebrow\">{t('import.memory.heading')}</span>\n <ul className=\"mt-2 flex flex-wrap gap-1.5\">\n {preview.memory.map((m) => (\n <li\n key={m.filename}\n className=\"inline-flex items-center gap-1.5 rounded-[var(--radius-control)] border border-[var(--color-hairline)] bg-[var(--color-canvas)] px-2.5 py-1 font-mono text-[11px] text-[var(--color-fg-secondary)]\"\n >\n <span className=\"text-[var(--color-fg-primary)]\">{m.filename}</span>\n <span className=\"text-[var(--color-fg-faint)]\">\n ·{' '}\n {m.action === 'conflict'\n ? t('import.memory.conflict', { name: m.writtenAs ?? '' })\n : t(MEM_KEY[m.action])}\n </span>\n </li>\n ))}\n </ul>\n </div>\n )}\n\n {commitMutation.error && (\n <p className=\"rounded-md border border-[var(--color-danger)]/40 bg-[var(--color-danger-soft)] px-3 py-2 text-sm text-[var(--color-danger)]\">\n {(commitMutation.error as Error).message}\n </p>\n )}\n\n {result ? (\n <div className=\"space-y-3 rounded-[var(--radius-card)] border border-[var(--color-moss)]/40 bg-[var(--color-moss-soft)] px-4 py-3\">\n <p className=\"font-display text-lg font-light text-[var(--color-fg-primary)]\">\n {t('import.result.title')}\n </p>\n <p className=\"text-sm text-[var(--color-fg-secondary)]\">\n {t('import.result.summary', {\n n: result.imported.length,\n skipped: result.skipped.length,\n memory: result.memoryWritten.length,\n lines: result.historyLinesAdded,\n })}\n </p>\n <Link\n to={`/projects/${encodeURIComponent(result.targetProjectId)}`}\n className=\"inline-flex w-fit items-center gap-2 rounded-[var(--radius-control)] bg-[var(--color-fg-primary)] px-4 py-1.5 text-sm font-medium text-[var(--color-canvas)] hover:opacity-90\"\n >\n {t('import.result.viewProject')}\n </Link>\n </div>\n ) : (\n <div className=\"flex justify-end border-t border-[var(--color-hairline)] pt-4\">\n <button\n type=\"button\"\n onClick={() => commitMutation.mutate()}\n disabled={targetCwd.trim() === '' || busy || commitMutation.isPending}\n className=\"rounded-[var(--radius-control)] bg-[var(--color-fg-primary)] px-5 py-2 text-sm font-medium text-[var(--color-canvas)] shadow-[var(--shadow-rise)] hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {commitMutation.isPending ? t('import.btn.committing') : t('import.btn.commit')}\n </button>\n </div>\n )}\n </div>\n )}\n </section>\n );\n}\n"],"names":["POLICIES","POLICY_KEY","ACTION_KEY","SUGGEST_KEY","MEM_KEY","actionTone","action","ImportPage","t","useT","queryClient","useQueryClient","bundleDir","setBundleDir","useState","targetCwd","setTargetCwd","policy","setPolicy","preview","setPreview","previewMutation","useMutation","vars","api","data","commitMutation","queryKeys","loadBundle","recheck","nextTarget","nextPolicy","changePolicy","p","result","busy","jsxs","jsx","PageHeader","e","s","m","Link"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as n,j as r}from"./react-CPkiFScu.js";import{C as c}from"./index-DTbWl1jb.js";import{M as d,r as i}from"./markdown-Bag5rX3T.js";import"./query-CS7JQ86v.js";import"./router-DwaHAh1G.js";import"./vendor-Cs8vYp-N.js";function s(o){let e="";for(const t of o.children)t.type==="text"?e+=t.value:t.type==="element"&&(e+=s(t));return e}function x(o){const e=Array.isArray(o)?o[0]:o;if(!n.isValidElement(e))return null;const t=e.props.className??"",a=/language-([\w+-]+)/.exec(t);return a?a[1]:null}const m={p:({node:o,...e})=>r.jsx("p",{className:"whitespace-pre-wrap break-words",...e}),h1:({node:o,...e})=>r.jsx("h1",{className:"font-display text-[17.5px] font-semibold tracking-[-0.01em] text-[var(--color-fg-primary)]",...e}),h2:({node:o,...e})=>r.jsx("h2",{className:"font-display text-[16.5px] font-semibold tracking-[-0.01em] text-[var(--color-fg-primary)]",...e}),h3:({node:o,...e})=>r.jsx("h3",{className:"font-display text-[15.5px] font-semibold text-[var(--color-fg-primary)]",...e}),h4:({node:o,...e})=>r.jsx("h4",{className:"font-display text-[14.5px] font-semibold text-[var(--color-fg-primary)]",...e}),h5:({node:o,...e})=>r.jsx("h5",{className:"font-display text-[13.5px] font-semibold text-[var(--color-fg-primary)]",...e}),h6:({node:o,...e})=>r.jsx("h6",{className:"eyebrow",...e}),a:({node:o,...e})=>r.jsx("a",{target:"_blank",rel:"noreferrer",className:"break-words text-[var(--color-accent-ink)] underline decoration-[var(--color-accent)]/50 underline-offset-2 transition hover:decoration-[var(--color-accent)] dark:text-[var(--color-accent)]",...e}),strong:({node:o,...e})=>r.jsx("strong",{className:"font-semibold text-[var(--color-fg-primary)]",...e}),del:({node:o,...e})=>r.jsx("del",{className:"text-[var(--color-fg-muted)] line-through decoration-[var(--color-hairline-strong)]",...e}),ul:({node:o,...e})=>r.jsx("ul",{className:"list-disc space-y-1 pl-5 marker:text-[var(--color-fg-faint)]",...e}),ol:({node:o,...e})=>r.jsx("ol",{className:"list-decimal space-y-1 pl-5 marker:font-mono marker:text-[12px] marker:text-[var(--color-fg-muted)]",...e}),li:({node:o,className:e,...t})=>r.jsx("li",{className:"break-words"+(e!=null&&e.includes("task-list-item")?" -ml-5 list-none":""),...t}),input:({node:o,...e})=>e.type==="checkbox"?r.jsx("span",{"aria-hidden":!0,className:"mr-1.5 inline-flex h-[13px] w-[13px] -translate-y-px items-center justify-center rounded-[3px] border align-middle font-mono text-[9px] leading-none "+(e.checked?"border-[var(--color-moss)] bg-[var(--color-moss-soft)] text-[var(--color-moss)]":"border-[var(--color-hairline-strong)] text-transparent"),children:"✓"}):null,blockquote:({node:o,...e})=>r.jsx("blockquote",{className:"space-y-1.5 border-l-2 border-[var(--color-accent)] pl-3 italic text-[var(--color-fg-secondary)]",...e}),hr:({node:o,...e})=>r.jsx("hr",{className:"rule-dotted my-1 border-0",...e}),code:({node:o,...e})=>r.jsx("code",{className:"rounded-[5px] border border-[var(--color-hairline)] bg-[var(--color-sunken)] px-[5px] py-[1.5px] font-mono text-[12.5px] text-[var(--color-accent-ink)] dark:text-[var(--color-accent)]",...e}),pre:({node:o,children:e,...t})=>{const a=x(e),l=o?s(o):"";return r.jsxs("div",{className:"group/code relative overflow-hidden rounded-[var(--radius-control)] border border-[var(--color-hairline)] bg-[var(--color-sunken)]",children:[r.jsxs("div",{className:"absolute right-1.5 top-1.5 z-[1] flex items-center gap-1.5",children:[a&&r.jsx("span",{className:"rounded-sm bg-[var(--color-surface)]/85 px-1.5 py-0.5 font-mono text-[9.5px] uppercase tracking-[0.14em] text-[var(--color-fg-faint)]",children:a}),r.jsx("span",{className:"opacity-0 transition group-hover/code:opacity-100",children:r.jsx(c,{text:l})})]}),r.jsx("pre",{className:"overflow-x-auto px-3.5 py-3 font-mono text-[12px] leading-[1.6] text-[var(--color-fg-primary)] [&_code]:rounded-none [&_code]:border-0 [&_code]:bg-transparent [&_code]:p-0 [&_code]:text-[12px] [&_code]:text-inherit",...t,children:e})]})},table:({node:o,...e})=>r.jsx("div",{className:"overflow-x-auto",children:r.jsx("table",{className:"w-max min-w-[50%] border-collapse text-[13.5px]",...e})}),th:({node:o,...e})=>r.jsx("th",{className:"border-b border-[var(--color-hairline-strong)] px-2.5 py-1.5 text-left text-[12.5px] font-semibold text-[var(--color-fg-secondary)]",...e}),td:({node:o,...e})=>r.jsx("td",{className:"border-b border-[var(--color-hairline)] px-2.5 py-1.5 align-top",...e}),img:({node:o,...e})=>r.jsx("img",{loading:"lazy",className:"my-1 max-w-full rounded-[var(--radius-control)] border border-[var(--color-hairline)]",...e})},p=[i];function f({text:o}){return r.jsx("div",{className:"space-y-2.5 break-words text-[14.5px] leading-relaxed",children:r.jsx(d,{remarkPlugins:p,components:m,children:o})})}const j=n.memo(f);export{j as default};
|
|
2
|
+
//# sourceMappingURL=MarkdownContent-BFu7Nkk_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownContent-BFu7Nkk_.js","sources":["../../web/src/components/MarkdownContent.tsx"],"sourcesContent":["import type { Element } from 'hast';\nimport { isValidElement, memo, type ReactNode } from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport type { PluggableList } from 'unified';\nimport { CopyButton } from './ToolBlock.tsx';\n\n// Claude 回复(assistant text block)的 markdown 排版。仅在【非搜索态】渲染:\n// 搜索时上层退回 plain HighlightedText(见 MessageBubble 的 markdown 开关),\n// 所以本组件不需要处理搜索高亮——「读用富渲染,搜用原文高亮」。\n// 仅 assistant 走这里:用户输入是终端原文,渲染成 markdown 会误伤 `*args`、路径等字面量。\n// 安全性:不挂 rehype-raw,react-markdown 默认不渲染原始 HTML(显示为字面文本),\n// URL 走默认 defaultUrlTransform 白名单。\n//\n// 本组件经 MessageBubble lazy() 引入,连同 remark/micromark 系列被 vite 拆进\n// `markdown` chunk(见 vite.config.ts),不进首屏。\n\n/** 收集 hast 节点下全部文本,供代码块复制按钮取原文。 */\nfunction hastText(node: Element): string {\n let out = '';\n for (const child of node.children) {\n if (child.type === 'text') out += child.value;\n else if (child.type === 'element') out += hastText(child);\n }\n return out;\n}\n\n/** 从 <pre> 的子 <code> 上取 ```lang 标注(className: language-x)。 */\nfunction codeLang(children: ReactNode): string | null {\n const el = Array.isArray(children) ? children[0] : children;\n if (!isValidElement(el)) return null;\n const cls = (el.props as { className?: string }).className ?? '';\n const m = /language-([\\w+-]+)/.exec(cls);\n return m ? m[1]! : null;\n}\n\n// 元素 → 设计 token 的映射。标题在气泡语境内整体缩阶;代码用 mono + sunken;\n// 引用沿用 tagline 的 accent 左边框 + 斜体;hr 复用 rule-dotted。\nconst COMPONENTS: Components = {\n p: ({ node: _n, ...props }) => (\n <p className=\"whitespace-pre-wrap break-words\" {...props} />\n ),\n h1: ({ node: _n, ...props }) => (\n <h1 className=\"font-display text-[17.5px] font-semibold tracking-[-0.01em] text-[var(--color-fg-primary)]\" {...props} />\n ),\n h2: ({ node: _n, ...props }) => (\n <h2 className=\"font-display text-[16.5px] font-semibold tracking-[-0.01em] text-[var(--color-fg-primary)]\" {...props} />\n ),\n h3: ({ node: _n, ...props }) => (\n <h3 className=\"font-display text-[15.5px] font-semibold text-[var(--color-fg-primary)]\" {...props} />\n ),\n h4: ({ node: _n, ...props }) => (\n <h4 className=\"font-display text-[14.5px] font-semibold text-[var(--color-fg-primary)]\" {...props} />\n ),\n h5: ({ node: _n, ...props }) => (\n <h5 className=\"font-display text-[13.5px] font-semibold text-[var(--color-fg-primary)]\" {...props} />\n ),\n h6: ({ node: _n, ...props }) => <h6 className=\"eyebrow\" {...props} />,\n a: ({ node: _n, ...props }) => (\n <a\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"break-words text-[var(--color-accent-ink)] underline decoration-[var(--color-accent)]/50 underline-offset-2 transition hover:decoration-[var(--color-accent)] dark:text-[var(--color-accent)]\"\n {...props}\n />\n ),\n strong: ({ node: _n, ...props }) => (\n <strong className=\"font-semibold text-[var(--color-fg-primary)]\" {...props} />\n ),\n del: ({ node: _n, ...props }) => (\n <del className=\"text-[var(--color-fg-muted)] line-through decoration-[var(--color-hairline-strong)]\" {...props} />\n ),\n ul: ({ node: _n, ...props }) => (\n <ul className=\"list-disc space-y-1 pl-5 marker:text-[var(--color-fg-faint)]\" {...props} />\n ),\n ol: ({ node: _n, ...props }) => (\n <ol className=\"list-decimal space-y-1 pl-5 marker:font-mono marker:text-[12px] marker:text-[var(--color-fg-muted)]\" {...props} />\n ),\n li: ({ node: _n, className, ...props }) => (\n <li\n className={\n 'break-words' +\n (className?.includes('task-list-item') ? ' -ml-5 list-none' : '')\n }\n {...props}\n />\n ),\n // GFM 任务清单的 checkbox:换成与 TodoWrite 同语言的方框打钩。\n input: ({ node: _n, ...props }) =>\n props.type === 'checkbox' ? (\n <span\n aria-hidden\n className={\n 'mr-1.5 inline-flex h-[13px] w-[13px] -translate-y-px items-center justify-center rounded-[3px] border align-middle font-mono text-[9px] leading-none ' +\n (props.checked\n ? 'border-[var(--color-moss)] bg-[var(--color-moss-soft)] text-[var(--color-moss)]'\n : 'border-[var(--color-hairline-strong)] text-transparent')\n }\n >\n ✓\n </span>\n ) : null,\n blockquote: ({ node: _n, ...props }) => (\n <blockquote\n className=\"space-y-1.5 border-l-2 border-[var(--color-accent)] pl-3 italic text-[var(--color-fg-secondary)]\"\n {...props}\n />\n ),\n hr: ({ node: _n, ...props }) => <hr className=\"rule-dotted my-1 border-0\" {...props} />,\n code: ({ node: _n, ...props }) => (\n <code\n className=\"rounded-[5px] border border-[var(--color-hairline)] bg-[var(--color-sunken)] px-[5px] py-[1.5px] font-mono text-[12.5px] text-[var(--color-accent-ink)] dark:text-[var(--color-accent)]\"\n {...props}\n />\n ),\n pre: ({ node, children, ...props }) => {\n const lang = codeLang(children);\n const raw = node ? hastText(node) : '';\n return (\n <div className=\"group/code relative overflow-hidden rounded-[var(--radius-control)] border border-[var(--color-hairline)] bg-[var(--color-sunken)]\">\n <div className=\"absolute right-1.5 top-1.5 z-[1] flex items-center gap-1.5\">\n {lang && (\n <span className=\"rounded-sm bg-[var(--color-surface)]/85 px-1.5 py-0.5 font-mono text-[9.5px] uppercase tracking-[0.14em] text-[var(--color-fg-faint)]\">\n {lang}\n </span>\n )}\n <span className=\"opacity-0 transition group-hover/code:opacity-100\">\n <CopyButton text={raw} />\n </span>\n </div>\n {/* 行内 code 的 chip 样式在代码块内用后代选择器整体中和。 */}\n <pre\n className=\"overflow-x-auto px-3.5 py-3 font-mono text-[12px] leading-[1.6] text-[var(--color-fg-primary)] [&_code]:rounded-none [&_code]:border-0 [&_code]:bg-transparent [&_code]:p-0 [&_code]:text-[12px] [&_code]:text-inherit\"\n {...props}\n >\n {children}\n </pre>\n </div>\n );\n },\n table: ({ node: _n, ...props }) => (\n <div className=\"overflow-x-auto\">\n <table className=\"w-max min-w-[50%] border-collapse text-[13.5px]\" {...props} />\n </div>\n ),\n th: ({ node: _n, ...props }) => (\n <th\n className=\"border-b border-[var(--color-hairline-strong)] px-2.5 py-1.5 text-left text-[12.5px] font-semibold text-[var(--color-fg-secondary)]\"\n {...props}\n />\n ),\n td: ({ node: _n, ...props }) => (\n <td className=\"border-b border-[var(--color-hairline)] px-2.5 py-1.5 align-top\" {...props} />\n ),\n img: ({ node: _n, ...props }) => (\n <img\n loading=\"lazy\"\n className=\"my-1 max-w-full rounded-[var(--radius-control)] border border-[var(--color-hairline)]\"\n {...props}\n />\n ),\n};\n\nconst REMARK_PLUGINS: PluggableList = [remarkGfm];\n\nfunction MarkdownContent({ text }: { text: string }) {\n return (\n <div className=\"space-y-2.5 break-words text-[14.5px] leading-relaxed\">\n <ReactMarkdown remarkPlugins={REMARK_PLUGINS} components={COMPONENTS}>\n {text}\n </ReactMarkdown>\n </div>\n );\n}\n\n// 时间线一次窗口化渲染 50 条消息,memo 避免轮询引发的全量重解析。\nexport default memo(MarkdownContent);\n"],"names":["hastText","node","out","child","codeLang","children","el","isValidElement","cls","m","COMPONENTS","_n","props","jsx","className","lang","raw","jsxs","CopyButton","REMARK_PLUGINS","remarkGfm","MarkdownContent","text","ReactMarkdown","MarkdownContent_default","memo"],"mappings":"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"}
|