claude-remote-cli 3.9.5 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frontend/assets/index-B7wmLeyf.js +52 -0
- package/dist/frontend/assets/index-BTOnhJQN.css +32 -0
- package/dist/frontend/index.html +2 -2
- package/dist/server/branch-linker.js +134 -0
- package/dist/server/config.js +31 -1
- package/dist/server/index.js +186 -2
- package/dist/server/integration-github.js +117 -0
- package/dist/server/integration-jira.js +172 -0
- package/dist/server/org-dashboard.js +222 -0
- package/dist/server/review-poller.js +241 -0
- package/dist/server/sessions.js +43 -3
- package/dist/server/ticket-transitions.js +153 -0
- package/dist/test/branch-linker.test.js +231 -0
- package/dist/test/config.test.js +56 -0
- package/dist/test/integration-github.test.js +203 -0
- package/dist/test/integration-jira.test.js +221 -0
- package/dist/test/org-dashboard.test.js +240 -0
- package/dist/test/review-poller.test.js +344 -0
- package/dist/test/ticket-transitions.test.js +265 -0
- package/package.json +1 -1
- package/dist/frontend/assets/index-BYv7-2w9.css +0 -32
- package/dist/frontend/assets/index-CO9tRKXI.js +0 -52
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.pin-gate.svelte-1qp96yb{display:flex;align-items:center;justify-content:center;height:100vh;background:var(--bg);padding:1rem}.pin-container.svelte-1qp96yb{display:flex;flex-direction:column;align-items:center;gap:1rem;width:100%;max-width:320px;text-align:center}.pin-container.svelte-1qp96yb h1:where(.svelte-1qp96yb){font-size:1.5rem;color:var(--text)}.pin-container.svelte-1qp96yb p:where(.svelte-1qp96yb){color:var(--text-muted);font-size:.95rem}input.svelte-1qp96yb{width:100%;padding:14px 16px;background:var(--surface);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:1.2rem;text-align:center;outline:none;-webkit-appearance:none}input.svelte-1qp96yb:focus{border-color:var(--accent)}button.svelte-1qp96yb{width:100%;padding:14px;background:var(--accent);color:#fff;border:none;border-radius:8px;font-size:1rem;font-weight:600;cursor:pointer;touch-action:manipulation}button.svelte-1qp96yb:active{opacity:.8}.error.svelte-1qp96yb{color:var(--accent);font-size:.9rem}.context-menu-trigger.svelte-1nmhce7{background:none;border:none;color:var(--text-muted);font-size:1rem;font-weight:700;cursor:pointer;padding:0 6px;border-radius:4px;touch-action:manipulation;flex-shrink:0;line-height:1;letter-spacing:1px;min-height:24px;display:inline-flex;align-items:center;transition:color .15s,background .15s}.context-menu-trigger.svelte-1nmhce7:hover{color:var(--text);background:var(--border)}.context-menu-backdrop.svelte-1nmhce7{position:fixed;top:0;right:0;bottom:0;left:0;z-index:999}.context-menu.svelte-1nmhce7{position:fixed;list-style:none;margin:0;padding:4px 0;background:var(--surface);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 16px #0006;z-index:1000;min-width:175px}.context-menu-item.svelte-1nmhce7{padding:9px 14px;font-size:.85rem;cursor:pointer;color:var(--text);white-space:nowrap}.context-menu-item.svelte-1nmhce7:hover{background:var(--border)}.context-menu-item.svelte-1nmhce7:focus{outline:2px solid var(--accent);outline-offset:-2px}.context-menu-item--danger.svelte-1nmhce7{color:#e74c3c}.context-menu-item--danger.svelte-1nmhce7:hover{background:#e74c3c1f}.context-menu-item--disabled.svelte-1nmhce7{opacity:.4;cursor:default}.context-menu-item--disabled.svelte-1nmhce7:hover{background:none}.workspace-item.svelte-168i8d5{display:flex;flex-direction:column}.workspace-header.svelte-168i8d5{display:flex;align-items:center;justify-content:space-between;padding:8px 10px;cursor:pointer;min-height:44px;transition:background .12s}.workspace-header.svelte-168i8d5:hover{background:var(--surface-hover)}.workspace-item.active.svelte-168i8d5 .workspace-header:where(.svelte-168i8d5){background:var(--surface-hover)}.workspace-left.svelte-168i8d5{display:flex;align-items:center;gap:8px;min-width:0;flex:1}.workspace-header.reorder-mode.svelte-168i8d5{cursor:grab}.workspace-header.reorder-mode.svelte-168i8d5:active{cursor:grabbing}.collapse-chevron.svelte-168i8d5{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:.7rem;color:var(--text-muted);cursor:pointer;flex-shrink:0;transition:color .12s}.collapse-chevron.svelte-168i8d5:hover{color:var(--text)}.collapse-count.svelte-168i8d5{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);background:var(--border);border-radius:8px;padding:1px 6px;flex-shrink:0}.initial-block.svelte-168i8d5{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:4px;font-size:var(--font-size-xs);font-weight:700;color:#000;font-family:var(--font-mono);flex-shrink:0;line-height:1}.workspace-name.svelte-168i8d5{font-size:var(--font-size-sm);font-weight:700;color:var(--text);font-family:var(--font-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.workspace-actions.svelte-168i8d5{display:flex;align-items:center;gap:2px;opacity:0;transition:opacity .12s;flex-shrink:0}.workspace-header.svelte-168i8d5:hover .workspace-actions:where(.svelte-168i8d5){opacity:1}.action-btn.svelte-168i8d5{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:3px;font-size:var(--font-size-xs);color:var(--text-muted);cursor:pointer;font-family:var(--font-mono);transition:background .1s,color .1s}.action-btn.svelte-168i8d5:hover{background:var(--border);color:var(--text)}.session-list.svelte-168i8d5{list-style:none}.session-row.svelte-168i8d5{position:relative;display:flex;flex-direction:column;gap:2px;padding:6px 10px 6px 36px;cursor:pointer;min-height:44px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);transition:background .1s;border-left:3px solid transparent;justify-content:center}.session-row.svelte-168i8d5:hover{background:var(--surface-hover);color:var(--text)}.session-row.selected.svelte-168i8d5{border-left-color:var(--accent);background:var(--surface-hover);color:var(--text)}.session-row.attention.svelte-168i8d5 .session-name:where(.svelte-168i8d5){font-weight:700;color:var(--text)}.session-row-primary.svelte-168i8d5{display:flex;align-items:center;gap:8px;min-width:0}.session-row-secondary.svelte-168i8d5{display:flex;align-items:center;gap:6px;padding-left:15px;font-size:.65rem;color:var(--text-muted);min-width:0}.secondary-branch.svelte-168i8d5{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.row-menu-overlay.svelte-168i8d5{position:absolute;right:8px;top:0;bottom:0;display:flex;align-items:center;opacity:0;transition:opacity .12s}.session-row.svelte-168i8d5:hover .row-menu-overlay:where(.svelte-168i8d5){opacity:1}.secondary-pr.svelte-168i8d5{white-space:nowrap;flex-shrink:0;color:var(--accent)}.secondary-time.svelte-168i8d5{white-space:nowrap;flex-shrink:0;opacity:.7}.session-count-badge.svelte-168i8d5{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;border-radius:8px;background:var(--border);color:var(--text-muted);font-size:.55rem;font-family:var(--font-mono);font-weight:600;padding:0 4px;flex-shrink:0}.diff-badge.svelte-168i8d5{display:inline-flex;align-items:center;gap:4px;font-size:.6rem;flex-shrink:0;margin-left:auto}.diff-add.svelte-168i8d5{color:var(--status-success)}.diff-del.svelte-168i8d5{color:var(--status-error)}.status-dot.svelte-168i8d5{display:inline-block;width:7px;height:7px;border-radius:50%;flex-shrink:0}.status-dot--running.svelte-168i8d5{background:var(--status-success)}.status-dot--idle.svelte-168i8d5{background:var(--status-info)}.dot-inactive.svelte-168i8d5{width:7px;height:7px;border-radius:50%;background:#555;flex-shrink:0}.session-row.inactive.svelte-168i8d5 .session-name:where(.svelte-168i8d5){color:var(--text-muted)}.session-row.inactive.svelte-168i8d5:hover .session-name:where(.svelte-168i8d5){color:var(--text)}.session-row.loading.svelte-168i8d5{pointer-events:none;opacity:.7}.session-row.loading.svelte-168i8d5 .session-name:where(.svelte-168i8d5){color:var(--accent)}.status-dot--attention.svelte-168i8d5{background:var(--status-warning);box-shadow:0 0 5px 1px #fbbf2473;animation:svelte-168i8d5-attention-glow 2s ease-in-out infinite}.status-dot--permission-prompt.svelte-168i8d5{background:#eab308;box-shadow:0 0 5px 1px #eab30873;animation:svelte-168i8d5-attention-glow 1.5s ease-in-out infinite}@keyframes svelte-168i8d5-attention-glow{0%,to{box-shadow:0 0 3px 1px #fbbf244d}50%{box-shadow:0 0 7px 2px #fbbf2499}}.terminal-icon.svelte-168i8d5{font-size:.6rem;font-weight:700;color:var(--text-muted);flex-shrink:0;font-family:var(--font-mono);line-height:1}.session-name.svelte-168i8d5{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;min-width:0}.session-name.bold.svelte-168i8d5{font-weight:700}.add-worktree-row.svelte-168i8d5{padding:4px 10px 6px 36px}.add-worktree-btn.svelte-168i8d5{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);opacity:.5;cursor:pointer;transition:opacity .1s,color .1s}.add-worktree-btn.svelte-168i8d5:hover{opacity:1;color:var(--text)}.add-worktree-row.disabled.svelte-168i8d5{pointer-events:none}.add-worktree-row.disabled.svelte-168i8d5 .add-worktree-btn:where(.svelte-168i8d5){opacity:.7;color:var(--accent)}.workspace-divider.svelte-168i8d5{height:1px;background:var(--border);margin:0}@media(max-width:600px){.workspace-header.svelte-168i8d5,.session-row.svelte-168i8d5{min-height:48px}.workspace-actions.svelte-168i8d5{opacity:1}.row-menu-overlay.svelte-168i8d5{display:none}}.smart-search.svelte-itm1qs{position:relative;flex-shrink:0}.input-row.svelte-itm1qs{display:flex;align-items:center;padding:6px 10px;border-bottom:1px solid var(--border);gap:6px}.prompt.svelte-itm1qs{font-family:var(--font-mono);font-size:var(--font-size-sm);color:var(--accent);flex-shrink:0;line-height:1;-webkit-user-select:none;user-select:none}.search-input.svelte-itm1qs{flex:1;background:transparent;border:none;outline:none;color:var(--text);font-family:var(--font-mono);font-size:var(--font-size-sm);caret-color:var(--accent)}.search-input.svelte-itm1qs::placeholder{color:var(--text-muted);opacity:.5}.dropdown.svelte-itm1qs{position:absolute;top:100%;left:0;right:0;background:var(--surface);border:1px solid var(--border);border-top:none;list-style:none;z-index:200;max-height:240px;overflow-y:auto}.dropdown-item.svelte-itm1qs{display:flex;align-items:baseline;gap:6px;padding:8px 10px;cursor:pointer;font-family:var(--font-mono);font-size:var(--font-size-sm);color:var(--text-muted);transition:background .1s;white-space:nowrap;overflow:hidden}.dropdown-item.svelte-itm1qs:hover,.dropdown-item.focused.svelte-itm1qs{background:var(--surface-hover);color:var(--text)}.dropdown-item.svelte-itm1qs strong:where(.svelte-itm1qs){color:var(--text);font-weight:700}.dropdown-path.svelte-itm1qs{font-size:var(--font-size-xs);color:var(--text-muted);opacity:.5;overflow:hidden;text-overflow:ellipsis;min-width:0;flex-shrink:1}@media(max-width:600px){.smart-search.svelte-itm1qs{width:100%}.input-row.svelte-itm1qs{width:100%;box-sizing:border-box}.search-input.svelte-itm1qs{width:100%;min-width:0}}.sidebar.svelte-owj5vn{position:relative;display:flex;flex-direction:column;background:var(--bg);border-right:1px solid var(--border);overflow:hidden;transition:transform .25s ease,width .2s ease,min-width .2s ease;z-index:100}.resize-handle.svelte-owj5vn{position:absolute;top:0;right:0;width:4px;height:100%;cursor:col-resize;z-index:10;transition:background .15s}.resize-handle.svelte-owj5vn:hover{background:var(--accent)}.sidebar-header.svelte-owj5vn{display:flex;align-items:center;justify-content:space-between;padding:12px 10px;border-bottom:1px solid var(--border);flex-shrink:0}.sidebar-label.svelte-owj5vn{flex:1;font-size:var(--font-size-xs);font-weight:600;color:var(--text-muted);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em}.collapse-btn.svelte-owj5vn{background:none;border:none;color:var(--text-muted);font-size:1.1rem;cursor:pointer;padding:8px 10px;border-radius:4px;flex-shrink:0;line-height:1;font-family:var(--font-mono);min-width:36px;min-height:36px;display:flex;align-items:center;justify-content:center}.collapse-btn.svelte-owj5vn:hover{color:var(--text);background:var(--border)}.sidebar.collapsed.svelte-owj5vn .sidebar-header:where(.svelte-owj5vn){justify-content:center;padding:12px 4px}.icon-btn.svelte-owj5vn{background:none;border:none;color:var(--text);font-size:1.2rem;cursor:pointer;padding:4px 6px;border-radius:4px;touch-action:manipulation;display:none}.icon-btn.svelte-owj5vn:active{background:var(--border)}.home-btn.svelte-owj5vn{display:flex;align-items:center;gap:8px;padding:8px 10px;min-height:44px;cursor:pointer;border-left:3px solid transparent;transition:background .12s,border-color .12s;flex-shrink:0}.home-btn.svelte-owj5vn:hover{background:var(--surface-hover)}.home-btn--active.svelte-owj5vn{border-left-color:var(--accent);background:var(--surface-hover)}.home-icon.svelte-owj5vn{font-size:1rem;color:var(--text-muted);flex-shrink:0}.home-label.svelte-owj5vn{font-size:var(--font-size-sm);font-family:var(--font-mono);font-weight:600;color:var(--text)}.group-header.svelte-owj5vn{padding:10px 10px 4px;font-size:10px;font-family:var(--font-mono);font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:1.5px}.workspace-list.svelte-owj5vn{flex:1;overflow-y:auto;overflow-x:hidden}.empty-state.svelte-owj5vn{padding:16px 10px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);opacity:.5;text-align:center}.sidebar-footer-row.svelte-owj5vn{display:flex;gap:8px;margin:8px;align-items:stretch;flex-shrink:0}.add-workspace-btn.svelte-owj5vn{flex:1;padding:10px 12px;min-height:40px;background:none;border:1px solid var(--accent);border-radius:0;color:var(--accent);font-size:var(--font-size-xs);font-family:var(--font-mono);cursor:pointer;touch-action:manipulation;text-align:center;transition:background .1s}.add-workspace-btn.svelte-owj5vn:hover{background:color-mix(in srgb,var(--accent) 12%,transparent)}.add-workspace-btn.svelte-owj5vn:active{background:var(--border)}.done-reorder-btn.svelte-owj5vn{margin:8px;padding:10px 12px;min-height:40px;background:none;border:1px solid var(--accent);border-radius:0;color:var(--accent);font-size:var(--font-size-xs);font-family:var(--font-mono);cursor:pointer;touch-action:manipulation;text-align:center;flex-shrink:0;transition:background .1s}.done-reorder-btn.svelte-owj5vn:hover{background:color-mix(in srgb,var(--accent) 12%,transparent)}.done-reorder-btn.svelte-owj5vn:active{background:var(--border)}.settings-icon-btn.svelte-owj5vn{width:40px;min-height:40px;background:none;border:1px solid var(--border);border-radius:0;color:var(--text-muted);font-size:1rem;cursor:pointer;touch-action:manipulation;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .1s,color .1s}.settings-icon-btn.svelte-owj5vn:hover{background:var(--surface-hover);color:var(--text)}.settings-icon-btn.svelte-owj5vn:active{background:var(--border)}@media(max-width:600px){.sidebar.svelte-owj5vn{position:fixed;top:0;left:0;height:100%;transform:translate(-100%);box-shadow:2px 0 12px #00000080;transition:transform .25s ease}.sidebar.open.svelte-owj5vn{transform:translate(0)}.collapse-btn.svelte-owj5vn{display:none}.icon-btn.svelte-owj5vn{display:block;font-size:1.4rem;padding:4px 8px}.resize-handle.svelte-owj5vn{display:none}}/**
|
|
2
|
+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
+
* https://github.com/chjj/term.js
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Originally forked from (with the author's permission):
|
|
26
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
+
* http://bellard.org/jslinux/
|
|
28
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
+
* The original design remains. The terminal itself
|
|
30
|
+
* has been extended to include xterm CSI codes, among
|
|
31
|
+
* other features.
|
|
32
|
+
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.terminal-wrapper.svelte-5qgfij{display:flex;flex:1;min-height:0;position:relative;overflow:hidden}.terminal-container.svelte-5qgfij{flex:1;min-width:0;min-height:0;overflow:hidden;padding:4px}.terminal-wrapper.drag-over.svelte-5qgfij{outline:2px dashed var(--accent);outline-offset:-2px}.terminal-scrollbar.svelte-5qgfij{width:8px;background:transparent;position:relative;flex-shrink:0}.terminal-scrollbar-thumb.svelte-5qgfij{position:absolute;right:0;width:6px;background:var(--border);border-radius:3px;cursor:pointer}@media(hover:none){.terminal-wrapper.selection-mode.svelte-5qgfij .terminal-container:where(.svelte-5qgfij){outline:2px solid var(--accent);outline-offset:-2px}.terminal-container.svelte-5qgfij{touch-action:none}.terminal-scrollbar.svelte-5qgfij{width:12px}.terminal-scrollbar-thumb.svelte-5qgfij{width:8px;min-height:44px}.scroll-fabs.svelte-5qgfij{position:absolute;right:16px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:12px;z-index:1;opacity:.6;pointer-events:auto}.scroll-fab.svelte-5qgfij{width:44px;height:44px;border-radius:50%;border:1px solid var(--border);background:var(--surface);color:var(--text);font-size:18px;display:flex;align-items:center;justify-content:center;cursor:pointer;touch-action:manipulation;-webkit-user-select:none;user-select:none}.scroll-fab.svelte-5qgfij:active{opacity:1;background:var(--border)}.scroll-fab-bottom.svelte-5qgfij{margin-top:4px}}.branch-switcher.svelte-1ogsozk{position:relative}.branch-trigger.svelte-1ogsozk{display:flex;align-items:center;gap:5px;background:none;border:none;color:var(--text);font-family:var(--font-mono);font-size:var(--font-size-sm);cursor:pointer;padding:4px 6px;border-radius:4px;transition:background .12s;white-space:nowrap;min-width:0}.branch-trigger.svelte-1ogsozk:hover{background:var(--surface-hover)}.branch-icon.svelte-1ogsozk{color:var(--text-muted);font-size:.9rem;flex-shrink:0}.branch-name.svelte-1ogsozk{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}.branch-caret.svelte-1ogsozk{flex-shrink:0;color:var(--text-muted);margin-left:1px}.branch-dropdown.svelte-1ogsozk{position:absolute;top:calc(100% + 4px);left:0;min-width:220px;max-width:340px;background:var(--surface);border:1px solid var(--border);border-radius:4px;z-index:200;overflow:hidden;box-shadow:0 4px 16px #00000080}.branch-filter-wrap.svelte-1ogsozk{padding:6px 6px 4px;border-bottom:1px solid var(--border)}.branch-filter.svelte-1ogsozk{width:100%;background:var(--bg);border:1px solid var(--border);border-radius:3px;color:var(--text);font-family:var(--font-mono);font-size:var(--font-size-xs);padding:4px 8px;outline:none;box-sizing:border-box}.branch-filter.svelte-1ogsozk:focus{border-color:var(--accent)}.branch-error.svelte-1ogsozk{font-size:var(--font-size-xs);color:var(--status-error);padding:4px 10px}.branch-loading.svelte-1ogsozk,.branch-empty.svelte-1ogsozk{font-size:var(--font-size-xs);color:var(--text-muted);padding:8px 10px;font-style:italic}.branch-list.svelte-1ogsozk{list-style:none;margin:0;padding:4px 0;max-height:240px;overflow-y:auto}.branch-option.svelte-1ogsozk{display:flex;align-items:center;gap:6px;padding:5px 10px;font-size:var(--font-size-xs);cursor:pointer;white-space:nowrap;overflow:hidden;color:var(--text-muted);transition:background .1s,color .1s}.branch-option.svelte-1ogsozk:hover{background:var(--surface-hover);color:var(--text)}.branch-current.svelte-1ogsozk,.branch-current.svelte-1ogsozk:hover{color:var(--accent)}.branch-switching.svelte-1ogsozk{opacity:.6;pointer-events:none}.branch-check.svelte-1ogsozk{font-size:.65rem;width:10px;flex-shrink:0;color:var(--accent)}.branch-check--empty.svelte-1ogsozk{display:inline-block}.branch-option-name.svelte-1ogsozk{overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.branch-spinner.svelte-1ogsozk{color:var(--text-muted);font-size:var(--font-size-xs);flex-shrink:0}.pr-top-bar.svelte-1shtc4l{display:flex;align-items:center;height:36px;background:var(--surface);border-bottom:1px solid var(--border);padding:0 8px;gap:0;flex-shrink:0;overflow:hidden;font-family:var(--font-mono);font-size:var(--font-size-sm)}.bar-left.svelte-1shtc4l{display:flex;align-items:center;gap:4px;flex:1;min-width:0;overflow:hidden;padding-right:8px;border-right:1px solid var(--border)}.target-branch.svelte-1shtc4l{display:flex;align-items:center;gap:3px;color:var(--text-muted);font-size:var(--font-size-xs);flex-shrink:0;white-space:nowrap}.target-sep.svelte-1shtc4l{color:var(--border);font-size:.75rem}.target-name.svelte-1shtc4l{overflow:hidden;text-overflow:ellipsis;max-width:100px}.bar-middle.svelte-1shtc4l{display:flex;align-items:center;padding:0 12px;border-right:1px solid var(--border);flex-shrink:0;white-space:nowrap}.pr-link.svelte-1shtc4l{display:flex;align-items:center;gap:4px;color:var(--text-muted);text-decoration:none;font-size:var(--font-size-xs);transition:color .12s}.pr-link.svelte-1shtc4l:hover{color:var(--accent)}.pr-ext-icon.svelte-1shtc4l{flex-shrink:0;opacity:.6}.bar-right.svelte-1shtc4l{display:flex;align-items:center;padding-left:10px;flex-shrink:0}.bar-loading.svelte-1shtc4l{color:var(--text-muted);font-size:var(--font-size-xs);padding:0 4px}.action-btn.svelte-1shtc4l{display:inline-flex;align-items:center;justify-content:center;height:22px;padding:0 10px;border-radius:11px;border:none;background:var(--action-color, var(--border));color:#fff;font-family:var(--font-mono);font-size:var(--font-size-xs);font-weight:500;cursor:pointer;white-space:nowrap;transition:opacity .12s,filter .12s;letter-spacing:.01em}.action-btn.svelte-1shtc4l:hover:not(:disabled){filter:brightness(1.15)}.action-btn.svelte-1shtc4l:active:not(:disabled){filter:brightness(.9)}.action-btn--dark-text.svelte-1shtc4l{color:#000}.action-btn--disabled.svelte-1shtc4l{cursor:default;opacity:.7}.bar-merged.svelte-1shtc4l{background:color-mix(in srgb,var(--status-merged) 8%,var(--surface))}.bar-conflicts.svelte-1shtc4l{background:color-mix(in srgb,var(--status-error) 8%,var(--surface))}.diff-stats.svelte-1shtc4l{display:flex;align-items:center;gap:6px;font-family:var(--font-mono);font-size:var(--font-size-xs);padding:0 8px;flex-shrink:0}.diff-add.svelte-1shtc4l{color:var(--status-success)}.diff-del.svelte-1shtc4l{color:var(--status-error)}.action-btn--secondary.svelte-1shtc4l{background:var(--border)!important;color:var(--text)!important;margin-right:6px}@media(max-width:600px){.target-branch.svelte-1shtc4l,.bar-middle.svelte-1shtc4l,.diff-stats.svelte-1shtc4l{display:none}.bar-left.svelte-1shtc4l{border-right:none;padding-right:4px}}.session-tab-bar.svelte-3dfyyn{display:flex;align-items:stretch;height:32px;background:var(--bg);border-bottom:1px solid var(--border);flex-shrink:0;font-family:var(--font-mono);font-size:var(--font-size-xs)}.tabs-scroll.svelte-3dfyyn{display:flex;align-items:stretch;overflow-x:auto;overflow-y:hidden;flex:1;min-width:0;scrollbar-width:none}.tabs-scroll.svelte-3dfyyn::-webkit-scrollbar{display:none}.tab.svelte-3dfyyn{display:inline-flex;align-items:center;gap:5px;height:32px;padding:0 10px;background:transparent;border:none;border-bottom:2px solid transparent;color:var(--text-muted);font-family:var(--font-mono);font-size:var(--font-size-xs);cursor:pointer;white-space:nowrap;flex-shrink:0;position:relative;transition:color .12s,background .12s;border-radius:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.tab.svelte-3dfyyn:hover{color:var(--text);background:var(--surface-hover)}.tab--active.svelte-3dfyyn{background:var(--surface);color:var(--text);border-bottom-color:var(--accent)}.tab--active.svelte-3dfyyn:hover{background:var(--surface)}.tab-icon.svelte-3dfyyn{font-size:.7rem;line-height:1;flex-shrink:0}.tab-name.svelte-3dfyyn{max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tab-close.svelte-3dfyyn{font-size:var(--font-size-xs);color:var(--text-muted);cursor:pointer;line-height:1;flex-shrink:0;border-radius:3px;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;opacity:0;transition:opacity .1s,color .1s,background .1s}.tab.svelte-3dfyyn:hover .tab-close:where(.svelte-3dfyyn){opacity:1}.tab-close.svelte-3dfyyn:hover{color:var(--text);background:var(--border)}.tab--active.svelte-3dfyyn .tab-close:where(.svelte-3dfyyn){opacity:0}.tab--active.svelte-3dfyyn:hover .tab-close:where(.svelte-3dfyyn){opacity:1}.new-btn-wrap.svelte-3dfyyn{position:relative;display:flex;align-items:center;flex-shrink:0;border-left:1px solid var(--border)}.tab-new.svelte-3dfyyn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;background:none;border:none;color:var(--text-muted);font-size:1rem;cursor:pointer;font-family:var(--font-mono);transition:color .12s,background .12s;-webkit-appearance:none;-moz-appearance:none;appearance:none;line-height:1}.tab-new.svelte-3dfyyn:hover{color:var(--text);background:var(--surface-hover)}.new-menu.svelte-3dfyyn{position:absolute;top:calc(100% + 2px);right:0;background:var(--surface);border:1px solid var(--border);border-radius:4px;z-index:200;min-width:180px;box-shadow:0 4px 16px #00000080;padding:4px 0}.new-menu-item.svelte-3dfyyn{display:flex;align-items:center;gap:8px;width:100%;padding:7px 12px;background:none;border:none;color:var(--text-muted);font-family:var(--font-mono);font-size:var(--font-size-xs);cursor:pointer;text-align:left;transition:background .1s,color .1s;-webkit-appearance:none;-moz-appearance:none;appearance:none;white-space:nowrap}.new-menu-item.svelte-3dfyyn:hover{background:var(--surface-hover);color:var(--text)}.new-menu-icon.svelte-3dfyyn{font-size:.75rem;flex-shrink:0}.new-menu-divider.svelte-3dfyyn{height:1px;background:var(--border);margin:4px 0}@media(max-width:600px){.session-tab-bar.svelte-3dfyyn{height:44px}.tab.svelte-3dfyyn{height:44px;padding:0 12px;min-width:44px}.tab-close.svelte-3dfyyn{opacity:1;width:18px;height:18px}.tab--active.svelte-3dfyyn .tab-close:where(.svelte-3dfyyn){opacity:1}.tab-new.svelte-3dfyyn{width:44px;height:44px}}.repo-dashboard.svelte-bvvs2r{display:flex;flex-direction:column;gap:20px;padding:20px;background:var(--bg);min-height:0;max-width:none;overflow:hidden;flex:1}.dashboard-section.svelte-bvvs2r{display:flex;flex-direction:column;gap:8px;flex-shrink:0}.dashboard-section--scroll.svelte-bvvs2r{flex:1;min-height:120px;overflow:hidden}.scroll-container.svelte-bvvs2r{position:relative;flex:1;min-height:0;overflow-y:auto;overflow-x:hidden}.dashboard-section--scroll.svelte-bvvs2r{position:relative}.dashboard-section--scroll.svelte-bvvs2r:after{content:"";position:absolute;bottom:0;left:0;right:0;height:32px;background:linear-gradient(to bottom,transparent,var(--bg));pointer-events:none;z-index:1}.section-heading.svelte-bvvs2r{font-size:var(--font-size-sm);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);padding-bottom:6px;border-bottom:1px solid var(--border)}.section-message.svelte-bvvs2r{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text-muted);padding:6px 0}.section-message.info.svelte-bvvs2r a:where(.svelte-bvvs2r){color:var(--accent);text-decoration:none}.section-message.info.svelte-bvvs2r a:where(.svelte-bvvs2r):hover{text-decoration:underline}.pr-search.svelte-bvvs2r{padding:8px 10px;font-size:var(--font-size-sm);font-family:var(--font-mono);background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);outline:none;transition:border-color .12s}.pr-search.svelte-bvvs2r::placeholder{color:var(--text-muted);opacity:.6}.pr-search.svelte-bvvs2r:focus{border-color:var(--accent)}.pr-list.svelte-bvvs2r{display:flex;flex-direction:column;gap:0;border:1px solid var(--border);border-radius:4px;overflow:hidden}.pr-row.svelte-bvvs2r{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border-bottom:1px solid var(--border)}.pr-row.svelte-bvvs2r:last-child{border-bottom:none}.pr-row-left.svelte-bvvs2r{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}.pr-row-title-line.svelte-bvvs2r{display:flex;align-items:center;gap:8px;min-width:0}.pr-title-link.svelte-bvvs2r{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text);text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1}.pr-title-link.svelte-bvvs2r:hover{color:var(--accent);text-decoration:underline}.pr-row-actions.svelte-bvvs2r{display:flex;align-items:center;gap:8px;flex-shrink:0}.pr-session-btn.svelte-bvvs2r{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;border:1px solid var(--border);background:transparent;color:var(--text-muted);font-size:var(--font-size-sm);font-family:var(--font-mono);cursor:pointer;transition:background .12s,color .12s,border-color .12s;flex-shrink:0}.pr-session-btn.svelte-bvvs2r:hover{background:color-mix(in srgb,var(--accent) 12%,transparent);border-color:var(--accent);color:var(--accent)}.pr-conflict-pill.svelte-bvvs2r{--pill-color: var(--status-error);font-weight:600}.pr-merge-pill.svelte-bvvs2r{--pill-color: var(--status-success);color:#1a1a1a;font-weight:600}.pr-row-meta.svelte-bvvs2r{display:flex;align-items:center;gap:4px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted)}.pr-sep.svelte-bvvs2r{opacity:.4}.dot.svelte-bvvs2r{width:7px;height:7px;border-radius:50%;flex-shrink:0;display:inline-block}.dot-success.svelte-bvvs2r{background:var(--status-success)}.dot-error.svelte-bvvs2r{background:var(--status-error)}.dot-warning.svelte-bvvs2r{background:var(--status-warning)}.dot-muted.svelte-bvvs2r{background:var(--border)}.pr-action-pill.svelte-bvvs2r{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:6px 12px;min-height:32px;border-radius:20px;border:none;background:var(--pill-color, var(--border));font-size:var(--font-size-xs);font-family:var(--font-mono);color:#fff;text-decoration:none;white-space:nowrap;cursor:pointer;transition:opacity .12s}.pr-action-pill.svelte-bvvs2r:hover{opacity:.85}.pr-action-pill.dark-text.svelte-bvvs2r{color:#1a1a1a}.activity-list.svelte-bvvs2r{display:flex;flex-direction:column;gap:4px}.activity-row.svelte-bvvs2r{display:flex;align-items:baseline;gap:8px;font-size:var(--font-size-xs);font-family:var(--font-mono);min-width:0}.commit-hash.svelte-bvvs2r{color:var(--text-muted);flex-shrink:0;letter-spacing:.02em}.commit-msg.svelte-bvvs2r{color:var(--text);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.commit-branch.svelte-bvvs2r{color:var(--text-muted);flex-shrink:0;white-space:nowrap}.commit-time.svelte-bvvs2r{color:var(--text-muted);flex-shrink:0;white-space:nowrap;opacity:.6}.non-git-notice.svelte-bvvs2r{padding:8px 0}.non-git-msg.svelte-bvvs2r{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text-muted)}.cta-row.svelte-bvvs2r{display:flex;align-items:center;gap:10px;padding-top:4px;flex-shrink:0}.cta-btn.svelte-bvvs2r{display:inline-flex;align-items:center;justify-content:center;padding:10px 18px;min-height:40px;background:transparent;border:1px solid var(--accent);border-radius:4px;color:var(--accent);font-size:var(--font-size-sm);font-family:var(--font-mono);cursor:pointer;transition:background .12s,color .12s;white-space:nowrap}.cta-btn.svelte-bvvs2r:hover:not(:disabled){background:color-mix(in srgb,var(--accent) 12%,transparent)}.cta-btn.svelte-bvvs2r:disabled{opacity:.5;cursor:not-allowed}.skeleton.svelte-bvvs2r{pointer-events:none}.skeleton-line.svelte-bvvs2r{background:var(--border);border-radius:3px;animation:svelte-bvvs2r-skeleton-pulse 1.4s ease-in-out infinite}.skeleton-title.svelte-bvvs2r{height:13px;width:60%;margin-bottom:5px}.skeleton-meta.svelte-bvvs2r{height:10px;width:40%}.skeleton-activity.svelte-bvvs2r{height:12px;width:75%}@keyframes svelte-bvvs2r-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}@media(max-width:600px){.repo-dashboard.svelte-bvvs2r{padding:14px}.pr-row.svelte-bvvs2r{flex-wrap:wrap;gap:8px;padding:12px 10px;min-height:44px;align-items:flex-start}.pr-row-left.svelte-bvvs2r{width:100%}.pr-action-pill.svelte-bvvs2r{align-self:flex-end;margin-left:auto;padding:5px 12px;min-height:32px}.cta-btn.svelte-bvvs2r{flex:1;min-height:44px}}.ticket-card.svelte-wipetl{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border-bottom:1px solid var(--border);background:var(--bg);transition:background .1s}.ticket-card.svelte-wipetl:last-child{border-bottom:none}.ticket-card.svelte-wipetl:hover{background:var(--surface)}.ticket-left.svelte-wipetl{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}.ticket-title-line.svelte-wipetl{display:flex;align-items:center;gap:8px;min-width:0}.ticket-title-link.svelte-wipetl{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text);text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1}.ticket-title-link.svelte-wipetl:hover{color:var(--accent);text-decoration:underline}.ticket-meta.svelte-wipetl{display:flex;align-items:center;gap:4px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);flex-wrap:wrap}.ticket-sep.svelte-wipetl{opacity:.4}.ticket-number.svelte-wipetl{opacity:.6}.ticket-key.svelte-wipetl{font-weight:600;opacity:.8}.repo-chip.svelte-wipetl{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:700;color:#000;white-space:nowrap;line-height:1.4}.label-chip.svelte-wipetl{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:600;color:#000;white-space:nowrap;line-height:1.4;max-width:80px;overflow:hidden;text-overflow:ellipsis}.status-badge.svelte-wipetl{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:600;color:var(--text-muted);background:var(--surface);border:1px solid var(--border);white-space:nowrap;line-height:1.4}.priority-badge.svelte-wipetl{font-weight:600;white-space:nowrap}.sprint-chip.svelte-wipetl{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);background:var(--surface);border:1px solid var(--border);white-space:nowrap;line-height:1.4;max-width:100px;overflow:hidden;text-overflow:ellipsis}.points-badge.svelte-wipetl{font-weight:600;opacity:.7}.branch-chip.svelte-wipetl{display:inline-flex;align-items:center;gap:4px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);opacity:.8}.dot.svelte-wipetl{width:7px;height:7px;border-radius:50%;flex-shrink:0;display:inline-block}.dot-inline.svelte-wipetl{width:6px;height:6px}.dot-success.svelte-wipetl{background:var(--status-success)}.dot-muted.svelte-wipetl{background:var(--border)}.dot-active.svelte-wipetl{background:var(--accent)}.dot-info.svelte-wipetl{background:var(--accent);opacity:.6}.ticket-actions.svelte-wipetl{display:flex;align-items:center;flex-shrink:0}.start-work-btn.svelte-wipetl{padding:5px 12px;font-size:var(--font-size-xs);font-family:var(--font-mono);background:none;border:1px solid var(--border);border-radius:4px;color:var(--text-muted);cursor:not-allowed;opacity:.45;white-space:nowrap;transition:border-color .12s,color .12s,opacity .12s}.start-work-btn--active.svelte-wipetl{cursor:pointer;opacity:1}.start-work-btn--active.svelte-wipetl:hover{border-color:var(--accent);color:var(--accent)}@media(max-width:600px){.ticket-card.svelte-wipetl{flex-direction:column;align-items:flex-start;gap:8px;padding:12px 10px}.ticket-left.svelte-wipetl{width:100%}.ticket-actions.svelte-wipetl{align-self:flex-end}}.tickets-panel.svelte-htgqk2{display:flex;flex-direction:column;gap:12px}.tab-strip.svelte-htgqk2{display:flex;gap:0;border-bottom:1px solid var(--border);flex-shrink:0}.tab-btn.svelte-htgqk2{padding:6px 14px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:600;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;margin-bottom:-1px;transition:color .12s,border-color .12s;white-space:nowrap;text-transform:uppercase;letter-spacing:.06em}.tab-btn.svelte-htgqk2:hover{color:var(--text)}.tab-btn--active.svelte-htgqk2{color:var(--accent);border-bottom-color:var(--accent)}.panel-header.svelte-htgqk2{display:flex;align-items:baseline;gap:8px;flex-shrink:0}.panel-title.svelte-htgqk2{font-size:var(--font-size-sm);font-family:var(--font-mono);font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.panel-count.svelte-htgqk2{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);opacity:.7;font-weight:400;text-transform:none;letter-spacing:0}.state-message.svelte-htgqk2{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text-muted);padding:6px 0;display:flex;align-items:center;gap:10px;flex-shrink:0}.state-message--info.svelte-htgqk2 a:where(.svelte-htgqk2){color:var(--accent);text-decoration:none}.state-message--info.svelte-htgqk2 a:where(.svelte-htgqk2):hover{text-decoration:underline}.retry-btn.svelte-htgqk2{background:none;border:1px solid var(--border);border-radius:4px;color:var(--text-muted);font-size:var(--font-size-xs);font-family:var(--font-mono);cursor:pointer;padding:4px 10px;transition:border-color .12s,color .12s}.retry-btn.svelte-htgqk2:hover{border-color:var(--accent);color:var(--accent)}.ticket-list.svelte-htgqk2{display:flex;flex-direction:column;gap:0;border:1px solid var(--border);border-radius:4px;overflow:hidden;flex-shrink:0}.ticket-skeleton.svelte-htgqk2{display:flex;flex-direction:column;justify-content:center;gap:6px;padding:10px 12px;border-bottom:1px solid var(--border);min-height:56px;pointer-events:none}.ticket-skeleton.svelte-htgqk2:last-child{border-bottom:none}.skeleton-line.svelte-htgqk2{background:var(--border);border-radius:3px;animation:svelte-htgqk2-skeleton-pulse 1.4s ease-in-out infinite}.skeleton-title.svelte-htgqk2{height:13px;width:60%}.skeleton-meta.svelte-htgqk2{height:10px;width:40%}@keyframes svelte-htgqk2-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}@media(max-width:600px){.tab-btn.svelte-htgqk2{padding:5px 10px}}.modal-backdrop.svelte-1d388up{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000}.modal.svelte-1d388up{background:var(--bg);border:1px solid var(--border);border-radius:8px;width:90%;max-width:420px;box-shadow:0 8px 32px #0000004d}.modal-header.svelte-1d388up{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--border)}.modal-title.svelte-1d388up{font-size:var(--font-size-sm);font-family:var(--font-mono);font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text)}.modal-close.svelte-1d388up{background:none;border:none;color:var(--text-muted);font-size:18px;cursor:pointer;padding:0 4px;line-height:1}.modal-close.svelte-1d388up:hover{color:var(--text)}.modal-body.svelte-1d388up{padding:16px;display:flex;flex-direction:column;gap:12px}.ticket-info.svelte-1d388up{display:flex;flex-direction:column;gap:2px}.ticket-info-label.svelte-1d388up{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em}.ticket-info-value.svelte-1d388up{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text)}.field.svelte-1d388up{display:flex;flex-direction:column;gap:4px}.field-label.svelte-1d388up{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em}.field-input.svelte-1d388up{padding:8px 10px;font-size:var(--font-size-sm);font-family:var(--font-mono);background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);outline:none;transition:border-color .12s}.field-input.svelte-1d388up:focus{border-color:var(--accent)}.error-msg.svelte-1d388up{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--status-error);padding:6px 8px;background:#ff64641a;border-radius:4px}.modal-footer.svelte-1d388up{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border)}.btn.svelte-1d388up{padding:7px 16px;font-size:var(--font-size-xs);font-family:var(--font-mono);border-radius:4px;border:1px solid var(--border);cursor:pointer;transition:background .12s,border-color .12s,color .12s;white-space:nowrap}.btn.svelte-1d388up:disabled{opacity:.5;cursor:not-allowed}.btn-secondary.svelte-1d388up{background:none;color:var(--text-muted)}.btn-secondary.svelte-1d388up:hover:not(:disabled){color:var(--text);border-color:var(--text-muted)}.btn-primary.svelte-1d388up{background:var(--accent);color:#000;border-color:var(--accent);font-weight:600}.btn-primary.svelte-1d388up:hover:not(:disabled){opacity:.9}.automation-panel.svelte-13z9fw2{display:flex;flex-direction:column;gap:10px;border:1px solid var(--border);border-radius:4px;padding:12px;background:var(--bg);flex-shrink:0}.panel-header.svelte-13z9fw2{display:flex;align-items:center;gap:8px}.panel-title.svelte-13z9fw2{font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-muted)}.panel-loading.svelte-13z9fw2,.panel-error.svelte-13z9fw2{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);display:flex;align-items:center;gap:8px}.retry-btn.svelte-13z9fw2{background:none;border:1px solid var(--border);border-radius:4px;color:var(--text-muted);font-size:var(--font-size-xs);font-family:var(--font-mono);cursor:pointer;padding:3px 8px;transition:border-color .12s,color .12s}.retry-btn.svelte-13z9fw2:hover{border-color:var(--accent);color:var(--accent)}.toggle-list.svelte-13z9fw2{display:flex;flex-direction:column;gap:8px}.toggle-row.svelte-13z9fw2{display:flex;align-items:flex-start;gap:10px;cursor:pointer;padding:4px 0}.toggle-row--disabled.svelte-13z9fw2{opacity:.5;pointer-events:none}.toggle-checkbox.svelte-13z9fw2{margin-top:2px;accent-color:var(--accent);flex-shrink:0;cursor:pointer}.toggle-info.svelte-13z9fw2{display:flex;flex-direction:column;gap:2px}.toggle-label.svelte-13z9fw2{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text)}.toggle-desc.svelte-13z9fw2{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);opacity:.7}.org-dashboard.svelte-126xfdh{display:flex;flex-direction:column;gap:16px;padding:20px;background:var(--bg);flex:1;min-height:0;overflow-y:auto}.org-header.svelte-126xfdh{display:flex;align-items:baseline;gap:12px;padding-bottom:8px;border-bottom:1px solid var(--border);flex-shrink:0}.org-title.svelte-126xfdh{font-size:var(--font-size-sm);font-family:var(--font-mono);font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.org-subtitle.svelte-126xfdh{font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);opacity:.7}.tab-strip.svelte-126xfdh{display:flex;gap:0;border-bottom:1px solid var(--border);flex-shrink:0;margin-top:-4px}.tab-btn.svelte-126xfdh{padding:6px 14px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:600;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;margin-bottom:-1px;transition:color .12s,border-color .12s;white-space:nowrap;text-transform:uppercase;letter-spacing:.06em}.tab-btn.svelte-126xfdh:hover{color:var(--text)}.tab-btn--active.svelte-126xfdh{color:var(--accent);border-bottom-color:var(--accent)}.filter-bar.svelte-126xfdh{display:flex;gap:8px;flex-shrink:0}.filter-select.svelte-126xfdh{padding:6px 10px;font-size:var(--font-size-xs);font-family:var(--font-mono);background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);cursor:pointer;outline:none;transition:border-color .12s}.filter-select.svelte-126xfdh:focus{border-color:var(--accent)}.state-message.svelte-126xfdh{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text-muted);padding:6px 0;display:flex;align-items:center;gap:10px;flex-shrink:0}.state-message--info.svelte-126xfdh a:where(.svelte-126xfdh){color:var(--accent);text-decoration:none}.state-message--info.svelte-126xfdh a:where(.svelte-126xfdh):hover{text-decoration:underline}.retry-btn.svelte-126xfdh{background:none;border:1px solid var(--border);border-radius:4px;color:var(--text-muted);font-size:var(--font-size-xs);font-family:var(--font-mono);cursor:pointer;padding:4px 10px;transition:border-color .12s,color .12s}.retry-btn.svelte-126xfdh:hover{border-color:var(--accent);color:var(--accent)}.pr-list.svelte-126xfdh{display:flex;flex-direction:column;gap:0;border:1px solid var(--border);border-radius:4px;overflow:hidden;flex-shrink:0}.pr-row.svelte-126xfdh{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border-bottom:1px solid var(--border);background:var(--bg);transition:background .1s}.pr-row.svelte-126xfdh:last-child{border-bottom:none}.pr-row.svelte-126xfdh:hover{background:var(--surface)}.pr-row-left.svelte-126xfdh{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}.pr-row-title-line.svelte-126xfdh{display:flex;align-items:center;gap:8px;min-width:0}.pr-title-link.svelte-126xfdh{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text);text-decoration:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1}.pr-title-link.svelte-126xfdh:hover{color:var(--accent);text-decoration:underline}.pr-row-actions.svelte-126xfdh{display:flex;align-items:center;gap:8px;flex-shrink:0}.pr-row-meta.svelte-126xfdh{display:flex;align-items:center;gap:4px;font-size:var(--font-size-xs);font-family:var(--font-mono);color:var(--text-muted);flex-wrap:wrap}.pr-sep.svelte-126xfdh{opacity:.4}.repo-chip.svelte-126xfdh{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:700;color:#000;cursor:pointer;white-space:nowrap;transition:opacity .12s;line-height:1.4}.repo-chip.svelte-126xfdh:hover{opacity:.8}.ticket-chip.svelte-126xfdh{display:inline-flex;align-items:center;padding:1px 6px;border-radius:3px;font-size:var(--font-size-xs);font-family:var(--font-mono);font-weight:600;color:var(--text-muted);background:var(--surface);border:1px solid var(--border);white-space:nowrap;line-height:1.4}.dot.svelte-126xfdh{width:7px;height:7px;border-radius:50%;flex-shrink:0;display:inline-block}.dot-success.svelte-126xfdh{background:var(--status-success)}.dot-error.svelte-126xfdh{background:var(--status-error)}.dot-muted.svelte-126xfdh{background:var(--border)}.pr-action-pill.svelte-126xfdh{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;padding:6px 12px;min-height:32px;border-radius:20px;border:none;background:var(--pill-color, var(--border));font-size:var(--font-size-xs);font-family:var(--font-mono);color:#fff;text-decoration:none;white-space:nowrap;cursor:pointer;transition:opacity .12s}.pr-action-pill.svelte-126xfdh:hover{opacity:.85}.pr-action-pill.dark-text.svelte-126xfdh{color:#1a1a1a}.skeleton.svelte-126xfdh{pointer-events:none;min-height:56px;flex-direction:column;justify-content:center;gap:6px}.skeleton-line.svelte-126xfdh{background:var(--border);border-radius:3px;animation:svelte-126xfdh-skeleton-pulse 1.4s ease-in-out infinite}.skeleton-title.svelte-126xfdh{height:13px;width:60%}.skeleton-meta.svelte-126xfdh{height:10px;width:40%}@keyframes svelte-126xfdh-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}@media(max-width:600px){.org-dashboard.svelte-126xfdh{padding:14px}.pr-row.svelte-126xfdh{flex-direction:column;align-items:flex-start;gap:8px;padding:12px 10px}.pr-row-left.svelte-126xfdh{width:100%}.pr-row-actions.svelte-126xfdh{align-self:flex-end}.pr-action-pill.svelte-126xfdh{padding:5px 12px;min-height:32px}.filter-bar.svelte-126xfdh{flex-wrap:wrap}}.empty-state.svelte-1luen49{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;max-width:320px;text-align:center;padding:32px 16px;flex:1;margin:0 auto}.empty-icon.svelte-1luen49{font-size:2rem;line-height:1;color:var(--text-muted);opacity:.5}.empty-heading.svelte-1luen49{font-size:var(--font-size-lg);font-family:var(--font-mono);color:var(--text);font-weight:600;line-height:1.3}.empty-description.svelte-1luen49{font-size:var(--font-size-sm);font-family:var(--font-mono);color:var(--text-muted);line-height:1.5}.empty-action.svelte-1luen49{display:inline-flex;align-items:center;justify-content:center;padding:10px 18px;min-height:40px;background:transparent;border:1px solid var(--accent);border-radius:4px;color:var(--accent);font-size:var(--font-size-sm);font-family:var(--font-mono);cursor:pointer;margin-top:4px;transition:background .12s,color .12s;white-space:nowrap}.empty-action.svelte-1luen49:hover{background:color-mix(in srgb,var(--accent) 12%,transparent)}.toolbar.svelte-k7we1m{background:var(--surface);border-top:1px solid var(--border);padding:4px;padding-bottom:calc(4px + env(safe-area-inset-bottom,0px));flex-shrink:0}.toolbar-grid.svelte-k7we1m{display:grid;grid-template-columns:repeat(6,1fr);gap:4px}.tb-btn.svelte-k7we1m{background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.85rem;padding:8px 4px;cursor:pointer;touch-action:manipulation;min-height:40px;display:flex;align-items:center;justify-content:center;user-select:none;-webkit-user-select:none}.tb-btn.svelte-k7we1m:active{background:var(--border)}.tb-enter.svelte-k7we1m{background:var(--accent);border-color:var(--accent);color:#fff}.tb-enter.svelte-k7we1m:active{opacity:.8}.mobile-header.svelte-wp0i5g{display:none;align-items:center;gap:8px;padding:8px 12px;background:var(--surface);border-bottom:1px solid var(--border);min-height:44px;flex-shrink:0}@media(max-width:768px){.mobile-header.svelte-wp0i5g{display:flex}.mobile-header.hidden.svelte-wp0i5g{display:none}}.mobile-title.svelte-wp0i5g{font-size:.95rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.icon-btn.svelte-wp0i5g{background:none;border:none;color:var(--text);font-size:1.2rem;cursor:pointer;padding:6px;min-width:36px;min-height:36px;display:flex;align-items:center;justify-content:center;border-radius:6px;touch-action:manipulation}.icon-btn.svelte-wp0i5g:hover{background:var(--border)}.update-toast.svelte-1trivgv{position:fixed;bottom:0;left:0;right:0;z-index:150;display:flex;justify-content:center;padding:12px 12px calc(12px + env(safe-area-inset-bottom));pointer-events:none;animation:svelte-1trivgv-toast-slide-up .25s ease-out}@keyframes svelte-1trivgv-toast-slide-up{0%{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}.update-toast-content.svelte-1trivgv{display:flex;flex-direction:row;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:12px 16px;max-width:500px;box-shadow:0 4px 16px #0000004d;pointer-events:auto}.update-toast-text.svelte-1trivgv{flex:1;font-size:.85rem;color:var(--text)}.update-toast-actions.svelte-1trivgv{display:flex;gap:8px;flex-shrink:0}.update-toast-btn.svelte-1trivgv{padding:8px 14px;border-radius:6px;font-size:.8rem;border:none;background:var(--accent);color:#fff;cursor:pointer;white-space:nowrap}.update-toast-btn.svelte-1trivgv:disabled{opacity:.6;cursor:not-allowed}.update-toast-dismiss.svelte-1trivgv{background:none;border:none;color:var(--text-muted);font-size:1.2rem;padding:4px 6px;cursor:pointer}.update-toast-dismiss.svelte-1trivgv:hover{color:var(--text)}.image-toast.svelte-1y8sviv{position:fixed;bottom:60px;left:50%;transform:translate(-50%);z-index:1000;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:8px 14px;color:var(--text);font-size:13px;max-width:90vw;box-shadow:0 4px 12px #0006}.image-toast-content.svelte-1y8sviv{display:flex;align-items:center;gap:10px}.image-toast-text.svelte-1y8sviv{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60vw}.image-toast-actions.svelte-1y8sviv{display:flex;gap:6px;align-items:center;flex-shrink:0}.image-toast-insert.svelte-1y8sviv{background:var(--accent);color:#fff;border:none;border-radius:4px;padding:4px 10px;font-size:12px;cursor:pointer}.image-toast-insert.svelte-1y8sviv:active{opacity:.8}.image-toast-dismiss.svelte-1y8sviv{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:16px;padding:2px 6px}.image-toast-dismiss.svelte-1y8sviv:hover{color:var(--text)}.dialog.svelte-8ywkqk{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(480px,95vw);max-height:90vh;overflow:hidden}.dialog.svelte-8ywkqk::backdrop{background:#0009}.dialog-content.svelte-8ywkqk{display:flex;flex-direction:column;max-height:90vh;overflow:hidden}.dialog-title.svelte-8ywkqk{font-size:1.1rem;font-weight:600;padding:16px 20px 12px;margin:0;border-bottom:1px solid var(--border);flex-shrink:0}.dialog-title-repo.svelte-8ywkqk{font-weight:400;color:var(--text-muted);font-size:1rem}.dialog-body.svelte-8ywkqk{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:14px}.dialog-field.svelte-8ywkqk{display:flex;flex-direction:column;gap:5px}.dialog-field--inline.svelte-8ywkqk{flex-direction:row;align-items:center;gap:8px}.dialog-label.svelte-8ywkqk{font-size:.85rem;color:var(--text-muted)}.dialog-label-inline.svelte-8ywkqk{font-size:.9rem;cursor:pointer}.dialog-select.svelte-8ywkqk,.dialog-input.svelte-8ywkqk{background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.9rem;padding:7px 10px;width:100%;box-sizing:border-box}.dialog-select.svelte-8ywkqk:disabled{opacity:.5;cursor:not-allowed}.dialog-checkbox.svelte-8ywkqk{width:16px;height:16px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.dialog-footer.svelte-8ywkqk{display:flex;justify-content:flex-end;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border);flex-shrink:0}.btn.svelte-8ywkqk{padding:8px 18px;border-radius:6px;font-size:.9rem;cursor:pointer;border:1px solid transparent;font-weight:500;transition:opacity .15s}.btn.svelte-8ywkqk:disabled{opacity:.4;cursor:not-allowed}.btn-primary.svelte-8ywkqk{background:var(--accent);color:#fff}.btn-primary.svelte-8ywkqk:hover:not(:disabled){opacity:.9}.btn-ghost.svelte-8ywkqk{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-8ywkqk:hover{background:var(--border);color:var(--text)}.dialog.svelte-fdtoa4{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(460px,95vw);max-height:90vh;overflow:hidden}.dialog.svelte-fdtoa4::backdrop{background:#0009}.dialog-content.svelte-fdtoa4{display:flex;flex-direction:column;max-height:90vh;overflow:hidden}.dialog-header.svelte-fdtoa4{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid var(--border);flex-shrink:0}.dialog-title.svelte-fdtoa4{font-size:1.1rem;font-weight:600;margin:0}.close-btn.svelte-fdtoa4{background:none;border:none;color:var(--text-muted);font-size:1rem;cursor:pointer;padding:4px 6px;border-radius:4px}.close-btn.svelte-fdtoa4:hover{background:var(--border);color:var(--text)}.dialog-body.svelte-fdtoa4{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:20px}.settings-section.svelte-fdtoa4{display:flex;flex-direction:column;gap:10px}.section-title.svelte-fdtoa4{font-size:.9rem;font-weight:600;color:var(--text);margin:0}.section-desc.svelte-fdtoa4{font-size:.82rem;color:var(--text-muted);margin:0}.error-msg.svelte-fdtoa4{font-size:.82rem;color:#e74c3c;margin:0}.agent-select.svelte-fdtoa4{background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.9rem;padding:7px 10px;width:100%;box-sizing:border-box}.devtools-row.svelte-fdtoa4{display:flex;align-items:center;gap:8px}.dialog-checkbox.svelte-fdtoa4{width:16px;height:16px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.devtools-label.svelte-fdtoa4{font-size:.9rem;cursor:pointer}.dialog-footer.svelte-fdtoa4{display:flex;justify-content:flex-end;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border);flex-shrink:0}.btn.svelte-fdtoa4{padding:8px 18px;border-radius:6px;font-size:.9rem;cursor:pointer;border:1px solid transparent;font-weight:500}.btn-primary.svelte-fdtoa4{background:var(--accent);color:#fff;flex-shrink:0}.btn-primary.svelte-fdtoa4:hover{opacity:.9}.btn-ghost.svelte-fdtoa4{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-fdtoa4:hover{background:var(--border);color:var(--text)}.btn-sm.svelte-fdtoa4{padding:5px 12px;font-size:.8rem}.version-row.svelte-fdtoa4{display:flex;align-items:center;gap:10px}.version-current.svelte-fdtoa4{font-size:.9rem;font-family:monospace;color:var(--text)}.version-status.svelte-fdtoa4{font-size:.8rem;color:var(--text-muted)}.version-update-row.svelte-fdtoa4{display:flex;align-items:center;justify-content:space-between;gap:10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:8px 10px}.version-update-text.svelte-fdtoa4{font-size:.85rem;color:var(--accent)}.version-status-msg.svelte-fdtoa4{font-size:.82rem;color:var(--text-muted);margin:0}.dialog.svelte-15sco2n{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(400px,95vw);overflow:hidden}.dialog.svelte-15sco2n::backdrop{background:#0009}.dialog-content.svelte-15sco2n{display:flex;flex-direction:column}.dialog-title.svelte-15sco2n{font-size:1.1rem;font-weight:600;padding:16px 20px 12px;margin:0;border-bottom:1px solid var(--border)}.dialog-body.svelte-15sco2n{padding:16px 20px;display:flex;flex-direction:column;gap:8px}.confirm-msg.svelte-15sco2n{font-size:.95rem;margin:0;line-height:1.5}.wt-name.svelte-15sco2n{color:var(--text)}.wt-path.svelte-15sco2n{font-size:.82rem;color:var(--text-muted);font-family:monospace;margin:0;word-break:break-all}.warning-msg.svelte-15sco2n{font-size:.82rem;color:#e74c3c;margin:0}.error-msg.svelte-15sco2n{font-size:.85rem;color:#e74c3c;margin:0;padding:8px 10px;background:#e74c3c1a;border-radius:6px;border:1px solid rgba(231,76,60,.3)}.dialog-footer.svelte-15sco2n{display:flex;justify-content:flex-end;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border)}.btn.svelte-15sco2n{padding:8px 18px;border-radius:6px;font-size:.9rem;cursor:pointer;border:1px solid transparent;font-weight:500}.btn.svelte-15sco2n:disabled{opacity:.4;cursor:not-allowed}.btn-danger.svelte-15sco2n{background:#e74c3c;color:#fff}.btn-danger.svelte-15sco2n:hover:not(:disabled){opacity:.9}.btn-ghost.svelte-15sco2n{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-15sco2n:hover:not(:disabled){background:var(--border);color:var(--text)}.file-browser.svelte-15gfcbp{display:flex;flex-direction:column;gap:8px}.filter-row.svelte-15gfcbp{display:flex;gap:8px}.filter-input.svelte-15gfcbp{flex:1;background:var(--bg);border:1px solid var(--border);border-radius:0;color:var(--text);font-family:var(--font-mono);font-size:var(--font-size-sm);padding:8px 10px;outline:none}.filter-input.svelte-15gfcbp:focus{border-color:var(--accent)}.filter-input.svelte-15gfcbp::placeholder{color:var(--text-muted);opacity:.5}.tree-container.svelte-15gfcbp{background:var(--bg);border:1px solid var(--border);max-height:50vh;overflow-y:auto;outline:none}.tree-container.svelte-15gfcbp:focus-visible{border-color:var(--accent)}.loading-placeholder.svelte-15gfcbp,.empty-placeholder.svelte-15gfcbp{padding:20px 16px;color:var(--text-muted);font-family:var(--font-mono);font-size:var(--font-size-sm);text-align:center}.tree-row.svelte-15gfcbp{display:flex;align-items:center;gap:6px;padding-top:4px;padding-bottom:4px;padding-right:12px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:background .1s;min-height:32px}.tree-row.svelte-15gfcbp:hover{background:var(--border)}.tree-row.focused.svelte-15gfcbp{outline:2px solid var(--accent);outline-offset:-2px}.tree-row.selected.svelte-15gfcbp{background:color-mix(in srgb,var(--accent) 10%,transparent)}.expand-btn.svelte-15gfcbp{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px;width:18px;height:18px;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:10px;border-radius:2px}.expand-btn.svelte-15gfcbp:hover{background:var(--surface);color:var(--text)}.expand-spacer.svelte-15gfcbp{width:18px;flex-shrink:0}.arrow.svelte-15gfcbp{display:inline-block;transition:transform .15s}.arrow.expanded.svelte-15gfcbp{transform:rotate(90deg)}.spinner.svelte-15gfcbp{animation:svelte-15gfcbp-blink 1s infinite;font-size:10px}@keyframes svelte-15gfcbp-blink{0%,to{opacity:1}50%{opacity:.3}}.node-checkbox.svelte-15gfcbp{width:14px;height:14px;accent-color:var(--accent);cursor:pointer;flex-shrink:0;margin:0}.node-name.svelte-15gfcbp{font-family:var(--font-mono);font-size:var(--font-size-sm);color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.git-badge.svelte-15gfcbp{font-family:var(--font-mono);font-size:10px;color:var(--accent);background:color-mix(in srgb,var(--accent) 15%,transparent);padding:1px 5px;border-radius:3px;flex-shrink:0;text-transform:lowercase}.truncated-notice.svelte-15gfcbp{padding:8px 12px;font-family:var(--font-mono);font-size:11px;color:var(--text-muted);border-top:1px solid var(--border);text-align:center}.dialog.svelte-4yj2yx{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:0;width:min(520px,95vw);max-height:85vh;overflow:hidden}.dialog.svelte-4yj2yx::backdrop{background:#000000b3}.dialog-content.svelte-4yj2yx{display:flex;flex-direction:column;max-height:85vh}.dialog-header.svelte-4yj2yx{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid var(--border);flex-shrink:0}.dialog-title.svelte-4yj2yx{font-size:var(--font-size-lg, 1.1rem);font-weight:600;font-family:var(--font-mono, monospace);margin:0}.close-btn.svelte-4yj2yx{background:none;border:none;color:var(--text-muted);font-size:1rem;cursor:pointer;padding:4px 6px;border-radius:4px}.close-btn.svelte-4yj2yx:hover{background:var(--border);color:var(--text)}.dialog-body.svelte-4yj2yx{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:12px}.dialog-desc.svelte-4yj2yx{font-size:var(--font-size-sm, .85rem);color:var(--text-muted);font-family:var(--font-mono, monospace);margin:0;line-height:1.5}.error-msg.svelte-4yj2yx{font-size:var(--font-size-xs, .75rem);color:var(--status-error, #e57373);font-family:var(--font-mono, monospace);margin:0}.dialog-footer.svelte-4yj2yx{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border);flex-shrink:0}.selected-count.svelte-4yj2yx{font-size:var(--font-size-sm, .85rem);color:var(--text-muted);font-family:var(--font-mono, monospace)}.footer-actions.svelte-4yj2yx{display:flex;gap:10px}.btn.svelte-4yj2yx{padding:8px 18px;border-radius:0;font-size:var(--font-size-sm, .85rem);font-family:var(--font-mono, monospace);cursor:pointer;border:1px solid transparent;font-weight:500}.btn.svelte-4yj2yx:disabled{opacity:.5;cursor:not-allowed}.btn-primary.svelte-4yj2yx{background:var(--accent);color:#fff}.btn-primary.svelte-4yj2yx:hover:not(:disabled){opacity:.9}.btn-ghost.svelte-4yj2yx{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-4yj2yx:hover{background:var(--border);color:var(--text)}.dialog.svelte-1n78dcx{background:var(--surface);color:var(--text);border:1px solid var(--border);border-radius:10px;padding:0;width:min(480px,95vw);max-height:90vh;overflow:hidden}.dialog.svelte-1n78dcx::backdrop{background:#0009}.dialog-content.svelte-1n78dcx{display:flex;flex-direction:column;max-height:90vh;overflow:hidden}.dialog-header.svelte-1n78dcx{display:flex;align-items:center;justify-content:space-between;padding:16px 20px 12px;border-bottom:1px solid var(--border);flex-shrink:0;gap:8px}.dialog-title.svelte-1n78dcx{font-size:1.05rem;font-weight:600;margin:0;display:flex;align-items:center;gap:8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.gear-icon.svelte-1n78dcx{flex-shrink:0;color:var(--text-muted);font-size:1rem}.close-btn.svelte-1n78dcx{background:none;border:none;color:var(--text-muted);font-size:1rem;cursor:pointer;padding:4px 6px;border-radius:4px;flex-shrink:0;line-height:1}.close-btn.svelte-1n78dcx:hover{background:var(--border);color:var(--text)}.dialog-body.svelte-1n78dcx{padding:16px 20px;overflow-y:auto;flex:1;display:flex;flex-direction:column;gap:16px}.settings-section.svelte-1n78dcx{display:flex;flex-direction:column;gap:10px}.section-label.svelte-1n78dcx{font-size:var(--font-size-xs, .72rem);font-weight:600;color:var(--text-muted);letter-spacing:.08em;margin:0 0 2px;text-transform:uppercase}.field-group.svelte-1n78dcx{display:flex;flex-direction:column;gap:4px}.field-label.svelte-1n78dcx{font-size:.82rem;color:var(--text-muted)}.field-input.svelte-1n78dcx{background:var(--bg);border:1px solid var(--border);border-radius:0;color:var(--text);font-family:var(--font-mono, monospace);font-size:.88rem;padding:6px 9px;width:100%;box-sizing:border-box;outline:none}.field-input.svelte-1n78dcx:focus{border-color:var(--accent)}.field-select.svelte-1n78dcx{background:var(--bg);border:1px solid var(--border);border-radius:0;color:var(--text);font-family:var(--font-mono, monospace);font-size:.88rem;padding:6px 9px;width:100%;box-sizing:border-box;cursor:pointer;outline:none}.field-select.svelte-1n78dcx:focus{border-color:var(--accent)}.inline-row.svelte-1n78dcx{display:flex;align-items:center;gap:10px}.inline-row.svelte-1n78dcx .field-label:where(.svelte-1n78dcx){flex-shrink:0}.field-select-inline.svelte-1n78dcx{width:auto;flex:1;max-width:160px}.checkbox-row.svelte-1n78dcx{display:flex;align-items:center;gap:16px;flex-wrap:wrap}.checkbox-label.svelte-1n78dcx{display:flex;align-items:center;gap:6px;font-size:.88rem;cursor:pointer;-webkit-user-select:none;user-select:none}.dialog-checkbox.svelte-1n78dcx{width:15px;height:15px;accent-color:var(--accent);cursor:pointer;flex-shrink:0}.divider.svelte-1n78dcx{height:1px;background:var(--border);margin:0 -20px}.prompt-group.svelte-1n78dcx{display:flex;flex-direction:column;gap:6px}.prompt-toggle.svelte-1n78dcx{background:none;border:none;color:var(--text);font-size:.88rem;cursor:pointer;padding:4px 0;text-align:left;display:flex;align-items:center;gap:6px;width:100%}.prompt-toggle.svelte-1n78dcx:hover{color:var(--accent)}.prompt-arrow.svelte-1n78dcx{color:var(--text-muted);font-size:.8rem;flex-shrink:0;width:10px}.prompt-textarea.svelte-1n78dcx{background:var(--bg);border:1px solid var(--border);border-radius:0;color:var(--text);font-family:var(--font-mono, monospace);font-size:.82rem;padding:8px 10px;width:100%;box-sizing:border-box;resize:vertical;line-height:1.5;outline:none}.prompt-textarea.svelte-1n78dcx:focus{border-color:var(--accent)}.error-msg.svelte-1n78dcx{font-size:.82rem;color:#e74c3c;margin:0;padding:6px 10px;background:#e74c3c14;border:1px solid rgba(231,76,60,.25)}.dialog-footer.svelte-1n78dcx{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 20px 16px;border-top:1px solid var(--border);flex-shrink:0}.footer-right.svelte-1n78dcx{display:flex;align-items:center;gap:10px}.save-success.svelte-1n78dcx{font-size:.82rem;color:var(--accent)}.btn.svelte-1n78dcx{padding:7px 16px;border-radius:4px;font-size:.88rem;cursor:pointer;border:1px solid transparent;font-weight:500;line-height:1.4}.btn.svelte-1n78dcx:disabled{opacity:.6;cursor:not-allowed}.btn-primary.svelte-1n78dcx{background:var(--accent);color:#fff;border-color:var(--accent)}.btn-primary.svelte-1n78dcx:hover:not(:disabled){opacity:.88}.btn-danger.svelte-1n78dcx{background:transparent;color:#c0392b;border-color:#c0392b66}.btn-danger.svelte-1n78dcx:hover{background:#c0392b1a;border-color:#c0392b}.btn-ghost.svelte-1n78dcx{background:transparent;color:var(--text-muted);border-color:var(--border)}.btn-ghost.svelte-1n78dcx:hover:not(:disabled){background:var(--border);color:var(--text)}.override-badge.svelte-1n78dcx{font-size:.68rem;font-weight:400;color:var(--accent);letter-spacing:0;text-transform:none;margin-left:6px}.main-app.svelte-13zv0lp{display:flex;flex-direction:row;width:100%;height:100vh;height:100dvh;overflow:hidden}.sidebar-overlay.svelte-13zv0lp{display:none}.terminal-area.svelte-13zv0lp{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden;position:relative}@media(max-width:600px){.main-app.svelte-13zv0lp{position:fixed;top:0;right:0;bottom:0;left:0;width:100%}.sidebar-overlay.svelte-13zv0lp{display:block;position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;z-index:99}.terminal-area.svelte-13zv0lp{width:100%}}:root{--bg: #000000;--surface: #0a0a0a;--surface-hover: #141414;--accent: #d97757;--text: #e0e0e0;--text-muted: #888888;--border: #333333;--status-success: #4ade80;--status-error: #f87171;--status-warning: #fbbf24;--status-merged: #a78bfa;--status-info: #60a5fa;--font-mono: "SF Mono", "Cascadia Code", "JetBrains Mono", "Fira Code", "Consolas", monospace;--font-size-xs: .75rem;--font-size-sm: .8125rem;--font-size-base: .875rem;--font-size-lg: 1rem;--sidebar-width: 240px;--toolbar-height: auto}[hidden]{display:none!important}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}dialog{margin:auto}html,body{height:100%;overflow:hidden;overscroll-behavior:none;background:var(--bg);color:var(--text);font-family:var(--font-mono);font-size:var(--font-size-base);color-scheme:dark}:focus-visible{outline:2px solid var(--accent);outline-offset:2px}::-webkit-scrollbar{width:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}
|
package/dist/frontend/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
12
12
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
13
13
|
<meta name="theme-color" content="#1a1a1a" />
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-B7wmLeyf.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BTOnhJQN.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="app"></div>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
import { loadConfig } from './config.js';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
const GIT_TIMEOUT_MS = 10_000;
|
|
8
|
+
const CACHE_TTL_MS = 60_000;
|
|
9
|
+
let cache = null;
|
|
10
|
+
/** Clears the branch linker cache (call when sessions are created or ended). */
|
|
11
|
+
export function invalidateBranchLinkerCache() {
|
|
12
|
+
cache = null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extracts all ticket IDs from a branch name.
|
|
16
|
+
* Returns an array of normalized ticket IDs (e.g. "PROJ-123", "GH-456").
|
|
17
|
+
*/
|
|
18
|
+
function extractTicketIds(branchName) {
|
|
19
|
+
const ids = [];
|
|
20
|
+
// Jira style: PROJECT-123 (2+ uppercase letters, dash, digits)
|
|
21
|
+
// Skip "GH" prefix — that's our GitHub Issues namespace, handled separately below.
|
|
22
|
+
const jiraRegex = /([A-Z]{2,}-\d+)/gi;
|
|
23
|
+
let match;
|
|
24
|
+
while ((match = jiraRegex.exec(branchName)) !== null) {
|
|
25
|
+
if (match[1] && match[1].toUpperCase().split('-')[0] !== 'GH') {
|
|
26
|
+
ids.push(match[1].toUpperCase());
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// GitHub Issues: gh-123 at word boundaries (start/end or preceded/followed by dash or slash)
|
|
30
|
+
const ghRegex = /(?:^|[-/])gh-(\d+)(?:[-/]|$)/gi;
|
|
31
|
+
while ((match = ghRegex.exec(branchName)) !== null) {
|
|
32
|
+
ids.push(`GH-${match[1]}`);
|
|
33
|
+
}
|
|
34
|
+
return ids;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates and returns an Express Router that handles all /branch-linker routes.
|
|
38
|
+
*
|
|
39
|
+
* Caller is responsible for mounting and applying auth middleware:
|
|
40
|
+
* app.use('/branch-linker', requireAuth, createBranchLinkerRouter({ configPath }));
|
|
41
|
+
*/
|
|
42
|
+
export function createBranchLinkerRouter(deps) {
|
|
43
|
+
const { configPath } = deps;
|
|
44
|
+
const exec = deps.execAsync ?? execFileAsync;
|
|
45
|
+
const getActiveBranchNames = deps.getActiveBranchNames ?? (() => new Map());
|
|
46
|
+
const router = Router();
|
|
47
|
+
function getConfig() {
|
|
48
|
+
return loadConfig(configPath);
|
|
49
|
+
}
|
|
50
|
+
/** Core link-building logic, usable both from the HTTP handler and internal callers. */
|
|
51
|
+
async function fetchLinks() {
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
const workspacePaths = config.workspaces ?? [];
|
|
54
|
+
if (workspacePaths.length === 0) {
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
// Return cached result if still fresh
|
|
59
|
+
if (cache && now - cache.fetchedAt < CACHE_TTL_MS) {
|
|
60
|
+
return cache.links;
|
|
61
|
+
}
|
|
62
|
+
// Get active branch names per repo from sessions
|
|
63
|
+
const activeBranchNames = getActiveBranchNames();
|
|
64
|
+
// Fetch branches per workspace using Promise.allSettled (partial failures are non-fatal)
|
|
65
|
+
const results = await Promise.allSettled(workspacePaths.map(async (wsPath) => {
|
|
66
|
+
let stdout;
|
|
67
|
+
try {
|
|
68
|
+
({ stdout } = await exec('git', ['branch', '--format=%(refname:short)'], { cwd: wsPath, timeout: GIT_TIMEOUT_MS }));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Not a git repo or git not available — non-fatal
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const repoName = path.basename(wsPath);
|
|
75
|
+
const activeInRepo = activeBranchNames.get(wsPath) ?? new Set();
|
|
76
|
+
const branchNames = stdout.split('\n').map((b) => b.trim()).filter(Boolean);
|
|
77
|
+
const links = [];
|
|
78
|
+
for (const branchName of branchNames) {
|
|
79
|
+
const ticketIds = extractTicketIds(branchName);
|
|
80
|
+
for (const ticketId of ticketIds) {
|
|
81
|
+
// Infer ticket source from ID pattern
|
|
82
|
+
let source;
|
|
83
|
+
if (ticketId.startsWith('GH-')) {
|
|
84
|
+
source = 'github';
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Non-GH ticket IDs (e.g., PROJ-123) assumed to be Jira
|
|
88
|
+
source = 'jira';
|
|
89
|
+
}
|
|
90
|
+
links.push({
|
|
91
|
+
ticketId,
|
|
92
|
+
link: {
|
|
93
|
+
repoPath: wsPath,
|
|
94
|
+
repoName,
|
|
95
|
+
branchName,
|
|
96
|
+
hasActiveSession: activeInRepo.has(branchName),
|
|
97
|
+
source,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return links;
|
|
103
|
+
}));
|
|
104
|
+
// Build the ticket -> BranchLink[] map
|
|
105
|
+
const linksMap = new Map();
|
|
106
|
+
for (const result of results) {
|
|
107
|
+
if (result.status === 'fulfilled') {
|
|
108
|
+
for (const { ticketId, link } of result.value) {
|
|
109
|
+
const existing = linksMap.get(ticketId);
|
|
110
|
+
if (existing) {
|
|
111
|
+
existing.push(link);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
linksMap.set(ticketId, [link]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Convert Map to plain object for JSON serialization
|
|
120
|
+
const response = {};
|
|
121
|
+
for (const [ticketId, links] of linksMap) {
|
|
122
|
+
response[ticketId] = links;
|
|
123
|
+
}
|
|
124
|
+
// Update module-level cache
|
|
125
|
+
cache = { links: response, fetchedAt: now };
|
|
126
|
+
return response;
|
|
127
|
+
}
|
|
128
|
+
// GET /branch-linker/links — map of ticketId -> BranchLink[]
|
|
129
|
+
router.get('/links', async (_req, res) => {
|
|
130
|
+
const response = await fetchLinks();
|
|
131
|
+
res.json(response);
|
|
132
|
+
});
|
|
133
|
+
return Object.assign(router, { fetchLinks });
|
|
134
|
+
}
|
package/dist/server/config.js
CHANGED
|
@@ -21,7 +21,37 @@ export function loadConfig(configPath) {
|
|
|
21
21
|
}
|
|
22
22
|
const raw = fs.readFileSync(configPath, 'utf8');
|
|
23
23
|
const parsed = JSON.parse(raw);
|
|
24
|
-
|
|
24
|
+
const config = { ...DEFAULTS, ...parsed };
|
|
25
|
+
// Validate and clean workspaceGroups
|
|
26
|
+
if (config.workspaceGroups != null) {
|
|
27
|
+
const validPaths = new Set(config.workspaces ?? []);
|
|
28
|
+
const seenPaths = new Set();
|
|
29
|
+
const cleaned = {};
|
|
30
|
+
for (const [groupName, paths] of Object.entries(config.workspaceGroups)) {
|
|
31
|
+
if (!Array.isArray(paths)) {
|
|
32
|
+
console.warn(`workspaceGroups: group "${groupName}" value is not an array, skipping`);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const filteredPaths = [];
|
|
36
|
+
for (const p of paths) {
|
|
37
|
+
if (!validPaths.has(p)) {
|
|
38
|
+
console.warn(`workspaceGroups: path "${p}" in group "${groupName}" is not in workspaces[], skipping`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (seenPaths.has(p)) {
|
|
42
|
+
console.warn(`workspaceGroups: path "${p}" in group "${groupName}" is already assigned to another group, skipping`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
seenPaths.add(p);
|
|
46
|
+
filteredPaths.push(p);
|
|
47
|
+
}
|
|
48
|
+
if (filteredPaths.length > 0) {
|
|
49
|
+
cleaned[groupName] = filteredPaths;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
config.workspaceGroups = cleaned;
|
|
53
|
+
}
|
|
54
|
+
return config;
|
|
25
55
|
}
|
|
26
56
|
export function saveConfig(configPath, config) {
|
|
27
57
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
package/dist/server/index.js
CHANGED
|
@@ -20,7 +20,13 @@ import { listBranches, isBranchStale } from './git.js';
|
|
|
20
20
|
import * as push from './push.js';
|
|
21
21
|
import { initAnalytics, closeAnalytics, createAnalyticsRouter } from './analytics.js';
|
|
22
22
|
import { createWorkspaceRouter } from './workspaces.js';
|
|
23
|
+
import { createOrgDashboardRouter } from './org-dashboard.js';
|
|
24
|
+
import { createIntegrationGitHubRouter } from './integration-github.js';
|
|
25
|
+
import { createBranchLinkerRouter, invalidateBranchLinkerCache } from './branch-linker.js';
|
|
23
26
|
import { createHooksRouter } from './hooks.js';
|
|
27
|
+
import { createTicketTransitionsRouter } from './ticket-transitions.js';
|
|
28
|
+
import { createIntegrationJiraRouter } from './integration-jira.js';
|
|
29
|
+
import { startPolling, stopPolling } from './review-poller.js';
|
|
24
30
|
import { MOUNTAIN_NAMES } from './types.js';
|
|
25
31
|
import { semverLessThan } from './utils.js';
|
|
26
32
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -269,6 +275,42 @@ async function main() {
|
|
|
269
275
|
// Mount workspace router
|
|
270
276
|
const workspaceRouter = createWorkspaceRouter({ configPath: CONFIG_PATH });
|
|
271
277
|
app.use('/workspaces', requireAuth, workspaceRouter);
|
|
278
|
+
// Mount GitHub integration router
|
|
279
|
+
const integrationGitHubRouter = createIntegrationGitHubRouter({ configPath: CONFIG_PATH });
|
|
280
|
+
app.use('/integration-github', requireAuth, integrationGitHubRouter);
|
|
281
|
+
// Mount Jira integration router
|
|
282
|
+
const integrationJiraRouter = createIntegrationJiraRouter({ configPath: CONFIG_PATH });
|
|
283
|
+
app.use('/integration-jira', requireAuth, integrationJiraRouter);
|
|
284
|
+
// Mount branch linker router
|
|
285
|
+
const branchLinkerRouter = createBranchLinkerRouter({
|
|
286
|
+
configPath: CONFIG_PATH,
|
|
287
|
+
getActiveBranchNames: () => {
|
|
288
|
+
const workspaces = config.workspaces ?? [];
|
|
289
|
+
const map = new Map();
|
|
290
|
+
for (const s of sessions.list()) {
|
|
291
|
+
if (!s.branchName)
|
|
292
|
+
continue;
|
|
293
|
+
// Normalize: match session repoPath to workspace root
|
|
294
|
+
// (worktree sessions store the worktree path, not workspace root)
|
|
295
|
+
const wsRoot = workspaces.find((ws) => s.repoPath.startsWith(ws)) ?? s.repoPath;
|
|
296
|
+
const existing = map.get(wsRoot);
|
|
297
|
+
if (existing) {
|
|
298
|
+
existing.add(s.branchName);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
map.set(wsRoot, new Set([s.branchName]));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return map;
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
app.use('/branch-linker', requireAuth, branchLinkerRouter);
|
|
308
|
+
// Mount ticket transitions router
|
|
309
|
+
const { router: ticketTransitionsRouter, transitionOnSessionCreate, checkPrTransitions } = createTicketTransitionsRouter({ configPath: CONFIG_PATH });
|
|
310
|
+
app.use('/ticket-transitions', requireAuth, ticketTransitionsRouter);
|
|
311
|
+
// Mount org dashboard router — use branchLinkerRouter.fetchLinks() directly (no loopback HTTP)
|
|
312
|
+
const orgDashboardRouter = createOrgDashboardRouter({ configPath: CONFIG_PATH, checkPrTransitions, getBranchLinks: () => branchLinkerRouter.fetchLinks() });
|
|
313
|
+
app.use('/org-dashboard', requireAuth, orgDashboardRouter);
|
|
272
314
|
// Mount analytics router
|
|
273
315
|
app.use('/analytics', requireAuth, createAnalyticsRouter(configDir));
|
|
274
316
|
// Restore sessions from a previous update restart
|
|
@@ -278,6 +320,45 @@ async function main() {
|
|
|
278
320
|
}
|
|
279
321
|
// Populate session metadata cache in background (non-blocking)
|
|
280
322
|
populateMetaCache().catch(() => { });
|
|
323
|
+
// Build shared deps for review poller
|
|
324
|
+
function buildPollerDeps() {
|
|
325
|
+
return {
|
|
326
|
+
configPath: CONFIG_PATH,
|
|
327
|
+
getWorkspacePaths: () => config.workspaces ?? [],
|
|
328
|
+
getWorkspaceSettings: (wsPath) => config.workspaceSettings?.[wsPath],
|
|
329
|
+
createSession: async (opts) => {
|
|
330
|
+
const resolved = resolveSessionSettings(config, opts.repoPath, {});
|
|
331
|
+
const roots = config.rootDirs || [];
|
|
332
|
+
const root = roots.find((r) => opts.repoPath.startsWith(r)) || '';
|
|
333
|
+
const repoName = opts.repoPath.split('/').filter(Boolean).pop() || 'session';
|
|
334
|
+
const worktreeName = opts.worktreePath.split('/').pop() || '';
|
|
335
|
+
const displayName = sessions.nextAgentName();
|
|
336
|
+
sessions.create({
|
|
337
|
+
type: 'worktree',
|
|
338
|
+
agent: resolved.agent,
|
|
339
|
+
repoName,
|
|
340
|
+
repoPath: opts.worktreePath,
|
|
341
|
+
cwd: opts.worktreePath,
|
|
342
|
+
root,
|
|
343
|
+
worktreeName,
|
|
344
|
+
branchName: opts.branchName,
|
|
345
|
+
displayName,
|
|
346
|
+
args: [...resolved.claudeArgs, ...(resolved.yolo ? AGENT_YOLO_ARGS[resolved.agent] : [])],
|
|
347
|
+
configPath: CONFIG_PATH,
|
|
348
|
+
useTmux: resolved.useTmux,
|
|
349
|
+
...(opts.initialPrompt != null && { initialPrompt: opts.initialPrompt }),
|
|
350
|
+
});
|
|
351
|
+
},
|
|
352
|
+
broadcastEvent,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
// Start review request poller if enabled
|
|
356
|
+
if (config.automations?.autoCheckoutReviewRequests) {
|
|
357
|
+
startPolling(buildPollerDeps());
|
|
358
|
+
}
|
|
359
|
+
// Invalidate branch linker cache on session lifecycle changes
|
|
360
|
+
sessions.onSessionCreate(() => { invalidateBranchLinkerCache(); });
|
|
361
|
+
sessions.onSessionEnd(() => { invalidateBranchLinkerCache(); });
|
|
281
362
|
// Push notifications on session idle (skip when hooks already sent attention notification)
|
|
282
363
|
sessions.onIdleChange((sessionId, idle) => {
|
|
283
364
|
if (idle) {
|
|
@@ -509,6 +590,50 @@ async function main() {
|
|
|
509
590
|
await execFileAsync('tmux', ['-V']);
|
|
510
591
|
});
|
|
511
592
|
boolConfigEndpoints('defaultNotifications', true);
|
|
593
|
+
// GET /config/automations — get automation settings
|
|
594
|
+
app.get('/config/automations', requireAuth, (_req, res) => {
|
|
595
|
+
res.json(config.automations ?? {});
|
|
596
|
+
});
|
|
597
|
+
// PATCH /config/automations — update automation settings and start/stop poller
|
|
598
|
+
app.patch('/config/automations', requireAuth, (req, res) => {
|
|
599
|
+
const body = req.body;
|
|
600
|
+
const prev = config.automations ?? {};
|
|
601
|
+
const next = { ...prev };
|
|
602
|
+
if (typeof body.autoCheckoutReviewRequests === 'boolean') {
|
|
603
|
+
next.autoCheckoutReviewRequests = body.autoCheckoutReviewRequests;
|
|
604
|
+
}
|
|
605
|
+
if (typeof body.autoReviewOnCheckout === 'boolean') {
|
|
606
|
+
next.autoReviewOnCheckout = body.autoReviewOnCheckout;
|
|
607
|
+
}
|
|
608
|
+
if (typeof body.pollIntervalMs === 'number' && body.pollIntervalMs >= 60000) {
|
|
609
|
+
next.pollIntervalMs = body.pollIntervalMs;
|
|
610
|
+
}
|
|
611
|
+
// Enforce: auto-review requires auto-checkout
|
|
612
|
+
if (!next.autoCheckoutReviewRequests) {
|
|
613
|
+
next.autoReviewOnCheckout = false;
|
|
614
|
+
}
|
|
615
|
+
config.automations = next;
|
|
616
|
+
try {
|
|
617
|
+
saveConfig(CONFIG_PATH, config);
|
|
618
|
+
}
|
|
619
|
+
catch (err) {
|
|
620
|
+
config.automations = prev;
|
|
621
|
+
console.error('[config] Failed to save automation settings:', err);
|
|
622
|
+
res.status(500).json({ error: 'Failed to save settings' });
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
// Start or stop poller based on new setting
|
|
626
|
+
void stopPolling().then(() => {
|
|
627
|
+
if (next.autoCheckoutReviewRequests) {
|
|
628
|
+
startPolling(buildPollerDeps());
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
res.json(next);
|
|
632
|
+
});
|
|
633
|
+
// GET /config/workspace-groups — return workspace group configuration
|
|
634
|
+
app.get('/config/workspace-groups', requireAuth, (_req, res) => {
|
|
635
|
+
res.json({ groups: config.workspaceGroups ?? {} });
|
|
636
|
+
});
|
|
512
637
|
// GET /push/vapid-key
|
|
513
638
|
app.get('/push/vapid-key', requireAuth, (_req, res) => {
|
|
514
639
|
const key = push.getVapidPublicKey();
|
|
@@ -606,7 +731,7 @@ async function main() {
|
|
|
606
731
|
});
|
|
607
732
|
// POST /sessions
|
|
608
733
|
app.post('/sessions', requireAuth, async (req, res) => {
|
|
609
|
-
const { repoPath, repoName, worktreePath, branchName, claudeArgs, yolo, agent, useTmux, cols, rows, needsBranchRename, branchRenamePrompt } = req.body;
|
|
734
|
+
const { repoPath, repoName, worktreePath, branchName, claudeArgs, yolo, agent, useTmux, cols, rows, needsBranchRename, branchRenamePrompt, ticketContext } = req.body;
|
|
610
735
|
if (!repoPath) {
|
|
611
736
|
res.status(400).json({ error: 'repoPath is required' });
|
|
612
737
|
return;
|
|
@@ -617,6 +742,46 @@ async function main() {
|
|
|
617
742
|
const resolved = resolveSessionSettings(config, repoPath, { agent, yolo, useTmux, claudeArgs });
|
|
618
743
|
const resolvedAgent = resolved.agent;
|
|
619
744
|
const name = repoName || repoPath.split('/').filter(Boolean).pop() || 'session';
|
|
745
|
+
let initialPrompt;
|
|
746
|
+
if (ticketContext && (typeof ticketContext.ticketId !== 'string' || typeof ticketContext.title !== 'string' || typeof ticketContext.url !== 'string')) {
|
|
747
|
+
res.status(400).json({ error: 'ticketContext requires string ticketId, title, and url' });
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
if (ticketContext) {
|
|
751
|
+
// Validate source is a known integration
|
|
752
|
+
if (ticketContext.source !== 'github' && ticketContext.source !== 'jira') {
|
|
753
|
+
res.status(400).json({ error: "ticketContext.source must be 'github' or 'jira'" });
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
// Validate repoPath is a configured workspace
|
|
757
|
+
const configuredWorkspaces = config.workspaces || [];
|
|
758
|
+
if (!configuredWorkspaces.includes(ticketContext.repoPath)) {
|
|
759
|
+
res.status(400).json({ error: 'ticketContext.repoPath is not a configured workspace' });
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
// Jira integration is configured via acli CLI — no env var check needed.
|
|
763
|
+
// Auth validation happens when acli commands are actually called.
|
|
764
|
+
// Validate ticket ID format per source
|
|
765
|
+
if (ticketContext.source === 'github' && !/^GH-\d+$/.test(ticketContext.ticketId)) {
|
|
766
|
+
res.status(400).json({ error: 'ticketContext.ticketId for github must match GH-<number>' });
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
if (ticketContext.source === 'jira' && !/^[A-Z][A-Z0-9]*-\d+$/.test(ticketContext.ticketId)) {
|
|
770
|
+
res.status(400).json({ error: 'ticketContext.ticketId must match <PROJECT>-<number>' });
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (ticketContext) {
|
|
775
|
+
// Use ticketContext.repoPath (workspace root) for settings lookup
|
|
776
|
+
const settings = config.workspaceSettings?.[ticketContext.repoPath];
|
|
777
|
+
const template = settings?.promptStartWork ??
|
|
778
|
+
'You are working on ticket {ticketId}: {title}\n\nTicket URL: {ticketUrl}\n\nPlease start by understanding the issue and proposing an approach.';
|
|
779
|
+
initialPrompt = template
|
|
780
|
+
.replace(/\{ticketId\}/g, ticketContext.ticketId)
|
|
781
|
+
.replace(/\{title\}/g, ticketContext.title)
|
|
782
|
+
.replace(/\{ticketUrl\}/g, ticketContext.url)
|
|
783
|
+
.replace(/\{description\}/g, ticketContext.description ?? '');
|
|
784
|
+
}
|
|
620
785
|
const baseArgs = [
|
|
621
786
|
...(resolved.claudeArgs),
|
|
622
787
|
...(resolved.yolo ? AGENT_YOLO_ARGS[resolvedAgent] : []),
|
|
@@ -728,7 +893,13 @@ async function main() {
|
|
|
728
893
|
useTmux: resolved.useTmux,
|
|
729
894
|
...(safeCols != null && { cols: safeCols }),
|
|
730
895
|
...(safeRows != null && { rows: safeRows }),
|
|
896
|
+
...(initialPrompt != null && { initialPrompt }),
|
|
731
897
|
});
|
|
898
|
+
if (ticketContext) {
|
|
899
|
+
transitionOnSessionCreate(ticketContext).catch((err) => {
|
|
900
|
+
console.error('[index] transition on session create failed:', err);
|
|
901
|
+
});
|
|
902
|
+
}
|
|
732
903
|
res.status(201).json(repoSession);
|
|
733
904
|
return;
|
|
734
905
|
}
|
|
@@ -754,6 +925,7 @@ async function main() {
|
|
|
754
925
|
useTmux: resolved.useTmux,
|
|
755
926
|
...(safeCols != null && { cols: safeCols }),
|
|
756
927
|
...(safeRows != null && { rows: safeRows }),
|
|
928
|
+
...(initialPrompt != null && { initialPrompt }),
|
|
757
929
|
});
|
|
758
930
|
writeMeta(CONFIG_PATH, {
|
|
759
931
|
worktreePath: sessionRepoPath,
|
|
@@ -761,6 +933,11 @@ async function main() {
|
|
|
761
933
|
lastActivity: new Date().toISOString(),
|
|
762
934
|
branchName: branchName || worktreeName,
|
|
763
935
|
});
|
|
936
|
+
if (ticketContext) {
|
|
937
|
+
transitionOnSessionCreate(ticketContext).catch((err) => {
|
|
938
|
+
console.error('[index] transition on session create failed:', err);
|
|
939
|
+
});
|
|
940
|
+
}
|
|
764
941
|
res.status(201).json(session);
|
|
765
942
|
return;
|
|
766
943
|
}
|
|
@@ -801,6 +978,7 @@ async function main() {
|
|
|
801
978
|
...(safeRows != null && { rows: safeRows }),
|
|
802
979
|
needsBranchRename: isMountainName || (needsBranchRename ?? false),
|
|
803
980
|
branchRenamePrompt: branchRenamePrompt ?? '',
|
|
981
|
+
...(initialPrompt != null && { initialPrompt }),
|
|
804
982
|
});
|
|
805
983
|
if (!worktreePath) {
|
|
806
984
|
writeMeta(CONFIG_PATH, {
|
|
@@ -810,6 +988,11 @@ async function main() {
|
|
|
810
988
|
branchName: branchName || worktreeName,
|
|
811
989
|
});
|
|
812
990
|
}
|
|
991
|
+
if (ticketContext) {
|
|
992
|
+
transitionOnSessionCreate(ticketContext).catch((err) => {
|
|
993
|
+
console.error('[index] transition on session create failed:', err);
|
|
994
|
+
});
|
|
995
|
+
}
|
|
813
996
|
res.status(201).json(session);
|
|
814
997
|
});
|
|
815
998
|
// POST /sessions/repo — start a session in the repo root (no worktree)
|
|
@@ -999,7 +1182,8 @@ async function main() {
|
|
|
999
1182
|
catch {
|
|
1000
1183
|
// tmux not installed or no sessions — ignore
|
|
1001
1184
|
}
|
|
1002
|
-
function gracefulShutdown() {
|
|
1185
|
+
async function gracefulShutdown() {
|
|
1186
|
+
await stopPolling();
|
|
1003
1187
|
closeAnalytics();
|
|
1004
1188
|
branchWatcher.close();
|
|
1005
1189
|
server.close();
|