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.
@@ -0,0 +1 @@
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}.static{position:static}.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))}}
@@ -7,8 +7,8 @@
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
10
- <script type="module" crossorigin src="/assets/index-B9Ku0w1F.js"></script>
11
- <link rel="stylesheet" crossorigin href="/assets/index-CFUAZEOC.css">
10
+ <script type="module" crossorigin src="/assets/index-BRrHI1zG.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-DjikHpVb.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
@@ -2,89 +2,136 @@
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import os from 'node:os';
5
+ import readline from 'node:readline';
5
6
  import { execSync } from 'node:child_process';
6
- const SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json');
7
- const HOOKS_DIR = path.join(os.homedir(), '.claude', 'hooks');
8
- // Resolve the hook script path
9
- // When compiled: dist/server/bin/ → dist/server/ → dist/ → pkg root → hooks/
10
- // When running via tsx: bin/ → pkg root → hooks/
11
- const hookSource = path.resolve(import.meta.dirname, '..', '..', '..', 'hooks', 'plan-viewer-hook.cjs');
12
- // Fallback for dev mode (running from bin/ directly)
13
- const hookSourceDev = path.resolve(import.meta.dirname, '..', 'hooks', 'plan-viewer-hook.cjs');
14
- const resolvedHookSource = fs.existsSync(hookSource) ? hookSource : hookSourceDev;
15
- function readSettings() {
7
+ // ─── Stable install location ───
8
+ const INSTALL_DIR = path.join(os.homedir(), '.cc-plan-viewer');
9
+ const INSTALLED_HOOK = path.join(INSTALL_DIR, 'plan-viewer-hook.cjs');
10
+ const INSTALLED_SERVER = path.join(INSTALL_DIR, 'server-bundle.mjs');
11
+ const INSTALLED_CLIENT = path.join(INSTALL_DIR, 'client');
12
+ // ─── Source paths (inside the npm package) ───
13
+ // When compiled: dist/server/bin/cc-plan-viewer.js
14
+ // Package root is 3 levels up: dist/server/bin → dist/server → dist → root
15
+ const PKG_ROOT_COMPILED = path.resolve(import.meta.dirname, '..', '..', '..');
16
+ // When running via tsx in dev: bin/ → root
17
+ const PKG_ROOT_DEV = path.resolve(import.meta.dirname, '..');
18
+ function getPkgRoot() {
19
+ // Check compiled path first (has dist/ dir)
20
+ if (fs.existsSync(path.join(PKG_ROOT_COMPILED, 'hooks', 'plan-viewer-hook.cjs'))) {
21
+ return PKG_ROOT_COMPILED;
22
+ }
23
+ return PKG_ROOT_DEV;
24
+ }
25
+ // ─── Settings file resolution ───
26
+ const DEFAULT_SETTINGS = path.join(os.homedir(), '.claude', 'settings.json');
27
+ function readSettings(settingsPath) {
16
28
  try {
17
- return JSON.parse(fs.readFileSync(SETTINGS_PATH, 'utf8'));
29
+ return JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
18
30
  }
19
31
  catch {
20
32
  return {};
21
33
  }
22
34
  }
23
- function writeSettings(settings) {
24
- fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n', 'utf8');
35
+ function writeSettings(settingsPath, settings) {
36
+ const dir = path.dirname(settingsPath);
37
+ if (!fs.existsSync(dir))
38
+ fs.mkdirSync(dir, { recursive: true });
39
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
25
40
  }
26
- function getHookCommand() {
27
- return `node "${resolvedHookSource}"`;
41
+ // ─── Multi-config detection ───
42
+ function findAllClaudeSettings() {
43
+ const home = os.homedir();
44
+ const found = new Set();
45
+ // Scan ~/.claude*/settings.json
46
+ try {
47
+ for (const name of fs.readdirSync(home)) {
48
+ if (!name.startsWith('.claude'))
49
+ continue;
50
+ const candidate = path.join(home, name, 'settings.json');
51
+ if (fs.existsSync(candidate))
52
+ found.add(candidate);
53
+ }
54
+ }
55
+ catch { }
56
+ // Include CLAUDE_CONFIG_DIR if set (may point outside ~/.claude*)
57
+ if (process.env.CLAUDE_CONFIG_DIR) {
58
+ const candidate = path.join(process.env.CLAUDE_CONFIG_DIR, 'settings.json');
59
+ if (fs.existsSync(candidate))
60
+ found.add(candidate);
61
+ }
62
+ return [...found].sort();
28
63
  }
29
- function install() {
30
- console.log('[cc-plan-viewer] Installing hook...');
31
- // Ensure hooks directory exists
32
- if (!fs.existsSync(HOOKS_DIR)) {
33
- fs.mkdirSync(HOOKS_DIR, { recursive: true });
64
+ function tildePath(p) {
65
+ return p.replace(os.homedir(), '~');
66
+ }
67
+ async function promptMultiSelect(options, question, activeConfigDir) {
68
+ // Non-interactive: fall back to CLAUDE_CONFIG_DIR or all
69
+ if (!process.stdin.isTTY) {
70
+ if (activeConfigDir) {
71
+ const match = options.findIndex(p => p.startsWith(activeConfigDir));
72
+ return match >= 0 ? [match] : [0];
73
+ }
74
+ return options.map((_, i) => i);
34
75
  }
35
- // Read current settings
36
- const settings = readSettings();
37
- // Ensure hooks object exists
76
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
77
+ console.log('');
78
+ console.log(`[cc-plan-viewer] Found ${options.length} Claude config directories:`);
79
+ options.forEach((opt, i) => {
80
+ const active = activeConfigDir && opt.startsWith(activeConfigDir) ? ' (active)' : '';
81
+ console.log(` ${i + 1}. ${tildePath(opt)}${active}`);
82
+ });
83
+ console.log('');
84
+ return new Promise((resolve) => {
85
+ rl.question(`${question} (comma-separated numbers, or "all"): `, (answer) => {
86
+ rl.close();
87
+ const trimmed = answer.trim().toLowerCase();
88
+ if (trimmed === 'all' || trimmed === '') {
89
+ resolve(options.map((_, i) => i));
90
+ return;
91
+ }
92
+ const indices = trimmed.split(',')
93
+ .map(s => parseInt(s.trim(), 10) - 1)
94
+ .filter(i => i >= 0 && i < options.length);
95
+ resolve(indices);
96
+ });
97
+ });
98
+ }
99
+ function addHookToSettings(settingsPath) {
100
+ const settings = readSettings(settingsPath);
38
101
  if (!settings.hooks || typeof settings.hooks !== 'object') {
39
102
  settings.hooks = {};
40
103
  }
41
104
  const hooks = settings.hooks;
42
- // Ensure PostToolUse array exists
43
105
  if (!Array.isArray(hooks.PostToolUse)) {
44
106
  hooks.PostToolUse = [];
45
107
  }
46
108
  const hookCommand = getHookCommand();
47
- // Check if already installed
48
- const alreadyInstalled = hooks.PostToolUse.some((entry) => {
109
+ // Remove any existing cc-plan-viewer hooks first (handles upgrades)
110
+ hooks.PostToolUse = hooks.PostToolUse.filter((entry) => {
49
111
  if (typeof entry !== 'object' || entry === null)
50
- return false;
112
+ return true;
51
113
  const e = entry;
52
114
  if (!Array.isArray(e.hooks))
53
- return false;
54
- return e.hooks.some((h) => {
115
+ return true;
116
+ return !e.hooks.some((h) => {
55
117
  if (typeof h !== 'object' || h === null)
56
118
  return false;
57
- return h.command === hookCommand;
119
+ const cmd = h.command;
120
+ return typeof cmd === 'string' && cmd.includes('plan-viewer-hook');
58
121
  });
59
122
  });
60
- if (alreadyInstalled) {
61
- console.log('[cc-plan-viewer] Hook already installed.');
62
- return;
63
- }
64
- // Add the hook entry
123
+ // Add fresh hook entry
65
124
  hooks.PostToolUse.push({
66
125
  matcher: 'Write|Edit',
67
- hooks: [
68
- {
69
- type: 'command',
70
- command: hookCommand,
71
- },
72
- ],
126
+ hooks: [{ type: 'command', command: hookCommand }],
73
127
  });
74
- writeSettings(settings);
75
- console.log('[cc-plan-viewer] Hook installed successfully.');
76
- console.log(`[cc-plan-viewer] Hook script: ${resolvedHookSource}`);
77
- console.log('[cc-plan-viewer] Added to: ~/.claude/settings.json (PostToolUse)');
128
+ writeSettings(settingsPath, settings);
78
129
  }
79
- function uninstall() {
80
- console.log('[cc-plan-viewer] Uninstalling hook...');
81
- const settings = readSettings();
130
+ function removeHookFromSettings(settingsPath) {
131
+ const settings = readSettings(settingsPath);
82
132
  const hooks = settings.hooks;
83
- if (!hooks?.PostToolUse || !Array.isArray(hooks.PostToolUse)) {
84
- console.log('[cc-plan-viewer] No hook found to remove.');
85
- return;
86
- }
87
- const hookCommand = getHookCommand();
133
+ if (!hooks?.PostToolUse || !Array.isArray(hooks.PostToolUse))
134
+ return false;
88
135
  const before = hooks.PostToolUse.length;
89
136
  hooks.PostToolUse = hooks.PostToolUse.filter((entry) => {
90
137
  if (typeof entry !== 'object' || entry === null)
@@ -99,16 +146,212 @@ function uninstall() {
99
146
  return typeof cmd === 'string' && cmd.includes('plan-viewer-hook');
100
147
  });
101
148
  });
102
- if (hooks.PostToolUse.length === before) {
103
- console.log('[cc-plan-viewer] No hook found to remove.');
149
+ if (hooks.PostToolUse.length < before) {
150
+ writeSettings(settingsPath, settings);
151
+ return true;
152
+ }
153
+ return false;
154
+ }
155
+ function settingsHasHook(settingsPath) {
156
+ const settings = readSettings(settingsPath);
157
+ const hooks = settings.hooks;
158
+ if (!hooks?.PostToolUse || !Array.isArray(hooks.PostToolUse))
159
+ return false;
160
+ return hooks.PostToolUse.some((entry) => {
161
+ if (typeof entry !== 'object' || entry === null)
162
+ return false;
163
+ const e = entry;
164
+ if (!Array.isArray(e.hooks))
165
+ return false;
166
+ return e.hooks.some((h) => {
167
+ if (typeof h !== 'object' || h === null)
168
+ return false;
169
+ const cmd = h.command;
170
+ return typeof cmd === 'string' && cmd.includes('plan-viewer-hook');
171
+ });
172
+ });
173
+ }
174
+ // ─── Copy files to stable location ───
175
+ function copyDir(src, dest) {
176
+ if (!fs.existsSync(src))
177
+ return;
178
+ if (fs.existsSync(dest))
179
+ fs.rmSync(dest, { recursive: true });
180
+ fs.mkdirSync(dest, { recursive: true });
181
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
182
+ const srcPath = path.join(src, entry.name);
183
+ const destPath = path.join(dest, entry.name);
184
+ if (entry.isDirectory()) {
185
+ copyDir(srcPath, destPath);
186
+ }
187
+ else {
188
+ fs.copyFileSync(srcPath, destPath);
189
+ }
190
+ }
191
+ }
192
+ function installFiles() {
193
+ const pkgRoot = getPkgRoot();
194
+ // Create install dir
195
+ if (!fs.existsSync(INSTALL_DIR)) {
196
+ fs.mkdirSync(INSTALL_DIR, { recursive: true });
197
+ }
198
+ // Copy hook
199
+ const hookSrc = path.join(pkgRoot, 'hooks', 'plan-viewer-hook.cjs');
200
+ if (fs.existsSync(hookSrc)) {
201
+ fs.copyFileSync(hookSrc, INSTALLED_HOOK);
202
+ }
203
+ // Copy bundled server (single file, all deps included)
204
+ const serverSrc = path.join(pkgRoot, 'dist', 'server-bundle.mjs');
205
+ if (fs.existsSync(serverSrc)) {
206
+ fs.copyFileSync(serverSrc, INSTALLED_SERVER);
207
+ }
208
+ // Copy client SPA
209
+ const clientSrc = path.join(pkgRoot, 'dist', 'client');
210
+ if (fs.existsSync(clientSrc)) {
211
+ copyDir(clientSrc, INSTALLED_CLIENT);
212
+ }
213
+ // Write version file
214
+ try {
215
+ const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, 'package.json'), 'utf8'));
216
+ fs.writeFileSync(path.join(INSTALL_DIR, 'version.json'), JSON.stringify({ version: pkg.version, installedAt: new Date().toISOString() }, null, 2), 'utf8');
217
+ }
218
+ catch { }
219
+ }
220
+ // ─── Hook management ───
221
+ function getHookCommand() {
222
+ return `node "${INSTALLED_HOOK}"`;
223
+ }
224
+ async function install() {
225
+ console.log('[cc-plan-viewer] Installing...');
226
+ console.log(`[cc-plan-viewer] Install dir: ${INSTALL_DIR}`);
227
+ // Copy files to stable location
228
+ installFiles();
229
+ console.log('[cc-plan-viewer] Files copied to ~/.cc-plan-viewer/');
230
+ patchHookPaths();
231
+ // Determine which settings files to update
232
+ const configIdx = process.argv.indexOf('--config');
233
+ if (configIdx !== -1 && process.argv[configIdx + 1]) {
234
+ // Explicit --config flag: use exactly that path
235
+ const settingsPath = path.resolve(process.argv[configIdx + 1]);
236
+ if (!fs.existsSync(path.dirname(settingsPath))) {
237
+ console.error(`[cc-plan-viewer] Directory does not exist: ${path.dirname(settingsPath)}`);
238
+ process.exit(1);
239
+ }
240
+ addHookToSettings(settingsPath);
241
+ console.log(`[cc-plan-viewer] Hook added to ${tildePath(settingsPath)}`);
242
+ }
243
+ else {
244
+ const allSettings = findAllClaudeSettings();
245
+ if (allSettings.length === 0) {
246
+ // No existing configs — create default
247
+ addHookToSettings(DEFAULT_SETTINGS);
248
+ console.log(`[cc-plan-viewer] Hook added to ${tildePath(DEFAULT_SETTINGS)}`);
249
+ }
250
+ else if (allSettings.length === 1) {
251
+ // Single config — use it directly
252
+ addHookToSettings(allSettings[0]);
253
+ console.log(`[cc-plan-viewer] Hook added to ${tildePath(allSettings[0])}`);
254
+ }
255
+ else {
256
+ // Multiple configs — prompt user
257
+ const selected = await promptMultiSelect(allSettings, 'Install hook in which configs?', process.env.CLAUDE_CONFIG_DIR);
258
+ if (selected.length === 0) {
259
+ console.log('[cc-plan-viewer] No configs selected. Hook not installed.');
260
+ return;
261
+ }
262
+ for (const idx of selected) {
263
+ addHookToSettings(allSettings[idx]);
264
+ console.log(`[cc-plan-viewer] Hook added to ${tildePath(allSettings[idx])}`);
265
+ }
266
+ }
267
+ }
268
+ console.log('');
269
+ console.log('[cc-plan-viewer] Hook installed successfully.');
270
+ console.log('');
271
+ console.log(' Next time Claude Code writes a plan, the viewer will open in your browser.');
272
+ console.log('');
273
+ console.log(' Update anytime: npx cc-plan-viewer@latest update');
274
+ console.log(' Uninstall: npx cc-plan-viewer uninstall');
275
+ }
276
+ function patchHookPaths() {
277
+ // The installed hook is at ~/.cc-plan-viewer/plan-viewer-hook.cjs
278
+ // The server bundle is at ~/.cc-plan-viewer/server-bundle.mjs
279
+ // We patch the hook to point to the bundled server
280
+ if (!fs.existsSync(INSTALLED_HOOK))
104
281
  return;
282
+ let hookContent = fs.readFileSync(INSTALLED_HOOK, 'utf8');
283
+ // Replace server path to point to the bundled server in the same dir
284
+ hookContent = hookContent.replace(/const serverPath = path\.join\(__dirname, [^;]+;/, `const serverPath = path.join(__dirname, 'server-bundle.mjs');`);
285
+ fs.writeFileSync(INSTALLED_HOOK, hookContent, 'utf8');
286
+ }
287
+ function update() {
288
+ console.log('[cc-plan-viewer] Updating...');
289
+ if (!fs.existsSync(INSTALL_DIR)) {
290
+ console.log('[cc-plan-viewer] Not installed. Run: npx cc-plan-viewer install');
291
+ return;
292
+ }
293
+ // Read old version
294
+ let oldVersion = 'unknown';
295
+ try {
296
+ const v = JSON.parse(fs.readFileSync(path.join(INSTALL_DIR, 'version.json'), 'utf8'));
297
+ oldVersion = v.version;
298
+ }
299
+ catch { }
300
+ // Copy new files
301
+ installFiles();
302
+ patchHookPaths();
303
+ // Read new version
304
+ let newVersion = 'unknown';
305
+ try {
306
+ const v = JSON.parse(fs.readFileSync(path.join(INSTALL_DIR, 'version.json'), 'utf8'));
307
+ newVersion = v.version;
308
+ }
309
+ catch { }
310
+ if (oldVersion === newVersion) {
311
+ console.log(`[cc-plan-viewer] Already on latest version (${newVersion}).`);
312
+ }
313
+ else {
314
+ console.log(`[cc-plan-viewer] Updated: ${oldVersion} → ${newVersion}`);
105
315
  }
106
- writeSettings(settings);
107
- console.log('[cc-plan-viewer] Hook removed successfully.');
316
+ console.log('[cc-plan-viewer] Files updated in ~/.cc-plan-viewer/');
317
+ }
318
+ async function uninstall() {
319
+ console.log('[cc-plan-viewer] Uninstalling...');
320
+ // Determine which settings files to clean up
321
+ const configIdx = process.argv.indexOf('--config');
322
+ if (configIdx !== -1 && process.argv[configIdx + 1]) {
323
+ const settingsPath = path.resolve(process.argv[configIdx + 1]);
324
+ if (removeHookFromSettings(settingsPath)) {
325
+ console.log(`[cc-plan-viewer] Hook removed from ${tildePath(settingsPath)}`);
326
+ }
327
+ }
328
+ else {
329
+ const allSettings = findAllClaudeSettings();
330
+ const withHook = allSettings.filter(settingsHasHook);
331
+ if (withHook.length === 0) {
332
+ console.log('[cc-plan-viewer] No hooks found in any Claude config.');
333
+ }
334
+ else if (withHook.length === 1) {
335
+ removeHookFromSettings(withHook[0]);
336
+ console.log(`[cc-plan-viewer] Hook removed from ${tildePath(withHook[0])}`);
337
+ }
338
+ else {
339
+ const selected = await promptMultiSelect(withHook, 'Remove hook from which configs?');
340
+ for (const idx of selected) {
341
+ removeHookFromSettings(withHook[idx]);
342
+ console.log(`[cc-plan-viewer] Hook removed from ${tildePath(withHook[idx])}`);
343
+ }
344
+ }
345
+ }
346
+ // Remove installed files
347
+ if (fs.existsSync(INSTALL_DIR)) {
348
+ fs.rmSync(INSTALL_DIR, { recursive: true });
349
+ console.log('[cc-plan-viewer] Removed ~/.cc-plan-viewer/');
350
+ }
351
+ console.log('[cc-plan-viewer] Uninstalled.');
108
352
  }
109
353
  function start() {
110
354
  console.log('[cc-plan-viewer] Starting server...');
111
- // Import and run the server
112
355
  import('../server/index.js');
113
356
  }
114
357
  function open(filename) {
@@ -124,14 +367,32 @@ function open(filename) {
124
367
  console.log(`[cc-plan-viewer] Open this URL in your browser: ${url}`);
125
368
  }
126
369
  }
127
- // CLI
370
+ function version() {
371
+ try {
372
+ const v = JSON.parse(fs.readFileSync(path.join(INSTALL_DIR, 'version.json'), 'utf8'));
373
+ console.log(`Installed: ${v.version} (${v.installedAt})`);
374
+ }
375
+ catch {
376
+ console.log('Not installed locally. Run: npx cc-plan-viewer install');
377
+ }
378
+ try {
379
+ const pkgRoot = getPkgRoot();
380
+ const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, 'package.json'), 'utf8'));
381
+ console.log(`Package: ${pkg.version}`);
382
+ }
383
+ catch { }
384
+ }
385
+ // ─── CLI ───
128
386
  const command = process.argv[2];
129
387
  switch (command) {
130
388
  case 'install':
131
- install();
389
+ await install();
390
+ break;
391
+ case 'update':
392
+ update();
132
393
  break;
133
394
  case 'uninstall':
134
- uninstall();
395
+ await uninstall();
135
396
  break;
136
397
  case 'start':
137
398
  start();
@@ -139,14 +400,23 @@ switch (command) {
139
400
  case 'open':
140
401
  open(process.argv[3]);
141
402
  break;
403
+ case 'version':
404
+ version();
405
+ break;
142
406
  default:
143
407
  console.log(`
144
408
  cc-plan-viewer — Browser-based review UI for Claude Code plans
145
409
 
146
- Commands:
147
- install Add the PostToolUse hook to ~/.claude/settings.json
148
- uninstall Remove the hook
149
- start Start the server (for development)
150
- open [file] Open a plan in the browser
410
+ Usage:
411
+ npx cc-plan-viewer install Install hook + viewer files
412
+ npx cc-plan-viewer install --config <path> Use specific settings.json path
413
+ npx cc-plan-viewer@latest update Update to latest version
414
+ npx cc-plan-viewer uninstall Remove hook + viewer files
415
+ npx cc-plan-viewer version Show installed version
416
+
417
+ When multiple Claude configs are detected (~/.claude*/settings.json),
418
+ you'll be prompted to choose which ones to install the hook in.
419
+
420
+ Files are installed to ~/.cc-plan-viewer/ so they persist across npm cache clears.
151
421
  `);
152
422
  }