/** * dsh-ui-tweaks — GitBar (browser half). * * Git integration for the conversation UI, all riding DSH-native surfaces: * * - **branch chip** (`conversation.session.header.actions`, beside the * title): folder + current branch; opens a popup with local/remote * branches, a new-branch field, and the commit graph. * - **diff** (right-sidebar tab): the changed-file list and per-file * diff (changed hunks by default, whole file on toggle) in the same * sidebar, keeping its commit band at the foot so committing works from * the tab. * * Opening the project in external apps is DSH's own `open-in-app` header * button now, so this plugin no longer ships one. * * All colors ride the DSH theme tokens (`--dsw-alias-*`), so light and dark * both work. Each entry renders nothing when the setting is off; the diff tab * shows a not-a-repo note when the session has no git repository. * @module dsh-ui-tweaks/client/gitbar */ import type { ISessions, SessionSnapshot } from '@deepseek-ai/dsh-api-session-controller/client'; import type { SessionId } from '@deepseek-ai/dsh-session/types'; import type { SettingsClient } from './index.tsx'; /** Locale keys the GitBar reads off the `ui-tweaks` dictionary. */ type GitBarLabelKey = 'commitMessage' | 'diffFiles' | 'branchLocal' | 'branchRemote' | 'branchNew' | 'branchNewPlaceholder' | 'branchCreate' | 'diffView' | 'diffOnly' | 'diffFull' | 'commitTitle' | 'commitPlaceholder' | 'commitHint' | 'commitWillCommit' | 'commitViewDiff' | 'commitEmpty' | 'commitCancel' | 'commitSubmit' | 'commitSubmitPush' | 'commitBusy' | 'dirty' | 'clean' | 'noChanges' | 'loading' | 'branchDelete' | 'branchDeleteConfirm' | 'includeFile' | 'excludeFile' | 'branchPushRemote' | 'branchPull' | 'branchRename' | 'tagsTitle' | 'tagCreate' | 'tagCreatePlaceholder' | 'tagMessagePlaceholder' | 'tagPush' | 'tagDelete' | 'tagCommitPlaceholder' | 'branchRemoteDelete' | 'branchFrom' | 'branchFromHead' | 'branchGraph' | 'branchRefresh' | 'branchCancel' | 'graphTitle' | 'graphColGraph' | 'graphColCommit' | 'graphColSubject' | 'graphColAuthor' | 'graphColDate' | 'notRepo'; type Translate = (key: GitBarLabelKey) => string; /** * Where git ops resolve their working directory: a real session id, or a * workspace title for the hero/new-session screen (which has no materialized * session yet — the server resolves the picked workspace's path instead). */ export interface GitTarget { session?: string; ws?: string; } export declare const GITBAR_CSS = "\n/* DSH does not force border-box globally; normalize it for the whole GitBar\n subtree (including the body-portaled panels/modal), or widths overflow. */\n.gbar,.gbar *,.gbar-view,.gbar-view *,.gbar-modal-wrap,.gbar-modal-wrap *,.gbar-notice,.gbar-notice *{box-sizing:border-box}\n/* Anchor around each pill inside the composer tool row\n (conversation.input.left / .right): the branch pill's containing block, so\n its popup opens from the pill itself. flex:0 1 auto + min-width:0 let the\n pill compress when the row is squeezed instead of spilling over neighbours. */\n.gbar{position:relative;display:inline-flex;align-items:center;gap:6px;flex:0 1 auto;min-width:0}\n/* Pills match the input bar's resident chrome (access mode / model select):\n 28px tall, fully-rounded, transparent at rest with a soft hover fill.\n overflow:hidden clips the pill's content while it compresses. */\n.gbar-pill{\n display:inline-flex;align-items:center;gap:6px;\n height:28px;padding:0 8px;min-width:0;overflow:hidden;\n background:transparent;\n border:none;\n border-radius:24px;\n color:var(--dsw-alias-label-secondary);\n font:inherit;font-size:13px;font-weight:500;line-height:20px;\n cursor:pointer;\n transition:background .15s ease;\n white-space:nowrap;\n -webkit-user-select:none;user-select:none;\n}\n.gbar-pill:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-pill:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}\n/* Long branch names ellipsize instead of stretching the row. */\n.gbar-pill .gbar-branch{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:140px}\n/* Icons match the resident access-mode trigger exactly: 14px, full color,\n no fade, and box-centered (same vertical centre as the access icon). */\n.gbar-pill .gbar-ico{width:14px;height:14px;flex:none;opacity:1}\n.gbar-pill .gbar-caret{font-size:8px;color:var(--dsw-alias-label-tertiary);margin-left:1px}\n.gbar-pill .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}\n.gbar-pill .gbar-add{color:var(--dsw-alias-state-success-primary);font-weight:600;font-variant-numeric:tabular-nums}\n.gbar-pill .gbar-del{color:var(--dsw-alias-state-error-primary);font-weight:600;font-variant-numeric:tabular-nums}\n.gbar-pill .gbar-meta{color:var(--dsw-alias-label-secondary)}\n.gbar-pill .gbar-hint{color:var(--dsw-alias-label-tertiary);font-weight:400}\n.gbar-pill.gbar-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-business-primary)}\n.gbar-pill.gbar-active .gbar-hint{color:var(--dsw-alias-state-business-primary)}\n.gbar-pill:disabled{opacity:.5;cursor:default}\n/* The composer tool row is an inline-size container (DSH sets\n container-type:inline-size on it), so these container queries track the\n row's actual width. When the stretched diff panel pushes the conversation\n column and the row tightens \u2014 the same squeeze that makes the resident\n access / model chrome collapse its labels to icons \u2014 the pills follow suit\n instead of ever overlapping their neighbours: first drop the \"\u00B7 K \u4E2A\u6587\u4EF6\"\n meta, then go icon-only (before the row gets narrow enough for the branch\n name to collide with the access control). */\n@container (max-width: 700px){\n .gbar-pill .gbar-meta{display:none}\n}\n@container (max-width: 620px){\n .gbar-pill .gbar-text{display:none}\n .gbar-pill .gbar-caret{display:none}\n}\n\n/* branch popup \u2014 the chip lives in the session HEADER now, so the menu opens\n DOWNWARD (top-anchored, small arrow pointing up). Pinned header (current\n branch + worktree state) and pinned action bar surround a freely scrolling\n branch list. */\n.gbar-pop{\n position:absolute;left:0;top:calc(100% + 8px);z-index:120;\n width:300px;\n background:var(--dsw-alias-bg-layer-1);\n border:1px solid var(--dsw-alias-border-l2);border-radius:14px;\n box-shadow:var(--dsw-shadow-lv2);\n display:flex;flex-direction:column;overflow:hidden;\n animation:gpop-down .16s cubic-bezier(.32,.72,0,1);\n}\n.gbar-pop::before{content:\"\";position:absolute;top:-5px;left:22px;width:9px;height:9px;\n background:var(--dsw-alias-bg-layer-1);border-left:1px solid var(--dsw-alias-border-l2);\n border-top:1px solid var(--dsw-alias-border-l2);transform:rotate(45deg)}\n@keyframes gpop-down{from{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:none}}\n.gbar-pop-head{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform)}\n.gbar-pop-head .gbar-bicon{width:14px;height:14px;flex:none}\n.gbar-pop-head .gbar-curname{display:flex;align-items:center;gap:7px;min-width:0;font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}\n.gbar-pop-head .gbar-curname .gbar-bicon{color:var(--dsw-alias-state-business-primary)}\n.gbar-pop-head .gbar-curname>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.gbar-pop-head .gbar-state{margin-left:auto;flex:none;display:flex;align-items:center;gap:6px;font-size:11px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}\n.gbar-pop-head .gbar-dot{width:6px;height:6px;border-radius:50%;flex:none}\n.gbar-pop-head .gbar-dot.gbar-dirty{background:var(--dsw-alias-state-warn-primary)}\n.gbar-pop-head .gbar-dot.gbar-clean{background:var(--dsw-alias-state-success-primary)}\n/* Pull-current-branch icon button at the popup header's right edge; hidden\n entirely when the branch has no upstream (nothing to pull from). */\n.gbar-pop-head .gbar-pull{flex:none;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;border-radius:7px;padding:0;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;transition:background .12s ease,color .12s ease}\n.gbar-pop-head .gbar-pull svg{width:13px;height:13px;display:block}\n.gbar-pop-head .gbar-pull:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.gbar-pop-head .gbar-pull:disabled{opacity:.5;cursor:default}\n.gbar-pop-body{max-height:min(330px,calc(100vh - 250px));overflow-y:auto;padding:3px 6px 5px;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent) transparent}\n.gbar-pop-body::-webkit-scrollbar{width:5px}\n.gbar-pop-body::-webkit-scrollbar-track{background:transparent}\n.gbar-pop-body::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent);border-radius:4px}\n.gbar-pop .gbar-sec{display:flex;align-items:center;gap:6px;font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:8px 9px 3px}\n.gbar-pop .gbar-sec .gbar-count{margin-left:auto;font-size:10px;font-weight:500;letter-spacing:0;line-height:15px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:0 7px}\n.gbar-pop .gbar-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:14px 9px;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.gbar-pop .gbar-row{\n display:flex;align-items:center;gap:8px;width:100%;\n padding:6px 8px;border:none;border-radius:8px;\n background:transparent;color:var(--dsw-alias-label-primary);\n font:inherit;font-size:12.5px;cursor:pointer;text-align:left;\n transition:background .12s ease;\n}\n.gbar-pop .gbar-row:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-pop .gbar-row.gbar-cur{color:var(--dsw-alias-state-business-primary);font-weight:600}\n.gbar-pop .gbar-row .gbar-bicon{width:13px;height:13px;flex:none;color:var(--dsw-alias-label-tertiary);opacity:.85}\n.gbar-pop .gbar-row.gbar-cur .gbar-bicon{color:var(--dsw-alias-state-business-primary);opacity:1}\n.gbar-pop .gbar-row .gbar-check{margin-left:auto;color:var(--dsw-alias-state-business-primary);font-weight:700}\n.gbar-pop .gbar-row .gbar-rm{flex:none;font-size:10px;line-height:15px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:0 7px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:90px}\n/* branch row wrapper: main switch button + delete button */\n.gbar-pop .gbar-rowwrap{display:flex;align-items:center;gap:2px;border-radius:8px;transition:background .12s ease}\n.gbar-pop .gbar-rowwrap:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-pop .gbar-rowwrap .gbar-row{background:transparent}\n.gbar-pop .gbar-del{\n flex:none;display:inline-flex;align-items:center;justify-content:center;\n width:26px;height:26px;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);\n font:inherit;font-size:10.5px;cursor:pointer;border-radius:7px;margin-right:4px;\n transition:color .12s ease,background .12s ease;\n}\n.gbar-pop .gbar-del svg{width:13px;height:13px;display:block}\n.gbar-pop .gbar-del:hover{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}\n.gbar-pop .gbar-del.gbar-arm{width:auto;padding:0 8px;color:var(--dsw-alias-state-error-primary);font-weight:600;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}\n/* rename/create entry beside the delete one \u2014 neutral/hover-primary, so the\n eye keeps reading red strictly as \"destructive\"; also used by the tag rows\n and the graph table (both under .gbar-pop / .gbar-modal scopes) */\n.gbar-pop .gbar-ren,.gbar-modal .gbar-ren{\n flex:none;display:inline-flex;align-items:center;justify-content:center;\n width:26px;height:26px;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);\n cursor:pointer;border-radius:7px;margin-right:4px;\n transition:color .12s ease,background .12s ease;\n}\n.gbar-pop .gbar-ren svg,.gbar-modal .gbar-ren svg{width:13px;height:13px;display:block}\n.gbar-pop .gbar-ren:hover,.gbar-modal .gbar-ren:hover{color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent)}\n.gbar-pop .gbar-ren:disabled,.gbar-modal .gbar-ren:disabled{opacity:.5;cursor:default}\n.gbar-pushrow{display:flex;align-items:center;gap:7px;padding:0 8px 7px}\n.gbar-pushrow .gbar-pushlabel{font-size:12px;color:var(--dsw-alias-label-secondary)}\n.gbar-pop .gbar-newrow{display:flex;gap:6px;padding:8px 6px 6px}\n.gbar-pop input{\n flex:1;min-width:0;height:32px;padding:0 11px;\n border:1px solid var(--dsw-alias-border-l2);border-radius:9px;\n background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);\n font:inherit;font-size:13px;outline:none;\n}\n.gbar-pop input:focus{border-color:var(--dsw-alias-state-business-primary)}\n.gbar-pop input::placeholder{color:var(--dsw-alias-label-tertiary)}\n.gbar-mini{\n flex:none;height:32px;padding:0 14px;border:none;border-radius:9px;\n background:var(--dsw-alias-state-business-primary);color:#fff;\n font:inherit;font-size:13px;font-weight:500;cursor:pointer;\n}\n.gbar-mini:hover{opacity:.92}\n.gbar-mini:disabled{opacity:.5;cursor:default}\n\n/* branch popup action entries (new branch / graph) \u2014 pinned below the\n scrolling list; the border-top separates it from the body. */\n.gbar-actions{display:flex;gap:6px;padding:8px;border-top:1px solid var(--dsw-alias-border-l1)}\n.gbar-act{\n flex:1;display:inline-flex;align-items:center;justify-content:center;gap:7px;\n height:34px;border:none;border-radius:10px;\n background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);\n font:inherit;font-size:12.5px;font-weight:500;cursor:pointer;\n}\n.gbar-act:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}\n.gbar-act svg{width:14px;height:14px;opacity:.9;flex:none}\n/* base-branch selector (new-branch dialog): the pill stretches across the row\n * (its right edge lines up with the full-width name input above) and its\n * popup pins to the same width. */\n.gbar-baserow{display:flex;align-items:center;gap:7px;padding:0}\n.gbar-baselabel{font-size:12px;color:var(--dsw-alias-label-secondary);flex:none}\n.gbar-modal input{\n width:100%;height:38px;padding:0 13px;\n border:1px solid var(--dsw-alias-border-l2);border-radius:10px;\n background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);\n font:inherit;font-size:13.5px;outline:none;\n}\n.gbar-modal input:focus{border-color:var(--dsw-alias-state-business-primary)}\n.gbar-modal input::placeholder{color:var(--dsw-alias-label-tertiary)}\n.gbar-modal .gbar-head{padding-bottom:10px;border-bottom:1px solid var(--dsw-alias-border-l1)}\n/* \"push to remote\" row becomes an inset card so it reads as one option group. */\n.gbar-modal .gbar-pushrow{padding:9px 11px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}\n.gbar-modal .gbar-pushrow .gbar-pushlabel{font-size:12.5px;color:var(--dsw-alias-label-primary)}\n.gbar-x:disabled{opacity:.5;cursor:default}\n/* commit-graph dialog */\n.gbar-modal.gbar-graph-modal{width:min(860px,calc(100vw - 40px));gap:10px}\n/* Refresh sits immediately left of close, both pinned to the right edge: the\n refresh takes the auto margin (specificity .gbar-x.gbar-refresh beats the\n .gbar-x override below), close drops it so they stay adjacent. */\n.gbar-modal.gbar-graph-modal .gbar-head .gbar-x.gbar-refresh{margin-left:auto}\n.gbar-modal.gbar-graph-modal .gbar-head .gbar-x{margin-left:0}\n.gbar-modal.gbar-graph-modal .gbar-x svg{width:15px;height:15px;display:block}\n.gbar-graph-empty{padding:28px 12px;text-align:center;font-size:13px;color:var(--dsw-alias-label-tertiary)}\n.gbar-graph-table{display:flex;flex-direction:column;max-height:min(60vh,540px);overflow:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}\n/* Fixed row height so the per-row graph SVGs tile exactly \u2014 lane lines must\n read as continuous across rows. Body rows therefore separate by zebra +\n hover only: a 1px border would cut through the lane strokes. */\n.gbar-graph-row{display:grid;grid-template-columns:auto 62px 1fr 96px 90px 26px;align-items:center;gap:8px;height:28px;padding:0 12px;transition:background .12s ease}\n/* Zebra striping for scanability; the hover rule matches its specificity and\n comes later in the sheet, so pointing at a row still wins. */\n.gbar-graph-row:not(.gbar-graph-head):nth-child(odd){background:color-mix(in srgb,var(--dsw-alias-bg-module-platform) 35%,transparent)}\n.gbar-graph-row:not(.gbar-graph-head):hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-graph-head{position:sticky;top:0;background:var(--dsw-alias-bg-module-platform);font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);z-index:1;border-bottom:1px solid var(--dsw-alias-border-l1)}\n.gbar-c-graph svg{display:block}\n.gbar-c-hash code{font-family:var(--dsw-font-markdown-code-font-family,\"SF Mono\",Consolas,monospace);font-size:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:6px;padding:2px 6px}\n.gbar-c-subject{min-width:0;display:flex;align-items:center;gap:8px}\n.gbar-subject{font-size:12.5px;color:var(--dsw-alias-label-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.gbar-refs{flex:none;font-size:10.5px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);border-radius:999px;padding:1px 8px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis}\n.gbar-c-author{font-size:12px;color:var(--dsw-alias-label-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.gbar-c-date{font-size:11.5px;color:var(--dsw-alias-label-tertiary);text-align:right;white-space:nowrap}\n/* per-row tag action \u2014 hidden until the row is hovered, so the table stays calm */\n.gbar-c-tag{display:inline-flex;justify-content:center}\n.gbar-c-tag .gbar-ren{opacity:0;transition:opacity .12s ease,color .12s ease,background .12s ease}\n.gbar-graph-row:hover .gbar-c-tag .gbar-ren,.gbar-c-tag .gbar-ren:focus-visible{opacity:1}\n\n/* diff view \u2014 fills the native conversation-view tab: full height flex\n column; the inner head/body/foot sections keep their own rules. */\n.gbar-view{\n position:relative;box-sizing:border-box;height:100%;min-height:0;\n display:flex;flex-direction:column;overflow:hidden;\n /* bg-base instead of bg-layer-1: in dark mode layer-1 (#232324) reads gray\n next to the conversation's base (#151517); base matches it exactly, and in\n light mode both aliases are #fff so nothing changes. */\n background:var(--dsw-alias-bg-base);\n color:var(--dsw-alias-label-primary);\n animation:gbar-in .18s cubic-bezier(.32,.72,0,1);\n}\n/* empty note (e.g. the diff tab without a git repository) */\n.gbar-view-empty{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;\n font-size:12px;color:var(--dsw-alias-label-tertiary)}\n/* uncommitted-changes dot in the diff tab chip \u2014 warn-primary, the same\n signal the branch chip's tooltip carries, so the dirty state reads on the\n tab strip without opening the tab */\n.gbar-tab-dot{display:inline-block;width:6px;height:6px;border-radius:50%;\n background:var(--dsw-alias-state-warn-primary);margin-left:6px;vertical-align:1px;pointer-events:none}\n@keyframes gbar-in{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}\n.gbar-side-head{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--dsw-alias-border-l1)}\n.gbar-side-head .gbar-title{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.gbar-side-head .gbar-sub{font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none;font-variant-numeric:tabular-nums}\n.gbar-side-head .gbar-sub .gbar-a{color:var(--dsw-alias-state-success-primary)}\n.gbar-side-head .gbar-sub .gbar-d{color:var(--dsw-alias-state-error-primary)}\n.gbar-side-head .gbar-spacer{flex:1}\n.gbar-seg{display:inline-flex;padding:3px;gap:2px;border-radius:10px;background:var(--dsw-alias-bg-module-platform);flex:none}\n.gbar-seg button{border:none;border-radius:8px;padding:4px 10px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}\n.gbar-seg button.gbar-on{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1)}\n.gbar-side-body{flex:1;overflow:hidden;display:flex;flex-direction:column;min-height:0}\n/* The three stacked sections (files / diff / commit) are sized by drag: the two\n neighbours carry an explicit inline height and the diff pane absorbs whatever\n is left, so a drag can never overflow the panel. The dividing hairlines are\n painted by the splitters, not by the sections' own borders. */\n.gbar-files{flex:none;overflow-y:auto;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent) transparent}\n.gbar-files::-webkit-scrollbar{width:5px}\n.gbar-files::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent);border-radius:4px}\n/* horizontal drag splitters between the sections */\n.gbar-vsplit{\n flex:none;position:relative;height:7px;\n cursor:row-resize;touch-action:none;-webkit-user-select:none;user-select:none;\n}\n.gbar-vsplit::after{\n content:\"\";position:absolute;left:0;right:0;top:3px;height:1px;\n background:var(--dsw-alias-border-l1);transition:background .15s ease,height .15s ease;\n}\n.gbar-vsplit:hover::after{background:var(--dsw-alias-border-l2);height:2px}\n.gbar-vsplit.gbar-dragging::after{background:var(--dsw-alias-state-business-primary);height:2px}\n.gbar-file{\n display:flex;align-items:center;gap:6px;width:100%;\n padding:3px 14px;background:transparent;\n}\n.gbar-file .gbar-file-main{\n flex:1;min-width:0;display:flex;align-items:center;gap:9px;\n padding:5px 4px;border:none;border-radius:7px;background:transparent;\n color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;cursor:pointer;text-align:left;\n}\n.gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-file.gbar-on .gbar-file-main{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 9%,transparent);box-shadow:inset 2px 0 0 var(--dsw-alias-state-business-primary)}\n.gbar-file.gbar-excl{opacity:.55}\n.gbar-chk{\n flex:none;width:16px;height:16px;padding:0;\n border:1px solid var(--dsw-alias-border-l2);border-radius:5px;\n background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-state-business-primary);\n font-size:11px;line-height:1;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;\n}\n.gbar-chk:hover{border-color:var(--dsw-alias-state-business-primary)}\n.gbar-chk.gbar-off{color:transparent}\n.gbar-file .gbar-st{\n flex:none;min-width:17px;height:17px;padding:0 4px;\n display:inline-flex;align-items:center;justify-content:center;\n font-weight:700;font-size:10.5px;border-radius:5px;\n}\n.gbar-file .gbar-st.gbar-m{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 13%,transparent)}\n.gbar-file .gbar-st.gbar-a{color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 13%,transparent)}\n.gbar-file .gbar-st.gbar-d{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent)}\n.gbar-file .gbar-st.gbar-u{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform)}\n.gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,\"SF Mono\",Consolas,monospace);font-size:12px}\n/* Directory part dims, filename stays bright \u2014 GitHub-style path rendering. */\n.gbar-file .gbar-path .gbar-dir{color:var(--dsw-alias-label-tertiary)}\n.gbar-file .gbar-nums{flex:none;font-variant-numeric:tabular-nums;font-size:11.5px}\n.gbar-file .gbar-nums .gbar-a{color:var(--dsw-alias-state-success-primary)}\n.gbar-file .gbar-nums .gbar-d{color:var(--dsw-alias-state-error-primary)}\n.gbar-diff{\n flex:1;min-height:0;overflow:auto;\n font-family:var(--dsw-font-markdown-code-font-family,\"SF Mono\",Consolas,monospace);font-size:12px;line-height:1.7;padding:8px 0;\n scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent) transparent;\n}\n.gbar-diff::-webkit-scrollbar{width:5px;height:5px}\n.gbar-diff::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-label-tertiary) 35%,transparent);border-radius:4px}\n/* Hunk header: a centered pill strip (GitHub-style), gutter numbers hidden but\n still occupying space so the code column stays aligned. */\n.gbar-diff .gbar-line.gbar-hunk{background:transparent;padding-top:7px;padding-bottom:3px}\n.gbar-diff .gbar-line.gbar-hunk .gbar-ln{visibility:hidden}\n.gbar-diff .gbar-line.gbar-hunk .gbar-code{color:var(--dsw-alias-state-business-primary)}\n.gbar-diff .gbar-line{display:flex;align-items:center;min-height:21px;padding:0 14px 0 0;white-space:pre}\n.gbar-diff .gbar-line .gbar-ln{flex:none;width:34px;text-align:right;padding-right:8px;color:var(--dsw-alias-label-tertiary);font-size:11px;-webkit-user-select:none;user-select:none}\n.gbar-diff .gbar-line .gbar-ln+.gbar-ln{border-right:1px solid var(--dsw-alias-border-l1);margin-right:10px}\n.gbar-diff .gbar-line .gbar-code{flex:1;white-space:pre;color:var(--dsw-alias-label-primary);padding-right:14px}\n.gbar-diff .gbar-line.gbar-add{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 13%,transparent);box-shadow:inset 2px 0 0 color-mix(in srgb,var(--dsw-alias-state-success-primary) 55%,transparent)}\n.gbar-diff .gbar-line.gbar-add .gbar-ln{color:var(--dsw-alias-state-success-primary)}\n.gbar-diff .gbar-line.gbar-del{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);box-shadow:inset 2px 0 0 color-mix(in srgb,var(--dsw-alias-state-error-primary) 50%,transparent)}\n.gbar-diff .gbar-line.gbar-del .gbar-ln{color:var(--dsw-alias-state-error-primary)}\n.gbar-diff .gbar-line.gbar-ctx .gbar-code{color:var(--dsw-alias-label-secondary)}\n.gbar-diff .gbar-empty{display:flex;align-items:center;justify-content:center;min-height:140px;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n/* The hairline above the foot is drawn by the commit splitter that precedes it. */\n.gbar-side-foot{flex:none;padding:8px 14px;font-size:11.5px;color:var(--dsw-alias-label-tertiary);display:flex;gap:8px;align-items:center}\n.gbar-side-foot .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}\n/* commit row inside the diff panel \u2014 height is drag-adjustable, so the message\n field stretches to fill whatever the user gives this section. */\n.gbar-side-commit{flex:none;min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:7px;padding:9px 12px;border-top:1px solid var(--dsw-alias-border-l1)}\n.gbar-side-commit .gbar-crow{flex:1;min-height:0;display:flex;align-items:stretch;gap:6px}\n.gbar-side-commit textarea{\n flex:1;min-width:0;min-height:30px;padding:6px 10px;resize:none;\n border:1px solid var(--dsw-alias-border-l2);border-radius:8px;\n background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);\n font:inherit;font-size:12px;line-height:1.6;outline:none;overflow-y:auto;\n}\n.gbar-side-commit textarea:focus{border-color:var(--dsw-alias-state-business-primary)}\n.gbar-side-commit textarea::placeholder{color:var(--dsw-alias-label-tertiary)}\n/* optional tag input riding the commit buttons \u2014 same chrome as the textarea */\n.gbar-taginput{\n flex:none;width:118px;height:28px;padding:0 10px;\n border:1px solid var(--dsw-alias-border-l2);border-radius:8px;\n background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);\n font:inherit;font-size:12px;outline:none;\n}\n.gbar-taginput:focus{border-color:var(--dsw-alias-state-business-primary)}\n.gbar-taginput::placeholder{color:var(--dsw-alias-label-tertiary)}\n.gbar-side-commit .gbar-actions{flex:none;display:flex;align-items:center;justify-content:flex-end;gap:6px}\n.gbar-side-commit .gbar-btn{height:28px;padding:0 12px;font-size:12px;border-radius:8px}\n\n/* commit modal */\n.gbar-modal-wrap{\n position:fixed;inset:0;z-index:120;\n display:flex;align-items:center;justify-content:center;\n background:rgba(0,0,0,.35);\n}\n.gbar-modal{\n width:min(520px,calc(100vw - 40px));max-height:calc(100vh - 48px);overflow:hidden auto;\n background:var(--dsw-alias-bg-layer-1);\n border:1px solid var(--dsw-alias-border-l2);border-radius:16px;\n box-shadow:var(--dsw-shadow-lv2);\n padding:18px;\n display:flex;flex-direction:column;gap:12px;\n animation:gbar-in .18s cubic-bezier(.32,.72,0,1);\n}\n.gbar-modal .gbar-head{display:flex;align-items:center;gap:10px}\n.gbar-modal .gbar-head .gbar-title{font-size:15px;font-weight:600}\n.gbar-modal .gbar-head .gbar-branch{font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:3px 10px}\n.gbar-modal .gbar-head .gbar-x{margin-left:auto;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:16px;cursor:pointer;width:28px;height:28px;border-radius:8px}\n.gbar-modal .gbar-head .gbar-x:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.gbar-modal textarea{\n width:100%;min-height:64px;height:auto;max-height:220px;resize:none;\n overflow-y:auto;scrollbar-width:none;\n border:1px solid var(--dsw-alias-border-l2);border-radius:12px;\n background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);\n font:inherit;font-size:14px;line-height:1.6;padding:10px 14px;outline:none;\n}\n.gbar-modal textarea::-webkit-scrollbar{display:none}\n.gbar-modal textarea:focus{border-color:var(--dsw-alias-state-business-primary)}\n.gbar-modal textarea::placeholder{color:var(--dsw-alias-label-tertiary)}\n.gbar-modal .gbar-hint{font-size:12px;color:var(--dsw-alias-label-tertiary);line-height:1.6}\n/* tag manager dialog \u2014 mirrors the popup row chrome inside a centered dialog */\n.gbar-modal .gbar-rowwrap{display:flex;align-items:center;gap:2px;border-radius:8px;transition:background .12s ease}\n.gbar-modal .gbar-rowwrap:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-modal .gbar-rowwrap .gbar-row{background:transparent}\n.gbar-modal .gbar-row .gbar-bicon{width:13px;height:13px;flex:none;color:var(--dsw-alias-label-tertiary);opacity:.85}\n.gbar-modal .gbar-row .gbar-rm{flex:none;font-size:10px;line-height:15px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:0 7px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:90px}\n.gbar-modal .gbar-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:14px 9px;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.gbar-modal .gbar-del{flex:none;display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:10.5px;cursor:pointer;border-radius:7px;margin-right:4px;transition:color .12s ease,background .12s ease}\n.gbar-modal .gbar-del svg{width:13px;height:13px;display:block}\n.gbar-modal .gbar-del:hover{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}\n.gbar-modal .gbar-del.gbar-arm{width:auto;padding:0 8px;color:var(--dsw-alias-state-error-primary);font-weight:600;background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}\n.gbar-tags-modal .gbar-tags-list{display:flex;flex-direction:column;gap:1px;max-height:280px;overflow-y:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2);padding:4px}\n.gbar-tags-modal .gbar-tags-list .gbar-rowwrap .gbar-row{flex:1;min-width:0}\n.gbar-modal .gbar-files-head{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);margin-top:2px}\n.gbar-modal .gbar-files-head .gbar-hint{font-size:11px;font-weight:400;text-transform:none;letter-spacing:0}\n.gbar-modal .gbar-files{\n display:flex;flex-direction:column;gap:1px;max-height:132px;overflow-y:auto;\n border:1px solid var(--dsw-alias-border-l1);border-radius:10px;\n background:var(--dsw-alias-bg-layer-2);padding:4px;\n}\n.gbar-modal .gbar-file{\n display:flex;align-items:center;gap:6px;width:100%;\n padding:2px 6px;border-radius:7px;background:transparent;\n}\n.gbar-modal .gbar-file .gbar-file-main{\n padding:4px 4px;font-size:12px;border-radius:6px;\n}\n.gbar-modal .gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-modal .gbar-file.gbar-on .gbar-file-main{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent)}\n.gbar-modal .gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,\"SF Mono\",Consolas,monospace);font-size:11.5px}\n.gbar-modal .gbar-file .gbar-goto{flex:none;color:var(--dsw-alias-label-tertiary);font-size:10px}\n.gbar-modal .gbar-file.gbar-on .gbar-goto{color:var(--dsw-alias-state-business-primary)}\n.gbar-modal .gbar-foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin-top:2px;flex-wrap:wrap}\n.gbar-btn{\n height:34px;padding:0 16px;border:none;border-radius:10px;\n font:inherit;font-size:13.5px;cursor:pointer;\n display:inline-flex;align-items:center;gap:6px;\n}\n.gbar-btn.gbar-ghost{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n.gbar-btn.gbar-ghost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}\n.gbar-btn.gbar-soft{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary)}\n.gbar-btn.gbar-soft:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent)}\n.gbar-btn.gbar-primary{background:var(--dsw-alias-state-business-primary);color:#fff;font-weight:500}\n.gbar-btn.gbar-primary:hover:not(:disabled){opacity:.92}\n/* Disabled buttons (e.g. while a task is running) must NOT light up on hover \u2014\n they keep their muted look, though the tooltip hint still shows. */\n.gbar-btn:disabled{opacity:.5;cursor:default}\n.gbar-btn:disabled:hover{opacity:.5}\n.gbar-notice{\n position:fixed;z-index:150;left:50%;bottom:28px;transform:translateX(-50%);\n max-width:min(520px,90vw);padding:9px 16px;border-radius:10px;font-size:12.5px;line-height:1.5;\n box-shadow:var(--dsw-shadow-lv2);animation:gbar-in .18s cubic-bezier(.32,.72,0,1);\n}\n.gbar-notice.gbar-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 16%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-state-success-primary)}\n.gbar-notice.gbar-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 14%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-state-error-primary)}\n.gbar-spin{width:12px;height:12px;border-radius:50%;border:2px solid color-mix(in srgb,var(--dsw-alias-label-tertiary) 30%,transparent);border-top-color:currentColor;animation:gbar-spin .7s linear infinite}\n@keyframes gbar-spin{to{transform:rotate(360deg)}}\n\n/* branch capsule \u2014 the only interactive half of the header seat: 22px tall\n like the resident agent-preset badge (same 12px type), fully-rounded,\n quiet fill on hover, active tint while the popup is open. */\n.gbar-chip{position:relative;display:inline-flex;align-items:center;gap:4px;height:22px;padding:0 9px;\n border:none;border-radius:16px;background:transparent;color:var(--dsw-alias-label-secondary);\n font:inherit;font-size:12px;font-weight:400;line-height:22px;cursor:pointer;white-space:nowrap;\n -webkit-user-select:none;user-select:none;transition:background .15s ease}\n.gbar-chip:hover,.gbar-chip:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}\n.gbar-chip.gbar-open{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-business-primary)}\n.gbar-chip svg{width:14px;height:14px;flex:none;opacity:.9}\n.gbar-chip-dot{width:6px;height:6px;border-radius:50%;flex:none;pointer-events:none;\n background:var(--dsw-alias-state-warn-primary)}\n.gbar-chip .gbar-bname{max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* folder label \u2014 plain context beside the capsule: NO background (not a\n capsule), not clickable and no hover, so only the branch carries the pill.\n Same 22px / 12px type as the agent-preset badge beside it, and like that\n label the folder name stays selectable so it can be copied with the mouse;\n cursor:auto lets the browser show the text caret over the selectable name,\n exactly like that label. */\n.gbar-fchip{display:inline-flex;align-items:center;gap:4px;height:22px;padding:0 2px;\n color:var(--dsw-alias-label-secondary);\n font:inherit;font-size:12px;font-weight:400;line-height:22px;white-space:nowrap;\n -webkit-user-select:text;user-select:text;cursor:auto}\n.gbar-fchip svg{width:14px;height:14px;flex:none;opacity:.9}\n.gbar-fchip .gbar-folder{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* wraps the interactive branch capsule so its popup anchors to the capsule,\n not to the whole folder + branch row */\n.gbar-bwrap{position:relative;display:inline-flex;align-items:center}\n\n/* icon buttons in side-panel heads (half-screen toggle, diff refresh) */\n.gbar-side-half{border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-tertiary);\n width:28px;height:28px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;\n cursor:pointer;flex:none;transition:background .15s ease,color .15s ease,border-color .15s ease}\n.gbar-side-half:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.gbar-side-half:disabled{opacity:.5;cursor:default}\n.gbar-side-half.gbar-on{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);\n color:var(--dsw-alias-state-business-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 40%,transparent)}\n.gbar-side-half svg{width:15px;height:15px;display:block}\n\n/* hero (new-session) floating chip wrapper */\n.gbar-hero{position:fixed;z-index:110;transform:translateY(-50%);display:inline-flex;align-items:center;gap:6px}\n@media (prefers-reduced-motion:reduce){.gbar-view,.gbar-modal,.gbar-notice,.gbar-pop{animation:none}}\n"; /** Install the GitBar stylesheet once (idempotent); returns the disposer. */ export declare function installGitBarStyles(): () => void; /** * Fetch a target's status into the shared cache WITHOUT rendering anything. * * The session-header chips mount only after the conversation projection * finishes loading — seconds on large inactive sessions — so their own fetch * would start just as late. This warmup runs from the input dock, which mounts * immediately on session switch: by the time the header chip appears it reads * a warm cache and paints folder+branch instantly. */ export declare function warmGitStatus(target: GitTarget): void; /** Input-dock seat for {@link warmGitStatus}: mounts immediately on session * switch (long before the session header does) and kicks off the prefetch. */ export declare function GitWarmup({ sessionId }: { sessionId: SessionId; }): null; export interface BranchChipProps { /** Framework session kit: the definite current session id. */ sessionId: SessionId; /** Injected: the client sessions service (list feed carrying each row's cwd). */ sessionsService: ISessions; /** Injected: the ui-tweaks settings store (reads `gitBarEnabled`). */ controller: SettingsClient; /** Locale-bound translator for the GitBar labels. */ t: Translate; } export declare function BranchChipEntry({ sessionId, sessionsService, controller, t }: BranchChipProps): import("react").JSX.Element | null; export interface DiffPanelProps { /** Framework session kit: the definite current session id. */ sessionId: SessionId; /** Framework session kit: live conversation snapshot selector. */ useSession: (selector: (snapshot: SessionSnapshot) => T) => T; /** Injected: the ui-tweaks settings store (reads `gitBarEnabled`). */ controller: SettingsClient; /** Locale-bound translator for the GitBar labels. */ t: Translate; } export declare function DiffPanel({ sessionId, useSession, controller, t }: DiffPanelProps): import("react").JSX.Element | null; export declare function DiffTabTitle({ sessionId, controller, t }: { sessionId: SessionId; controller: SettingsClient; t: Translate; }): import("react").JSX.Element; /** * Mount the hero floating chip: watch for the workspace picker appearing * (hero mounts/unmounts as sessions open and close), keep a fixed-position * React root anchored just left of it, and re-render on settings changes. */ export declare function installHeroChip(controller: SettingsClient, t: Translate): () => void; export {}; //# sourceMappingURL=gitbar.d.ts.map