cc-plan-viewer 0.1.0 → 0.2.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.
@@ -12,19 +12,19 @@ const { execSync, spawn } = require('child_process');
12
12
  const SERVER_PORT = 3847;
13
13
  const PORT_FILE = path.join(os.tmpdir(), 'cc-plan-viewer-port');
14
14
  const DEBOUNCE_FILE = path.join(os.tmpdir(), 'cc-plan-viewer-opened.json');
15
- const DEBOUNCE_MS = 30000; // 30 seconds
15
+ const DEBOUNCE_MS = 5000; // 5 seconds (prevents rapid re-opens during multi-chunk writes)
16
16
 
17
- // Plans directory candidates
18
- const PLANS_DIRS = [
19
- path.join(os.homedir(), '.claude-personal', 'plans'),
20
- path.join(os.homedir(), '.claude', 'plans'),
21
- ];
22
-
23
- function getPlansDir() {
24
- for (const dir of PLANS_DIRS) {
25
- if (fs.existsSync(dir)) return dir;
17
+ // Dynamically find all ~/.claude*/plans/ directories
18
+ function getAllPlansDirs() {
19
+ const home = os.homedir();
20
+ try {
21
+ return fs.readdirSync(home)
22
+ .filter(name => name.startsWith('.claude'))
23
+ .map(name => path.join(home, name, 'plans'))
24
+ .filter(dir => fs.existsSync(dir));
25
+ } catch {
26
+ return [];
26
27
  }
27
- return null;
28
28
  }
29
29
 
30
30
  function getServerPort() {
@@ -37,9 +37,10 @@ function getServerPort() {
37
37
 
38
38
  function isPlanFile(filePath) {
39
39
  if (!filePath || !filePath.endsWith('.md')) return false;
40
- const plansDir = getPlansDir();
41
- if (!plansDir) return false;
42
- return path.dirname(filePath) === plansDir;
40
+ // Match any ~/.claude*/plans/*.md
41
+ const home = os.homedir();
42
+ const rel = path.relative(home, filePath);
43
+ return /^\.claude[^/]*\/plans\/[^/]+\.md$/.test(rel);
43
44
  }
44
45
 
45
46
  function shouldOpenBrowser(filename) {
@@ -110,9 +111,10 @@ async function waitForServer(port, maxWaitMs = 3000) {
110
111
  }
111
112
 
112
113
  function checkUnconsumedReviews() {
113
- const plansDir = getPlansDir();
114
- if (!plansDir) return null;
114
+ const plansDirs = getAllPlansDirs();
115
+ if (plansDirs.length === 0) return null;
115
116
 
117
+ for (const plansDir of plansDirs) {
116
118
  const files = fs.readdirSync(plansDir).filter(f => f.endsWith('.review.json'));
117
119
  for (const file of files) {
118
120
  try {
@@ -146,6 +148,7 @@ function checkUnconsumedReviews() {
146
148
  }
147
149
  } catch {}
148
150
  }
151
+ } // end plansDirs loop
149
152
  return null;
150
153
  }
151
154
 
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "cc-plan-viewer",
3
- "version": "0.1.0",
3
+ "version": "0.2.2",
4
4
  "description": "Browser-based PR-style review UI for Claude Code plans",
5
5
  "type": "module",
6
6
  "bin": {
7
- "cc-plan-viewer": "./dist/server/bin/cc-plan-viewer.js"
7
+ "cc-plan-viewer": "./dist/cli-bundle.mjs"
8
8
  },
9
9
  "files": [
10
10
  "dist/",
@@ -14,12 +14,24 @@
14
14
  ],
15
15
  "scripts": {
16
16
  "dev": "concurrently \"tsx watch server/index.ts\" \"vite\"",
17
- "build": "vite build && tsc -p tsconfig.server.json",
18
- "start": "node dist/server/server/index.js",
19
- "install-hook": "node dist/server/bin/cc-plan-viewer.js install",
20
- "prepublishOnly": "npm run build"
17
+ "build": "vite build && tsc -p tsconfig.server.json && npm run bundle:server",
18
+ "bundle:server": "esbuild dist/server/server/index.js --bundle --platform=node --format=esm --outfile=dist/server-bundle.mjs --banner:js=\"import{createRequire}from'module';const require=createRequire(import.meta.url);\" && esbuild dist/server/bin/cc-plan-viewer.js --bundle --platform=node --format=esm --outfile=dist/cli-bundle.mjs --banner:js=\"import{createRequire}from'module';const require=createRequire(import.meta.url);\"",
19
+ "start": "node dist/server-bundle.mjs",
20
+ "install-hook": "node dist/cli-bundle.mjs install",
21
+ "prepublishOnly": "npm run build",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "test:coverage": "vitest run --coverage",
25
+ "test:e2e": "playwright test",
26
+ "test:all": "vitest run && playwright test"
21
27
  },
22
- "keywords": ["claude", "claude-code", "plan", "review", "viewer"],
28
+ "keywords": [
29
+ "claude",
30
+ "claude-code",
31
+ "plan",
32
+ "review",
33
+ "viewer"
34
+ ],
23
35
  "license": "MIT",
24
36
  "author": "Damià Fuentes Escoté",
25
37
  "repository": {
@@ -34,23 +46,32 @@
34
46
  "ws": "^8.18.0"
35
47
  },
36
48
  "devDependencies": {
49
+ "@playwright/test": "^1.59.1",
50
+ "@testing-library/jest-dom": "^6.9.1",
51
+ "@testing-library/react": "^16.3.2",
52
+ "@testing-library/user-event": "^14.6.1",
37
53
  "@types/express": "^5.0.0",
38
54
  "@types/node": "^22.0.0",
39
- "@types/ws": "^8.5.0",
40
55
  "@types/react": "^19.0.0",
41
56
  "@types/react-dom": "^19.0.0",
57
+ "@types/supertest": "^7.2.0",
58
+ "@types/ws": "^8.5.0",
42
59
  "@vitejs/plugin-react": "^4.3.0",
43
60
  "autoprefixer": "^10.4.0",
44
61
  "concurrently": "^9.0.0",
62
+ "esbuild": "^0.28.0",
63
+ "jsdom": "^29.0.2",
45
64
  "postcss": "^8.4.0",
46
65
  "react": "^19.0.0",
47
66
  "react-dom": "^19.0.0",
48
67
  "react-markdown": "^9.0.0",
49
68
  "rehype-highlight": "^7.0.0",
50
69
  "remark-gfm": "^4.0.0",
70
+ "supertest": "^7.2.2",
51
71
  "tailwindcss": "^3.4.0",
52
72
  "tsx": "^4.19.0",
53
73
  "typescript": "^5.7.0",
54
- "vite": "^6.0.0"
74
+ "vite": "^6.0.0",
75
+ "vitest": "^4.1.3"
55
76
  }
56
77
  }
@@ -1 +0,0 @@
1
- *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.-left-10{left:-2.5rem}.bottom-0{bottom:0}.left-0{left:0}.right-0{right:0}.top-0{top:0}.top-2{top:.5rem}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.float-right{float:right}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-lg{margin-bottom:24px}.mb-md{margin-bottom:16px}.mb-sm{margin-bottom:8px}.mb-xs{margin-bottom:4px}.ml-4{margin-left:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-lg{margin-top:24px}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.hidden{display:none}.h-2{height:.5rem}.h-5{height:1.25rem}.h-7{height:1.75rem}.max-h-\[80vh\]{max-height:80vh}.min-h-\[80px\]{min-height:80px}.min-h-screen{min-height:100vh}.w-2{width:.5rem}.w-5{width:1.25rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-\[300px\]{width:300px}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-\[1200px\]{max-width:1200px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.scale-\[1\.02\]{--tw-scale-x: 1.02;--tw-scale-y: 1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.resize-none{resize:none}.resize-y{resize:vertical}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-lg{gap:24px}.gap-sm{gap:8px}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:20px}.rounded-md{border-radius:12px}.rounded-sm{border-radius:6px}.border{border-width:1px}.border-l-2{border-left-width:2px}.border-t{border-top-width:1px}.border-none{border-style:none}.border-claude-accent-light{--tw-border-opacity: 1;border-color:rgb(205 115 87 / var(--tw-border-opacity, 1))}.border-claude-border-light{--tw-border-opacity: 1;border-color:rgb(223 215 198 / var(--tw-border-opacity, 1))}.bg-black\/40{background-color:#0006}.bg-claude-accent-light{--tw-bg-opacity: 1;background-color:rgb(205 115 87 / var(--tw-bg-opacity, 1))}.bg-claude-bg-light{--tw-bg-opacity: 1;background-color:rgb(245 240 229 / var(--tw-bg-opacity, 1))}.bg-claude-success-light{--tw-bg-opacity: 1;background-color:rgb(72 149 172 / var(--tw-bg-opacity, 1))}.bg-claude-surface-light{--tw-bg-opacity: 1;background-color:rgb(251 250 241 / var(--tw-bg-opacity, 1))}.bg-claude-surface-light\/80{background-color:#fbfaf1cc}.bg-claude-text-tertiary-light{--tw-bg-opacity: 1;background-color:rgb(142 131 112 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.p-1\.5{padding:.375rem}.p-3{padding:.75rem}.p-lg{padding:24px}.p-md{padding:16px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-md{padding-left:16px;padding-right:16px}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-xl{padding-top:40px;padding-bottom:40px}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-40{padding-bottom:10rem}.pl-2\.5{padding-left:.625rem}.pt-2\.5{padding-top:.625rem}.pt-md{padding-top:16px}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-claude-accent-light{--tw-text-opacity: 1;color:rgb(205 115 87 / var(--tw-text-opacity, 1))}.text-claude-text-primary-light{--tw-text-opacity: 1;color:rgb(40 34 24 / var(--tw-text-opacity, 1))}.text-claude-text-secondary-light{--tw-text-opacity: 1;color:rgb(102 102 86 / var(--tw-text-opacity, 1))}.text-claude-text-tertiary-light{--tw-text-opacity: 1;color:rgb(142 131 112 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-lg{--tw-backdrop-blur: blur(16px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}*{box-sizing:border-box}body{margin:0;font-family:Inter,system-ui,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.prose{color:#282218;line-height:1.75;max-width:none;font-size:15px}@media(prefers-color-scheme:dark){.prose{color:#ede7dc}}.prose h1,.prose h2,.prose h3,.prose h4,.prose h5,.prose h6{font-weight:700;line-height:1.35;margin-top:1.75em;margin-bottom:.6em;color:#1a1610}@media(prefers-color-scheme:dark){.prose h1,.prose h2,.prose h3,.prose h4,.prose h5,.prose h6{color:#f5f0e5}}.prose h1{font-size:1.75rem;margin-top:0}.prose h2{font-size:1.35rem;padding-bottom:.35em;border-bottom:1px solid #DFD7C6}.prose h3{font-size:1.15rem}.prose h4{font-size:1rem;font-weight:600}@media(prefers-color-scheme:dark){.prose h2{border-bottom-color:#44403b}}.prose p{margin-top:.75em;margin-bottom:.75em}.prose ul{margin-top:.5em;margin-bottom:.5em;padding-left:1.6em;list-style-type:disc}.prose ol{margin-top:.5em;margin-bottom:.5em;padding-left:1.6em;list-style-type:decimal}.prose li{margin-top:.3em;margin-bottom:.3em}.prose li::marker{color:#8e8370}@media(prefers-color-scheme:dark){.prose li::marker{color:#6d676a}}.prose strong{font-weight:700;color:#1a1610}@media(prefers-color-scheme:dark){.prose strong{color:#f5f0e5}}.prose em{font-style:italic}.prose a{color:#b05a3c;text-decoration:underline;text-underline-offset:2px;text-decoration-color:#b05a3c66}.prose a:hover{text-decoration-color:#b05a3c}@media(prefers-color-scheme:dark){.prose a{color:#d6896e;text-decoration-color:#d6896e66}.prose a:hover{text-decoration-color:#d6896e}}.prose code{font-family:SF Mono,Fira Code,JetBrains Mono,Cascadia Code,Menlo,Consolas,monospace;font-size:.85em;padding:.2em .45em;border-radius:5px;background:#e8e0d0;color:#5c3d2e;font-weight:500}@media(prefers-color-scheme:dark){.prose code{background:#382f2a;color:#e0c4a8}}.prose pre{margin-top:1em;margin-bottom:1em;padding:1.1em 1.3em;border-radius:10px;overflow-x:auto;background:#2b2420;border:1px solid #3D3530;line-height:1.6}@media(prefers-color-scheme:dark){.prose pre{background:#1a1514;border-color:#332c28}}.prose pre code{padding:0;background:none;border-radius:0;font-size:.8125em;font-weight:400;color:#e8ded0}.prose pre code .hljs-keyword,.prose pre code .hljs-selector-tag,.prose pre code .hljs-built_in{color:#e8a87c}.prose pre code .hljs-string,.prose pre code .hljs-attr{color:#a8c9a0}.prose pre code .hljs-number,.prose pre code .hljs-literal{color:#d4a574}.prose pre code .hljs-type,.prose pre code .hljs-title,.prose pre code .hljs-class .hljs-title{color:#c4b4e0;font-weight:500}.prose pre code .hljs-function,.prose pre code .hljs-title.function_{color:#8cc8d0}.prose pre code .hljs-comment,.prose pre code .hljs-doctag{color:#7a7068;font-style:italic}.prose pre code .hljs-variable,.prose pre code .hljs-template-variable{color:#e0c4a8}.prose pre code .hljs-property{color:#d0b8a0}.prose pre code .hljs-meta,.prose pre code .hljs-preprocessor{color:#b0a090}.prose pre code .hljs-punctuation{color:#9a8e80}.prose pre code .hljs-addition{color:#a8c9a0;background:#a8c9a01a}.prose pre code .hljs-deletion{color:#d08080;background:#d080801a}.prose blockquote{border-left:3px solid #CD7357;padding-left:1em;margin-left:0;margin-top:.75em;margin-bottom:.75em;color:#504838}@media(prefers-color-scheme:dark){.prose blockquote{border-left-color:#d67f63;color:#b8aea0}}.prose table{width:100%;border-collapse:collapse;margin-top:1em;margin-bottom:1em;font-size:.875em}.prose th,.prose td{border:1px solid #DFD7C6;padding:.6em .85em;text-align:left}.prose th{font-weight:600;background:#ede5d5;color:#1a1610}@media(prefers-color-scheme:dark){.prose th,.prose td{border-color:#44403b}.prose th{background:#332c28;color:#f5f0e5}}.prose hr{border:none;border-top:1px solid #DFD7C6;margin:2em 0}@media(prefers-color-scheme:dark){.prose hr{border-top-color:#44403b}}mark.comment-highlight{background-color:#cd735724;border-bottom:2px solid rgba(205,115,87,.45);padding:1px 0;border-radius:2px;cursor:pointer;transition:background-color .2s ease,border-color .2s ease;color:inherit}mark.comment-highlight:hover,mark.comment-highlight.active{background-color:#cd73574d;border-bottom-color:#cd7357cc}mark.comment-highlight-pending{background-color:#cd73572e;border-bottom:2px solid rgba(205,115,87,.5);padding:1px 0;border-radius:2px;color:inherit}@media(prefers-color-scheme:dark){mark.comment-highlight{background-color:#d67f6324;border-bottom-color:#d67f6373}mark.comment-highlight:hover,mark.comment-highlight.active{background-color:#d67f634d;border-bottom-color:#d67f63cc}mark.comment-highlight-pending{background-color:#d67f632e;border-bottom-color:#d67f6380}}::-moz-selection{background:#cd735738;color:inherit}::selection{background:#cd735738;color:inherit}@media(prefers-color-scheme:dark){::-moz-selection{background:#d67f6347}::selection{background:#d67f6347}}.placeholder\:text-claude-text-tertiary-light::-moz-placeholder{--tw-text-opacity: 1;color:rgb(142 131 112 / var(--tw-text-opacity, 1))}.placeholder\:text-claude-text-tertiary-light::placeholder{--tw-text-opacity: 1;color:rgb(142 131 112 / var(--tw-text-opacity, 1))}.hover\:scale-110:hover{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-claude-border-light\/30:hover{background-color:#dfd7c64d}.hover\:bg-claude-border-light\/50:hover{background-color:#dfd7c680}.hover\:bg-red-50:hover{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.hover\:text-claude-accent-light:hover{--tw-text-opacity: 1;color:rgb(205 115 87 / var(--tw-text-opacity, 1))}.hover\:text-claude-text-primary-light:hover{--tw-text-opacity: 1;color:rgb(40 34 24 / var(--tw-text-opacity, 1))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.hover\:opacity-90:hover{opacity:.9}.focus\:border-claude-accent-light:focus{--tw-border-opacity: 1;border-color:rgb(205 115 87 / var(--tw-border-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:768px){.md\:p-xl{padding:40px}}@media(min-width:1280px){.xl\:block{display:block}.xl\:hidden{display:none}}@media(prefers-color-scheme:dark){.dark\:border-claude-accent-dark{--tw-border-opacity: 1;border-color:rgb(214 127 99 / var(--tw-border-opacity, 1))}.dark\:border-claude-border-dark{--tw-border-opacity: 1;border-color:rgb(68 64 59 / var(--tw-border-opacity, 1))}.dark\:bg-claude-accent-dark{--tw-bg-opacity: 1;background-color:rgb(214 127 99 / var(--tw-bg-opacity, 1))}.dark\:bg-claude-bg-dark{--tw-bg-opacity: 1;background-color:rgb(32 25 24 / var(--tw-bg-opacity, 1))}.dark\:bg-claude-success-dark{--tw-bg-opacity: 1;background-color:rgb(111 187 148 / var(--tw-bg-opacity, 1))}.dark\:bg-claude-surface-dark{--tw-bg-opacity: 1;background-color:rgb(42 39 35 / var(--tw-bg-opacity, 1))}.dark\:bg-claude-surface-dark\/80{background-color:#2a2723cc}.dark\:bg-claude-text-tertiary-dark{--tw-bg-opacity: 1;background-color:rgb(109 103 106 / var(--tw-bg-opacity, 1))}.dark\:text-claude-accent-dark{--tw-text-opacity: 1;color:rgb(214 127 99 / var(--tw-text-opacity, 1))}.dark\:text-claude-text-primary-dark{--tw-text-opacity: 1;color:rgb(237 231 220 / var(--tw-text-opacity, 1))}.dark\:text-claude-text-secondary-dark{--tw-text-opacity: 1;color:rgb(158 153 149 / var(--tw-text-opacity, 1))}.dark\:text-claude-text-tertiary-dark{--tw-text-opacity: 1;color:rgb(109 103 106 / var(--tw-text-opacity, 1))}.dark\:placeholder\:text-claude-text-tertiary-dark::-moz-placeholder{--tw-text-opacity: 1;color:rgb(109 103 106 / var(--tw-text-opacity, 1))}.dark\:placeholder\:text-claude-text-tertiary-dark::placeholder{--tw-text-opacity: 1;color:rgb(109 103 106 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-claude-border-dark\/30:hover{background-color:#44403b4d}.dark\:hover\:bg-claude-border-dark\/50:hover{background-color:#44403b80}.dark\:hover\:bg-red-900\/20:hover{background-color:#7f1d1d33}.dark\:hover\:text-claude-accent-dark:hover{--tw-text-opacity: 1;color:rgb(214 127 99 / var(--tw-text-opacity, 1))}.dark\:hover\:text-claude-text-primary-dark:hover{--tw-text-opacity: 1;color:rgb(237 231 220 / var(--tw-text-opacity, 1))}.dark\:focus\:border-claude-accent-dark:focus{--tw-border-opacity: 1;border-color:rgb(214 127 99 / var(--tw-border-opacity, 1))}}