codesesh 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +16 -0
- package/dist/chunk-H3D3GNQK.js +3574 -0
- package/dist/chunk-H3D3GNQK.js.map +1 -0
- package/dist/dist-KGHAVLGF.js +52 -0
- package/dist/dist-KGHAVLGF.js.map +1 -0
- package/dist/index.js +325 -0
- package/dist/index.js.map +1 -0
- package/dist/web/assets/index-Cbmq6KvN.js +67 -0
- package/dist/web/assets/index-vSqmWltx.css +2 -0
- package/dist/web/icon/agent/antigravity.svg +1 -0
- package/dist/web/icon/agent/claudecode.svg +1 -0
- package/dist/web/icon/agent/codex.svg +1 -0
- package/dist/web/icon/agent/cursor.svg +12 -0
- package/dist/web/icon/agent/kilocode.svg +1 -0
- package/dist/web/icon/agent/kimi.svg +1 -0
- package/dist/web/icon/agent/opencode.svg +1 -0
- package/dist/web/index.html +18 -0
- package/dist/web/logo.svg +29 -0
- package/package.json +34 -0
- package/scripts/copy-web-dist.js +31 -0
- package/src/api/__tests__/handlers.test.ts +191 -0
- package/src/api/__tests__/routes.test.ts +16 -0
- package/src/api/handlers.ts +76 -0
- package/src/api/routes.ts +13 -0
- package/src/commands/serve.ts +78 -0
- package/src/index.ts +203 -0
- package/src/output.ts +47 -0
- package/src/server.ts +56 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +16 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-content:"";--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:"Avenir Next", "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", -apple-system, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-2xl:42rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-sm:calc(var(--radius) - 4px);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-border:hsl(var(--border));--color-background:hsl(var(--background));--color-foreground:hsl(var(--foreground))}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{--background:0 0% 100%;--foreground:0 0% 3.9%;--card:0 0% 100%;--card-foreground:0 0% 3.9%;--popover:0 0% 100%;--popover-foreground:0 0% 3.9%;--primary:0 0% 9%;--primary-foreground:0 0% 98%;--secondary:0 0% 96.1%;--secondary-foreground:0 0% 9%;--muted:0 0% 96.1%;--muted-foreground:0 0% 45.1%;--accent:0 0% 96.1%;--accent-foreground:0 0% 9%;--destructive:0 84.2% 60.2%;--destructive-foreground:0 0% 98%;--border:0 0% 89.8%;--input:0 0% 89.8%;--ring:0 0% 3.9%;--radius:.5rem;--console-bg:#f7f7f7;--console-sidebar-bg:#fbfbfb;--console-surface-muted:#f5f5f5;--console-border:#e5e5e5;--console-border-strong:#d4d4d4;--console-text:#1a1a1a;--console-muted:#666;--console-accent:#2d2d2d;--console-accent-strong:#1f1f1f;--console-thread:#e8e8e8;--console-thinking-bg:#f9f9f9;--console-thinking-border:#ebebeb;--console-success:#15803d;--console-success-bg:#dcfce7;--console-success-border:#bbf7d0;--console-warning:#b45309;--console-warning-bg:#fef3c7;--console-warning-border:#fde68a;--console-error:#b91c1c;--console-error-bg:#fee2e2;--console-error-border:#fecaca}.dark{--background:0 0% 3.9%;--foreground:0 0% 98%;--card:0 0% 3.9%;--card-foreground:0 0% 98%;--popover:0 0% 3.9%;--popover-foreground:0 0% 98%;--primary:0 0% 98%;--primary-foreground:0 0% 9%;--secondary:0 0% 14.9%;--secondary-foreground:0 0% 98%;--muted:0 0% 14.9%;--muted-foreground:0 0% 63.9%;--accent:0 0% 14.9%;--accent-foreground:0 0% 98%;--destructive:0 62.8% 30.6%;--destructive-foreground:0 0% 98%;--border:0 0% 14.9%;--input:0 0% 14.9%;--ring:0 0% 83.1%}*{border-color:var(--color-border)}body{background-color:var(--color-background);color:var(--color-foreground)}}@layer components;@layer utilities{.relative{position:relative}.static{position:static}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-14{height:calc(var(--spacing) * 14)}.h-\[calc\(100vh-56px\)\]{height:calc(100vh - 56px)}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[200px\]{max-height:200px}.max-h-\[280px\]{max-height:280px}.max-h-\[420px\]{max-height:420px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-24{min-height:calc(var(--spacing) * 24)}.min-h-full{min-height:100%}.w-4{width:calc(var(--spacing) * 4)}.w-5\/12{width:41.6667%}.w-6{width:calc(var(--spacing) * 6)}.w-7\/12{width:58.3333%}.w-8\/12{width:66.6667%}.w-9\/12{width:75%}.w-10\/12{width:83.3333%}.w-11\/12{width:91.6667%}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-24{width:calc(var(--spacing) * 24)}.w-64{width:calc(var(--spacing) * 64)}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[42rem\]{max-width:42rem}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-\[2px\]{border-radius:2px}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[var\(--console-border\)\]{border-color:var(--console-border)}.border-\[var\(--console-border-strong\)\]{border-color:var(--console-border-strong)}.border-\[var\(--console-error-border\)\]{border-color:var(--console-error-border)}.border-\[var\(--console-success-border\)\]{border-color:var(--console-success-border)}.border-\[var\(--console-thinking-border\)\]{border-color:var(--console-thinking-border)}.border-\[var\(--console-thread\)\]{border-color:var(--console-thread)}.border-\[var\(--console-warning-border\)\]{border-color:var(--console-warning-border)}.border-transparent{border-color:#0000}.bg-\[\#eff6ff\]{background-color:#eff6ff}.bg-\[\#f0fdf4\]{background-color:#f0fdf4}.bg-\[\#f3f4f6\]{background-color:#f3f4f6}.bg-\[\#f5f3ff\]{background-color:#f5f3ff}.bg-\[\#fafafa\]{background-color:#fafafa}.bg-\[\#fef2f2\]{background-color:#fef2f2}.bg-\[var\(--console-bg\)\]{background-color:var(--console-bg)}.bg-\[var\(--console-border\)\]{background-color:var(--console-border)}.bg-\[var\(--console-border-strong\)\]{background-color:var(--console-border-strong)}.bg-\[var\(--console-error-bg\)\]{background-color:var(--console-error-bg)}.bg-\[var\(--console-sidebar-bg\)\]{background-color:var(--console-sidebar-bg)}.bg-\[var\(--console-success-bg\)\]{background-color:var(--console-success-bg)}.bg-\[var\(--console-surface-muted\)\]{background-color:var(--console-surface-muted)}.bg-\[var\(--console-thinking-bg\)\]{background-color:var(--console-thinking-bg)}.bg-\[var\(--console-warning-bg\)\]{background-color:var(--console-warning-bg)}.bg-white{background-color:var(--color-white)}.bg-white\/60{background-color:#fff9}@supports (color:color-mix(in lab, red, red)){.bg-white\/60{background-color:color-mix(in oklab, var(--color-white) 60%, transparent)}}.bg-white\/70{background-color:#ffffffb3}@supports (color:color-mix(in lab, red, red)){.bg-white\/70{background-color:color-mix(in oklab, var(--color-white) 70%, transparent)}}.bg-white\/85{background-color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.bg-white\/85{background-color:color-mix(in oklab, var(--color-white) 85%, transparent)}}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-left{text-align:left}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.05em\]{--tw-tracking:.05em;letter-spacing:.05em}.tracking-\[0\.16em\]{--tw-tracking:.16em;letter-spacing:.16em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#1d4ed8\]{color:#1d4ed8}.text-\[\#7c3aed\]{color:#7c3aed}.text-\[\#15803d\]{color:#15803d}.text-\[\#b91c1c\]{color:#b91c1c}.text-\[var\(--console-accent\)\]{color:var(--console-accent)}.text-\[var\(--console-error\)\]{color:var(--console-error)}.text-\[var\(--console-muted\)\]{color:var(--console-muted)}.text-\[var\(--console-success\)\]{color:var(--console-success)}.text-\[var\(--console-text\)\]{color:var(--console-text)}.text-\[var\(--console-warning\)\]{color:var(--console-warning)}.uppercase{text-transform:uppercase}.accent-\[var\(--console-accent-strong\)\]{accent-color:var(--console-accent-strong)}.opacity-50{opacity:.5}.shadow-\[0_1px_2px_rgba\(15\,23\,42\,0\.04\)\]{--tw-shadow:0 1px 2px var(--tw-shadow-color,#0f172a0a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[2px_2px_0_0_rgba\(15\,23\,42\,0\.05\)\]{--tw-shadow:2px 2px 0 0 var(--tw-shadow-color,#0f172a0d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.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-sm{--tw-backdrop-blur:blur(var(--blur-sm));-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-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.animate-in{--tw-enter-opacity:initial;--tw-enter-scale:initial;--tw-enter-rotate:initial;--tw-enter-translate-x:initial;--tw-enter-translate-y:initial;animation-name:enter;animation-duration:.15s}.duration-200{animation-duration:.2s}.duration-300{animation-duration:.3s}.fade-in{--tw-enter-opacity:0}.running{animation-play-state:running}.slide-in-from-bottom-2{--tw-enter-translate-y:.5rem}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:top-0:before{content:var(--tw-content);top:calc(var(--spacing) * 0)}.before\:bottom-0:before{content:var(--tw-content);bottom:calc(var(--spacing) * 0)}.before\:left-0:before{content:var(--tw-content);left:calc(var(--spacing) * 0)}.before\:w-0\.5:before{content:var(--tw-content);width:calc(var(--spacing) * .5)}.before\:bg-\[var\(--console-accent\)\]:before{content:var(--tw-content);background-color:var(--console-accent)}@media (hover:hover){.hover\:border-\[var\(--console-border\)\]:hover{border-color:var(--console-border)}.hover\:bg-\[var\(--console-surface-muted\)\]:hover{background-color:var(--console-surface-muted)}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-\[var\(--console-accent\)\]:focus-visible{outline-color:var(--console-accent)}@media (width>=40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=48rem){.md\:w-24{width:calc(var(--spacing) * 24)}.md\:w-\[560px\]{width:560px}.md\:max-w-xs{max-width:var(--container-xs)}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:justify-between{justify-content:space-between}.md\:gap-3{gap:calc(var(--spacing) * 3)}.md\:p-6{padding:calc(var(--spacing) * 6)}.md\:px-4{padding-inline:calc(var(--spacing) * 4)}.md\:px-8{padding-inline:calc(var(--spacing) * 8)}.md\:pr-5{padding-right:calc(var(--spacing) * 5)}.md\:text-\[2rem\]{font-size:2rem}}@media (width>=64rem){.lg\:sticky{position:sticky}.lg\:top-4{top:calc(var(--spacing) * 4)}.lg\:flex{display:flex}.lg\:grid-cols-\[240px_minmax\(0\,1fr\)\]{grid-template-columns:240px minmax(0,1fr)}.lg\:items-start{align-items:flex-start}}.console-ui{font-family:IBM Plex Sans,Avenir Next,PingFang SC,-apple-system,sans-serif}.console-mono{font-family:JetBrains Mono,IBM Plex Mono,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.bg-grid{background-image:linear-gradient(90deg,#0000000a 1px,#0000 1px),linear-gradient(#0000000a 1px,#0000 1px);background-size:40px 40px}}.console-scrollbar::-webkit-scrollbar{width:6px;height:6px}.console-scrollbar::-webkit-scrollbar-track{background:0 0}.console-scrollbar::-webkit-scrollbar-thumb{background:#d1d5db;border-radius:2px}.console-scrollbar::-webkit-scrollbar-thumb:hover{background:#9ca3af}.console-scrollbar{scrollbar-width:thin;scrollbar-color:#d1d5db transparent}.console-markdown>*+*{margin-top:.75rem}.console-markdown p{margin:0}.console-markdown h1,.console-markdown h2,.console-markdown h3,.console-markdown h4,.console-markdown h5,.console-markdown h6{color:var(--console-text);margin:0;font-weight:700;line-height:1.3}.console-markdown h1{letter-spacing:-.02em;font-size:1.5rem}.console-markdown h2{letter-spacing:-.015em;font-size:1.25rem}.console-markdown h3{font-size:1.1rem}.console-markdown h4,.console-markdown h5,.console-markdown h6{font-size:1rem}.console-markdown ul,.console-markdown ol{margin:.5rem 0;padding-left:1.25rem}.console-markdown ul{list-style:outside}.console-markdown ol{list-style:decimal}.console-markdown li+li{margin-top:.25rem}.console-markdown li>p{margin:0}.console-markdown strong{font-weight:700}.console-markdown blockquote{border-left:3px solid var(--console-border-strong);color:var(--console-muted);margin:0;padding-left:.875rem}.console-markdown hr{border:0;border-top:1px solid var(--console-border);margin:1rem 0}.console-markdown a{color:#4f46e5;text-decoration:underline}.console-markdown-link{color:inherit;cursor:text;text-decoration:none}.console-markdown code{background:#f5f5f5;border:1px solid #e5e7eb;border-radius:.125rem;padding:.08rem .32rem;font-family:JetBrains Mono,IBM Plex Mono,SFMono-Regular,Menlo,Monaco,Consolas,monospace;font-size:.8rem}.console-markdown pre{background:#fafafa;border:1px solid #e5e7eb;border-radius:.125rem;margin:0;padding:.75rem;overflow-x:auto}.console-markdown pre code{background:0 0;border:none;padding:0}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0), var(--tw-enter-translate-y,0), 0) scale3d(var(--tw-enter-scale,1), var(--tw-enter-scale,1), var(--tw-enter-scale,1)) rotate(var(--tw-enter-rotate,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0), var(--tw-exit-translate-y,0), 0) scale3d(var(--tw-exit-scale,1), var(--tw-exit-scale,1), var(--tw-exit-scale,1)) rotate(var(--tw-exit-rotate,0))}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Antigravity</title><mask height="23" id="lobe-icons-antigravity-fill-0" maskUnits="userSpaceOnUse" width="24" x="0" y="1"><path d="M21.751 22.607c1.34 1.005 3.35.335 1.508-1.508C17.73 15.74 18.904 1 12.037 1 5.17 1 6.342 15.74.815 21.1c-2.01 2.009.167 2.511 1.507 1.506 5.192-3.517 4.857-9.714 9.715-9.714 4.857 0 4.522 6.197 9.714 9.715z" fill="#fff"></path></mask><g mask="url(#lobe-icons-antigravity-fill-0)"><g filter="url(#lobe-icons-antigravity-fill-1)"><path d="M-1.018-3.992c-.408 3.591 2.686 6.89 6.91 7.37 4.225.48 7.98-2.043 8.387-5.633.408-3.59-2.686-6.89-6.91-7.37-4.225-.479-7.98 2.043-8.387 5.633z" fill="#FFE432"></path></g><g filter="url(#lobe-icons-antigravity-fill-2)"><path d="M15.269 7.747c1.058 4.557 5.691 7.374 10.348 6.293 4.657-1.082 7.575-5.653 6.516-10.21-1.058-4.556-5.691-7.374-10.348-6.292-4.657 1.082-7.575 5.653-6.516 10.21z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-fill-3)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-fill-4)"><path d="M-12.443 10.804c1.338 4.703 7.36 7.11 13.453 5.378 6.092-1.733 9.947-6.95 8.61-11.652C8.282-.173 2.26-2.58-3.833-.848-9.925.884-13.78 6.1-12.443 10.804z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-fill-5)"><path d="M-7.608 14.703c3.352 3.424 9.126 3.208 12.896-.483 3.77-3.69 4.108-9.459.756-12.883C2.69-2.087-3.083-1.871-6.853 1.82c-3.77 3.69-4.108 9.458-.755 12.883z" fill="#00B95C"></path></g><g filter="url(#lobe-icons-antigravity-fill-6)"><path d="M9.932 27.617c1.04 4.482 5.384 7.303 9.7 6.3 4.316-1.002 6.971-5.448 5.93-9.93-1.04-4.483-5.384-7.304-9.7-6.301-4.316 1.002-6.971 5.448-5.93 9.93z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-fill-7)"><path d="M2.572-8.185C.392-3.329 2.778 2.472 7.9 4.771c5.122 2.3 11.042.227 13.222-4.63 2.18-4.855-.205-10.656-5.327-12.955-5.122-2.3-11.042-.227-13.222 4.63z" fill="#FBBC04"></path></g><g filter="url(#lobe-icons-antigravity-fill-8)"><path d="M-3.267 38.686c-5.277-2.072 3.742-19.117 5.984-24.83 2.243-5.712 8.34-8.664 13.616-6.592 5.278 2.071 11.533 13.482 9.29 19.195-2.242 5.713-23.613 14.298-28.89 12.227z" fill="#3186FF"></path></g><g filter="url(#lobe-icons-antigravity-fill-9)"><path d="M28.71 17.471c-1.413 1.649-5.1.808-8.236-1.878-3.135-2.687-4.531-6.201-3.118-7.85 1.412-1.649 5.1-.808 8.235 1.878s4.532 6.2 3.119 7.85z" fill="#749BFF"></path></g><g filter="url(#lobe-icons-antigravity-fill-10)"><path d="M18.163 9.077c5.81 3.93 12.502 4.19 14.946.577 2.443-3.612-.287-9.727-6.098-13.658-5.81-3.931-12.502-4.19-14.946-.577-2.443 3.612.287 9.727 6.098 13.658z" fill="#FC413D"></path></g><g filter="url(#lobe-icons-antigravity-fill-11)"><path d="M-.915 2.684c-1.44 3.473-.97 6.967 1.05 7.804 2.02.837 4.824-1.3 6.264-4.772 1.44-3.473.97-6.967-1.05-7.804-2.02-.837-4.824 1.3-6.264 4.772z" fill="#FFEE48"></path></g></g><defs><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="17.587" id="lobe-icons-antigravity-fill-1" width="19.838" x="-3.288" y="-11.917"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="1.117"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="38.565" id="lobe-icons-antigravity-fill-2" width="38.9" x="4.251" y="-13.493"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="5.4"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-fill-3" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.517" id="lobe-icons-antigravity-fill-4" width="40.955" x="-21.889" y="-10.592"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="36.595" id="lobe-icons-antigravity-fill-5" width="36.632" x="-19.099" y="-10.278"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.591"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="34.087" id="lobe-icons-antigravity-fill-6" width="33.533" x=".981" y="8.758"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="4.363"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="35.276" id="lobe-icons-antigravity-fill-7" width="35.978" x="-6.143" y="-21.659"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.954"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="46.523" id="lobe-icons-antigravity-fill-8" width="45.114" x="-11.96" y="-.46"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.531"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="24.054" id="lobe-icons-antigravity-fill-9" width="25.094" x="10.485" y=".58"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.159"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="30.007" id="lobe-icons-antigravity-fill-10" width="33.508" x="5.833" y="-12.467"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="2.669"></feGaussianBlur></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="26.151" id="lobe-icons-antigravity-fill-11" width="22.194" x="-8.355" y="-8.876"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur result="effect1_foregroundBlur_977_115" stdDeviation="3.303"></feGaussianBlur></filter></defs></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" fill="#D97757" fill-rule="nonzero"></path></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenAI</title><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"></path></svg>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg id="Ebene_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 466.73 532.09">
|
|
3
|
+
<!-- Generator: Adobe Illustrator 29.6.1, SVG Export Plug-In . SVG Version: 2.1.1 Build 9) -->
|
|
4
|
+
<defs>
|
|
5
|
+
<style>
|
|
6
|
+
.st0 {
|
|
7
|
+
fill: #26251e;
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
</defs>
|
|
11
|
+
<path class="st0" d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z"/>
|
|
12
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kilo Code</title><path d="M0 0v24h24V0H0zm22.222 22.222H1.778V1.778h20.444v20.444zm-7.555-4.964h2.222v1.778h-2.794L12.89 17.83v-2.794h1.778v2.222zm4 0h-1.778v-2.222h-2.222v-1.778h2.793l1.207 1.207v2.793zm-7.556-2.591H9.333v-1.778h1.778v1.778zm-5.778-1.778h1.778v4h4v1.778H6.54L5.333 17.46V12.89zm13.334-3.556v1.778h-5.778V9.333h1.987V7.111h-1.987V5.333h2.558l1.206 1.207v2.793h2.014zm-11.556-2h2.222l1.778 1.778v2H9.333v-2H7.111v2H5.333V5.333h1.778v2zm4 0H9.333v-2h1.778v2z"></path></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>MoonshotAI</title><path d="M1.052 16.916l9.539 2.552a21.007 21.007 0 00.06 2.033l5.956 1.593a11.997 11.997 0 01-5.586.865l-.18-.016-.044-.004-.084-.009-.094-.01a11.605 11.605 0 01-.157-.02l-.107-.014-.11-.016a11.962 11.962 0 01-.32-.051l-.042-.008-.075-.013-.107-.02-.07-.015-.093-.019-.075-.016-.095-.02-.097-.023-.094-.022-.068-.017-.088-.022-.09-.024-.095-.025-.082-.023-.109-.03-.062-.02-.084-.025-.093-.028-.105-.034-.058-.019-.08-.026-.09-.031-.066-.024a6.293 6.293 0 01-.044-.015l-.068-.025-.101-.037-.057-.022-.08-.03-.087-.035-.088-.035-.079-.032-.095-.04-.063-.028-.063-.027a5.655 5.655 0 01-.041-.018l-.066-.03-.103-.047-.052-.024-.096-.046-.062-.03-.084-.04-.086-.044-.093-.047-.052-.027-.103-.055-.057-.03-.058-.032a6.49 6.49 0 01-.046-.026l-.094-.053-.06-.034-.051-.03-.072-.041-.082-.05-.093-.056-.052-.032-.084-.053-.061-.039-.079-.05-.07-.047-.053-.035a7.785 7.785 0 01-.054-.036l-.044-.03-.044-.03a6.066 6.066 0 01-.04-.028l-.057-.04-.076-.054-.069-.05-.074-.054-.056-.042-.076-.057-.076-.059-.086-.067-.045-.035-.064-.052-.074-.06-.089-.073-.046-.039-.046-.039a7.516 7.516 0 01-.043-.037l-.045-.04-.061-.053-.07-.062-.068-.06-.062-.058-.067-.062-.053-.05-.088-.084a13.28 13.28 0 01-.099-.097l-.029-.028-.041-.042-.069-.07-.05-.051-.05-.053a6.457 6.457 0 01-.168-.179l-.08-.088-.062-.07-.071-.08-.042-.049-.053-.062-.058-.068-.046-.056a7.175 7.175 0 01-.027-.033l-.045-.055-.066-.082-.041-.052-.05-.064-.02-.025a11.99 11.99 0 01-1.44-2.402zm-1.02-5.794l11.353 3.037a20.468 20.468 0 00-.469 2.011l10.817 2.894a12.076 12.076 0 01-1.845 2.005L.657 15.923l-.016-.046-.035-.104a11.965 11.965 0 01-.05-.153l-.007-.023a11.896 11.896 0 01-.207-.741l-.03-.126-.018-.08-.021-.097-.018-.081-.018-.09-.017-.084-.018-.094c-.026-.141-.05-.283-.071-.426l-.017-.118-.011-.083-.013-.102a12.01 12.01 0 01-.019-.161l-.005-.047a12.12 12.12 0 01-.034-2.145zm1.593-5.15l11.948 3.196c-.368.605-.705 1.231-1.01 1.875l11.295 3.022c-.142.82-.368 1.612-.668 2.365l-11.55-3.09L.124 10.26l.015-.1.008-.049.01-.067.015-.087.018-.098c.026-.148.056-.295.088-.442l.028-.124.02-.085.024-.097c.022-.09.045-.18.07-.268l.028-.102.023-.083.03-.1.025-.082.03-.096.026-.082.031-.095a11.896 11.896 0 011.01-2.232zm4.442-4.4L17.352 4.59a20.77 20.77 0 00-1.688 1.721l7.823 2.093c.267.852.442 1.744.513 2.665L2.106 5.213l.045-.065.027-.04.04-.055.046-.065.055-.076.054-.072.064-.086.05-.065.057-.073.055-.07.06-.074.055-.069.065-.077.054-.066.066-.077.053-.06.072-.082.053-.06.067-.074.054-.058.073-.078.058-.06.063-.067.168-.17.1-.098.059-.056.076-.071a12.084 12.084 0 012.272-1.677zM12.017 0h.097l.082.001.069.001.054.002.068.002.046.001.076.003.047.002.06.003.054.002.087.005.105.007.144.011.088.007.044.004.077.008.082.008.047.005.102.012.05.006.108.014.081.01.042.006.065.01.207.032.07.012.065.011.14.026.092.018.11.022.046.01.075.016.041.01L14.7.3l.042.01.065.015.049.012.071.017.096.024.112.03.113.03.113.032.05.015.07.02.078.024.073.023.05.016.05.016.076.025.099.033.102.036.048.017.064.023.093.034.11.041.116.045.1.04.047.02.06.024.041.018.063.026.04.018.057.025.11.048.1.046.074.035.075.036.06.028.092.046.091.045.102.052.053.028.049.026.046.024.06.033.041.022.052.029.088.05.106.06.087.051.057.034.053.032.096.059.088.055.098.062.036.024.064.041.084.056.04.027.062.042.062.043.023.017c.054.037.108.075.161.114l.083.06.065.048.056.043.086.065.082.064.04.03.05.041.086.069.079.065.085.071c.712.6 1.353 1.283 1.909 2.031L7.222.994l.062-.027.065-.028.081-.034.086-.035c.113-.045.227-.09.341-.131l.096-.035.093-.033.084-.03.096-.031c.087-.03.176-.058.264-.085l.091-.027.086-.025.102-.03.085-.023.1-.026L9.04.37l.09-.023.091-.022.095-.022.09-.02.098-.021.091-.02.095-.018.092-.018.1-.018.091-.016.098-.017.092-.014.097-.015.092-.013.102-.013.091-.012.105-.012.09-.01.105-.01c.093-.01.186-.018.28-.024l.106-.008.09-.005.11-.006.093-.004.1-.004.097-.002.099-.002.197-.002z"></path></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>opencode</title><path d="M16 6H8v12h8V6zm4 16H4V2h16v20z"></path></svg>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta
|
|
7
|
+
name="description"
|
|
8
|
+
content="Discover, aggregate, and visualize AI coding agent sessions."
|
|
9
|
+
/>
|
|
10
|
+
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
11
|
+
<title>CodeSesh</title>
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-Cbmq6KvN.js"></script>
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-vSqmWltx.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div id="root"></div>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="100%" height="100%">
|
|
2
|
+
<path d="M 50 95 L 70 95 L 75 105 L 45 105 Z" fill="#334155"/>
|
|
3
|
+
<path d="M 55 85 L 65 85 L 68 95 L 52 95 Z" fill="#475569"/>
|
|
4
|
+
|
|
5
|
+
<rect x="15" y="25" width="90" height="60" rx="6" fill="#1e293b" stroke="#334155" stroke-width="3"/>
|
|
6
|
+
|
|
7
|
+
<rect x="20" y="30" width="80" height="50" rx="3" fill="#0f172a"/>
|
|
8
|
+
|
|
9
|
+
<path d="M 28 35 h 35 a 3 3 0 0 1 3 3 v 9 a 3 3 0 0 1 -3 3 h -30 l -4 4 v -4 a 3 3 0 0 1 -3 -3 v -9 a 3 3 0 0 1 3 -3 z" fill="#14532d" stroke="#4ade80" stroke-width="1.5" stroke-linejoin="round"/>
|
|
10
|
+
<line x1="31" y1="40" x2="60" y2="40" stroke="#4ade80" stroke-width="1.5" stroke-linecap="round"/>
|
|
11
|
+
<line x1="31" y1="45" x2="50" y2="45" stroke="#4ade80" stroke-width="1.5" stroke-linecap="round"/>
|
|
12
|
+
|
|
13
|
+
<path d="M 55 50 h 35 a 3 3 0 0 1 3 3 v 9 a 3 3 0 0 1 -3 3 h -3 v 4 l -4 -4 h -28 a 3 3 0 0 1 -3 -3 v -9 a 3 3 0 0 1 3 -3 z" fill="#0c4a6e" stroke="#38bdf8" stroke-width="1.5" stroke-linejoin="round"/>
|
|
14
|
+
<line x1="58" y1="55" x2="87" y2="55" stroke="#38bdf8" stroke-width="1.5" stroke-linecap="round"/>
|
|
15
|
+
<line x1="58" y1="60" x2="75" y2="60" stroke="#38bdf8" stroke-width="1.5" stroke-linecap="round"/>
|
|
16
|
+
|
|
17
|
+
<path d="M 28 65 h 35 a 3 3 0 0 1 3 3 v 9 a 3 3 0 0 1 -3 3 h -30 l -4 4 v -4 a 3 3 0 0 1 -3 -3 v -9 a 3 3 0 0 1 3 -3 z" fill="#14532d" stroke="#4ade80" stroke-width="1.5" stroke-linejoin="round"/>
|
|
18
|
+
<line x1="31" y1="70" x2="55" y2="70" stroke="#4ade80" stroke-width="1.5" stroke-linecap="round"/>
|
|
19
|
+
<line x1="31" y1="75" x2="45" y2="75" stroke="#4ade80" stroke-width="1.5" stroke-linecap="round"/>
|
|
20
|
+
|
|
21
|
+
<circle cx="70" cy="65" r="16" fill="#0f172a" fill-opacity="0.85" stroke="#4ade80" stroke-width="3"/>
|
|
22
|
+
<circle cx="70" cy="65" r="14" fill="none" stroke="#22c55e" stroke-width="1" opacity="0.6"/>
|
|
23
|
+
|
|
24
|
+
<line x1="62" y1="61" x2="78" y2="61" stroke="#4ade80" stroke-width="2.5" stroke-linecap="round"/>
|
|
25
|
+
<line x1="62" y1="69" x2="72" y2="69" stroke="#4ade80" stroke-width="2.5" stroke-linecap="round"/>
|
|
26
|
+
|
|
27
|
+
<line x1="81" y1="76" x2="95" y2="90" stroke="#334155" stroke-width="6" stroke-linecap="round"/>
|
|
28
|
+
<line x1="81" y1="76" x2="93" y2="88" stroke="#475569" stroke-width="2" stroke-linecap="round"/>
|
|
29
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codesesh",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"bin": {
|
|
5
|
+
"codesesh": "dist/index.js"
|
|
6
|
+
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/xingkaixin/codesesh"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup && node scripts/copy-web-dist.js",
|
|
17
|
+
"release": "tsup && node scripts/copy-web-dist.js",
|
|
18
|
+
"dev": "tsup --watch",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"start": "node dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@hono/node-server": "^1.14.0",
|
|
24
|
+
"citty": "^0.1.6",
|
|
25
|
+
"consola": "^3.4.2",
|
|
26
|
+
"hono": "^4.7.4",
|
|
27
|
+
"open": "^10.1.2"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22.14.0",
|
|
31
|
+
"tsup": "^8.4.0",
|
|
32
|
+
"typescript": "^5.9.3"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Post-build script to copy web dist into CLI package
|
|
4
|
+
* This ensures the CLI can serve the web UI as static files
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, cpSync, mkdirSync } from "node:fs";
|
|
7
|
+
import { resolve, dirname } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const rootDir = resolve(__dirname, "../../..");
|
|
12
|
+
const cliDir = resolve(__dirname, "..");
|
|
13
|
+
|
|
14
|
+
const webDistSource = resolve(rootDir, "apps", "web", "dist");
|
|
15
|
+
const webDistTarget = resolve(cliDir, "dist/web");
|
|
16
|
+
|
|
17
|
+
if (!existsSync(webDistSource)) {
|
|
18
|
+
console.warn("⚠️ Web dist not found at:", webDistSource);
|
|
19
|
+
console.warn(" Run 'pnpm --filter @codesesh/web build' first");
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Ensure target directory exists
|
|
24
|
+
try {
|
|
25
|
+
mkdirSync(dirname(webDistTarget), { recursive: true });
|
|
26
|
+
cpSync(webDistSource, webDistTarget, { recursive: true, force: true });
|
|
27
|
+
console.log("✓ Copied web dist to:", webDistTarget);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.error("✗ Failed to copy web dist:", err instanceof Error ? err.message : String(err));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { handleGetAgents, handleGetSessions, handleGetSessionData } from "../handlers.js";
|
|
3
|
+
import type { ScanResult, SessionHead, SessionData } from "@codesesh/core";
|
|
4
|
+
import { BaseAgent } from "@codesesh/core";
|
|
5
|
+
|
|
6
|
+
// --- Helpers ---
|
|
7
|
+
|
|
8
|
+
function makeSession(id: string, overrides?: Partial<SessionHead>): SessionHead {
|
|
9
|
+
return {
|
|
10
|
+
id,
|
|
11
|
+
slug: `agent/${id}`,
|
|
12
|
+
title: `Session ${id}`,
|
|
13
|
+
time_created: 1000,
|
|
14
|
+
time_updated: 1000,
|
|
15
|
+
directory: "/home/user/project",
|
|
16
|
+
...overrides,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function makeMockContext(
|
|
21
|
+
overrides: {
|
|
22
|
+
query?: Record<string, string>;
|
|
23
|
+
param?: Record<string, string>;
|
|
24
|
+
} = {},
|
|
25
|
+
) {
|
|
26
|
+
const jsonFn = vi.fn().mockReturnValue({ status: 200 });
|
|
27
|
+
return {
|
|
28
|
+
req: {
|
|
29
|
+
query: (key: string) => overrides.query?.[key] ?? "",
|
|
30
|
+
param: (key: string) => overrides.param?.[key] ?? "",
|
|
31
|
+
},
|
|
32
|
+
json: jsonFn,
|
|
33
|
+
} as any;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class MockAgent extends BaseAgent {
|
|
37
|
+
readonly name = "claudecode";
|
|
38
|
+
readonly displayName = "Claude Code";
|
|
39
|
+
|
|
40
|
+
isAvailable() {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
scan(): SessionHead[] {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getSessionData(_sessionId: string): SessionData {
|
|
49
|
+
return {
|
|
50
|
+
id: "s1",
|
|
51
|
+
slug: "claudecode/s1",
|
|
52
|
+
title: "Test Session",
|
|
53
|
+
time_created: 1000,
|
|
54
|
+
time_updated: 1000,
|
|
55
|
+
messages: [],
|
|
56
|
+
stats: {
|
|
57
|
+
message_count: 0,
|
|
58
|
+
total_input_tokens: 0,
|
|
59
|
+
total_output_tokens: 0,
|
|
60
|
+
total_cost: 0,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function makeScanResult(overrides?: Partial<ScanResult>): ScanResult {
|
|
67
|
+
const agent = new MockAgent();
|
|
68
|
+
return {
|
|
69
|
+
sessions: [makeSession("s1"), makeSession("s2")],
|
|
70
|
+
byAgent: { claudecode: [makeSession("s1"), makeSession("s2")] },
|
|
71
|
+
agents: [agent],
|
|
72
|
+
...overrides,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// --- Tests ---
|
|
77
|
+
|
|
78
|
+
describe("handleGetAgents", () => {
|
|
79
|
+
it("returns agent info list", () => {
|
|
80
|
+
const c = makeMockContext();
|
|
81
|
+
const result = makeScanResult();
|
|
82
|
+
handleGetAgents(c, result);
|
|
83
|
+
expect(c.json).toHaveBeenCalled();
|
|
84
|
+
const response = c.json.mock.calls[0]![0];
|
|
85
|
+
expect(Array.isArray(response)).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("handleGetSessions", () => {
|
|
90
|
+
it("returns all sessions without filters", () => {
|
|
91
|
+
const c = makeMockContext();
|
|
92
|
+
const result = makeScanResult();
|
|
93
|
+
handleGetSessions(c, result);
|
|
94
|
+
const response = c.json.mock.calls[0]![0];
|
|
95
|
+
expect(response.sessions).toHaveLength(2);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("filters by agent", () => {
|
|
99
|
+
const c = makeMockContext({ query: { agent: "claudecode" } });
|
|
100
|
+
const result = makeScanResult();
|
|
101
|
+
handleGetSessions(c, result);
|
|
102
|
+
const response = c.json.mock.calls[0]![0];
|
|
103
|
+
expect(response.sessions).toHaveLength(2);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("falls back to all sessions when agent not found in byAgent", () => {
|
|
107
|
+
const c = makeMockContext({ query: { agent: "nonexistent" } });
|
|
108
|
+
const result = makeScanResult();
|
|
109
|
+
handleGetSessions(c, result);
|
|
110
|
+
const response = c.json.mock.calls[0]![0];
|
|
111
|
+
// Falls back to scanResult.sessions
|
|
112
|
+
expect(response.sessions).toHaveLength(2);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("filters by q (title search)", () => {
|
|
116
|
+
const c = makeMockContext({ query: { q: "s1" } });
|
|
117
|
+
const result = makeScanResult();
|
|
118
|
+
handleGetSessions(c, result);
|
|
119
|
+
const response = c.json.mock.calls[0]![0];
|
|
120
|
+
expect(response.sessions).toHaveLength(1);
|
|
121
|
+
expect(response.sessions[0].id).toBe("s1");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("filters by cwd (substring match)", () => {
|
|
125
|
+
const c = makeMockContext({ query: { cwd: "project" } });
|
|
126
|
+
const result = makeScanResult();
|
|
127
|
+
handleGetSessions(c, result);
|
|
128
|
+
const response = c.json.mock.calls[0]![0];
|
|
129
|
+
expect(response.sessions).toHaveLength(2);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("filters by from date", () => {
|
|
133
|
+
const c = makeMockContext({ query: { from: "2024-01-01" } });
|
|
134
|
+
const result = makeScanResult({
|
|
135
|
+
sessions: [
|
|
136
|
+
makeSession("old", { time_created: new Date("2023-01-01").getTime() }),
|
|
137
|
+
makeSession("new", { time_created: new Date("2025-01-01").getTime() }),
|
|
138
|
+
],
|
|
139
|
+
byAgent: {},
|
|
140
|
+
});
|
|
141
|
+
handleGetSessions(c, result);
|
|
142
|
+
const response = c.json.mock.calls[0]![0];
|
|
143
|
+
expect(response.sessions).toHaveLength(1);
|
|
144
|
+
expect(response.sessions[0].id).toBe("new");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("ignores invalid from date", () => {
|
|
148
|
+
const c = makeMockContext({ query: { from: "not-a-date" } });
|
|
149
|
+
const result = makeScanResult();
|
|
150
|
+
handleGetSessions(c, result);
|
|
151
|
+
const response = c.json.mock.calls[0]![0];
|
|
152
|
+
// Invalid date → filter not applied
|
|
153
|
+
expect(response.sessions).toHaveLength(2);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("handleGetSessionData", () => {
|
|
158
|
+
it("returns session data for valid agent and id", async () => {
|
|
159
|
+
const c = makeMockContext({ param: { agent: "claudecode", id: "s1" } });
|
|
160
|
+
const result = makeScanResult();
|
|
161
|
+
await handleGetSessionData(c, result);
|
|
162
|
+
expect(c.json).toHaveBeenCalled();
|
|
163
|
+
const response = c.json.mock.calls[0]![0];
|
|
164
|
+
expect(response.title).toBe("Test Session");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("returns 400 when session ID is missing", async () => {
|
|
168
|
+
const c = makeMockContext({ param: { agent: "claudecode", id: "" } });
|
|
169
|
+
const result = makeScanResult();
|
|
170
|
+
await handleGetSessionData(c, result);
|
|
171
|
+
expect(c.json).toHaveBeenCalledWith({ error: "Missing session ID" }, 400);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("returns 404 for unknown agent", async () => {
|
|
175
|
+
const c = makeMockContext({ param: { agent: "unknown", id: "s1" } });
|
|
176
|
+
const result = makeScanResult();
|
|
177
|
+
await handleGetSessionData(c, result);
|
|
178
|
+
expect(c.json).toHaveBeenCalledWith({ error: "Unknown agent: unknown" }, 404);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("returns 500 when agent throws", async () => {
|
|
182
|
+
const agent = new MockAgent();
|
|
183
|
+
agent.getSessionData = () => {
|
|
184
|
+
throw new Error("DB not found");
|
|
185
|
+
};
|
|
186
|
+
const c = makeMockContext({ param: { agent: "claudecode", id: "s1" } });
|
|
187
|
+
const result = makeScanResult({ agents: [agent] });
|
|
188
|
+
await handleGetSessionData(c, result);
|
|
189
|
+
expect(c.json).toHaveBeenCalledWith({ error: "DB not found" }, 500);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { createApiRoutes } from "../routes.js";
|
|
3
|
+
import type { ScanResult } from "@codesesh/core";
|
|
4
|
+
|
|
5
|
+
describe("createApiRoutes", () => {
|
|
6
|
+
it("returns a Hono instance with route handlers", () => {
|
|
7
|
+
const scanResult = {
|
|
8
|
+
sessions: [],
|
|
9
|
+
byAgent: {},
|
|
10
|
+
agents: [],
|
|
11
|
+
} as unknown as ScanResult;
|
|
12
|
+
const app = createApiRoutes(scanResult);
|
|
13
|
+
expect(app).toBeDefined();
|
|
14
|
+
expect(app.fetch).toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type { ScanResult, SessionData, SessionHead } from "@codesesh/core";
|
|
3
|
+
import { getAgentInfoMap } from "@codesesh/core";
|
|
4
|
+
|
|
5
|
+
export function handleGetAgents(c: Context, scanResult: ScanResult) {
|
|
6
|
+
const counts: Record<string, number> = {};
|
|
7
|
+
for (const agent of scanResult.agents) {
|
|
8
|
+
counts[agent.name] = scanResult.byAgent[agent.name]?.length ?? 0;
|
|
9
|
+
}
|
|
10
|
+
const info = getAgentInfoMap(counts);
|
|
11
|
+
return c.json(info);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function handleGetSessions(c: Context, scanResult: ScanResult) {
|
|
15
|
+
const agent = c.req.query("agent");
|
|
16
|
+
const q = c.req.query("q")?.toLowerCase();
|
|
17
|
+
const cwd = c.req.query("cwd")?.toLowerCase();
|
|
18
|
+
const from = c.req.query("from");
|
|
19
|
+
const to = c.req.query("to");
|
|
20
|
+
|
|
21
|
+
let sessions: SessionHead[] = [];
|
|
22
|
+
|
|
23
|
+
// If agent filter is specified, use byAgent directly
|
|
24
|
+
if (agent && scanResult.byAgent[agent]) {
|
|
25
|
+
sessions = [...scanResult.byAgent[agent]!];
|
|
26
|
+
} else {
|
|
27
|
+
sessions = [...scanResult.sessions];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (cwd) {
|
|
31
|
+
sessions = sessions.filter((s) => s.directory.toLowerCase().includes(cwd));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (from) {
|
|
35
|
+
const fromTs = new Date(from).getTime();
|
|
36
|
+
if (!Number.isNaN(fromTs)) {
|
|
37
|
+
sessions = sessions.filter((s) => s.time_created >= fromTs);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (to) {
|
|
42
|
+
const toTs = new Date(to).getTime();
|
|
43
|
+
if (!Number.isNaN(toTs)) {
|
|
44
|
+
sessions = sessions.filter((s) => s.time_created <= toTs);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (q) {
|
|
49
|
+
sessions = sessions.filter((s) => s.title.toLowerCase().includes(q));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return c.json({ sessions });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function handleGetSessionData(c: Context, scanResult: ScanResult) {
|
|
56
|
+
const agentName = c.req.param("agent");
|
|
57
|
+
const sessionId = c.req.param("id");
|
|
58
|
+
|
|
59
|
+
if (!sessionId) {
|
|
60
|
+
return c.json({ error: "Missing session ID" }, 400);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const agent = scanResult.agents.find((a) => a.name === agentName);
|
|
64
|
+
|
|
65
|
+
if (!agent) {
|
|
66
|
+
return c.json({ error: `Unknown agent: ${agentName}` }, 404);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const data: SessionData = agent.getSessionData(sessionId);
|
|
71
|
+
return c.json(data);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
const message = err instanceof Error ? err.message : "Failed to load session";
|
|
74
|
+
return c.json({ error: message }, 500);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { ScanResult } from "@codesesh/core";
|
|
3
|
+
import { handleGetAgents, handleGetSessions, handleGetSessionData } from "./handlers.js";
|
|
4
|
+
|
|
5
|
+
export function createApiRoutes(scanResult: ScanResult): Hono {
|
|
6
|
+
const api = new Hono();
|
|
7
|
+
|
|
8
|
+
api.get("/agents", (c) => handleGetAgents(c, scanResult));
|
|
9
|
+
api.get("/sessions", (c) => handleGetSessions(c, scanResult));
|
|
10
|
+
api.get("/sessions/:agent/:id", (c) => handleGetSessionData(c, scanResult));
|
|
11
|
+
|
|
12
|
+
return api;
|
|
13
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
import { createServer } from "../server.js";
|
|
3
|
+
import { printScanResults } from "../output.js";
|
|
4
|
+
import { scanSessions, createRegisteredAgents } from "@codesesh/core";
|
|
5
|
+
|
|
6
|
+
export const serveCommand = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "serve",
|
|
9
|
+
description: "Scan sessions and start web server",
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
port: {
|
|
13
|
+
type: "string",
|
|
14
|
+
alias: "p",
|
|
15
|
+
default: "4321",
|
|
16
|
+
},
|
|
17
|
+
agent: {
|
|
18
|
+
type: "string",
|
|
19
|
+
alias: "a",
|
|
20
|
+
},
|
|
21
|
+
cwd: {
|
|
22
|
+
type: "string",
|
|
23
|
+
},
|
|
24
|
+
from: {
|
|
25
|
+
type: "string",
|
|
26
|
+
},
|
|
27
|
+
to: {
|
|
28
|
+
type: "string",
|
|
29
|
+
},
|
|
30
|
+
json: {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
alias: "j",
|
|
33
|
+
default: false,
|
|
34
|
+
},
|
|
35
|
+
"no-open": {
|
|
36
|
+
type: "boolean",
|
|
37
|
+
default: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
async run({ args }) {
|
|
41
|
+
const port = parseInt(args.port as string, 10) || 4321;
|
|
42
|
+
const noOpen = args["no-open"] as boolean;
|
|
43
|
+
const jsonOnly = args.json as boolean;
|
|
44
|
+
|
|
45
|
+
// Scan sessions
|
|
46
|
+
const result = scanSessions();
|
|
47
|
+
const agents = createRegisteredAgents();
|
|
48
|
+
|
|
49
|
+
if (jsonOnly) {
|
|
50
|
+
const { getAgentInfoMap } = await import("@codesesh/core");
|
|
51
|
+
const info = getAgentInfoMap(
|
|
52
|
+
Object.fromEntries(Object.entries(result.byAgent).map(([k, v]) => [k, v.length])),
|
|
53
|
+
);
|
|
54
|
+
const output = {
|
|
55
|
+
agents: info.map(({ name, displayName, count }) => ({
|
|
56
|
+
name,
|
|
57
|
+
displayName,
|
|
58
|
+
count,
|
|
59
|
+
available: count > 0,
|
|
60
|
+
})),
|
|
61
|
+
sessions: result.sessions,
|
|
62
|
+
};
|
|
63
|
+
console.log(JSON.stringify(output, null, 2));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Print console output
|
|
68
|
+
printScanResults(agents, result);
|
|
69
|
+
|
|
70
|
+
// Start server
|
|
71
|
+
const { url } = await createServer(port, result);
|
|
72
|
+
|
|
73
|
+
if (!noOpen) {
|
|
74
|
+
const open = (await import("open")).default;
|
|
75
|
+
await open(url);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
});
|