forge-cw 0.1.3 → 0.1.5

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.
@@ -29,4 +29,4 @@
29
29
  * The original design remains. The terminal itself
30
30
  * has been extended to include xterm CSI codes, among
31
31
  * other features.
32
- */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root,[data-theme=dark]{--bg: #161618;--bg-2: #1f1f22;--card: #26262a;--card-2: #2e2e33;--elev: rgba(255,255,255,.04);--hair: rgba(255,255,255,.1);--hair-2: rgba(255,255,255,.16);--ink: #f5f5f7;--ink-2: #a1a1a8;--ink-3: #6e6e76;--blue: #0a84ff;--blue-2: #409cff;--green: #30d158;--orange: #ff9f0a;--red: #ff453a;--purple: #bf5af2;--teal: #40c8e0;--glass: rgba(28,28,30,.72);--shadow-s: 0 1px 2px rgba(0,0,0,.4);--shadow-m: 0 6px 20px rgba(0,0,0,.42);--shadow-l: 0 24px 60px rgba(0,0,0,.55);--term: #0e0e10;--sel: rgba(10,132,255,.18);--forge-harness-claude: #e08a68;--forge-harness-codex: #2fbf97;--forge-harness-pi: #6b9bff;--forge-harness-opencode: #e8b44a;--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, sans-serif;--mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;--ease: cubic-bezier(.32,.72,0,1);color-scheme:dark}[data-theme=light]{--bg: #f2f2f5;--bg-2: #f8f8fa;--card: #ffffff;--card-2: #ffffff;--elev: rgba(0,0,0,.02);--hair: rgba(0,0,0,.09);--hair-2: rgba(0,0,0,.16);--ink: #1d1d1f;--ink-2: #6e6e73;--ink-3: #8e8e93;--blue: #007aff;--blue-2: #0a6cff;--green: #28a745;--orange: #e08600;--red: #e0352b;--purple: #8944ab;--teal: #0d9bb5;--glass: rgba(248,248,250,.78);--shadow-s: 0 1px 2px rgba(0,0,0,.06);--shadow-m: 0 6px 18px rgba(0,0,0,.09);--shadow-l: 0 24px 60px rgba(0,0,0,.14);--term: #1c1c1e;--sel: rgba(0,122,255,.14);--forge-harness-claude: #c9633f;--forge-harness-codex: #0f8f6f;--forge-harness-pi: #2f6fe0;--forge-harness-opencode: #c98a12;color-scheme:light}*{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--font);font-size:13.5px;line-height:1.45;letter-spacing:-.003em;background:var(--bg);color:var(--ink);-webkit-font-smoothing:antialiased}input,textarea,select,button{font-family:inherit;letter-spacing:inherit}input::placeholder,textarea::placeholder{color:var(--ink-3)}a{color:var(--blue);text-decoration:none}a:hover{color:var(--blue-2)}::selection{background:var(--sel)}.mono,code,pre,kbd{font-family:var(--mono);font-variant-numeric:tabular-nums}select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}:focus-visible{outline:3px solid color-mix(in srgb,var(--blue) 55%,transparent);outline-offset:2px;border-radius:8px}input:focus-visible,textarea:focus-visible,select:focus-visible{outline:none}.field{width:100%;height:38px;padding:0 12px;border-radius:11px;border:1px solid var(--hair);background-color:var(--card);color:var(--ink);font-size:13.5px;outline:none;transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}textarea.field{height:auto;padding:10px 12px;resize:none;line-height:1.45}select.field{padding-right:28px}.field:focus,.field:focus-within{border-color:var(--blue)!important;box-shadow:0 0 0 4px var(--sel)!important}@keyframes riseIn{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}@keyframes slideIn{0%{transform:translate(24px);opacity:0}to{transform:none;opacity:1}}@keyframes popIn{0%{transform:scale(.96);opacity:0}to{transform:none;opacity:1}}@keyframes breathe{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.82)}}@keyframes sweep{0%{transform:translate(-100%)}to{transform:translate(320%)}}.sb-toggle,.sb-scrim{display:none}@media(max-width:900px){.forge-shell{grid-template-columns:56px minmax(0,1fr)!important}.forge-sidebar{padding:14px 8px 12px!important;align-items:stretch}.forge-sidebar .sb-label,.forge-sidebar .sb-section{display:none!important}.forge-sidebar nav button,.forge-sidebar>[role=button],.forge-sidebar>button{justify-content:center;padding:0!important}.forge-sidebar>button{height:32px}.task-row .harness-pill{display:none}}@media(max-width:700px){.forge-shell{grid-template-columns:minmax(0,1fr)!important}.forge-sidebar{position:fixed!important;z-index:65;left:0;width:min(272px,86vw);padding:14px 10px 12px!important;box-shadow:var(--shadow-l);transform:translate(-105%);transition:transform .3s var(--ease)}.forge-sidebar.open{transform:none}.forge-sidebar .sb-label,.forge-sidebar .sb-section{display:revert!important}.forge-sidebar .sb-section{display:flex!important}.forge-sidebar nav button,.forge-sidebar>[role=button],.forge-sidebar>button{justify-content:flex-start;padding:0 9px!important}.forge-sidebar>button{padding:6px 9px!important;height:auto}.sb-scrim.open{display:block;position:fixed;top:0;right:0;bottom:0;left:0;z-index:64;background:#00000061;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}.sb-toggle{display:grid}.task-row .task-meta,.task-row .task-chip,.task-row .task-done{display:none}.task-row{gap:10px!important}.skills-page{grid-template-columns:minmax(0,1fr)!important;grid-template-rows:auto minmax(0,1fr);height:auto!important;min-height:100vh}.skills-rail{max-height:42vh;border-right:0!important;border-bottom:1px solid var(--hair)}.task-terminal{margin:0 12px 12px!important}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }.i-lucide-check{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-chevron-down{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9l6 6l6-6'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-chevron-right{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m9 18l6-6l-6-6'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-chevrons-up-down{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m7 15l5 5l5-5M7 9l5-5l5 5'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-clock{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 6v6l4 2'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-copy{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-external-link{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 3h6v6m-11 5L21 3m-3 10v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-folder{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-frame{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M22 6H2m20 12H2M6 2v20M18 2v20'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-loader-2{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12a9 9 0 1 1-6.219-8.56'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-menu{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 5h16M4 12h16M4 19h16'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-package{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73zm1 .27V12'/%3E%3Cpath d='M3.29 7L12 12l8.71-5M7.5 4.27l9 5.15'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-plus{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 12h14m-7-7v14'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-search{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='m21 21l-4.34-4.34'/%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-x{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M18 6L6 18M6 6l12 12'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.right-0{right:0}.right-4{right:1rem}.top-0{top:0}.top-full{top:100%}.z-\[55\]{z-index:55}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.z-1{z-index:1}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.grid{display:grid}.mx-auto{margin-left:auto;margin-right:auto}.my{margin-top:1rem;margin-bottom:1rem}.me{margin-inline-end:1rem}.ml-3{margin-left:.75rem}.ms{margin-inline-start:1rem}.block{display:block}.contents{display:contents}.hidden{display:none}.h-0\.5{height:.125rem}.h-16{height:4rem}.h-full{height:100%}.max-w-full{max-width:100%}.min-h-0{min-height:0}.min-w-0{min-width:0}.w-1{width:.25rem}.w-full{width:100%}.flex{display:flex}.inline-flex{display:inline-flex}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.hover\:-translate-y-px:hover{--un-translate-y:-1px;transform:translate(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotate(var(--un-rotate-z)) skew(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}.transform{transform:translate(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotate(var(--un-rotate-z)) skew(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.disabled\:cursor-wait:disabled{cursor:wait}.cursor-not-allowed{cursor:not-allowed}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.cursor-col-resize{cursor:col-resize}.resize{resize:both}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-center{align-items:center}.self-start{align-self:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.space-y-1>:not([hidden])~:not([hidden]){--un-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--un-space-y-reverse)));margin-bottom:calc(.25rem * var(--un-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--un-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--un-space-y-reverse)));margin-bottom:calc(.5rem * var(--un-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--un-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--un-space-y-reverse)));margin-bottom:calc(1rem * var(--un-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.b,.border{border-width:1px}.hover\:border-hair2:hover{border-color:var(--hair-2)}.hover\:bg-blue:hover{background-color:var(--blue)}.hover\:bg-elev:hover{background-color:var(--elev)}.px{padding-left:1rem;padding-right:1rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pt-1{padding-top:.25rem}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.indent{text-indent:1.5rem}.text-ink2{color:var(--ink-2)}.text-ink3{color:var(--ink-3)}.hover\:text-green:hover{color:var(--green)}.hover\:text-ink:hover{color:var(--ink)}.hover\:text-red:hover{color:var(--red)}.uppercase{text-transform:uppercase}.hover\:underline:hover{text-decoration-line:underline}.tab{-moz-tab-size:4;-o-tab-size:4;tab-size:4}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.group:hover .group-hover\:opacity-100{opacity:1}.focus-visible\:opacity-100:focus-visible{opacity:1}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-60:disabled{opacity:.6}.outline{outline-style:solid}.hover\:brightness-106:hover{--un-brightness:brightness(1.06);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia)}.filter{filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia)}.backdrop-filter{-webkit-backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia);backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.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-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-140{transition-duration:.14s}.duration-160{transition-duration:.16s}.duration-180{transition-duration:.18s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:shadow-m:hover{box-shadow:var(--shadow-m)}.ease-spring{transition-timing-function:var(--ease)}.glass{background:var(--glass);backdrop-filter:blur(22px) saturate(180%);-webkit-backdrop-filter:blur(22px) saturate(180%)}.popover{background:var(--glass);backdrop-filter:blur(30px) saturate(180%);-webkit-backdrop-filter:blur(30px) saturate(180%);border:1px solid var(--hair-2);box-shadow:var(--shadow-l);animation:popIn .2s var(--ease) both}.breathe{animation:breathe 2.4s ease-in-out infinite}
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root,[data-theme=dark]{--bg: #161618;--bg-2: #1f1f22;--card: #26262a;--card-2: #2e2e33;--elev: rgba(255,255,255,.04);--hair: rgba(255,255,255,.1);--hair-2: rgba(255,255,255,.16);--ink: #f5f5f7;--ink-2: #a1a1a8;--ink-3: #6e6e76;--blue: #0a84ff;--blue-2: #409cff;--green: #30d158;--orange: #ff9f0a;--red: #ff453a;--purple: #bf5af2;--teal: #40c8e0;--glass: rgba(28,28,30,.72);--shadow-s: 0 1px 2px rgba(0,0,0,.4);--shadow-m: 0 6px 20px rgba(0,0,0,.42);--shadow-l: 0 24px 60px rgba(0,0,0,.55);--term: #0e0e10;--sel: rgba(10,132,255,.18);--forge-harness-claude: #e08a68;--forge-harness-codex: #2fbf97;--forge-harness-pi: #6b9bff;--forge-harness-opencode: #e8b44a;--font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, sans-serif;--mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;--ease: cubic-bezier(.32,.72,0,1);color-scheme:dark}[data-theme=light]{--bg: #f2f2f5;--bg-2: #f8f8fa;--card: #ffffff;--card-2: #ffffff;--elev: rgba(0,0,0,.02);--hair: rgba(0,0,0,.09);--hair-2: rgba(0,0,0,.16);--ink: #1d1d1f;--ink-2: #6e6e73;--ink-3: #8e8e93;--blue: #007aff;--blue-2: #0a6cff;--green: #28a745;--orange: #e08600;--red: #e0352b;--purple: #8944ab;--teal: #0d9bb5;--glass: rgba(248,248,250,.78);--shadow-s: 0 1px 2px rgba(0,0,0,.06);--shadow-m: 0 6px 18px rgba(0,0,0,.09);--shadow-l: 0 24px 60px rgba(0,0,0,.14);--term: #1c1c1e;--sel: rgba(0,122,255,.14);--forge-harness-claude: #c9633f;--forge-harness-codex: #0f8f6f;--forge-harness-pi: #2f6fe0;--forge-harness-opencode: #c98a12;color-scheme:light}*{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--font);font-size:13.5px;line-height:1.45;letter-spacing:-.003em;background:var(--bg);color:var(--ink);-webkit-font-smoothing:antialiased}input,textarea,select,button{font-family:inherit;letter-spacing:inherit}input::placeholder,textarea::placeholder{color:var(--ink-3)}a{color:var(--blue);text-decoration:none}a:hover{color:var(--blue-2)}::selection{background:var(--sel)}.mono,code,pre,kbd{font-family:var(--mono);font-variant-numeric:tabular-nums}select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}:focus-visible{outline:3px solid color-mix(in srgb,var(--blue) 55%,transparent);outline-offset:2px;border-radius:8px}input:focus-visible,textarea:focus-visible,select:focus-visible{outline:none}.field{width:100%;height:38px;padding:0 12px;border-radius:11px;border:1px solid var(--hair);background-color:var(--card);color:var(--ink);font-size:13.5px;outline:none;transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}textarea.field{height:auto;padding:10px 12px;resize:none;line-height:1.45}select.field{padding-right:28px}.field:focus,.field:focus-within{border-color:var(--blue)!important;box-shadow:0 0 0 4px var(--sel)!important}@keyframes riseIn{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}@keyframes slideIn{0%{transform:translate(24px);opacity:0}to{transform:none;opacity:1}}@keyframes popIn{0%{transform:scale(.96);opacity:0}to{transform:none;opacity:1}}@keyframes breathe{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.82)}}@keyframes sweep{0%{transform:translate(-100%)}to{transform:translate(320%)}}.sb-toggle,.sb-scrim{display:none}@media(max-width:900px){.forge-shell{grid-template-columns:56px minmax(0,1fr)!important}.forge-sidebar{padding:14px 8px 12px!important;align-items:stretch}.forge-sidebar .sb-label,.forge-sidebar .sb-section{display:none!important}.forge-sidebar nav button,.forge-sidebar>[role=button],.forge-sidebar>button{justify-content:center;padding:0!important}.forge-sidebar>button{height:32px}.task-row .harness-pill{display:none}}@media(max-width:700px){.forge-shell{grid-template-columns:minmax(0,1fr)!important}.forge-sidebar{position:fixed!important;z-index:65;left:0;width:min(272px,86vw);padding:14px 10px 12px!important;box-shadow:var(--shadow-l);transform:translate(-105%);transition:transform .3s var(--ease)}.forge-sidebar.open{transform:none}.forge-sidebar .sb-label,.forge-sidebar .sb-section{display:revert!important}.forge-sidebar .sb-section{display:flex!important}.forge-sidebar nav button,.forge-sidebar>[role=button],.forge-sidebar>button{justify-content:flex-start;padding:0 9px!important}.forge-sidebar>button{padding:6px 9px!important;height:auto}.sb-scrim.open{display:block;position:fixed;top:0;right:0;bottom:0;left:0;z-index:64;background:#00000061;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}.sb-toggle{display:grid}.task-row .task-meta,.task-row .task-chip,.task-row .task-done{display:none}.task-row{gap:10px!important}.skills-page{grid-template-columns:minmax(0,1fr)!important;grid-template-rows:auto minmax(0,1fr);height:auto!important;min-height:100vh}.skills-rail{max-height:42vh;border-right:0!important;border-bottom:1px solid var(--hair)}.task-terminal{margin:0 12px 12px!important}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }.i-lucide-check{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-chevron-down{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9l6 6l6-6'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-chevron-right{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m9 18l6-6l-6-6'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-chevrons-up-down{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m7 15l5 5l5-5M7 9l5-5l5 5'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-clock{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 6v6l4 2'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-copy{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-external-link{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 3h6v6m-11 5L21 3m-3 10v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-folder{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-frame{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M22 6H2m20 12H2M6 2v20M18 2v20'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-loader-2{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12a9 9 0 1 1-6.219-8.56'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-menu{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 5h16M4 12h16M4 19h16'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-package{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73zm1 .27V12'/%3E%3Cpath d='M3.29 7L12 12l8.71-5M7.5 4.27l9 5.15'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-plus{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 12h14m-7-7v14'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-search{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='m21 21l-4.34-4.34'/%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.i-lucide-x{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' width='1.2em' height='1.2em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M18 6L6 18M6 6l12 12'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;width:1.2em;height:1.2em}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.right-0{right:0}.right-4{right:1rem}.top-0{top:0}.top-full{top:100%}.z-\[55\]{z-index:55}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.z-1{z-index:1}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.grid{display:grid}.mx-auto{margin-left:auto;margin-right:auto}.my{margin-top:1rem;margin-bottom:1rem}.me{margin-inline-end:1rem}.ml-3{margin-left:.75rem}.ms{margin-inline-start:1rem}.block{display:block}.contents{display:contents}.hidden{display:none}.h-0\.5{height:.125rem}.h-16{height:4rem}.h-full{height:100%}.max-w-full{max-width:100%}.min-h-0{min-height:0}.min-w-0{min-width:0}.w-1{width:.25rem}.w-full{width:100%}.flex{display:flex}.inline-flex{display:inline-flex}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.hover\:-translate-y-px:hover{--un-translate-y:-1px;transform:translate(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotate(var(--un-rotate-z)) skew(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}.transform{transform:translate(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotate(var(--un-rotate-z)) skew(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z))}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.disabled\:cursor-wait:disabled{cursor:wait}.cursor-copy{cursor:copy}.cursor-not-allowed{cursor:not-allowed}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.cursor-col-resize{cursor:col-resize}.resize{resize:both}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-center{align-items:center}.self-start{align-self:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.space-y-1>:not([hidden])~:not([hidden]){--un-space-y-reverse:0;margin-top:calc(.25rem * calc(1 - var(--un-space-y-reverse)));margin-bottom:calc(.25rem * var(--un-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--un-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--un-space-y-reverse)));margin-bottom:calc(.5rem * var(--un-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--un-space-y-reverse:0;margin-top:calc(1rem * calc(1 - var(--un-space-y-reverse)));margin-bottom:calc(1rem * var(--un-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.b,.border{border-width:1px}.hover\:border-hair2:hover{border-color:var(--hair-2)}.hover\:bg-blue:hover{background-color:var(--blue)}.hover\:bg-elev:hover{background-color:var(--elev)}.px{padding-left:1rem;padding-right:1rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pt-1{padding-top:.25rem}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.indent{text-indent:1.5rem}.text-ink2{color:var(--ink-2)}.text-ink3{color:var(--ink-3)}.hover\:text-green:hover{color:var(--green)}.hover\:text-ink:hover{color:var(--ink)}.hover\:text-red:hover{color:var(--red)}.uppercase{text-transform:uppercase}.hover\:underline:hover{text-decoration-line:underline}.tab{-moz-tab-size:4;-o-tab-size:4;tab-size:4}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.group:hover .group-hover\:opacity-100{opacity:1}.focus-visible\:opacity-100:focus-visible{opacity:1}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-60:disabled{opacity:.6}.outline{outline-style:solid}.hover\:brightness-106:hover{--un-brightness:brightness(1.06);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia)}.filter{filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia)}.backdrop-filter{-webkit-backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia);backdrop-filter:var(--un-backdrop-blur) var(--un-backdrop-brightness) var(--un-backdrop-contrast) var(--un-backdrop-grayscale) var(--un-backdrop-hue-rotate) var(--un-backdrop-invert) var(--un-backdrop-opacity) var(--un-backdrop-saturate) var(--un-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.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-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-140{transition-duration:.14s}.duration-160{transition-duration:.16s}.duration-180{transition-duration:.18s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:shadow-m:hover{box-shadow:var(--shadow-m)}.ease-spring{transition-timing-function:var(--ease)}.glass{background:var(--glass);backdrop-filter:blur(22px) saturate(180%);-webkit-backdrop-filter:blur(22px) saturate(180%)}.popover{background:var(--glass);backdrop-filter:blur(30px) saturate(180%);-webkit-backdrop-filter:blur(30px) saturate(180%);border:1px solid var(--hair-2);box-shadow:var(--shadow-l);animation:popIn .2s var(--ease) both}.breathe{animation:breathe 2.4s ease-in-out infinite}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Forge Console</title>
7
- <script type="module" crossorigin src="/assets/index-BLBzdbIU.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-Digctq9W.css">
7
+ <script type="module" crossorigin src="/assets/index-CER8DSNM.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-D_58OQhA.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="app"></div>
package/dist/index.js CHANGED
@@ -2441,14 +2441,17 @@ function manifestRepo(manifest) {
2441
2441
  return repo["url"];
2442
2442
  return void 0;
2443
2443
  }
2444
- function marketplaceRepo(marketplaces, marketplace) {
2445
- const entry = marketplaces[marketplace];
2444
+ function marketplaceSource(entry) {
2446
2445
  const source = isRecord(entry) ? entry["source"] : void 0;
2447
2446
  if (!isRecord(source))
2448
2447
  return void 0;
2449
- const value = source["repo"] ?? source["url"];
2448
+ const value = source["repo"] ?? source["url"] ?? source["path"];
2450
2449
  return typeof value === "string" ? value : void 0;
2451
2450
  }
2451
+ function splitPluginId(id) {
2452
+ const at = id.lastIndexOf("@");
2453
+ return { name: id.slice(0, at), marketplace: id.slice(at + 1) };
2454
+ }
2452
2455
  function projectSkillNames(projectPath) {
2453
2456
  const dir = join8(projectPath, ".claude", "skills");
2454
2457
  if (!existsSync6(dir))
@@ -2456,17 +2459,13 @@ function projectSkillNames(projectPath) {
2456
2459
  return readdirSync4(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync6(join8(dir, e.name, "SKILL.md"))).map((e) => e.name).sort();
2457
2460
  }
2458
2461
  async function listPlugins(reader, remoteOf) {
2459
- const scopes = [
2460
- { scope: "global", scopeRef: "global" },
2461
- ...reader.getAccounts().map((a) => ({ scope: "account", scopeRef: a }))
2462
- ];
2463
2462
  const found = /* @__PURE__ */ new Map();
2464
- for (const { scope, scopeRef } of scopes) {
2463
+ for (const { scope, scopeRef } of pluginScopes(reader)) {
2465
2464
  const configDir = reader.getSkillConfigDir(scope, scopeRef);
2466
2465
  const installed = readJson(join8(configDir, "plugins", "installed_plugins.json"))["plugins"];
2467
2466
  if (!isRecord(installed))
2468
2467
  continue;
2469
- const marketplaces = readJson(join8(configDir, "plugins", "known_marketplaces.json"));
2468
+ const marketplaces = knownMarketplaces(configDir);
2470
2469
  const enabledPlugins = readJson(join8(configDir, "settings.json"))["enabledPlugins"];
2471
2470
  for (const [id, entries] of Object.entries(installed)) {
2472
2471
  if (!Array.isArray(entries))
@@ -2474,7 +2473,6 @@ async function listPlugins(reader, remoteOf) {
2474
2473
  const user = entries.find((e) => isRecord(e) && e["scope"] === "user" && typeof e["installPath"] === "string");
2475
2474
  if (!user)
2476
2475
  continue;
2477
- const marketplace = id.slice(id.lastIndexOf("@") + 1);
2478
2476
  const install = {
2479
2477
  scope,
2480
2478
  scopeRef,
@@ -2484,7 +2482,7 @@ async function listPlugins(reader, remoteOf) {
2484
2482
  lastUpdated: typeof user["lastUpdated"] === "string" ? user["lastUpdated"] : void 0
2485
2483
  };
2486
2484
  const list = found.get(id) ?? [];
2487
- list.push({ install, repo: marketplaceRepo(marketplaces, marketplace) });
2485
+ list.push({ install, repo: marketplaceSource(marketplaces[splitPluginId(id).marketplace]) });
2488
2486
  found.set(id, list);
2489
2487
  }
2490
2488
  }
@@ -2498,8 +2496,7 @@ async function listPlugins(reader, remoteOf) {
2498
2496
  const match = repo ? remotes.find((r) => r.repo === repo) : void 0;
2499
2497
  plugins.push({
2500
2498
  id,
2501
- name: id.slice(0, id.lastIndexOf("@")),
2502
- marketplace: id.slice(id.lastIndexOf("@") + 1),
2499
+ ...splitPluginId(id),
2503
2500
  description: String(manifest["description"] ?? ""),
2504
2501
  repo,
2505
2502
  installs: list.map((f) => f.install),
@@ -2521,7 +2518,41 @@ function readPluginSkill(plugin, name) {
2521
2518
  return null;
2522
2519
  }
2523
2520
  }
2524
- var isRecord, inside;
2521
+ function readCatalog(location, marketplace) {
2522
+ const listed = readJson(join8(location, ".claude-plugin", "marketplace.json"))["plugins"];
2523
+ return (Array.isArray(listed) ? listed : []).filter((p) => isRecord(p) && typeof p["name"] === "string").map((p) => ({
2524
+ id: `${String(p["name"])}@${marketplace}`,
2525
+ name: String(p["name"]),
2526
+ description: String(p["description"] ?? ""),
2527
+ category: typeof p["category"] === "string" ? p["category"] : void 0
2528
+ })).sort((a, b) => a.name.localeCompare(b.name));
2529
+ }
2530
+ function listMarketplaces(reader) {
2531
+ const byName = /* @__PURE__ */ new Map();
2532
+ for (const target of pluginScopes(reader)) {
2533
+ for (const [name, entry] of Object.entries(knownMarketplaces(reader.getSkillConfigDir(target.scope, target.scopeRef)))) {
2534
+ const source = marketplaceSource(entry);
2535
+ if (!source)
2536
+ continue;
2537
+ const known = byName.get(name) ?? { name, source, scopes: [], plugins: [] };
2538
+ known.scopes.push(target);
2539
+ const location = isRecord(entry) ? entry["installLocation"] : void 0;
2540
+ if (known.plugins.length === 0 && typeof location === "string")
2541
+ known.plugins = readCatalog(location, name);
2542
+ byName.set(name, known);
2543
+ }
2544
+ }
2545
+ return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
2546
+ }
2547
+ function marketplaceSourceOf(reader, marketplace) {
2548
+ for (const { scope, scopeRef } of pluginScopes(reader)) {
2549
+ const source = marketplaceSource(knownMarketplaces(reader.getSkillConfigDir(scope, scopeRef))[marketplace]);
2550
+ if (source)
2551
+ return source;
2552
+ }
2553
+ return void 0;
2554
+ }
2555
+ var isRecord, inside, pluginScopes, knownMarketplaces, knowsMarketplace;
2525
2556
  var init_plugins = __esm({
2526
2557
  "../core/dist/plugins.js"() {
2527
2558
  "use strict";
@@ -2531,6 +2562,12 @@ var init_plugins = __esm({
2531
2562
  const p = resolve2(path);
2532
2563
  return p === r || p.startsWith(r + sep);
2533
2564
  };
2565
+ pluginScopes = (reader) => [
2566
+ { scope: "global", scopeRef: "global" },
2567
+ ...reader.getAccounts().map((a) => ({ scope: "account", scopeRef: a }))
2568
+ ];
2569
+ knownMarketplaces = (configDir) => readJson(join8(configDir, "plugins", "known_marketplaces.json"));
2570
+ knowsMarketplace = (configDir, marketplace) => isRecord(knownMarketplaces(configDir)[marketplace]);
2534
2571
  }
2535
2572
  });
2536
2573
 
@@ -2559,7 +2596,26 @@ function skillRoutes(reader, options = {}) {
2559
2596
  const runnerFor = options.runnerFor ?? ((env) => createRunner(env, INSTALL_TIMEOUT_MS));
2560
2597
  const remoteOf = options.remoteOf ?? createRemoteLookup(runCommand);
2561
2598
  const app = new Hono2();
2562
- const updating = /* @__PURE__ */ new Set();
2599
+ const busy = /* @__PURE__ */ new Set();
2600
+ const runClaude = async (scope, ref, commands, failure) => {
2601
+ const configDir = reader.getSkillConfigDir(scope, ref);
2602
+ if (busy.has(configDir))
2603
+ return { error: `A plugin command is already running for ${ref}`, status: 409 };
2604
+ busy.add(configDir);
2605
+ try {
2606
+ const { CLAUDE_CONFIG_DIR: _ignored, ...base } = envWithoutHarness();
2607
+ const run = runnerFor(scope === "global" ? base : { ...base, CLAUDE_CONFIG_DIR: configDir });
2608
+ for (const args of commands) {
2609
+ const result2 = await run("claude", args, configDir);
2610
+ if (result2.code !== 0)
2611
+ return { error: `${failure}: ${commandFailure(result2)}`, status: 500 };
2612
+ }
2613
+ return null;
2614
+ } finally {
2615
+ busy.delete(configDir);
2616
+ }
2617
+ };
2618
+ const knownAccount = (account) => account && reader.getAccounts().includes(account) ? account : null;
2563
2619
  const refOf = (scope, scopeRef) => scope === "global" ? "global" : scopeRef ?? "";
2564
2620
  const knownScope = (scope, ref) => scope === "global" || (scope === "account" ? reader.getAccounts().includes(ref) : scope === "project" && ref in reader.getProjects());
2565
2621
  app.get("/", (c) => c.json(reader.getSkills()));
@@ -2763,27 +2819,50 @@ function skillRoutes(reader, options = {}) {
2763
2819
  const install = plugin?.installs.find((i) => i.scope === scope && i.scopeRef === ref);
2764
2820
  if (!plugin || !install)
2765
2821
  return c.json({ error: `${id} is not installed in ${ref || "that scope"}` }, 404);
2766
- const configDir = reader.getSkillConfigDir(install.scope, install.scopeRef);
2767
- if (updating.has(configDir))
2768
- return c.json({ error: `An update is already running for ${ref}` }, 409);
2769
- updating.add(configDir);
2770
- try {
2771
- const { CLAUDE_CONFIG_DIR: _ignored, ...base } = envWithoutHarness();
2772
- const run = runnerFor(install.scope === "global" ? base : { ...base, CLAUDE_CONFIG_DIR: configDir });
2773
- for (const args of [["plugin", "marketplace", "update", plugin.marketplace], ["plugin", "update", plugin.id]]) {
2774
- const result2 = await run("claude", args, configDir);
2775
- if (result2.code !== 0)
2776
- return c.json({ error: `Failed to update ${plugin.name}: ${commandFailure(result2)}` }, 500);
2777
- }
2778
- } finally {
2779
- updating.delete(configDir);
2780
- }
2822
+ const failed = await runClaude(install.scope, ref, [["plugin", "marketplace", "update", plugin.marketplace], ["plugin", "update", plugin.id]], `Failed to update ${plugin.name}`);
2823
+ if (failed)
2824
+ return c.json({ error: failed.error }, failed.status);
2781
2825
  const version = (await find())?.installs.find((i) => i.scope === install.scope && i.scopeRef === ref)?.version ?? install.version;
2782
2826
  return c.json({ ok: true, version });
2783
2827
  });
2828
+ app.get("/marketplaces", (c) => c.json(listMarketplaces(reader)));
2829
+ app.post("/marketplaces", async (c) => {
2830
+ const body = await c.req.json().catch(() => ({}));
2831
+ const source = body.source?.trim() ?? "";
2832
+ if (!source || source.startsWith("-"))
2833
+ return c.json({ error: "A GitHub repo, URL or path is required" }, 400);
2834
+ const account = knownAccount(body.account);
2835
+ if (!account)
2836
+ return c.json({ error: "Unknown account" }, 404);
2837
+ const failed = await runClaude("account", account, [["plugin", "marketplace", "add", source]], `Failed to add ${source}`);
2838
+ if (failed)
2839
+ return c.json({ error: failed.error }, failed.status);
2840
+ return c.json({ ok: true });
2841
+ });
2842
+ app.post("/plugins/install", async (c) => {
2843
+ const body = await c.req.json().catch(() => ({}));
2844
+ const id = body.id ?? "";
2845
+ if (!PLUGIN_ID_RE.test(id))
2846
+ return c.json({ error: "Invalid plugin id" }, 400);
2847
+ const account = knownAccount(body.account);
2848
+ if (!account)
2849
+ return c.json({ error: "Unknown account" }, 404);
2850
+ const { name, marketplace } = splitPluginId(id);
2851
+ const commands = [["plugin", "install", id]];
2852
+ if (!knowsMarketplace(reader.getSkillConfigDir("account", account), marketplace)) {
2853
+ const source = marketplaceSourceOf(reader, marketplace);
2854
+ if (!source)
2855
+ return c.json({ error: `Unknown marketplace ${marketplace}` }, 404);
2856
+ commands.unshift(["plugin", "marketplace", "add", source]);
2857
+ }
2858
+ const failed = await runClaude("account", account, commands, `Failed to install ${name}`);
2859
+ if (failed)
2860
+ return c.json({ error: failed.error }, failed.status);
2861
+ return c.json({ ok: true });
2862
+ });
2784
2863
  return app;
2785
2864
  }
2786
- var INSTALL_TIMEOUT_MS, SKILL_NAME_RE;
2865
+ var INSTALL_TIMEOUT_MS, SKILL_NAME_RE, PLUGIN_ID_RE;
2787
2866
  var init_skill_routes = __esm({
2788
2867
  "../core/dist/skill-routes.js"() {
2789
2868
  "use strict";
@@ -2792,6 +2871,7 @@ var init_skill_routes = __esm({
2792
2871
  init_plugins();
2793
2872
  INSTALL_TIMEOUT_MS = 12e4;
2794
2873
  SKILL_NAME_RE = /^\w[\w.-]*$/;
2874
+ PLUGIN_ID_RE = /^\w[\w.-]*@\w[\w.-]*$/;
2795
2875
  }
2796
2876
  });
2797
2877
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-cw",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "A visual dashboard for your coding agents on Claude Code, Codex, Pi or OpenCode. Installs CW for you.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,8 +39,8 @@
39
39
  "@types/node": "^22.0.0",
40
40
  "esbuild": "^0.25.0",
41
41
  "typescript": "^5.8.0",
42
- "@forge-dev/core": "0.1.0",
43
- "@forge-dev/console": "0.1.0"
42
+ "@forge-dev/console": "0.1.0",
43
+ "@forge-dev/core": "0.1.0"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsc",