getgloss 0.3.0 → 0.4.1
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/README.md +12 -18
- package/dist/cli/index.js +397 -299
- package/dist/cli/index.js.map +1 -1
- package/dist/server/daemon.js +239 -28
- package/dist/server/daemon.js.map +1 -1
- package/dist/web/assets/index-Da2TNJX9.js +188 -0
- package/dist/web/assets/index-uGiivUSv.css +1 -0
- package/dist/web/index.html +2 -2
- package/dist/web/prompt.md +13 -6
- package/dist/web/setup/index.html +4 -1
- package/dist/web/setup.md +18 -4
- package/package.json +2 -4
- package/skill/SKILL.md +7 -2
- package/dist/mcp/index.js +0 -378
- package/dist/mcp/index.js.map +0 -1
- package/dist/web/assets/index-DuGSsf8O.js +0 -181
- package/dist/web/assets/index-SRKfUpIg.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&display=swap";/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@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-border-style:solid;--tw-outline-style:solid;--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}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--font-weight-medium:500;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@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%;-moz-tab-size:4;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;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]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.fixed{position:fixed}.block{display:block}.contents{display:contents}.hidden{display:none}.rounded{border-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);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-filter{-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,)}}:root{color-scheme:dark;--color-midnight-ink:#111;--color-ghost-ash:#f9f9f9;--color-deep-graphite:#2b2b2b;--color-muted-stone:#b7b3a2;--color-light-grayscale:#eee;--color-shadow-ink:#000;--color-subtle-gray:#d6d6d6;--color-midtone-gray:#6e6e6e;--color-silver-mist:#9c9c9c;--color-dark-frost:#222;--color-slate-border:#565656;--font-primary:"JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;--font-mono:var(--font-primary);--text-caption:10px;--text-small:12px;--text-body:16px;--text-subheading:20px;--text-heading:24px;--text-display:80px;--leading-caption:1.73;--leading-body:1.5;--leading-subheading:1.3;--leading-heading:1.2;--leading-display:.9;--font-weight-regular:400;--font-weight-medium:500;--spacing-8:8px;--spacing-16:16px;--spacing-24:24px;--spacing-32:32px;--spacing-40:40px;--spacing-48:48px;--spacing-64:64px;--spacing-80:80px;--spacing-96:96px;--spacing-128:128px;--spacing-144:144px;--spacing-192:192px;--page-max-width:1200px;--section-gap:48px;--card-padding:32px;--element-gap:16px;--radius-nav:4px;--radius-cards:12px;--radius-buttons:4px;--radius-decorative:20px;--radius-panel:8px;--grid-line:#f9f9f90e;--surface-dark:var(--color-midnight-ink);--surface-inset:#191919;--surface-raised:var(--color-dark-frost);--surface-strong:var(--color-deep-graphite);--surface-soft:#f9f9f90b;--border-soft:#d6d6d62e;--border-strong:var(--color-slate-border);--text-primary:var(--color-ghost-ash);--text-secondary:var(--color-silver-mist);--text-muted:var(--color-muted-stone);--site-accent:#3fb950;--site-accent-hover:#56d364;--site-accent-muted:#2ea04326;--accent:var(--site-accent);--ide-bg:#0d1117;--ide-bg-muted:#151b23;--ide-fg:#f0f6fc;--ide-fg-muted:#9198a1;--ide-border:#3d444d;--ide-success:#3fb950;--ide-success-muted:#2ea04326;--ide-success-gutter:#3fb9504d;--ide-success-word:#2ea04366;--ide-danger:#f85149;--ide-danger-muted:#f851491a;--ide-danger-gutter:#f851494d;--ide-danger-word:#f8514966;--ide-warning:#d29922;--ide-warning-muted:#bb800926;--ide-warning-border:#bb800966;--ide-accent:#4493f8;--ide-accent-muted:#388bfd1a;--ide-accent-border:#388bfd66;font-family:var(--font-primary);background:var(--surface-dark);color:var(--text-primary);font-weight:var(--font-weight-regular)}*{box-sizing:border-box}html{background:var(--surface-dark);scroll-behavior:smooth}body{background:linear-gradient(var(--grid-line) 1px,transparent 1px),linear-gradient(90deg,var(--grid-line) 1px,transparent 1px),var(--surface-dark);min-width:320px;min-height:100vh;color:var(--text-primary);background-size:32px 32px;margin:0}button,textarea{font:inherit}button{color:inherit}a,button{-webkit-tap-highlight-color:transparent}a:focus-visible,button:focus-visible,textarea:focus-visible{outline:2px solid var(--accent);outline-offset:2px}code,pre{font-family:var(--font-mono)}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.brand-mark{border:1px solid var(--border-soft);border-radius:var(--radius-nav);background:var(--color-shadow-ink);width:28px;height:28px;display:block}.muted{color:var(--text-secondary);font-size:var(--text-small);line-height:var(--leading-body);margin:4px 0 0}.primary-button,.secondary-button,.icon-button,.marketing-copy,.hero-primary,.hero-secondary,.scene-composer button,.scene-inline-comment button,.scene-submit button{border-radius:var(--radius-buttons)}.primary-button,.secondary-button,.icon-button{cursor:pointer;border:1px solid #0000;justify-content:center;align-items:center;display:inline-flex}.primary-button{gap:var(--spacing-8);min-height:36px;padding:0 var(--spacing-16);background:var(--accent);color:var(--color-midnight-ink);font-size:var(--text-small);font-weight:var(--font-weight-medium)}.primary-button:hover:not(:disabled){background:var(--site-accent-hover)}.primary-button:disabled{cursor:default;opacity:.58}.secondary-button{gap:var(--spacing-8);min-height:36px;padding:0 var(--spacing-16);border:1px solid var(--ide-border);color:var(--ide-fg);font-size:var(--text-small);font-weight:var(--font-weight-medium);background:0 0}.secondary-button:hover{border-color:var(--ide-warning-border);background:var(--ide-warning-muted)}.icon-button{width:28px;height:28px;color:var(--text-secondary);background:0 0}.icon-button:hover{border-color:var(--border-soft);background:var(--surface-strong);color:var(--text-primary)}.spin{animation:1s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.review-shell{width:min(1320px,100vw - 32px);padding:var(--spacing-16) 0 112px;margin:0 auto}.topbar{z-index:5;justify-content:space-between;align-items:center;gap:var(--spacing-16);padding:var(--spacing-16) 0;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border-bottom:1px solid var(--border-soft);background:#111111f0;display:flex;position:sticky;top:0}.topbar-main{align-items:flex-start;gap:var(--spacing-16);min-width:0;display:flex}.review-heading{min-width:0}.review-heading h1{color:var(--text-primary);font-size:var(--text-subheading);font-weight:var(--font-weight-medium);letter-spacing:0;margin:0}.brand-row{align-items:center;gap:10px;display:flex}.brand-row h1{color:var(--text-primary);font-size:var(--text-subheading);font-weight:var(--font-weight-medium);letter-spacing:0;margin:0}.product-name{color:var(--text-secondary);font-size:var(--text-small);font-weight:var(--font-weight-medium);margin:0 0 2px}.meta-row{flex-wrap:wrap;gap:6px;margin-top:7px;display:flex}.meta-row span{border:1px solid var(--border-soft);border-radius:var(--radius-nav);background:var(--surface-raised);max-width:min(46vw,420px);min-height:24px;color:var(--text-secondary);font-size:var(--text-small);padding:0 var(--spacing-8);text-overflow:ellipsis;white-space:nowrap;align-items:center;line-height:1;display:inline-flex;overflow:hidden}.branch-pill{align-items:center;gap:var(--spacing-8);border:1px solid var(--border-soft);border-radius:var(--radius-nav);background:var(--surface-raised);min-width:0;max-width:46vw;color:var(--text-primary);font-size:var(--text-small);padding:7px 10px;display:inline-flex}.branch-pill span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.review-state-banner{align-items:center;gap:var(--spacing-16);margin-top:var(--spacing-16);border:1px solid var(--ide-border);border-radius:var(--radius-panel);color:var(--ide-fg-muted);font-size:var(--text-small);background:#151b23e6;padding:10px 12px;display:flex}.review-state-banner.resolved{border-color:var(--ide-success)}@supports (color:color-mix(in lab,red,red)){.review-state-banner.resolved{border-color:color-mix(in srgb,var(--ide-success) 50%,var(--ide-border))}}.review-state-banner.resolved{background:var(--ide-success)}@supports (color:color-mix(in lab,red,red)){.review-state-banner.resolved{background:color-mix(in srgb,var(--ide-success) 12%,#151b23e6)}}.review-state-title{align-items:center;gap:var(--spacing-8);color:var(--ide-fg);font-weight:var(--font-weight-medium);flex:none;display:inline-flex}.review-state-title svg{color:var(--ide-success)}.review-state-banner p{text-overflow:ellipsis;white-space:nowrap;min-width:0;margin:0;overflow:hidden}.review-state-banner time{color:var(--ide-fg-muted);white-space:nowrap;margin-left:auto}.diff-stack{gap:var(--spacing-16);padding-top:var(--spacing-16);display:grid}.file-card{border:1px solid var(--ide-border);border-radius:var(--radius-cards);background:var(--ide-bg);overflow:hidden}.file-header{width:100%;padding:11px var(--spacing-16);border:0;border-bottom:1px solid var(--ide-border);background:var(--ide-bg-muted);cursor:pointer;text-align:left;grid-template-columns:auto auto minmax(0,1fr) auto auto auto;align-items:center;gap:10px;display:grid}.file-header:hover{background:var(--ide-accent-muted)}.file-path,.rename-path{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.file-path{color:var(--ide-fg);font-family:var(--font-mono);font-size:13px}.rename-path{max-width:240px;color:var(--ide-fg-muted);font-size:var(--text-small)}.stat{font-family:var(--font-mono);font-size:var(--text-small);font-weight:var(--font-weight-medium)}.stat.add{color:var(--ide-success)}.stat.del{color:var(--ide-danger)}.diff-table{border:0;width:100%;margin:0;padding:6px 0;overflow-x:auto}.hunk+.hunk{border-top:1px solid var(--ide-border)}.hunk-header,.hidden-lines,.binary-note{background:var(--ide-accent-muted);width:100%;color:var(--ide-fg-muted);font-family:var(--font-mono);font-size:var(--text-small);text-align:left;border:0}.hunk-header{padding:var(--spacing-8) var(--spacing-16)}.hidden-lines{padding:7px var(--spacing-16);cursor:pointer;display:block}.hidden-lines:hover{color:var(--ide-accent)}.binary-note{padding:var(--spacing-16)}.diff-row{--range-background:var(--ide-accent)}@supports (color:color-mix(in lab,red,red)){.diff-row{--range-background:color-mix(in srgb, var(--ide-accent) 28%, var(--ide-bg-muted))}}.diff-row{--range-border:var(--ide-accent-border);--range-gutter-background:var(--ide-accent)}@supports (color:color-mix(in lab,red,red)){.diff-row{--range-gutter-background:color-mix(in srgb, var(--ide-accent) 40%, var(--ide-bg-muted))}}.diff-row{--range-rail:var(--ide-accent);width:100%;min-height:26px;color:var(--ide-fg);cursor:cell;text-align:left;background:0 0;border:0;grid-template-columns:58px 58px 24px minmax(680px,1fr);align-items:stretch;display:grid;position:relative}.diff-row:hover{background:var(--ide-accent-muted)}.diff-row.read-only{cursor:default}.diff-row.read-only:hover{background:0 0}.diff-row.add.read-only:hover{background:var(--ide-success-muted)}.diff-row.delete.read-only:hover{background:var(--ide-danger-muted)}.diff-row.add{background:var(--ide-success-muted)}.diff-row.delete{background:var(--ide-danger-muted)}.diff-row.add:hover{background:var(--ide-success-gutter)}.diff-row.delete:hover{background:var(--ide-danger-gutter)}.diff-row.range-selected{background:var(--range-background);box-shadow:none}.diff-row.add.range-selected{--range-background:var(--ide-success)}@supports (color:color-mix(in lab,red,red)){.diff-row.add.range-selected{--range-background:color-mix(in srgb, var(--ide-success) 28%, color-mix(in srgb, var(--ide-accent) 24%, var(--ide-bg-muted)))}}.diff-row.add.range-selected{--range-border:var(--ide-success)}@supports (color:color-mix(in lab,red,red)){.diff-row.add.range-selected{--range-border:color-mix(in srgb, var(--ide-success) 70%, var(--ide-accent))}}.diff-row.add.range-selected{--range-gutter-background:var(--ide-accent)}@supports (color:color-mix(in lab,red,red)){.diff-row.add.range-selected{--range-gutter-background:color-mix(in srgb, var(--ide-accent) 40%, color-mix(in srgb, var(--ide-success) 18%, var(--ide-bg-muted)))}}.diff-row.add.range-selected{--range-rail:var(--ide-success)}.diff-row.delete.range-selected{--range-background:var(--ide-danger)}@supports (color:color-mix(in lab,red,red)){.diff-row.delete.range-selected{--range-background:color-mix(in srgb, var(--ide-danger) 30%, color-mix(in srgb, var(--ide-accent) 28%, var(--ide-bg-muted)))}}.diff-row.delete.range-selected{--range-border:var(--ide-danger)}@supports (color:color-mix(in lab,red,red)){.diff-row.delete.range-selected{--range-border:color-mix(in srgb, var(--ide-danger) 72%, var(--ide-accent))}}.diff-row.delete.range-selected{--range-gutter-background:var(--ide-accent)}@supports (color:color-mix(in lab,red,red)){.diff-row.delete.range-selected{--range-gutter-background:color-mix(in srgb, var(--ide-accent) 42%, color-mix(in srgb, var(--ide-danger) 18%, var(--ide-bg-muted)))}}.diff-row.delete.range-selected{--range-rail:var(--ide-danger)}.selection-rail{z-index:2;background:repeating-linear-gradient(to bottom,var(--range-rail) 0 2px,var(--range-rail) 2px 3px,transparent 3px 5px);width:6px;position:absolute;top:0;bottom:0;left:0}@supports (color:color-mix(in lab,red,red)){.selection-rail{background:repeating-linear-gradient(to bottom,var(--range-rail) 0 2px,color-mix(in srgb,var(--range-rail) 42%,transparent) 2px 3px,transparent 3px 5px)}}.selection-rail{pointer-events:none}.diff-row.range-start{box-shadow:inset 0 1px var(--range-border)}.diff-row.range-end{box-shadow:inset 0 -1px var(--range-border)}.diff-row.range-single{box-shadow:inset 0 1px var(--range-border),inset 0 -1px var(--range-border)}.diff-row.range-continues{box-shadow:none}.diff-row.range-single.range-continues{box-shadow:inset 0 1px var(--range-border)}.line-number{-webkit-user-select:none;user-select:none;border-right:1px solid var(--ide-border);color:var(--ide-fg-muted);font-family:var(--font-mono);font-size:var(--text-small);text-align:right;padding-right:10px;line-height:26px}.marker{-webkit-user-select:none;user-select:none;color:var(--ide-fg-muted);font-family:var(--font-mono);font-size:var(--text-small);text-align:center;line-height:26px}.diff-row.add .line-number{background:var(--ide-success-gutter)}.diff-row.delete .line-number{background:var(--ide-danger-gutter)}.diff-row.add .marker{color:var(--ide-success)}.diff-row.delete .marker{color:var(--ide-danger)}.diff-row.range-selected .line-number{background:var(--range-gutter-background);color:var(--ide-fg)}.diff-row.range-selected .marker{color:var(--range-rail)}.diff-row code{white-space:pre;font-family:var(--font-mono);font-size:12.5px;line-height:26px;overflow:visible}.inline-comment{gap:var(--spacing-8);padding:var(--spacing-8) 10px;border:1px solid var(--ide-warning-border);border-radius:var(--radius-nav);background:var(--ide-warning-muted);color:var(--ide-fg);align-items:flex-start;margin:4px 12px 8px 140px;font-size:13px;display:flex}.inline-comment.resolved{border-color:var(--ide-success)}@supports (color:color-mix(in lab,red,red)){.inline-comment.resolved{border-color:color-mix(in srgb,var(--ide-success) 45%,var(--ide-border))}}.inline-comment.resolved{background:var(--ide-success-muted)}@supports (color:color-mix(in lab,red,red)){.inline-comment.resolved{background:color-mix(in srgb,var(--ide-success-muted) 70%,var(--ide-bg-muted))}}.inline-comment.resolved{color:var(--ide-fg)}@supports (color:color-mix(in lab,red,red)){.inline-comment.resolved{color:color-mix(in srgb,var(--ide-fg) 76%,var(--ide-fg-muted))}}.inline-comment svg{color:var(--ide-warning);flex:none}.inline-comment.resolved svg{color:var(--ide-success)}.inline-comment-content{gap:4px;min-width:0;display:grid}.inline-comment-status{color:var(--ide-fg-muted);font-size:11px;font-weight:var(--font-weight-medium);text-transform:uppercase;line-height:1.2}.inline-comment-body,.inline-comment-summary{overflow-wrap:anywhere}.inline-comment-summary{color:var(--ide-fg-muted);font-size:12px;line-height:1.4}.draft-comment-shell{--draft-range-background:var(--ide-accent)}@supports (color:color-mix(in lab,red,red)){.draft-comment-shell{--draft-range-background:color-mix(in srgb, var(--ide-accent) 28%, var(--ide-bg-muted))}}.draft-comment-shell{--draft-range-border:var(--ide-accent-border);background:var(--draft-range-background);width:100%;box-shadow:inset 0 -1px var(--draft-range-border);padding:10px 12px 10px 140px}.draft-comment-card{border:1px solid var(--ide-border);border-radius:var(--radius-cards);width:min(1040px,100%);color:var(--ide-fg);background:#262626;gap:0;display:grid;overflow:hidden}.draft-comment-title{justify-content:space-between;align-items:center;gap:var(--spacing-16);min-height:48px;padding:0 var(--spacing-16);color:var(--ide-fg);font-size:14px;font-weight:var(--font-weight-medium);border-bottom:1px solid #f0f6fc0f;display:flex}.draft-comment-heading{align-items:center;gap:12px;min-width:0;display:inline-flex}.draft-comment-icon{width:28px;height:28px;color:var(--ide-fg);background:#151515;border:1px solid #f0f6fc21;border-radius:999px;flex:none;justify-content:center;align-items:center;display:inline-flex}.draft-comment-label{color:var(--ide-fg-muted);font-size:var(--text-small);font-weight:var(--font-weight-regular);text-align:right;white-space:nowrap;flex:0 auto}.draft-comment-card textarea{resize:vertical;width:100%;min-height:72px;color:var(--ide-fg);padding:14px var(--spacing-16);font-family:var(--font-mono);background:0 0;border:0;border-radius:0;outline:none;font-size:14px;line-height:1.45}.draft-comment-card textarea::placeholder{color:#f0f6fc57}.draft-comment-actions{justify-content:flex-end;align-items:center;gap:var(--spacing-8);padding:0 var(--spacing-16) 12px;display:flex}.draft-comment-actions .secondary-button{min-height:34px;color:var(--ide-fg-muted);background:0 0;border-color:#0000;padding:0 10px;font-size:14px}.draft-comment-actions .secondary-button:hover{color:var(--ide-fg);background:0 0;border-color:#0000}.draft-comment-actions .primary-button{min-height:34px;padding:0 var(--spacing-16);color:var(--ide-bg);background:#8b949e;border-color:#8b949e;font-size:14px}.draft-comment-actions .primary-button:hover:not(:disabled){background:#b1bac4;border-color:#b1bac4}.popover{z-index:20;width:min(360px,100vw - 24px);padding:var(--spacing-16);border:1px solid var(--ide-border);border-radius:var(--radius-panel);background:var(--ide-bg-muted);position:fixed}.popover-title{color:var(--ide-fg);font-size:13px;font-weight:var(--font-weight-medium);justify-content:space-between;align-items:center;display:flex}.popover-subtitle{color:var(--ide-fg-muted);font-size:var(--text-small);margin-top:2px}.popover textarea{resize:vertical;border:1px solid var(--ide-border);background:var(--ide-bg);width:100%;min-height:96px;color:var(--ide-fg);border-radius:0;outline:none;margin-top:10px;padding:9px}.popover textarea:focus{border-color:var(--ide-accent)}.popover-actions,.submit-actions{justify-content:flex-end;align-items:center;gap:10px;display:flex}.popover-actions{margin-top:10px}.submit-bar{right:var(--spacing-16);bottom:var(--spacing-16);left:var(--spacing-16);z-index:10;justify-content:space-between;align-items:center;gap:var(--spacing-16);border:1px solid var(--ide-border);border-radius:var(--radius-cards);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);background:#151b23f5;width:min(1320px,100vw - 32px);margin:0 auto;padding:12px;display:flex;position:fixed}.comment-list{gap:var(--spacing-8);flex:1;min-width:0;display:flex;overflow-x:auto}.comment-chip{align-items:center;gap:var(--spacing-8);border:1px solid var(--ide-warning-border);border-radius:var(--radius-nav);background:var(--ide-warning-muted);min-width:max-content;color:var(--ide-fg);font-family:var(--font-mono);font-size:var(--text-small);padding:5px 7px 5px 10px;display:inline-flex}.comment-chip .icon-button{color:var(--ide-warning)}.submit-message{max-width:36vw;color:var(--ide-fg-muted);text-overflow:ellipsis;white-space:nowrap;font-size:13px;overflow:hidden}.submit-message.error{color:var(--ide-danger)}.submit-message.done{color:var(--ide-success)}.empty-shell{min-height:100vh;padding:var(--spacing-24);place-items:center;display:grid}.empty-panel,.empty-diff{border:1px solid var(--border-soft);border-radius:var(--radius-cards);background:var(--surface-raised)}.empty-panel{width:min(420px,100%);padding:var(--spacing-24);text-align:center}.empty-panel h1{margin:0 0 var(--spacing-8);font-size:var(--text-heading);font-weight:var(--font-weight-medium)}.empty-panel p{color:var(--text-secondary)}.empty-diff{padding:var(--spacing-24);color:var(--text-secondary)}.setup-page{width:min(860px,100vw - 32px);padding:var(--spacing-32) 0 var(--spacing-80);margin:0 auto}.setup-nav{z-index:3;justify-content:space-between;align-items:center;gap:var(--spacing-16);margin-bottom:var(--spacing-64);padding:var(--spacing-16) 0;border-bottom:1px solid var(--border-soft);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);font-size:var(--text-small);background:#111111f0;display:flex;position:sticky;top:0}.setup-nav>a:not(.marketing-wordmark),.setup-note a{color:var(--accent);text-decoration:none}.setup-nav>a:not(.marketing-wordmark):hover,.setup-note a:hover{text-decoration:underline}.setup-header h1{max-width:760px;color:var(--text-primary);font-size:64px;font-weight:var(--font-weight-medium);line-height:var(--leading-display);letter-spacing:0;margin:0}.setup-header p{max-width:660px;margin:var(--spacing-16) 0 0;color:var(--text-secondary);font-size:var(--text-body);line-height:var(--leading-body)}.setup-section{margin-top:var(--section-gap);border-top:1px solid var(--border-soft);padding-top:var(--spacing-32)}.setup-section h2{margin:0 0 var(--spacing-16);color:var(--accent);font-size:var(--text-small);font-weight:var(--font-weight-medium);letter-spacing:0;text-transform:uppercase}.setup-section p,.setup-section li{color:var(--color-subtle-gray);font-size:15px;line-height:1.65}.setup-section ul{margin:12px 0 0;padding-left:22px}.setup-section pre{overflow-wrap:anywhere;border:1px solid var(--border-soft);border-radius:var(--radius-panel);background:var(--surface-raised);color:var(--text-primary);padding:var(--spacing-16);white-space:pre-wrap;margin:12px 0 0;font-size:13px;line-height:1.7;overflow-x:auto}.setup-section code{color:var(--text-primary)}.setup-note{margin-top:var(--section-gap);border:1px solid var(--border-strong);border-radius:var(--radius-cards);background:var(--surface-raised);padding:var(--spacing-16)}.setup-note p{color:var(--color-subtle-gray);margin:0;font-size:15px;line-height:1.65}.marketing-page{--marketing-max:var(--page-max-width);background:var(--surface-dark);min-height:100vh}.marketing-hero{border-bottom:1px solid var(--border-soft);background:linear-gradient(to bottom,transparent 68%,var(--surface-dark) 100%),linear-gradient(var(--grid-line) 1px,transparent 1px),linear-gradient(90deg,var(--grid-line) 1px,transparent 1px),var(--surface-dark);min-height:100vh;padding-bottom:var(--spacing-64);background-size:100% 100%,32px 32px,32px 32px}.marketing-wordmark{color:var(--text-primary);font-weight:var(--font-weight-medium);align-items:center;gap:9px;margin-right:auto;text-decoration:none;display:inline-flex}.marketing-wordmark .brand-mark{width:26px;height:26px}.hero-copy{width:min(var(--marketing-max),calc(100vw - 40px));gap:var(--spacing-64);padding:var(--spacing-80) 0 var(--spacing-32);grid-template-columns:minmax(0,760px) minmax(260px,360px);align-items:end;margin:0 auto;display:grid}.hero-copy-main{min-width:0}.hero-logo{margin-bottom:var(--spacing-32);display:inline-flex}.hero-logo .brand-mark{width:76px;height:76px}.hero-kicker,.section-heading p{color:var(--accent);font-size:var(--text-small);font-weight:var(--font-weight-medium);letter-spacing:0;text-transform:uppercase;margin:0}.hero-copy h1{color:var(--text-primary);font-size:var(--text-display);font-weight:var(--font-weight-medium);line-height:var(--leading-display);letter-spacing:0;margin:0}.hero-subtitle{max-width:720px;margin:var(--spacing-16) 0 0;color:var(--text-primary);font-size:40px;font-weight:var(--font-weight-medium);line-height:1}.hero-body{max-width:640px;margin:var(--spacing-16) 0 0;color:var(--color-subtle-gray);font-size:var(--text-body);line-height:var(--leading-body)}.hero-actions{margin-top:var(--spacing-24);flex-wrap:wrap;gap:10px;display:flex}.hero-primary,.hero-secondary{justify-content:center;align-items:center;gap:var(--spacing-8);min-height:42px;padding:0 var(--spacing-16);font-size:var(--text-body);font-weight:var(--font-weight-medium);text-decoration:none;display:inline-flex}.hero-primary{border:1px solid var(--accent);background:var(--accent);color:var(--color-midnight-ink)}.hero-primary:hover{border-color:var(--site-accent-hover);background:var(--site-accent-hover);color:var(--color-midnight-ink);text-decoration:none}.hero-secondary{border:1px solid var(--accent);color:var(--accent);background:0 0}.hero-secondary:hover{background:var(--site-accent-muted);text-decoration:none}.hero-quickstart{border-left:2px solid var(--accent);padding:2px 0 2px var(--spacing-16);justify-items:start;gap:10px;display:grid}.hero-quickstart span{color:var(--text-secondary);font-size:var(--text-small);font-weight:var(--font-weight-medium)}.hero-quickstart code{max-width:100%;color:var(--text-primary);font-family:var(--font-mono);font-size:var(--text-small);white-space:nowrap;line-height:1.55;overflow-x:auto}.hero-scene{width:min(var(--marketing-max),calc(100vw - 40px));border:1px solid var(--ide-border);border-radius:var(--radius-cards);background:var(--ide-bg);margin:0 auto;overflow:hidden}.demo-interaction-hint{width:min(var(--marketing-max),calc(100vw - 40px));align-items:center;gap:var(--spacing-8);margin:0 auto var(--spacing-16);border-left:2px solid var(--accent);padding-left:var(--spacing-16);color:var(--color-subtle-gray);font-size:14px;line-height:1.5;display:flex}.demo-interaction-hint svg,.demo-interaction-hint strong{color:var(--accent)}.demo-interaction-hint strong{font-weight:var(--font-weight-medium)}.scene-topbar,.scene-shell,.scene-submit{min-width:0}.scene-topbar{justify-content:space-between;align-items:center;gap:var(--spacing-16);border-bottom:1px solid var(--ide-border);background:var(--ide-bg-muted);padding:10px 12px;display:flex}.scene-brand,.scene-meta,.terminal-header,.feedback-title{align-items:center;gap:var(--spacing-8);min-width:0;color:var(--ide-fg-muted);font-size:var(--text-small);display:flex}.scene-meta span,.feedback-title span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.scene-shell{background:var(--ide-bg);grid-template-rows:auto minmax(0,1fr);grid-template-columns:minmax(0,1fr) minmax(320px,.42fr);display:grid}.scene-terminal{border-bottom:1px solid var(--ide-border);background:var(--ide-bg);grid-column:1/-1;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:14px;padding:10px 12px;display:grid}.terminal-lines{min-width:0;color:var(--ide-fg-muted);font-family:var(--font-mono);font-size:var(--text-small);white-space:nowrap;gap:14px;display:flex;overflow:hidden}.terminal-lines p{margin:0}.terminal-lines span{color:var(--ide-success)}.scene-review{min-height:520px;position:relative;overflow:hidden}.scene-file-header{align-items:center;gap:var(--spacing-8);border:0;border-bottom:1px solid var(--ide-border);background:var(--ide-bg-muted);width:100%;color:var(--ide-fg);cursor:default;text-align:left;grid-template-columns:auto auto minmax(0,1fr) auto auto;padding:9px 12px;display:grid}.scene-file-header span{font-family:var(--font-mono);font-size:var(--text-small);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.scene-add{color:var(--ide-success);font-size:var(--text-small)}.scene-del{color:var(--ide-danger);font-size:var(--text-small)}.scene-hidden,.scene-hunk{background:var(--ide-accent-muted);width:100%;color:var(--ide-fg-muted);font-family:var(--font-mono);font-size:var(--text-small);text-align:left;border:0}.scene-hidden{padding:var(--spacing-8) 12px;cursor:pointer}.scene-hidden:hover{color:var(--ide-accent)}.scene-hunk{padding:var(--spacing-8) 12px}.scene-row{width:100%;min-height:27px;color:var(--ide-fg);cursor:pointer;font-family:var(--font-mono);font-size:var(--text-small);text-align:left;background:0 0;border:0;grid-template-columns:48px 48px minmax(480px,1fr);align-items:center;padding:0;display:grid}.scene-row:hover{background:var(--ide-accent-muted)}.scene-row span{border-right:1px solid var(--ide-border);color:var(--ide-fg-muted);text-align:right;padding-right:9px;line-height:27px}.scene-row.add span{background:var(--ide-success-gutter)}.scene-row.remove span{background:var(--ide-danger-gutter)}.scene-row code{text-overflow:ellipsis;white-space:pre;min-width:0;padding-left:12px;display:block;overflow:hidden}.scene-row.add{background:var(--ide-success-muted)}.scene-row.add:hover{background:var(--ide-success-gutter)}.scene-row.remove{background:var(--ide-danger-muted)}.scene-row.remove:hover{background:var(--ide-danger-gutter)}.scene-row.selected{outline:1px solid var(--ide-accent-border);outline-offset:-1px}.scene-row.dimmed{color:var(--ide-fg-muted)}.scene-row.agent-dimmed{opacity:.5}.scene-row.agent-applied{outline:1px solid var(--ide-success)}@supports (color:color-mix(in lab,red,red)){.scene-row.agent-applied{outline:1px solid color-mix(in srgb,var(--ide-success) 42%,transparent)}}.scene-row.agent-applied{outline-offset:-1px}.scene-applied-status{border-left:2px solid var(--ide-success);color:var(--ide-success);font-size:var(--text-small);align-items:center;gap:7px;margin:4px 12px 4px 112px;padding:4px 0 4px 10px;display:inline-flex}.scene-inline-comment{border:1px solid var(--ide-warning-border);border-radius:var(--radius-nav);background:var(--ide-warning-muted);color:var(--ide-fg);grid-template-columns:minmax(0,1fr) auto;align-items:stretch;gap:0;margin:4px 12px 4px 112px;font-size:13px;line-height:1.45;display:grid;overflow:hidden}.scene-inline-comment-body{align-items:start;gap:var(--spacing-8);min-width:0;color:inherit;padding:var(--spacing-8) 10px;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;grid-template-columns:auto minmax(0,1fr);display:grid}.scene-inline-comment-body:hover{background:var(--ide-warning)}@supports (color:color-mix(in lab,red,red)){.scene-inline-comment-body:hover{background:color-mix(in srgb,var(--ide-warning) 14%,transparent)}}.scene-inline-comment svg{color:var(--ide-warning);flex:none}.scene-inline-comment span{overflow-wrap:anywhere;min-width:0}.scene-inline-comment-remove{width:32px;color:var(--ide-fg-muted);cursor:pointer;background:0 0;border:1px solid #0000;justify-content:center;align-items:center;display:inline-flex}.scene-inline-comment-remove:hover{background:var(--ide-warning)}@supports (color:color-mix(in lab,red,red)){.scene-inline-comment-remove:hover{background:color-mix(in srgb,var(--ide-warning) 14%,transparent)}}.scene-inline-comment-remove:hover{color:var(--ide-fg)}.scene-composer{width:min(560px,100% - 124px);margin:var(--spacing-8) 12px 12px 112px;border:1px solid var(--ide-border);border-radius:var(--radius-panel);background:var(--ide-bg-muted);display:grid;overflow:hidden}.scene-composer-title{justify-content:space-between;align-items:center;gap:var(--spacing-16);border-bottom:1px solid #f0f6fc0f;min-height:42px;padding:0 12px;display:flex}.scene-composer-title strong{color:var(--ide-fg);font-size:13px;font-weight:var(--font-weight-medium)}.scene-composer-title span{color:var(--ide-fg-muted);font-size:var(--text-small);text-align:right}.scene-composer textarea{resize:vertical;width:100%;min-height:72px;color:var(--ide-fg);font-family:var(--font-mono);background:0 0;border:0;outline:none;padding:12px;font-size:13px;line-height:1.45}.scene-composer textarea::placeholder{color:#f0f6fc57}.scene-composer-actions{justify-content:flex-end;gap:var(--spacing-8);padding:0 12px 12px;display:flex}.scene-composer button,.scene-submit button{border:1px solid var(--accent);background:var(--accent);min-height:30px;color:var(--color-midnight-ink);font-size:var(--text-small);font-weight:var(--font-weight-medium);cursor:pointer;align-items:center;gap:7px;padding:0 10px;display:inline-flex}.scene-composer button:disabled,.scene-submit button:disabled{cursor:default;opacity:.56}.scene-composer .scene-secondary-action{color:var(--ide-fg-muted);background:0 0;border-color:#0000}.scene-composer .scene-secondary-action:hover{color:var(--ide-fg)}.scene-feedback{border-left:1px solid var(--ide-border);background:var(--ide-bg-muted);grid-template-rows:auto minmax(0,1fr);align-items:stretch;gap:12px;padding:12px;display:grid}.scene-feedback pre{border-radius:var(--radius-nav);background:var(--ide-bg);min-height:0;max-height:100%;color:var(--ide-fg-muted);font-family:var(--font-mono);white-space:pre-wrap;border:1px solid #f0f6fc14;margin:0;padding:10px;font-size:11px;line-height:1.5;overflow:auto}.agent-update-card{align-content:start;gap:var(--spacing-16);border-radius:var(--radius-nav);background:var(--ide-bg);min-height:0;color:var(--ide-fg-muted);border:1px solid #f0f6fc14;padding:12px;display:grid}.agent-update-card code{color:var(--ide-fg);font-family:var(--font-mono);text-overflow:ellipsis;white-space:nowrap;font-size:11px;line-height:1.45;display:block;overflow:hidden}.agent-update-card ul{gap:10px;margin:0;padding:0;display:grid}.agent-update-card li{align-items:center;gap:var(--spacing-8);color:var(--ide-fg);font-size:13px;list-style:none;display:flex}.agent-update-card li svg{color:var(--ide-success);flex:none}.scene-submit{border-top:1px solid var(--ide-border);background:var(--ide-bg-muted);color:var(--ide-fg-muted);justify-content:flex-end;align-items:center;gap:12px;padding:10px;font-size:13px;display:flex}.marketing-band{border-bottom:1px solid var(--border-soft);padding:var(--spacing-80) max(20px,calc((100vw - var(--marketing-max)) / 2));scroll-margin-top:var(--spacing-24)}.section-heading{gap:10px;max-width:760px;display:grid}.section-heading h2{max-width:720px;color:var(--text-primary);font-size:40px;font-weight:var(--font-weight-medium);letter-spacing:0;margin:0;line-height:1.06}.install-grid{margin-top:var(--spacing-32);border-top:1px solid var(--border-soft);gap:0;display:grid}.command-line{border-bottom:1px solid var(--border-soft);color:var(--color-subtle-gray);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:10px;padding:13px 0;display:grid}.command-line>span{color:var(--accent);font-family:var(--font-mono)}.command-line code{color:var(--text-primary);font-family:var(--font-mono);white-space:nowrap;font-size:13px;overflow:auto}.marketing-copy{border:1px solid var(--accent);min-height:30px;color:var(--accent);font-size:var(--text-small);font-weight:var(--font-weight-medium);cursor:pointer;background:0 0;justify-content:center;align-items:center;gap:7px;padding:0 10px;display:inline-flex}.marketing-copy:hover{background:var(--site-accent-muted)}.agent-prompt{align-items:center;gap:var(--spacing-16);margin-top:var(--spacing-24);border-left:2px solid var(--accent);padding:2px 0 2px var(--spacing-16);grid-template-columns:auto minmax(0,1fr) auto;display:grid}.agent-prompt-label,.agent-prompt-links{align-items:center;gap:var(--spacing-8);display:flex}.agent-prompt-label{color:var(--accent);font-size:13px;font-weight:var(--font-weight-medium)}.agent-prompt p{color:var(--text-primary);margin:0;font-size:14px;line-height:1.55}.agent-skill-command{border:1px solid var(--border-soft);border-radius:var(--radius-panel);background:var(--surface-raised);grid-column:1/-1;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:10px;padding:10px 12px;display:grid}.agent-skill-command code{white-space:nowrap;font-size:12px;overflow:auto}.agent-prompt pre{border:1px solid var(--border-soft);border-radius:var(--radius-panel);background:var(--surface-raised);color:var(--text-primary);font-family:var(--font-mono);white-space:pre-wrap;grid-column:1/-2;margin:0;padding:12px;font-size:12px;line-height:1.65;overflow-x:auto}.agent-prompt>.marketing-copy{place-self:start end}.agent-prompt code,.contract-copy code{color:var(--text-primary);font-family:var(--font-mono);font-size:.92em}.agent-prompt-links{white-space:nowrap;justify-content:flex-end}.agent-prompt-links a{color:var(--accent);font-size:13px;font-weight:var(--font-weight-medium);text-decoration:none}.agent-prompt-links a:hover{text-decoration:underline}.workflow-story{margin-top:var(--spacing-32);border-top:1px solid var(--border-soft);gap:0;display:grid}.workflow-step{gap:var(--spacing-24);border-bottom:1px solid var(--border-soft);padding:var(--spacing-24) 0;grid-template-columns:56px minmax(0,1fr);display:grid}.workflow-step:last-child{border-bottom:0}.workflow-step span{color:var(--accent);font-family:var(--font-mono);font-size:var(--text-small)}.workflow-step h3{color:var(--text-primary);font-size:var(--text-subheading);font-weight:var(--font-weight-medium);letter-spacing:0;margin:0}.workflow-step p,.contract-copy p{color:var(--color-subtle-gray);margin:6px 0 0;font-size:14px;line-height:1.65}.contract-layout{gap:var(--spacing-24);margin-top:var(--spacing-32);border-top:1px solid var(--border-soft);padding-top:var(--spacing-24);grid-template-columns:minmax(0,1fr) minmax(280px,.62fr);align-items:center;display:grid}.contract-layout pre{border-left:2px solid var(--border-soft);color:var(--color-subtle-gray);font-family:var(--font-mono);padding:2px 0 2px var(--spacing-16);margin:0;font-size:13px;line-height:1.7;overflow:auto}.contract-copy{max-width:460px}.contract-copy p{border-left:2px solid var(--accent);margin:0;padding-left:12px}.marketing-footer{padding:var(--spacing-32) max(20px,calc((100vw - var(--marketing-max)) / 2));justify-content:center;display:flex}.marketing-footer a{align-items:center;gap:var(--spacing-8);color:var(--accent);font-size:13px;font-weight:var(--font-weight-medium);text-decoration:none;display:inline-flex}.marketing-footer a:hover{text-underline-offset:6px;text-decoration:underline}@media(max-width:980px){.hero-copy,.hero-scene,.demo-interaction-hint{width:min(720px,100vw - 32px)}.hero-copy{gap:var(--spacing-32);padding:var(--spacing-64) 0 var(--spacing-32);grid-template-columns:1fr}.hero-copy h1{font-size:64px}.hero-subtitle,.section-heading h2{font-size:32px}.hero-quickstart{max-width:460px}.scene-terminal,.scene-feedback{grid-template-columns:1fr}.scene-shell{grid-template-columns:minmax(0,1fr)}.scene-feedback{border-top:1px solid var(--ide-border);border-left:0}.terminal-lines{gap:3px;display:grid}.scene-submit{justify-content:space-between}.contract-layout{grid-template-columns:1fr}}@media(max-width:720px){.review-shell{width:calc(100vw - 18px)}.topbar{flex-direction:column;align-items:flex-start}.branch-pill{max-width:100%}.review-state-banner{flex-direction:column;align-items:flex-start;gap:6px}.review-state-banner p{white-space:normal}.review-state-banner time{margin-left:0}.file-header{grid-template-columns:auto auto minmax(0,1fr) auto auto}.rename-path{display:none}.diff-row{grid-template-columns:46px 46px 22px minmax(520px,1fr)}.inline-comment{margin-left:108px}.draft-comment-shell{padding-left:114px}.draft-comment-title{min-height:auto;padding:12px var(--spacing-16);flex-direction:column;align-items:flex-start;gap:4px}.draft-comment-label{text-align:left;white-space:normal}.submit-bar{flex-direction:column;align-items:stretch}.submit-actions{justify-content:space-between}}@media(max-width:640px){.setup-nav{white-space:nowrap;justify-content:flex-start;gap:14px;overflow-x:auto}.marketing-wordmark{min-width:max-content}.hero-copy,.hero-scene,.demo-interaction-hint{width:calc(100vw - 28px)}.hero-copy{padding-top:var(--spacing-48)}.hero-copy h1,.setup-header h1{font-size:48px}.hero-logo .brand-mark{width:58px;height:58px}.hero-subtitle,.section-heading h2{font-size:var(--text-heading);line-height:var(--leading-heading)}.hero-body{font-size:15px}.hero-quickstart{max-width:none}.demo-interaction-hint{flex-direction:column;align-items:flex-start}.scene-meta,.scene-terminal,.scene-feedback{display:none}.scene-review{min-height:560px}.scene-row{grid-template-columns:38px 38px minmax(0,1fr)}.scene-inline-comment,.scene-composer{width:calc(100% - 100px);margin-left:88px}.scene-composer-title{flex-direction:column;align-items:flex-start;gap:3px;padding:10px 12px}.scene-composer-title span{text-align:left}.command-line,.agent-prompt{grid-template-columns:1fr}.agent-prompt-links{justify-content:flex-start}.agent-prompt pre,.agent-skill-command,.agent-prompt>.marketing-copy{grid-column:auto;justify-self:stretch}.agent-skill-command{grid-template-columns:1fr}.agent-skill-command .marketing-copy{justify-self:stretch}.workflow-step{gap:var(--spacing-8);grid-template-columns:1fr}.workflow-step:last-child{border-bottom:0}.marketing-band{padding:var(--spacing-64) var(--spacing-16)}.marketing-footer{padding:var(--spacing-32) var(--spacing-16);justify-content:center}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@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}
|
package/dist/web/index.html
CHANGED
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
content="Comment on local code diffs and save feedback in your repo."
|
|
29
29
|
/>
|
|
30
30
|
<meta name="twitter:image" content="https://getgloss.dev/og.png" />
|
|
31
|
-
<script type="module" crossorigin src="/assets/index-
|
|
32
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
31
|
+
<script type="module" crossorigin src="/assets/index-Da2TNJX9.js"></script>
|
|
32
|
+
<link rel="stylesheet" crossorigin href="/assets/index-uGiivUSv.css">
|
|
33
33
|
</head>
|
|
34
34
|
<body>
|
|
35
35
|
<div id="root"></div>
|
package/dist/web/prompt.md
CHANGED
|
@@ -25,7 +25,11 @@ user clicks Submit in the browser, and that exit is your signal to resume.
|
|
|
25
25
|
When `gloss open --json` exits, parse the JSON output. Prefer reading
|
|
26
26
|
`feedbackPath` from disk when present, because it contains the durable structured
|
|
27
27
|
feedback bundle. Address every comment in file/line order, then run the
|
|
28
|
-
narrowest relevant validation.
|
|
28
|
+
narrowest relevant validation. After validation, run
|
|
29
|
+
`gloss resolve <reviewId> --summary "<what changed>"`.
|
|
30
|
+
When tracking progress comment-by-comment is useful, run
|
|
31
|
+
`gloss resolve <reviewId> --comment <commentId> --summary "<what changed>"`
|
|
32
|
+
after applying that specific comment.
|
|
29
33
|
|
|
30
34
|
If the user only wants a review URL and does not want you to wait, run:
|
|
31
35
|
|
|
@@ -33,15 +37,20 @@ If the user only wants a review URL and does not want you to wait, run:
|
|
|
33
37
|
gloss open --json --no-watch
|
|
34
38
|
```
|
|
35
39
|
|
|
40
|
+
If the user asks for another pass after fixes, commits, or additional changes,
|
|
41
|
+
start a fresh review session with `gloss open --json`.
|
|
42
|
+
|
|
36
43
|
Gloss feedback is stored under:
|
|
37
44
|
|
|
38
45
|
```text
|
|
39
46
|
~/.gloss/reviews/<reviewId>/feedback.json
|
|
40
47
|
~/.gloss/reviews/<reviewId>/feedback.md
|
|
48
|
+
~/.gloss/reviews/<reviewId>/resolved.json
|
|
41
49
|
```
|
|
42
50
|
|
|
43
51
|
Use `feedback.json` for structured agent work. Use `feedback.md` when a human
|
|
44
|
-
readable summary is useful.
|
|
52
|
+
readable summary is useful. Use `resolved.json` as Gloss's mutable resolution
|
|
53
|
+
progress file; do not edit `feedback.json`.
|
|
45
54
|
|
|
46
55
|
Gloss is for code diffs. Do not use it for Markdown plan annotation; use
|
|
47
56
|
Roughdraft for Markdown review if the user has Roughdraft installed.
|
|
@@ -51,9 +60,7 @@ Useful commands:
|
|
|
51
60
|
```bash
|
|
52
61
|
gloss status --json
|
|
53
62
|
gloss watch <reviewId> --json
|
|
63
|
+
gloss resolve <reviewId> --comment <commentId> --summary "Applied one comment"
|
|
64
|
+
gloss resolve <reviewId> --summary "Applied review feedback"
|
|
54
65
|
gloss doctor
|
|
55
|
-
gloss mcp
|
|
56
66
|
```
|
|
57
|
-
|
|
58
|
-
The MCP server exposes tools to list pending reviews, fetch review details,
|
|
59
|
-
watch for completion, read feedback, and mark a review resolved.
|
|
@@ -255,7 +255,9 @@
|
|
|
255
255
|
3. Read feedbackPath from the JSON output.
|
|
256
256
|
4. Address each comment in file and line order.
|
|
257
257
|
5. Validate the fix with the narrowest relevant checks.
|
|
258
|
-
6.
|
|
258
|
+
6. Optionally mark individual comments handled:
|
|
259
|
+
gloss resolve <reviewId> --comment <commentId> --summary "<what changed>"
|
|
260
|
+
7. Run gloss resolve <reviewId> --summary "<what changed>", then summarize what changed.</pre>
|
|
259
261
|
</section>
|
|
260
262
|
|
|
261
263
|
<section>
|
|
@@ -276,6 +278,7 @@
|
|
|
276
278
|
Leave the command running. Gloss exits after the browser review is submitted and writes
|
|
277
279
|
feedback under <code>~/.gloss/reviews/<reviewId>/</code>.
|
|
278
280
|
</p>
|
|
281
|
+
<p>Start a fresh session with the same command for follow-up diffs.</p>
|
|
279
282
|
</section>
|
|
280
283
|
|
|
281
284
|
<section class="note">
|
package/dist/web/setup.md
CHANGED
|
@@ -55,8 +55,10 @@ The skill pairs the CLI with the browser app:
|
|
|
55
55
|
3. Read `feedbackPath` from the JSON output.
|
|
56
56
|
4. Address each comment in file and line order.
|
|
57
57
|
5. Validate the fix with the narrowest relevant checks.
|
|
58
|
-
6.
|
|
59
|
-
changed
|
|
58
|
+
6. Optionally mark individual comments handled with
|
|
59
|
+
`gloss resolve <reviewId> --comment <commentId> --summary "<what changed>"`.
|
|
60
|
+
7. Run `gloss resolve <reviewId> --summary "<what changed>"`, then summarize
|
|
61
|
+
what changed.
|
|
60
62
|
|
|
61
63
|
## Update Your Persistent Instructions
|
|
62
64
|
|
|
@@ -158,10 +160,22 @@ Open a review and return immediately:
|
|
|
158
160
|
gloss open --json --no-watch
|
|
159
161
|
```
|
|
160
162
|
|
|
161
|
-
|
|
163
|
+
Mark a submitted review handled after applying feedback:
|
|
162
164
|
|
|
163
165
|
```bash
|
|
164
|
-
gloss
|
|
166
|
+
gloss resolve <reviewId> --summary "Applied review feedback"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Mark one submitted comment handled while work is in progress:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
gloss resolve <reviewId> --comment <commentId> --summary "Applied this comment"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For a follow-up pass after fixes or new commits, start a fresh session:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
gloss open --json
|
|
165
179
|
```
|
|
166
180
|
|
|
167
181
|
Diagnose setup:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getgloss",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Local browser-based diff review for coding-agent loops.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.33.2",
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@hono/node-server": "^1.14.4",
|
|
34
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
34
|
"@pierre/diffs": "^1.2.1",
|
|
36
35
|
"@tailwindcss/vite": "^4.1.7",
|
|
37
36
|
"commander": "^14.0.0",
|
|
@@ -62,8 +61,7 @@
|
|
|
62
61
|
"keywords": [
|
|
63
62
|
"diff",
|
|
64
63
|
"review",
|
|
65
|
-
"coding-agents"
|
|
66
|
-
"mcp"
|
|
64
|
+
"coding-agents"
|
|
67
65
|
],
|
|
68
66
|
"author": "Raj Joshi",
|
|
69
67
|
"license": "MIT",
|
package/skill/SKILL.md
CHANGED
|
@@ -12,13 +12,14 @@ description: Open local working-tree or branch changes in Gloss for browser revi
|
|
|
12
12
|
3. Parse the JSON output and read `feedbackPath` when present.
|
|
13
13
|
4. Address every comment in file and line order.
|
|
14
14
|
5. Validate the fix with the narrowest relevant checks.
|
|
15
|
-
6.
|
|
15
|
+
6. When useful, run `gloss resolve <reviewId> --comment <commentId> --summary "<what changed>"` as each comment is handled.
|
|
16
|
+
7. Run `gloss resolve <reviewId> --summary "<what changed>"`, then summarize the feedback addressed and validation performed.
|
|
16
17
|
|
|
17
18
|
Feedback is stored under `~/.gloss/reviews/<reviewId>/`:
|
|
18
19
|
|
|
19
20
|
- `feedback.json` is the machine-readable handoff.
|
|
20
21
|
- `feedback.md` is the human-readable copy.
|
|
21
|
-
- `resolved.json`
|
|
22
|
+
- `resolved.json` tracks mutable comment-level and review-level resolution progress.
|
|
22
23
|
|
|
23
24
|
Gloss opens staged, unstaged, and untracked working changes first. If the
|
|
24
25
|
working tree is clean, it falls back to the branch diff against the best
|
|
@@ -28,5 +29,9 @@ comparison such as `origin/main`, `origin/master`, or `HEAD`.
|
|
|
28
29
|
If the user asks only to open the review and not wait, run
|
|
29
30
|
`gloss open --json --no-watch`.
|
|
30
31
|
|
|
32
|
+
If the user asks for a follow-up review after fixes, commits, or additional
|
|
33
|
+
changes, run a fresh `gloss open --json` session instead of reusing the old
|
|
34
|
+
review.
|
|
35
|
+
|
|
31
36
|
For less-common options, run `gloss open --help` or `gloss --help` instead of
|
|
32
37
|
guessing flags.
|
package/dist/mcp/index.js
DELETED
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
// src/mcp/index.ts
|
|
2
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import { z } from "zod/v4";
|
|
5
|
-
|
|
6
|
-
// src/cli/lifecycle.ts
|
|
7
|
-
import { spawn } from "child_process";
|
|
8
|
-
import { existsSync, openSync } from "fs";
|
|
9
|
-
import { readFile, rm, writeFile } from "fs/promises";
|
|
10
|
-
import { fileURLToPath } from "url";
|
|
11
|
-
import getPort from "get-port";
|
|
12
|
-
|
|
13
|
-
// src/shared/paths.ts
|
|
14
|
-
import { mkdir } from "fs/promises";
|
|
15
|
-
import { homedir } from "os";
|
|
16
|
-
import path from "path";
|
|
17
|
-
|
|
18
|
-
// package.json
|
|
19
|
-
var package_default = {
|
|
20
|
-
name: "getgloss",
|
|
21
|
-
version: "0.3.0",
|
|
22
|
-
description: "Local browser-based diff review for coding-agent loops.",
|
|
23
|
-
type: "module",
|
|
24
|
-
packageManager: "pnpm@10.33.2",
|
|
25
|
-
bin: {
|
|
26
|
-
getgloss: "./dist/cli/index.js",
|
|
27
|
-
gloss: "./dist/cli/index.js"
|
|
28
|
-
},
|
|
29
|
-
files: [
|
|
30
|
-
"dist",
|
|
31
|
-
"skill",
|
|
32
|
-
"README.md",
|
|
33
|
-
"LICENSE"
|
|
34
|
-
],
|
|
35
|
-
scripts: {
|
|
36
|
-
build: "pnpm build:web && pnpm build:node",
|
|
37
|
-
"build:web": "vite build",
|
|
38
|
-
"build:node": "tsup",
|
|
39
|
-
check: "biome check .",
|
|
40
|
-
format: "biome format --write .",
|
|
41
|
-
prepack: "pnpm build",
|
|
42
|
-
"dev:web": "vite --host 127.0.0.1",
|
|
43
|
-
setup: "tsx scripts/dev-cli.ts",
|
|
44
|
-
test: "vitest run",
|
|
45
|
-
"test:watch": "vitest"
|
|
46
|
-
},
|
|
47
|
-
engines: {
|
|
48
|
-
node: ">=20"
|
|
49
|
-
},
|
|
50
|
-
dependencies: {
|
|
51
|
-
"@hono/node-server": "^1.14.4",
|
|
52
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
53
|
-
"@pierre/diffs": "^1.2.1",
|
|
54
|
-
"@tailwindcss/vite": "^4.1.7",
|
|
55
|
-
commander: "^14.0.0",
|
|
56
|
-
execa: "^9.5.3",
|
|
57
|
-
"get-port": "^7.1.0",
|
|
58
|
-
hono: "^4.7.10",
|
|
59
|
-
"lucide-react": "^1.16.0",
|
|
60
|
-
open: "^10.1.2",
|
|
61
|
-
react: "^19.1.0",
|
|
62
|
-
"react-dom": "^19.1.0",
|
|
63
|
-
ulid: "^3.0.0",
|
|
64
|
-
zod: "^4.4.3",
|
|
65
|
-
zustand: "^5.0.5"
|
|
66
|
-
},
|
|
67
|
-
devDependencies: {
|
|
68
|
-
"@biomejs/biome": "^2.0.6",
|
|
69
|
-
"@types/node": "^24.0.1",
|
|
70
|
-
"@types/react": "^19.1.6",
|
|
71
|
-
"@types/react-dom": "^19.1.5",
|
|
72
|
-
"@vitejs/plugin-react": "^4.5.2",
|
|
73
|
-
playwright: "^1.52.0",
|
|
74
|
-
tsup: "^8.5.0",
|
|
75
|
-
tsx: "^4.20.3",
|
|
76
|
-
typescript: "^5.8.3",
|
|
77
|
-
vite: "^6.3.5",
|
|
78
|
-
vitest: "^3.2.3"
|
|
79
|
-
},
|
|
80
|
-
keywords: [
|
|
81
|
-
"diff",
|
|
82
|
-
"review",
|
|
83
|
-
"coding-agents",
|
|
84
|
-
"mcp"
|
|
85
|
-
],
|
|
86
|
-
author: "Raj Joshi",
|
|
87
|
-
license: "MIT",
|
|
88
|
-
homepage: "https://getgloss.dev",
|
|
89
|
-
repository: {
|
|
90
|
-
type: "git",
|
|
91
|
-
url: "git+https://github.com/iamrajjoshi/gloss.git"
|
|
92
|
-
},
|
|
93
|
-
bugs: {
|
|
94
|
-
url: "https://github.com/iamrajjoshi/gloss/issues"
|
|
95
|
-
},
|
|
96
|
-
publishConfig: {
|
|
97
|
-
access: "public"
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// src/shared/paths.ts
|
|
102
|
-
var packageVersion = package_default.version;
|
|
103
|
-
function expandHome(input) {
|
|
104
|
-
if (input === "~") {
|
|
105
|
-
return homedir();
|
|
106
|
-
}
|
|
107
|
-
if (input.startsWith("~/")) {
|
|
108
|
-
return path.join(homedir(), input.slice(2));
|
|
109
|
-
}
|
|
110
|
-
return input;
|
|
111
|
-
}
|
|
112
|
-
function globalStateDir() {
|
|
113
|
-
return expandHome(process.env.GLOSS_STATE_DIR ?? "~/.gloss");
|
|
114
|
-
}
|
|
115
|
-
function globalServerFile() {
|
|
116
|
-
return path.join(globalStateDir(), "server.json");
|
|
117
|
-
}
|
|
118
|
-
function globalLogDir() {
|
|
119
|
-
return path.join(globalStateDir(), "logs");
|
|
120
|
-
}
|
|
121
|
-
function globalServerLogFile() {
|
|
122
|
-
return path.join(globalLogDir(), "server.log");
|
|
123
|
-
}
|
|
124
|
-
async function ensureDir(dir) {
|
|
125
|
-
await mkdir(dir, { recursive: true });
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// src/cli/server-client.ts
|
|
129
|
-
var ServerClient = class {
|
|
130
|
-
constructor(baseUrl) {
|
|
131
|
-
this.baseUrl = baseUrl;
|
|
132
|
-
}
|
|
133
|
-
baseUrl;
|
|
134
|
-
async health() {
|
|
135
|
-
return this.get("/api/health");
|
|
136
|
-
}
|
|
137
|
-
async createReview(diff) {
|
|
138
|
-
return this.post("/api/reviews", diff);
|
|
139
|
-
}
|
|
140
|
-
async getReview(reviewId) {
|
|
141
|
-
return this.get(`/api/reviews/${reviewId}`);
|
|
142
|
-
}
|
|
143
|
-
async listReviews() {
|
|
144
|
-
return this.get("/api/reviews");
|
|
145
|
-
}
|
|
146
|
-
async getFeedback(reviewId) {
|
|
147
|
-
return this.get(`/api/reviews/${reviewId}/feedback`);
|
|
148
|
-
}
|
|
149
|
-
async markResolved(reviewId, summary) {
|
|
150
|
-
return this.post(`/api/reviews/${reviewId}/resolved`, { summary });
|
|
151
|
-
}
|
|
152
|
-
async submitReview(reviewId, comments) {
|
|
153
|
-
return this.post(`/api/reviews/${reviewId}/submit`, { comments });
|
|
154
|
-
}
|
|
155
|
-
async watchReview(reviewId, timeoutSeconds) {
|
|
156
|
-
const controller = new AbortController();
|
|
157
|
-
const timeout = timeoutSeconds && timeoutSeconds > 0 ? setTimeout(() => controller.abort(), timeoutSeconds * 1e3) : null;
|
|
158
|
-
try {
|
|
159
|
-
const response = await fetch(`${this.baseUrl}/api/reviews/${reviewId}/events`, {
|
|
160
|
-
signal: controller.signal
|
|
161
|
-
});
|
|
162
|
-
if (!response.ok || !response.body) {
|
|
163
|
-
throw new Error(`watch failed: ${response.status} ${await response.text()}`);
|
|
164
|
-
}
|
|
165
|
-
const reader = response.body.getReader();
|
|
166
|
-
const decoder = new TextDecoder();
|
|
167
|
-
let buffer = "";
|
|
168
|
-
while (true) {
|
|
169
|
-
const { value, done } = await reader.read();
|
|
170
|
-
if (done) {
|
|
171
|
-
throw new Error("watch stream ended before completion");
|
|
172
|
-
}
|
|
173
|
-
buffer += decoder.decode(value, { stream: true });
|
|
174
|
-
const events = buffer.split("\n\n");
|
|
175
|
-
buffer = events.pop() ?? "";
|
|
176
|
-
for (const eventChunk of events) {
|
|
177
|
-
const dataLine = eventChunk.split("\n").find((line) => line.startsWith("data:"));
|
|
178
|
-
if (!dataLine) {
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
const event = JSON.parse(dataLine.slice(5).trim());
|
|
182
|
-
if (event.type === "review.completed" || event.type === "review.cancelled") {
|
|
183
|
-
return event;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
} finally {
|
|
188
|
-
if (timeout) {
|
|
189
|
-
clearTimeout(timeout);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
async get(path2) {
|
|
194
|
-
const response = await fetch(`${this.baseUrl}${path2}`);
|
|
195
|
-
return parseResponse(response);
|
|
196
|
-
}
|
|
197
|
-
async post(path2, body) {
|
|
198
|
-
const response = await fetch(`${this.baseUrl}${path2}`, {
|
|
199
|
-
method: "POST",
|
|
200
|
-
headers: { "content-type": "application/json" },
|
|
201
|
-
body: JSON.stringify(body)
|
|
202
|
-
});
|
|
203
|
-
return parseResponse(response);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
async function parseResponse(response) {
|
|
207
|
-
if (!response.ok) {
|
|
208
|
-
throw new Error(`${response.status} ${response.statusText}: ${await response.text()}`);
|
|
209
|
-
}
|
|
210
|
-
return await response.json();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// src/cli/lifecycle.ts
|
|
214
|
-
async function readServerInfo() {
|
|
215
|
-
try {
|
|
216
|
-
return JSON.parse(await readFile(globalServerFile(), "utf8"));
|
|
217
|
-
} catch {
|
|
218
|
-
return null;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
function serverUrl(info) {
|
|
222
|
-
return `http://localhost:${info.port}`;
|
|
223
|
-
}
|
|
224
|
-
async function isServerResponsive(info) {
|
|
225
|
-
if (!isPidAlive(info.pid)) {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
try {
|
|
229
|
-
const health = await new ServerClient(serverUrl(info)).health();
|
|
230
|
-
return health.ok === true;
|
|
231
|
-
} catch {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
async function ensureServer(options = {}) {
|
|
236
|
-
const existing = await readServerInfo();
|
|
237
|
-
if (existing && await isServerResponsive(existing)) {
|
|
238
|
-
return existing;
|
|
239
|
-
}
|
|
240
|
-
return startServer(options);
|
|
241
|
-
}
|
|
242
|
-
async function startServer(options = {}) {
|
|
243
|
-
const existing = await readServerInfo();
|
|
244
|
-
if (existing && await isServerResponsive(existing)) {
|
|
245
|
-
return existing;
|
|
246
|
-
}
|
|
247
|
-
await ensureDir(globalStateDir());
|
|
248
|
-
await ensureDir(globalLogDir());
|
|
249
|
-
const port = options.port ?? await getPort();
|
|
250
|
-
const daemonPath = fileURLToPath(new URL("../server/daemon.js", import.meta.url));
|
|
251
|
-
if (!existsSync(daemonPath)) {
|
|
252
|
-
throw new Error(`Cannot find server daemon at ${daemonPath}. Run pnpm build first.`);
|
|
253
|
-
}
|
|
254
|
-
const logFd = openSync(globalServerLogFile(), "a");
|
|
255
|
-
const child = spawn(process.execPath, [daemonPath], {
|
|
256
|
-
detached: true,
|
|
257
|
-
env: {
|
|
258
|
-
...process.env,
|
|
259
|
-
GLOSS_PORT: String(port),
|
|
260
|
-
GLOSS_STATE_DIR: globalStateDir()
|
|
261
|
-
},
|
|
262
|
-
stdio: ["ignore", logFd, logFd]
|
|
263
|
-
});
|
|
264
|
-
child.unref();
|
|
265
|
-
const info = {
|
|
266
|
-
pid: child.pid ?? -1,
|
|
267
|
-
port,
|
|
268
|
-
version: packageVersion,
|
|
269
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
270
|
-
stateDir: globalStateDir()
|
|
271
|
-
};
|
|
272
|
-
await writeFile(globalServerFile(), `${JSON.stringify(info, null, 2)}
|
|
273
|
-
`);
|
|
274
|
-
const deadline = Date.now() + 8e3;
|
|
275
|
-
while (Date.now() < deadline) {
|
|
276
|
-
if (await isServerResponsive(info)) {
|
|
277
|
-
return info;
|
|
278
|
-
}
|
|
279
|
-
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
280
|
-
}
|
|
281
|
-
throw new Error(`Server did not become responsive. See ${globalServerLogFile()}`);
|
|
282
|
-
}
|
|
283
|
-
function isPidAlive(pid) {
|
|
284
|
-
if (pid <= 0) {
|
|
285
|
-
return false;
|
|
286
|
-
}
|
|
287
|
-
try {
|
|
288
|
-
process.kill(pid, 0);
|
|
289
|
-
return true;
|
|
290
|
-
} catch {
|
|
291
|
-
return false;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// src/mcp/index.ts
|
|
296
|
-
function textResult(value) {
|
|
297
|
-
return {
|
|
298
|
-
content: [
|
|
299
|
-
{
|
|
300
|
-
type: "text",
|
|
301
|
-
text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
|
|
302
|
-
}
|
|
303
|
-
]
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
async function client() {
|
|
307
|
-
const info = await ensureServer();
|
|
308
|
-
return new ServerClient(serverUrl(info));
|
|
309
|
-
}
|
|
310
|
-
async function startMcpServer() {
|
|
311
|
-
const server = new McpServer({
|
|
312
|
-
name: "gloss",
|
|
313
|
-
version: packageVersion
|
|
314
|
-
});
|
|
315
|
-
server.registerTool(
|
|
316
|
-
"list_pending_reviews",
|
|
317
|
-
{
|
|
318
|
-
title: "List pending Gloss reviews",
|
|
319
|
-
description: "List pending local Gloss review sessions."
|
|
320
|
-
},
|
|
321
|
-
async () => {
|
|
322
|
-
const api = await client();
|
|
323
|
-
const { reviews } = await api.listReviews();
|
|
324
|
-
return textResult({ reviews: reviews.filter((review) => review.status === "pending") });
|
|
325
|
-
}
|
|
326
|
-
);
|
|
327
|
-
server.registerTool(
|
|
328
|
-
"get_review",
|
|
329
|
-
{
|
|
330
|
-
title: "Get Gloss review",
|
|
331
|
-
description: "Fetch review metadata and diff payload.",
|
|
332
|
-
inputSchema: { id: z.string() }
|
|
333
|
-
},
|
|
334
|
-
async ({ id }) => textResult(await (await client()).getReview(id))
|
|
335
|
-
);
|
|
336
|
-
server.registerTool(
|
|
337
|
-
"watch_review",
|
|
338
|
-
{
|
|
339
|
-
title: "Watch Gloss review",
|
|
340
|
-
description: "Block until a review completes, then return feedback.",
|
|
341
|
-
inputSchema: {
|
|
342
|
-
id: z.string(),
|
|
343
|
-
timeout: z.number().optional()
|
|
344
|
-
}
|
|
345
|
-
},
|
|
346
|
-
async ({ id, timeout }) => {
|
|
347
|
-
const api = await client();
|
|
348
|
-
await api.watchReview(id, timeout);
|
|
349
|
-
return textResult(await api.getFeedback(id));
|
|
350
|
-
}
|
|
351
|
-
);
|
|
352
|
-
server.registerTool(
|
|
353
|
-
"get_review_feedback",
|
|
354
|
-
{
|
|
355
|
-
title: "Get Gloss review feedback",
|
|
356
|
-
description: "Fetch completed review feedback.",
|
|
357
|
-
inputSchema: { id: z.string() }
|
|
358
|
-
},
|
|
359
|
-
async ({ id }) => textResult(await (await client()).getFeedback(id))
|
|
360
|
-
);
|
|
361
|
-
server.registerTool(
|
|
362
|
-
"mark_review_resolved",
|
|
363
|
-
{
|
|
364
|
-
title: "Mark Gloss review resolved",
|
|
365
|
-
description: "Write a resolved marker for a completed review.",
|
|
366
|
-
inputSchema: {
|
|
367
|
-
id: z.string(),
|
|
368
|
-
summary: z.string().optional()
|
|
369
|
-
}
|
|
370
|
-
},
|
|
371
|
-
async ({ id, summary }) => textResult(await (await client()).markResolved(id, summary))
|
|
372
|
-
);
|
|
373
|
-
await server.connect(new StdioServerTransport());
|
|
374
|
-
}
|
|
375
|
-
export {
|
|
376
|
-
startMcpServer
|
|
377
|
-
};
|
|
378
|
-
//# sourceMappingURL=index.js.map
|